erebus

view liberebus/src/brdf.cc @ 21:e49f4d7ad04c

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