public static Vector3 Radiance(Ray ray, RNG rng) { Ray r = ray; Vector3 L = new Vector3(); Vector3 F = new Vector3(1.0); while (true) { int id; if (!Intersect(r, out id)) { return(L); } Sphere shape = spheres[id]; Vector3 p = r.Eval(r.tmax); Vector3 n = (p - shape.p).Normalize(); L += F * shape.e; F *= shape.f; // Russian roulette if (r.depth > 4) { double continue_probability = shape.f.Max(); if (rng.UniformFloat() >= continue_probability) { return(L); } F /= continue_probability; } // Next path segment switch (shape.reflection_t) { case Sphere.Reflection_t.SPECULAR: { Vector3 d = Specular.IdealSpecularReflect(r.d, n); r = new Ray(p, d, Sphere.EPSILON_SPHERE, double.PositiveInfinity, r.depth + 1); break; } case Sphere.Reflection_t.REFRACTIVE: { double pr; Vector3 d = Specular.IdealSpecularTransmit(r.d, n, REFRACTIVE_INDEX_OUT, REFRACTIVE_INDEX_IN, out pr, rng); F *= pr; r = new Ray(p, d, Sphere.EPSILON_SPHERE, double.PositiveInfinity, r.depth + 1); break; } default: { Vector3 w = n.Dot(r.d) < 0 ? n : -n; Vector3 u = ((Math.Abs(w[0]) > 0.1 ? new Vector3(0.0, 1.0, 0.0) : new Vector3(1.0, 0.0, 0.0)).Cross(w)).Normalize(); Vector3 v = w.Cross(u); Vector3 sample_d = Sampling.CosineWeightedSampleOnHemisphere(rng.UniformFloat(), rng.UniformFloat()); Vector3 d = (sample_d[0] * u + sample_d[1] * v + sample_d[2] * w).Normalize(); r = new Ray(p, d, Sphere.EPSILON_SPHERE, double.PositiveInfinity, r.depth + 1); break; } } } }
public static Vector3 IdealSpecularTransmit(Vector3 d, Vector3 n, double n_out, double n_in, out double pr, RNG rng) { Vector3 d_Re = IdealSpecularReflect(d, n); bool out_to_in = n.Dot(d) < 0; Vector3 nl = out_to_in ? n : -n; double nn = out_to_in ? n_out / n_in : n_in / n_out; double cos_theta = d.Dot(nl); double cos2_phi = 1.0 - nn * nn * (1.0 - cos_theta * cos_theta); // Total Internal Reflection if (cos2_phi < 0) { pr = 1.0; return(d_Re); } Vector3 d_Tr = (nn * d - nl * (nn * cos_theta + Math.Sqrt(cos2_phi))).Normalize(); double c = 1.0 - (out_to_in ? -cos_theta : d_Tr.Dot(n)); double Re = SchlickReflectance(n_out, n_in, c); double p_Re = 0.25 + 0.5 * Re; if (rng.UniformFloat() < p_Re) { pr = (Re / p_Re); return(d_Re); } else { double Tr = 1.0 - Re; double p_Tr = 1.0 - p_Re; pr = (Tr / p_Tr); return(d_Tr); } }