Arty
materials.h
1 #ifndef MATERIALS_H
2 #define MATERIALS_H
3 
4 #include <memory>
5 #include <cassert>
6 #include <cmath>
7 #include <type_traits>
8 
9 #include "color.h"
10 #include "float3.h"
11 #include "common.h"
12 #include "textures.h"
13 #include "samplers.h"
14 
16 struct BsdfSample {
18  float pdf;
20 
21  BsdfSample() {}
22  BsdfSample(const float3& i, float p, const rgb& c) : in(i), pdf(p), color(c) {}
23 };
24 
26 struct SurfaceParams {
27  bool entering;
32 };
33 
34 class Light;
35 class Bsdf;
36 
38 struct Material {
39  const Bsdf* bsdf;
40  const Light* emitter;
41 
42  Material() {}
43  Material(const Bsdf* f = nullptr,
44  const Light* e = nullptr)
45  : bsdf(f)
46  , emitter(e)
47  {}
48 };
49 
51 inline float shading_normal_adjoint(const float3& in, const SurfaceParams& surf, const float3& out) {
52  auto n = std::fabs(dot(in, surf.face_normal) * dot(out, surf.coords.n));
53  auto d = std::fabs(dot(out, surf.face_normal) * dot(in, surf.coords.n));
54  return d != 0 ? n / d : 0.0f;
55 }
56 
58 class Bsdf {
59 public:
61  enum class Type {
62  Diffuse = 0,
63  Glossy = 1,
64  Specular = 2
65  };
66 
67  Bsdf(Type ty)
68  : ty(ty)
69  {}
70 
71  virtual ~Bsdf() {}
72 
74  Type type() const { return ty; }
75 
77  virtual rgb eval(const float3& /*in*/, const SurfaceParams& /*surf*/, const float3& /*out*/) const { return rgb(0.0f); }
79  virtual BsdfSample sample(Sampler& /*sampler*/, const SurfaceParams& surf, const float3& /*out*/, bool /*adjoint*/ = false) const {
80  return BsdfSample(surf.face_normal, 1.0f, rgb(0.0f));
81  }
83  virtual float pdf(const float3& /*in*/, const SurfaceParams& /*surf*/, const float3& /*out*/) const { return 0.0f; }
84 
85 protected:
89  template <bool below_surface = false>
90  static BsdfSample make_sample(const float3& dir, float pdf, const rgb& color, const SurfaceParams& surf) {
91  auto sign = dot(dir, surf.face_normal);
92  return pdf > 0 && ((below_surface && sign < 0) || (!below_surface && sign > 0))
93  ? BsdfSample(dir, pdf, color)
94  : BsdfSample(dir, 1.0f, rgb(0.0f));
95  }
96 
97  Type ty;
98 };
99 
101 class DiffuseBsdf : public Bsdf {
102 public:
103  DiffuseBsdf(const Texture& tex)
104  : Bsdf(Type::Diffuse)
105  , tex(tex)
106  {}
107 
108  rgb eval(const float3&, const SurfaceParams& surf, const float3&) const override final {
109  return tex(surf.uv.x, surf.uv.y) * kd;
110  }
111 
112  BsdfSample sample(Sampler& sampler, const SurfaceParams& surf, const float3&, bool) const override final {
113  auto sample = sample_cosine_hemisphere(surf.coords, sampler(), sampler());
114  auto color = tex(surf.uv.x, surf.uv.y) * (std::max(dot(sample.dir, surf.coords.n), 0.0f) * kd);
115  return make_sample(sample.dir, sample.pdf, color, surf);
116  }
117 
118  float pdf(const float3& in, const SurfaceParams& surf, const float3&) const override final {
119  return cosine_hemisphere_pdf(dot(in, surf.coords.n));
120  }
121 
122 private:
123  static constexpr float kd = 1.0f / pi;
124 
125  const Texture& tex;
126 };
127 
129 class GlossyPhongBsdf : public Bsdf {
130 public:
131  GlossyPhongBsdf(const Texture& tex, float ns)
132  : Bsdf(Type::Glossy)
133  , tex(tex)
134  , ns(ns)
135  , ks((ns + 2) / (2.0f * pi))
136  {}
137 
138  rgb eval(const float3& in, const SurfaceParams& surf, const float3& out) const override final {
139  return tex(surf.uv.x, surf.uv.y) * std::pow(reflect_cosine(in, surf, out), ns) * ks;
140  }
141 
142  BsdfSample sample(Sampler& sampler, const SurfaceParams& surf, const float3& out, bool) const override final {
143  auto coords = gen_local_coords(reflect(out, surf.coords.n));
144  auto sample = sample_cosine_power_hemisphere(coords, ns, sampler(), sampler());
145  auto p = reflect_cosine(sample.dir, surf, out);
146  return make_sample(sample.dir, sample.pdf, tex(surf.uv.x, surf.uv.y) * (std::max(dot(sample.dir, surf.coords.n), 0.0f) * std::pow(p, ns) * ks), surf);
147  }
148 
149  float pdf(const float3& in, const SurfaceParams& surf, const float3& out) const override final {
150  return cosine_power_hemisphere_pdf(reflect_cosine(in, surf, out), ns);
151  }
152 
153 private:
154  float reflect_cosine(const float3& in, const SurfaceParams& surf, const float3& out) const {
155  return std::max(dot(in, reflect(out, surf.coords.n)), 0.0f);
156  }
157 
158  const Texture& tex;
159  float ns, ks;
160 };
161 
163 class MirrorBsdf : public Bsdf {
164 public:
165  MirrorBsdf() : Bsdf(Type::Specular) {}
166 
167  BsdfSample sample(Sampler&, const SurfaceParams& surf, const float3& out, bool) const override final {
168  return make_sample(reflect(out, surf.coords.n), 1.0f, rgb(1.0f, 1.0f, 1.0f), surf);
169  }
170 };
171 
173 class GlassBsdf : public Bsdf {
174 public:
175  GlassBsdf(float n1 = 1.0f, float n2 = 1.4f, const rgb& c = rgb(1.0f))
176  : Bsdf(Type::Specular)
177  , eta(n1 / n2)
178  , color(c)
179  {}
180 
181  BsdfSample sample(Sampler& sampler, const SurfaceParams& surf, const float3& out, bool adjoint) const override final {
182  auto k = surf.entering ? eta : 1.0f / eta;
183  auto cos_i = dot(out, surf.coords.n);
184  auto cos2_t = 1.0f - k * k * (1.0f - cos_i * cos_i);
185  if (cos2_t > 0) {
186  // Refraction
187  auto cos_t = std::sqrt(cos2_t);
188  auto F = fresnel_factor(k, cos_i, cos_t);
189  if (sampler() > F) {
190  auto t = (k * cos_i - cos_t) * surf.coords.n - k * out;
191  auto adjoint_term = adjoint ? k * k : 1.0f;
192  return make_sample<true>(t, 1.0f, color * adjoint_term, surf);
193  }
194  }
195 
196  // Reflection
197  return make_sample(reflect(out, surf.coords.n), 1.0f, color, surf);
198  }
199 
200 private:
202  static float fresnel_factor(float k, float cos_i, float cos_t) {
203  const float R_s = (k * cos_i - cos_t) / (k * cos_i + cos_t);
204  const float R_p = (cos_i - k * cos_t) / (cos_i + k * cos_t);
205  return (R_s * R_s + R_p * R_p) * 0.5f;
206  }
207 
208  float eta;
209  rgb color;
210 };
211 
213 class CombineBsdf : public Bsdf {
214 public:
215  CombineBsdf(Type ty, const Bsdf* a, const Bsdf* b, float k)
216  : Bsdf(ty), a(a), b(b), k(k)
217  {}
218 
219  rgb eval(const float3& in, const SurfaceParams& surf, const float3& out) const override final {
220  return lerp(a->eval(in, surf, out), b->eval(in, surf, out), k);
221  }
222 
223  BsdfSample sample(Sampler& sampler, const SurfaceParams& surf, const float3& out, bool adjoint) const override final {
224  auto use_b = sampler() < k;
225  auto sample = use_b ? b->sample(sampler, surf, out, adjoint) : a->sample(sampler, surf, out, adjoint);
226  sample.pdf = lerp(use_b ? a->pdf (sample.in, surf, out) : sample.pdf, use_b ? sample.pdf : b->pdf (sample.in, surf, out), k);
227  sample.color = lerp(use_b ? a->eval(sample.in, surf, out) : sample.color, use_b ? sample.color : b->eval(sample.in, surf, out), k);
228  return sample;
229  }
230 
231  float pdf(const float3& in, const SurfaceParams& surf, const float3& out) const override final {
232  return lerp(a->pdf(in, surf, out), b->pdf(in, surf, out), k);
233  }
234 
235 private:
236  std::unique_ptr<const Bsdf> a, b;
237  float k;
238 };
239 
240 #endif // MATERIALS_H
static BsdfSample make_sample(const float3 &dir, float pdf, const rgb &color, const SurfaceParams &surf)
Definition: materials.h:90
Base class for all lights.
Definition: lights.h:50
Definition: float2.h:10
BsdfSample sample(Sampler &sampler, const SurfaceParams &surf, const float3 &, bool) const override final
Samples the material given a surface point and an outgoing direction. The contribution DOES include t...
Definition: materials.h:112
float3 n
Normal.
Definition: random.h:11
Sampler object, used at the level of the integrator to control how the random number generation is do...
Definition: samplers.h:12
Type
Classification of BSDF shapes.
Definition: materials.h:61
Definition: float3.h:10
Base class for BSDFs.
Definition: materials.h:58
virtual BsdfSample sample(Sampler &, const SurfaceParams &surf, const float3 &, bool=false) const
Samples the material given a surface point and an outgoing direction. The contribution DOES include t...
Definition: materials.h:79
Base class for all textures.
Definition: textures.h:8
float pdf
Probability density function, evaluated for the direction.
Definition: materials.h:18
LocalCoords coords
Local coordinates at the hit point, w.r.t shading normal.
Definition: materials.h:31
Sample returned by a BSDF, including direction, pdf, and color.
Definition: materials.h:16
BsdfSample sample(Sampler &sampler, const SurfaceParams &surf, const float3 &out, bool adjoint) const override final
Samples the material given a surface point and an outgoing direction. The contribution DOES include t...
Definition: materials.h:223
Type type() const
Returns the type of the BSDF, useful to make sampling decisions.
Definition: materials.h:74
bool entering
True if entering the surface.
Definition: materials.h:27
const Light * emitter
BSDF associated with the material (if any)
Definition: materials.h:40
float3 in
Sampled direction.
Definition: materials.h:17
A BSDF that combines two materials.
Definition: materials.h:213
float3 face_normal
Geometric normal.
Definition: materials.h:30
A material is a combination of a BSDF and an optional light emitter.
Definition: materials.h:38
BSDF that can represent glass or any separation between two mediums.
Definition: materials.h:173
Specular part of the modified (physically correct) Phong.
Definition: materials.h:129
Purely Lambertian material.
Definition: materials.h:101
BsdfSample sample(Sampler &sampler, const SurfaceParams &surf, const float3 &out, bool adjoint) const override final
Samples the material given a surface point and an outgoing direction. The contribution DOES include t...
Definition: materials.h:181
float3 point
Hit point in world coordinates.
Definition: materials.h:28
Local coordinates for shading.
Definition: random.h:10
rgb eval(const float3 &, const SurfaceParams &surf, const float3 &) const override final
Evaluates the material for the given pair of directions and surface point. Does NOT include the cosin...
Definition: materials.h:108
rgb color
Color of the sample (BSDF value)
Definition: materials.h:19
virtual float pdf(const float3 &, const SurfaceParams &, const float3 &) const
Returns the probability to sample the given input direction (sampled using the sample function)...
Definition: materials.h:83
Purely specular mirror.
Definition: materials.h:163
float2 uv
Texture coordinates.
Definition: materials.h:29
float pdf(const float3 &in, const SurfaceParams &surf, const float3 &) const override final
Returns the probability to sample the given input direction (sampled using the sample function)...
Definition: materials.h:118
rgb eval(const float3 &in, const SurfaceParams &surf, const float3 &out) const override final
Evaluates the material for the given pair of directions and surface point. Does NOT include the cosin...
Definition: materials.h:138
virtual rgb eval(const float3 &, const SurfaceParams &, const float3 &) const
Evaluates the material for the given pair of directions and surface point. Does NOT include the cosin...
Definition: materials.h:77
BsdfSample sample(Sampler &sampler, const SurfaceParams &surf, const float3 &out, bool) const override final
Samples the material given a surface point and an outgoing direction. The contribution DOES include t...
Definition: materials.h:142
Surface parameters for a given point.
Definition: materials.h:26
BsdfSample sample(Sampler &, const SurfaceParams &surf, const float3 &out, bool) const override final
Samples the material given a surface point and an outgoing direction. The contribution DOES include t...
Definition: materials.h:167
float pdf(const float3 &in, const SurfaceParams &surf, const float3 &out) const override final
Returns the probability to sample the given input direction (sampled using the sample function)...
Definition: materials.h:149
float pdf(const float3 &in, const SurfaceParams &surf, const float3 &out) const override final
Returns the probability to sample the given input direction (sampled using the sample function)...
Definition: materials.h:231
rgb eval(const float3 &in, const SurfaceParams &surf, const float3 &out) const override final
Evaluates the material for the given pair of directions and surface point. Does NOT include the cosin...
Definition: materials.h:219
Definition: color.h:9
Material()
Light associated with the material (if any)
Definition: materials.h:42