Theme Catppuccin
Make yourself at homeCatppuccin

A softer light for long learning sessions.

Appearance

Loading your preference…

Dark palette

Choose a dark palette to try it.

Light uses Latte. Your choices stay in this browser.

Back to your source shelf

Inside the companion

Light Transport

Build a diffuse CPU path renderer and inspect its sampling, geometry, and tests.

Project files 11

Describe the diffuse renderer

The scene, image, and bounded rendering interfaces for the diffuse study.

57 lines diffuse.hpp
#pragma once
#include "lantern.hpp"
#include <array>
#include <cstddef>
#include <cstdint>
#include <expected>
#include <filesystem>
#include <optional>
#include <span>
#include <vector>

namespace lantern {
// A small, explicit RGB transport model: two-sided Lambertian spheres and
// two-sided surface emission, constant environment, no light sampling or MIS.
struct Surface { Sphere sphere; Vec3 reflectance; Vec3 emission; };
struct Frame { Vec3 tangent, bitangent, normal; };
[[nodiscard]] std::expected<Frame, Error> frame_from_normal(Vec3 normal);
[[nodiscard]] Vec3 to_world(const Frame& frame, Vec3 local) noexcept;

enum class PathEnd { environment, depth_limit, absorbed };
struct PathStep {
    std::optional<std::uint32_t> object;
    Vec3 point{}, normal{}, local_direction{};
    double pdf{}, cosine{};
    Vec3 throughput{1,1,1}, radiance{};
};
struct PathTrace {
    Vec3 radiance{};
    PathEnd end{};
    std::size_t count{};
    std::array<PathStep,9> steps{}; // At most eight scatters plus the terminal visit.
};

class DiffuseScene {
public:
    [[nodiscard]] static std::expected<DiffuseScene, Error>
    build(std::span<const Surface> surfaces, Vec3 environment);
    // max_bounces counts scattered rays, not visits. At the terminal visit,
    // emission or the environment is still accumulated before stopping.
    [[nodiscard]] std::expected<PathTrace, Error>
    trace(Ray ray, Rng& rng, unsigned max_bounces) const;
private:
    std::vector<Surface> surfaces_;
    SceneIndex index_;
    Vec3 environment_{};
};
struct Image { std::size_t width{}, height{}; std::vector<Vec3> linear; };
struct RenderSettings {
    std::size_t width{96}, height{64}, samples{32};
    unsigned max_bounces{4};
    std::uint64_t seed{47};
};
[[nodiscard]] std::expected<DiffuseScene, Error> study_scene();
[[nodiscard]] std::expected<Image, Error> render_diffuse(const DiffuseScene&, RenderSettings);
[[nodiscard]] std::expected<void, Error> write_ppm(const Image&, const std::filesystem::path&);
} // namespace lantern

This is the file included with the course. Copy and download give you its complete source.

Taking your work offline? Download all course companions