erebus

annotate 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
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 }