public Spectrum SpecularTransmit( RayDifferential ray, SurfaceInteraction isect, Scene scene, Sampler sampler, int depth) { Vector3D wo = isect.Wo; double pdf; Point3D p = isect.P; Normal3D ns = isect.ShadingN; Bsdf bsdf = isect.Bsdf; Spectrum f = bsdf.Sample_f(wo, out Vector3D wi, sampler.Get2D(), out pdf, out BxdfType sampledType, BxdfType.Transmission | BxdfType.Specular); Spectrum L = Spectrum.Create(0.0); if (pdf > 0.0 && !f.IsBlack() && wi.AbsDot(ns) != 0.0) { // Compute ray differential _rd_ for specular transmission RayDifferential rd = new RayDifferential(isect.SpawnRay(wi)); if (ray.HasDifferentials) { rd.HasDifferentials = true; rd.RxOrigin = p + isect.Dpdx.ToPoint3D(); rd.RyOrigin = p + isect.Dpdy.ToPoint3D(); double eta = bsdf.Eta; Vector3D w = -wo; if (wo.Dot(ns) < 0.0) { eta = 1.0 / eta; } Normal3D dndx = isect.ShadingDndu * isect.Dudx + isect.ShadingDndv * isect.Dvdx; Normal3D dndy = isect.ShadingDndu * isect.Dudy + isect.ShadingDndv * isect.Dvdy; Vector3D dwodx = -ray.RxDirection - wo, dwody = -ray.RyDirection - wo; double dDNdx = dwodx.Dot(ns) + wo.Dot(dndx); double dDNdy = dwody.Dot(ns) + wo.Dot(dndy); double mu = eta * w.Dot(ns) - wi.Dot(ns); double dmudx = (eta - (eta * eta * w.Dot(ns)) / wi.Dot(ns)) * dDNdx; double dmudy = (eta - (eta * eta * w.Dot(ns)) / wi.Dot(ns)) * dDNdy; rd.RxDirection = wi + eta * dwodx - (mu * dndx + dmudx * ns).ToVector3D(); rd.RyDirection = wi + eta * dwody - (mu * dndy + dmudy * ns).ToVector3D(); } L = f * Li(rd, scene, sampler, depth + 1) * wi.AbsDot(ns) / pdf; } return(L); }
/// <inheritdoc /> public override Spectrum Li(RayDifferential ray, Scene scene, Sampler sampler, int depth = 0) { Spectrum L = Spectrum.Create(0.0); // Find closest ray intersection or return background radiance if (!scene.Intersect(ray, out SurfaceInteraction isect)) { foreach (var light in scene.Lights) { L += light.Le(ray); } return(L); } // Compute emitted and reflected light at ray intersection point // Initialize common variables for Whitted integrator Normal3D n = isect.ShadingN; Vector3D wo = isect.Wo; // Compute scattering functions for surface interaction isect.ComputeScatteringFunctions(ray); if (isect.Bsdf == null) { return(Li(new RayDifferential(isect.SpawnRay(ray.Direction)), scene, sampler, depth)); } // Compute emitted light if ray hit an area light source L += isect.Le(wo); // Add contribution of each light source foreach (var light in scene.Lights) { Spectrum Li = light.Sample_Li(isect, sampler.Get2D(), out Vector3D wi, out double pdf, out VisibilityTester visibility); if (Li.IsBlack() || pdf == 0.0) { continue; } Spectrum f = isect.Bsdf.f(wo, wi); if (!f.IsBlack() && visibility.Unoccluded(scene)) { L += f * Li * wi.AbsDot(n) / pdf; } } if (depth + 1 < _maxDepth) { // Trace rays for specular reflection and refraction L += SpecularReflect(ray, isect, scene, sampler, depth); L += SpecularTransmit(ray, isect, scene, sampler, depth); } return(L); }
public Spectrum SpecularReflect( RayDifferential ray, SurfaceInteraction isect, Scene scene, Sampler sampler, int depth) { // Compute specular reflection direction _wi_ and BSDF value Vector3D wo = isect.Wo; BxdfType type = BxdfType.Reflection | BxdfType.Specular; Spectrum f = isect.Bsdf.Sample_f(wo, out Vector3D wi, sampler.Get2D(), out double pdf, out BxdfType sampledType, type); // Return contribution of specular reflection Normal3D ns = isect.ShadingN; if (pdf > 0.0 && !f.IsBlack() && wi.AbsDot(ns) != 0.0) { // Compute ray differential _rd_ for specular reflection RayDifferential rd = new RayDifferential(isect.SpawnRay(wi)); if (ray.HasDifferentials) { rd.HasDifferentials = true; rd.RxOrigin = isect.P + isect.Dpdx.ToPoint3D(); rd.RyOrigin = isect.P + isect.Dpdy.ToPoint3D(); // Compute differential reflected directions Normal3D dndx = isect.ShadingDndu * isect.Dudx + isect.ShadingDndv * isect.Dvdx; Normal3D dndy = isect.ShadingDndu * isect.Dudy + isect.ShadingDndv * isect.Dvdy; Vector3D dwodx = -ray.RxDirection - wo, dwody = -ray.RyDirection - wo; double dDNdx = dwodx.Dot(ns) + wo.Dot(dndx); double dDNdy = dwody.Dot(ns) + wo.Dot(dndy); rd.RxDirection = wi - dwodx + 2.0 * (wo.Dot(ns) * dndx + dDNdx * ns).ToVector3D(); rd.RyDirection = wi - dwody + 2.0 * (wo.Dot(ns) * dndy + dDNdy * ns).ToVector3D(); } return(f * Li(rd, scene, sampler, depth + 1) * wi.AbsDot(ns) / pdf); } else { return(Spectrum.Create(0.0)); } }
/// <inheritdoc /> public override Spectrum We(Ray ray, out Point2D pRaster2) { // Interpolate camera matrix and check if $\w{}$ is forward-facing CameraToWorld.Interpolate(ray.Time, out Transform c2w); double cosTheta = ray.Direction.Dot(c2w.ExecuteTransform(new Vector3D(0.0, 0.0, 1.0))); if (cosTheta <= 0.0) { pRaster2 = null; return(Spectrum.Create(0.0)); } // Map ray $(\p{}, \w{})$ onto the raster grid Point3D pFocus = ray.AtPoint((LensRadius > 0.0 ? FocalDistance : 1.0) / cosTheta); Point3D pRaster = RasterToCamera.ExecuteTransform(c2w.Inverse().ExecuteTransform(pFocus)); //Point3D pRaster = Inverse(RasterToCamera)(Inverse(c2w.Inverse)(pFocus)); // Return raster position if requested pRaster2 = new Point2D(pRaster.X, pRaster.Y); // Return zero importance for out of bounds points Bounds2I sampleBounds = Film.GetSampleBounds(); if (pRaster.X < sampleBounds.MinPoint.X || pRaster.Z >= sampleBounds.MaxPoint.X || pRaster.Y < sampleBounds.MinPoint.Y || pRaster.Y >= sampleBounds.MaxPoint.Y) { return(Spectrum.Create(0.0)); } // Compute lens area of perspective camera double lensArea = LensRadius != 0.0 ? (Math.PI * LensRadius * LensRadius) : 1.0; // Return importance for point on image plane double cos2Theta = cosTheta * cosTheta; return(Spectrum.Create(1.0 / (_a * lensArea * cos2Theta * cos2Theta))); }