rev |
line source |
nuclear@2
|
1 #include "brdf.h"
|
nuclear@2
|
2 #include "erebus_impl.h"
|
nuclear@2
|
3
|
nuclear@2
|
4 // ---- class Reflectance ----
|
nuclear@2
|
5 Reflectance::Reflectance()
|
nuclear@2
|
6 {
|
nuclear@2
|
7 }
|
nuclear@2
|
8
|
nuclear@2
|
9 float Reflectance::sample(const Vector3 &norm, const Vector3 &outdir, Vector3 *indir) const
|
nuclear@2
|
10 {
|
nuclear@2
|
11 *indir = sample_dir(norm, outdir);
|
nuclear@2
|
12 return eval(norm, outdir, *indir);
|
nuclear@2
|
13 }
|
nuclear@2
|
14
|
nuclear@21
|
15 // --- class CompositeRefl ----
|
nuclear@21
|
16 CompositeRefl::CompositeRefl()
|
nuclear@21
|
17 {
|
nuclear@21
|
18 valid_checked = false;
|
nuclear@21
|
19 }
|
nuclear@21
|
20
|
nuclear@21
|
21 int CompositeRefl::pick_brdf(const Vector3 &norm, const Vector3 &outdir) const
|
nuclear@21
|
22 {
|
nuclear@21
|
23 if(sub_brdf.empty()) {
|
nuclear@21
|
24 return -1;
|
nuclear@21
|
25 }
|
nuclear@21
|
26
|
nuclear@21
|
27 int brdf_count = (int)sub_brdf.size();
|
nuclear@21
|
28 if(brdf_count == 1) {
|
nuclear@21
|
29 return 0;
|
nuclear@21
|
30 }
|
nuclear@21
|
31
|
nuclear@21
|
32 // construct CDF from sub-brdf probabilities
|
nuclear@21
|
33 float *cdf = (float*)alloca(brdf_count * sizeof *cdf);
|
nuclear@21
|
34 for(int i=0; i<brdf_count; i++) {
|
nuclear@21
|
35 const SubRefl &sub = sub_brdf[i];
|
nuclear@21
|
36 float w = sub.weight_func ? sub.weight_func(norm, outdir) : sub.weight;
|
nuclear@21
|
37 cdf[i] = i > 0 ? cdf[i - 1] + w : w;
|
nuclear@21
|
38 }
|
nuclear@21
|
39
|
nuclear@21
|
40 float rval = randf(0.0, cdf[brdf_count - 1]);
|
nuclear@21
|
41 for(int i=0; i<brdf_count - 1; i++) {
|
nuclear@21
|
42 if(rval <= cdf[i]) return i;
|
nuclear@21
|
43 }
|
nuclear@21
|
44 return brdf_count - 1;
|
nuclear@21
|
45 }
|
nuclear@21
|
46
|
nuclear@21
|
47 void CompositeRefl::add_brdf(Reflectance *brdf, float weight)
|
nuclear@21
|
48 {
|
nuclear@21
|
49 SubRefl sub;
|
nuclear@21
|
50 sub.brdf = brdf;
|
nuclear@21
|
51 sub.weight = weight;
|
nuclear@21
|
52 sub.weight_func = 0;
|
nuclear@21
|
53 sub_brdf.push_back(sub);
|
nuclear@21
|
54
|
nuclear@21
|
55 valid_checked = false;
|
nuclear@21
|
56 }
|
nuclear@21
|
57
|
nuclear@21
|
58 void CompositeRefl::add_brdf(Reflectance *brdf, CompReflWeightFunc weight_func)
|
nuclear@21
|
59 {
|
nuclear@21
|
60 SubRefl sub;
|
nuclear@21
|
61 sub.brdf = brdf;
|
nuclear@21
|
62 sub.weight = 0.0;
|
nuclear@21
|
63 sub.weight_func = weight_func;
|
nuclear@21
|
64 sub_brdf.push_back(sub);
|
nuclear@21
|
65
|
nuclear@21
|
66 valid_checked = false;
|
nuclear@21
|
67 }
|
nuclear@21
|
68
|
nuclear@21
|
69 bool CompositeRefl::check_valid() const
|
nuclear@21
|
70 {
|
nuclear@21
|
71 float sum = 0.0;
|
nuclear@21
|
72 for(size_t i=0; i<sub_brdf.size(); i++) {
|
nuclear@21
|
73 if(!sub_brdf[i].weight_func) {
|
nuclear@21
|
74 sum += sub_brdf[i].weight;
|
nuclear@21
|
75 }
|
nuclear@21
|
76 }
|
nuclear@21
|
77 return sum < 1.0001;
|
nuclear@21
|
78 }
|
nuclear@21
|
79
|
nuclear@21
|
80 static bool warned_composite_usage;
|
nuclear@21
|
81 static const char *composite_usage_warnstr =
|
nuclear@21
|
82 "warning: don't call CompositeRefl's sample_dir and eval separately\n"
|
nuclear@21
|
83 " it'll pick different brdfs each time! use sample instead\n";
|
nuclear@21
|
84
|
nuclear@21
|
85 Vector3 CompositeRefl::sample_dir(const Vector3 &norm, const Vector3 &outdir) const
|
nuclear@21
|
86 {
|
nuclear@21
|
87 if(!warned_composite_usage) {
|
nuclear@21
|
88 fputs(composite_usage_warnstr, stderr);
|
nuclear@21
|
89 warned_composite_usage = true;
|
nuclear@21
|
90 }
|
nuclear@21
|
91 int bidx = pick_brdf(norm, outdir);
|
nuclear@21
|
92 return sub_brdf[bidx].brdf->sample_dir(norm, outdir);
|
nuclear@21
|
93 }
|
nuclear@21
|
94
|
nuclear@21
|
95 float CompositeRefl::sample(const Vector3 &norm, const Vector3 &outdir, Vector3 *indir) const
|
nuclear@21
|
96 {
|
nuclear@21
|
97 int bidx = pick_brdf(norm, outdir);
|
nuclear@21
|
98 return sub_brdf[bidx].brdf->sample(norm, outdir, indir);
|
nuclear@21
|
99 }
|
nuclear@21
|
100
|
nuclear@21
|
101 float CompositeRefl::eval(const Vector3 &norm, const Vector3 &outdir, const Vector3 &indir) const
|
nuclear@21
|
102 {
|
nuclear@21
|
103 if(!warned_composite_usage) {
|
nuclear@21
|
104 fputs(composite_usage_warnstr, stderr);
|
nuclear@21
|
105 warned_composite_usage = true;
|
nuclear@21
|
106 }
|
nuclear@21
|
107 int bidx = pick_brdf(norm, outdir);
|
nuclear@21
|
108 return sub_brdf[bidx].brdf->eval(norm, outdir, indir);
|
nuclear@21
|
109 }
|
nuclear@21
|
110
|
nuclear@2
|
111 // --- class LambertRefl ---
|
nuclear@2
|
112 Vector3 LambertRefl::sample_dir(const Vector3 &norm, const Vector3 &outdir) const
|
nuclear@2
|
113 {
|
nuclear@2
|
114 Vector3 dir = Vector3{randf(-1, 1), randf(-1, 1), randf(-1, 1)}.normalized();
|
nuclear@2
|
115 return dot_product(dir, norm) < 0.0 ? -dir : dir;
|
nuclear@2
|
116 }
|
nuclear@2
|
117
|
nuclear@2
|
118 float LambertRefl::eval(const Vector3 &norm, const Vector3 &outdir, const Vector3 &indir) const
|
nuclear@2
|
119 {
|
nuclear@2
|
120 return dot_product(norm, outdir);
|
nuclear@2
|
121 }
|
nuclear@21
|
122
|
nuclear@21
|
123 // --- class MirrorRefl ---
|
nuclear@21
|
124 Vector3 MirrorRefl::sample_dir(const Vector3 &norm, const Vector3 &outdir) const
|
nuclear@21
|
125 {
|
nuclear@21
|
126 return outdir.reflection(norm);
|
nuclear@21
|
127 }
|
nuclear@21
|
128
|
nuclear@21
|
129 float MirrorRefl::eval(const Vector3 &norm, const Vector3 &outdir, const Vector3 &indir) const
|
nuclear@21
|
130 {
|
nuclear@21
|
131 return 1.0f;
|
nuclear@21
|
132 }
|