nuclear@2: #ifndef BRDF_H_ nuclear@2: #define BRDF_H_ nuclear@2: nuclear@21: #include nuclear@2: #include "texture.h" nuclear@2: nuclear@31: class Material; nuclear@31: nuclear@31: class SurfaceGeometry { nuclear@31: public: nuclear@31: Vector3 normal, tangent; nuclear@31: Vector2 uv; nuclear@31: nuclear@31: enum VecLength { unit, unknown }; nuclear@31: nuclear@31: explicit SurfaceGeometry(const Vector3 &norm, VecLength st = unknown); nuclear@31: SurfaceGeometry(const Vector3 &norm, const Vector2 &uv, VecLength st = unknown); nuclear@31: SurfaceGeometry(const Vector3 &norm, const Vector3 &tang, VecLength st = unknown); nuclear@31: SurfaceGeometry(const Vector3 &norm, const Vector3 &tang, const Vector2 &uv, VecLength st = unknown); nuclear@31: nuclear@31: /** create a cartesian direction vector in sample space (zenith = +Z) and nuclear@31: * transform it to world space. nuclear@31: * \param theta the horizontal angle (azimuth, in radians) around the Z axis [0, 2pi] nuclear@31: * \param phi the vertical angle (elevation, in radians) away from the Z axis [0, pi] nuclear@31: */ nuclear@31: Vector3 spherical_to_world(float theta, float phi) const; nuclear@31: /// transforms a direction vector from sample space (centered around Z) to world space nuclear@31: Vector3 sample_to_world(const Vector3 &v) const; nuclear@31: /// transforms a direction vector from world space to sample space (centered around Z) nuclear@31: Vector3 world_to_sample(const Vector3 &v) const; nuclear@31: }; nuclear@31: nuclear@31: /// abstract bidirection reflectance distribution function base class nuclear@2: class Reflectance { nuclear@31: protected: nuclear@31: const Material *mtl; // pointer to the material we belong to nuclear@31: nuclear@2: public: nuclear@2: Reflectance(); nuclear@31: explicit Reflectance(const Material *mtl); nuclear@2: virtual ~Reflectance() = default; nuclear@2: nuclear@31: void set_material(const Material *mtl); nuclear@31: const Material *get_material() const; nuclear@31: nuclear@31: /// given an outgoing light direction generate an incidence direction to sample the BRDF nuclear@31: virtual Vector3 sample_dir(const SurfaceGeometry &geom, const Vector3 &outdir) const = 0; nuclear@31: /// given an outgoing direction, generate an incidence direction, and evaluate its probability nuclear@31: virtual float sample(const SurfaceGeometry &geom, const Vector3 &outdir, Vector3 *indir) const; nuclear@31: /// given an outgoing direction and an incidence direction, evaluate the probability of this path nuclear@31: virtual float eval(const SurfaceGeometry &geom, const Vector3 &outdir, const Vector3 &indir) const = 0; nuclear@2: }; nuclear@2: nuclear@31: typedef float (*CompReflWeightFunc)(const SurfaceGeometry &geom, const Vector3 &outdir); nuclear@21: nuclear@31: /// composite BRDF, with multiple weighted sub-reflectances. nuclear@21: class CompositeRefl : public Reflectance { nuclear@21: private: nuclear@21: struct SubRefl { nuclear@21: Reflectance *brdf; nuclear@21: float weight; nuclear@21: CompReflWeightFunc weight_func; // if null, use static weight above nuclear@21: }; nuclear@21: std::vector sub_brdf; nuclear@21: mutable bool valid_checked; nuclear@21: nuclear@31: int pick_brdf(const SurfaceGeometry &geom, const Vector3 &outdir) const; nuclear@21: nuclear@21: public: nuclear@21: CompositeRefl(); nuclear@31: explicit CompositeRefl(const Material *mtl); nuclear@21: nuclear@21: virtual void add_brdf(Reflectance *brdf, float weight); nuclear@21: virtual void add_brdf(Reflectance *brdf, CompReflWeightFunc weight_func); nuclear@21: nuclear@21: bool check_valid() const; nuclear@21: nuclear@31: Vector3 sample_dir(const SurfaceGeometry &geom, const Vector3 &outdir) const override; nuclear@31: float sample(const SurfaceGeometry &geom, const Vector3 &outdir, Vector3 *indir) const override; nuclear@31: float eval(const SurfaceGeometry &geom, const Vector3 &outdir, const Vector3 &indir) const override; nuclear@21: }; nuclear@21: nuclear@31: /// lambertian perfect diffuse reflectance nuclear@2: class LambertRefl : public Reflectance { nuclear@2: public: nuclear@31: Vector3 sample_dir(const SurfaceGeometry &geom, const Vector3 &outdir) const override; nuclear@31: float eval(const SurfaceGeometry &geom, const Vector3 &outdir, const Vector3 &indir) const override; nuclear@2: }; nuclear@2: nuclear@31: /// perfect specular reflectance nuclear@21: class MirrorRefl : public Reflectance { nuclear@21: public: nuclear@31: Vector3 sample_dir(const SurfaceGeometry &geom, const Vector3 &outdir) const override; nuclear@31: float eval(const SurfaceGeometry &geom, const Vector3 &outdir, const Vector3 &indir) const override; nuclear@21: }; nuclear@21: nuclear@31: /// glossy phong reflectance with lafortune sampling nuclear@28: class PhongRefl : public Reflectance { nuclear@28: public: nuclear@31: Vector3 sample_dir(const SurfaceGeometry &geom, const Vector3 &outdir) const override; nuclear@31: float eval(const SurfaceGeometry &geom, const Vector3 &outdir, const Vector3 &indir) const override; nuclear@28: }; nuclear@28: nuclear@2: #endif // BRDF_H_