/// <summary> /// Scatter a ray using the BRDF and Impulses /// </summary> public ScatteredRay Scatter(PositionNormalCoordinate surfel, float3 w) { float selection = random(); float impulseProb = 0; foreach (var impulse in GetBRDFImpulses(surfel, w)) { float pdf = (impulse.Ratio.x + impulse.Ratio.y + impulse.Ratio.z) / 3; if (selection < pdf) // this impulse is choosen { return new ScatteredRay { Ratio = impulse.Ratio / abs(dot(surfel.Normal, impulse.Direction)), Direction = impulse.Direction, PDF = pdf } } ; selection -= pdf; impulseProb += pdf; } float3 wout = randomHSDirection(surfel.Normal); /// BRDF uniform sampling return(new ScatteredRay { Direction = wout, Ratio = EvalBRDF(surfel, wout, w), PDF = (1 - impulseProb) / (2 * pi) }); } }
public float3 EvalBRDF(PositionNormalCoordinate surfel, float3 wout, float3 win) { float3 diffuse = Diffuse * (DiffuseMap == null ? float3(1, 1, 1) : DiffuseMap.Sample(TextureSampler, surfel.Coordinates).xyz) / pi; float3 H = normalize(win + wout); float3 specular = Specular * pow(max(0, dot(H, surfel.Normal)), SpecularPower) * (SpecularPower + 2) / two_pi; return(diffuse * WeightDiffuse / WeightNormalization + specular * WeightGlossy / WeightNormalization); }
public float3 EvalBRDF(PositionNormalCoordinate surfel, float3 wout, float3 win) { float3 diffuse = Diffuse.Sample(TextureSampler, surfel.Coordinates).xyz / pi; float3 H = normalize(win + wout); float3 specular = Specular * pow(max(0, dot(H, surfel.Normal)), SpecularPower) * (SpecularPower + 2) / two_pi; return(diffuse * (1 - Glossyness) + specular * Glossyness); }
public IEnumerable <Impulse> GetBRDFImpulses(PositionNormalCoordinate surfel, float3 wout) { if (!any(Specular)) { yield break; // No specular => Ratio == 0 } float NdotL = dot(surfel.Normal, wout); // Check if ray is entering the medium or leaving bool entering = NdotL > 0; // Invert all data if leaving NdotL = entering ? NdotL : -NdotL; surfel.Normal = entering ? surfel.Normal : -surfel.Normal; float ratio = entering ? 1.0f / this.RefractionIndex : this.RefractionIndex / 1.0f; // 1.0f air refraction index approx // Reflection vector float3 R = reflect(wout, surfel.Normal); // Refraction vector float3 T = refract(wout, surfel.Normal, ratio); // Reflection quantity, (1 - F) will be the refracted quantity. float F = ComputeFresnel(NdotL, ratio); if (!any(T)) { F = 1; // total internal reflection (produced with critical angles) } if (WeightMirror + WeightFresnel * F > 0) // something is reflected { yield return new Impulse { Direction = R, Ratio = Specular * (WeightMirror + WeightFresnel * F) / WeightNormalization } } ; if (WeightFresnel * (1 - F) > 0) // something to refract { yield return new Impulse { Direction = T, Ratio = Specular * WeightFresnel * (1 - F) / WeightNormalization } } ; }