nuclear@30: #include nuclear@2: #include "brdf.h" nuclear@2: #include "erebus_impl.h" nuclear@2: nuclear@2: // ---- class Reflectance ---- nuclear@2: Reflectance::Reflectance() nuclear@2: { nuclear@2: } nuclear@2: nuclear@2: float Reflectance::sample(const Vector3 &norm, const Vector3 &outdir, Vector3 *indir) const nuclear@2: { nuclear@2: *indir = sample_dir(norm, outdir); nuclear@2: return eval(norm, outdir, *indir); nuclear@2: } nuclear@2: nuclear@21: // --- class CompositeRefl ---- nuclear@21: CompositeRefl::CompositeRefl() nuclear@21: { nuclear@21: valid_checked = false; nuclear@21: } nuclear@21: nuclear@21: int CompositeRefl::pick_brdf(const Vector3 &norm, const Vector3 &outdir) const nuclear@21: { nuclear@21: if(sub_brdf.empty()) { nuclear@21: return -1; nuclear@21: } nuclear@21: nuclear@21: int brdf_count = (int)sub_brdf.size(); nuclear@21: if(brdf_count == 1) { nuclear@21: return 0; nuclear@21: } nuclear@21: nuclear@21: // construct CDF from sub-brdf probabilities nuclear@21: float *cdf = (float*)alloca(brdf_count * sizeof *cdf); nuclear@21: for(int i=0; i 0 ? cdf[i - 1] + w : w; nuclear@21: } nuclear@21: nuclear@21: float rval = randf(0.0, cdf[brdf_count - 1]); nuclear@21: for(int i=0; isample_dir(norm, outdir); nuclear@21: } nuclear@21: nuclear@21: float CompositeRefl::sample(const Vector3 &norm, const Vector3 &outdir, Vector3 *indir) const nuclear@21: { nuclear@21: int bidx = pick_brdf(norm, outdir); nuclear@21: return sub_brdf[bidx].brdf->sample(norm, outdir, indir); nuclear@21: } nuclear@21: nuclear@21: float CompositeRefl::eval(const Vector3 &norm, const Vector3 &outdir, const Vector3 &indir) const nuclear@21: { nuclear@21: if(!warned_composite_usage) { nuclear@21: fputs(composite_usage_warnstr, stderr); nuclear@21: warned_composite_usage = true; nuclear@21: } nuclear@21: int bidx = pick_brdf(norm, outdir); nuclear@21: return sub_brdf[bidx].brdf->eval(norm, outdir, indir); nuclear@21: } nuclear@21: nuclear@2: // --- class LambertRefl --- nuclear@2: Vector3 LambertRefl::sample_dir(const Vector3 &norm, const Vector3 &outdir) const nuclear@2: { nuclear@2: Vector3 dir = Vector3{randf(-1, 1), randf(-1, 1), randf(-1, 1)}.normalized(); nuclear@2: return dot_product(dir, norm) < 0.0 ? -dir : dir; nuclear@2: } nuclear@2: nuclear@2: float LambertRefl::eval(const Vector3 &norm, const Vector3 &outdir, const Vector3 &indir) const nuclear@2: { nuclear@2: return dot_product(norm, outdir); nuclear@2: } nuclear@21: nuclear@21: // --- class MirrorRefl --- nuclear@21: Vector3 MirrorRefl::sample_dir(const Vector3 &norm, const Vector3 &outdir) const nuclear@21: { nuclear@21: return outdir.reflection(norm); nuclear@21: } nuclear@21: nuclear@21: float MirrorRefl::eval(const Vector3 &norm, const Vector3 &outdir, const Vector3 &indir) const nuclear@21: { nuclear@21: return 1.0f; nuclear@21: } nuclear@28: nuclear@28: // --- class PhongRefl --- nuclear@28: PhongRefl::PhongRefl() nuclear@28: { nuclear@28: shininess = 42.0; nuclear@28: } nuclear@28: nuclear@28: Vector3 PhongRefl::sample_dir(const Vector3 &norm, const Vector3 &outdir) const nuclear@28: { nuclear@28: // construct orthonormal basis with k being the reflection dir nuclear@28: Vector3 refl = outdir.reflection(norm).normalized(); nuclear@28: Vector3 up = Vector3(0, 0, 1); nuclear@28: if(fabs(dot_product(refl, up)) - 1.0 < 0.001) { nuclear@28: up = Vector3(0, 1, 0); nuclear@28: } nuclear@28: Vector3 right = cross_product(up, refl); nuclear@28: up = cross_product(refl, right); nuclear@28: nuclear@28: // construct the matrix transposed to move the sample from reflection nuclear@28: // space to world space nuclear@28: Matrix3x3 xform; nuclear@28: xform.set_column_vector(right, 0); nuclear@28: xform.set_column_vector(up, 1); nuclear@28: xform.set_column_vector(refl, 2); nuclear@28: nuclear@28: float phi = acos(pow(randf(), 1.0 / (shininess + 1))); nuclear@28: float theta = 2.0 * M_PI * randf(); nuclear@28: nuclear@28: Vector3 v; nuclear@28: v.x = cos(theta) * sin(phi); nuclear@28: v.y = sin(theta) * sin(phi); nuclear@28: v.z = cos(phi); nuclear@28: v.transform(xform); nuclear@28: return v; nuclear@28: } nuclear@28: nuclear@28: float PhongRefl::eval(const Vector3 &norm, const Vector3 &outdir, const Vector3 &indir) const nuclear@28: { nuclear@28: Vector3 refl = outdir.reflection(norm); nuclear@28: float dot = std::max(dot_product(indir, refl), 0.0f); nuclear@28: return pow(dot, shininess); nuclear@28: }