public override SampledSpectrum Sample(Vector3 leaving, out Vector3 incoming) { var entering = CosTheta(ref leaving) > 0; float ei, et; if (entering) { ei = IndexOfRefractionIncident; et = IndexOfRefractionTransmitted; } else { et = IndexOfRefractionIncident; ei = IndexOfRefractionTransmitted; } var sinIncidentSquared = SinThetaSquared(ref leaving); var eta = ei / et; var sinTransmittedSquared = eta * eta * sinIncidentSquared; var cosTransmitted = (float)Math.Sqrt(1 - sinTransmittedSquared); if (entering) { cosTransmitted = -cosTransmitted; } var sinTOversinI = eta; incoming = new Vector3(sinTOversinI * -leaving.X, sinTOversinI * -leaving.Y, cosTransmitted); if (sinTransmittedSquared >= 1) { return(SampledSpectrum.Black()); } var f = _fresnel.Evaluate(CosTheta(ref leaving)); return((new SampledSpectrum(1) - f) * _s / AbsCosTheta(ref incoming) * (et * et) / (ei * ei)); }
public override SampledSpectrum Li(Scene scene, Ray ray, Renderer renderer, Sample sample, ref Intersection i) { var spectrum = SampledSpectrum.Black(); var lights = scene.Lights; var bsdfAtPoint = i.GetBSDF(); // we want to get the radiance coming from the surface to us, but the ray comes from us // to the surface var leaving = -ray.Direction; foreach (var light in lights) { Vector3 incoming; VisibilityTester visibilityTester; var lightSpectrum = light.Sample(ref i.Point, scene, out incoming, out visibilityTester); // We compute the BSDF value only if the light is not black and it is not occluded. Note that it is important // for the occlusion test to be after the test for black spectrum, because checking for intersection is an // expansive operation. if (!lightSpectrum.IsBlack() && !visibilityTester.Occluded()) { var cosangle = Math.Abs(Vector3.Dot(incoming, i.NormalVector)); // we get the light coming to us from transmission + reflection var bsdf = bsdfAtPoint.F(incoming, leaving, BxDF.BxDFType.All); // we scale the light by the incident angle of light on the surface and by the distribution // function from light to us and we add it to the spectrum spectrum += bsdf * lightSpectrum * cosangle; } } if (ray.Depth + 1 < MaxDepth) { spectrum += SpecularTransmit(ray, renderer, sample, bsdfAtPoint, ref i); spectrum += SpecularReflect(ray, renderer, sample, bsdfAtPoint, ref i); } return(spectrum); }
/// <summary> /// Choose an incoming direction on the view from a BxDF matching a type /// and returns its contribution /// </summary> /// <param name="leaving">the vector leaving the surface</param> /// <param name="incoming">the vector arriving at the surface, the function will set it</param> /// <param name="type">the type of scattering</param> /// <returns></returns> public SampledSpectrum Sample(Vector3 leaving, ref Vector3 incoming, BxDF.BxDFType type) { /* we randomly choose a BxDF that matches the type */ var matchingBxDFs = _bxdfs.Where(f => type.HasFlag(f.Type)).ToList(); // the list of bxdf matching the type if (matchingBxDFs.Count == 0) { return(SampledSpectrum.Black()); } // random selection over matching bxdfs var bxdf = matchingBxDFs.ElementAt(Math.Min((int)(StaticRandom.NextFloat() * matchingBxDFs.Count), matchingBxDFs.Count - 1)); var leavingLocal = WorldToLocal(ref leaving); Vector3 incomingLocal; // we sample the chosen bxdf var spectrum = bxdf.Sample(leavingLocal, out incomingLocal); // we transform the incoming ray returned by the sampling to world space incoming = LocalToWorld(ref incomingLocal); // is the reflection is not specular, we add contribution from other bxdfs of the same type if (!bxdf.Type.HasFlag(BxDF.BxDFType.Reflection)) { spectrum = _bxdfs.Where(b => type.HasFlag(b.Type)) .Aggregate(spectrum, (current, b) => current + b.F(incomingLocal, leavingLocal)); } return(spectrum); }
private SampledSpectrum SampleLights(Scene scene, BSDF bsdf, ref Intersection intersection, ref Vector3 leaving) { var lights = scene.Lights; var spectrum = SampledSpectrum.Black(); foreach (var light in lights) { var nsamples = _strategy == LightSamplingStrategy.Multiple ? light.NSamples : 1; var lightContribution = SampledSpectrum.Black(); for (var i = 0; i < nsamples; ++i) { Vector3 incoming; VisibilityTester visibilityTester; var lightSpectrum = light.Sample(ref intersection.Point, scene, out incoming, out visibilityTester); if (lightSpectrum.IsBlack() || visibilityTester.Occluded()) { continue; } var cosangle = Math.Abs(Vector3.Dot(incoming, intersection.NormalVector)); // we get the light coming to us from transmission + reflection var distribution = bsdf.F(incoming, leaving, BxDF.BxDFType.All); // we scale the light by the incident angle of light on the surface and by the distribution // function from light to us and we add it to the spectrum lightContribution += distribution * lightSpectrum * cosangle; } spectrum += lightContribution / nsamples; } return(spectrum); }
public SampledSpectrum F(Vector3 incoming, Vector3 leaving, BxDF.BxDFType type) { var s = SampledSpectrum.Black(); var incomingLocal = WorldToLocal(ref incoming); var leavingLocal = WorldToLocal(ref leaving); return(_bxdfs.Where(bxdf => type.HasFlag(bxdf.Type)) .Aggregate(s, (current, bxdf) => current + bxdf.F(incomingLocal, leavingLocal))); }
public override SampledSpectrum Li(Scene scene, Ray ray, Renderer renderer, Sample sample, ref Intersection intersection) { var spectrum = SampledSpectrum.Black(); var bsdfAtPoint = intersection.GetBSDF(); var leaving = -ray.Direction; spectrum += SampleLights(scene, bsdfAtPoint, ref intersection, ref leaving); if (ray.Depth + 1 < MaxDepth) { spectrum += SpecularTransmit(ray, renderer, sample, bsdfAtPoint, ref intersection); spectrum += SpecularReflect(ray, renderer, sample, bsdfAtPoint, ref intersection); } return(spectrum); }
public SampledSpectrum SpecularTransmit(Ray ray, Renderer renderer, Sample sample, BSDF bsdf, ref Intersection i) { var leaving = -ray.Direction; var incoming = new Vector3(); var f = bsdf.Sample(leaving, ref incoming, BxDF.BxDFType.Transmission | BxDF.BxDFType.Specular); var angle = Math.Abs(Vector3.Dot(incoming.Normalized(), i.NormalVector)); if (f.IsBlack() || angle == 0f) { return(SampledSpectrum.Black()); } var reflectedRay = new Ray(incoming.Normalized(), i.Point, 0.1f, Ray.DefaultEndValue, ray.Depth + 1); var li = renderer.Li(sample, reflectedRay); return(f * li * angle); }
/// <summary> /// Compute radiance for a sample /// </summary> /// <param name="sample"></param> /// <param name="ray"></param> /// <returns></returns> public SampledSpectrum Li(Sample sample, Ray ray = null) { ray = ray ?? Camera.GenerateRay(sample); var intersection = new Intersection(); var spectrum = SampledSpectrum.Black(); if (Scene.TryToIntersect(ray, ref intersection)) { spectrum = Integrator.Li(Scene, ray, this, sample, ref intersection); } else { spectrum = Scene.Lights.Aggregate(spectrum, (current, light) => current + light.Le(ray)); } return(spectrum); }
/// <summary> /// </summary> /// <remarks>This function let us choose the incoming vector</remarks> /// <param name="leaving"></param> /// <param name="incoming"></param> /// <returns></returns> public override SampledSpectrum Sample(Vector3 leaving, out Vector3 incoming) { /* Since we are in the reflection system, rotating the vector by PI radians * around the normal consists of negating its x component and its y component */ incoming = new Vector3(-leaving.X, -leaving.Y, leaving.Z); var abscostheta = AbsCosTheta(ref incoming); var reflectedLight = SampledSpectrum.Black(); if (_fresnel != null) { var reflectedAmount = _fresnel.Evaluate(CosTheta(ref incoming)); reflectedLight = _spectrum * reflectedAmount / abscostheta; } else { reflectedLight = _spectrum * _reflectiveness / abscostheta; } return(reflectedLight); }
/// <summary> /// </summary> /// <remarks> /// This function returns nothing since it is nearly impossible to have /// a correct incoming vector (there is only a single incoming vector) /// </remarks> /// <param name="incoming"></param> /// <param name="leaving"></param> /// <returns></returns> public override SampledSpectrum F(Vector3 incoming, Vector3 leaving) { return(SampledSpectrum.Black()); }
/// <summary> /// Return the spectrum of light when ray does not hit anything. /// </summary> /// <param name="ray">the ray</param> /// <returns></returns> public virtual SampledSpectrum Le(Ray ray) { return(SampledSpectrum.Black()); }