private Vector GetContributionFromLightSourceSampling(IntersectionPoint point, Random rand, Vector pathWeight) { //Sample Point on LightSource var lightPoint = data.LightSource.SampleRandomPointOnLightSource(rand); Vector directionToLight = (lightPoint.Position - point.Position).Normalize(); //Shadow-Ray-Test: Test is the Point on Lightsource visible from 'point'? var lightVisiblePoint = this.intersectionFinder.GetIntersectionPoint(new Ray(point.Position, directionToLight)); float DistanceForPoint2PointVisibleCheck = 0.0001f; //Magic Number bool isVisible = lightVisiblePoint != null && (lightVisiblePoint.Position - lightPoint.Position).Length() < DistanceForPoint2PointVisibleCheck; if (isVisible == false) { return(new Vector(0, 0, 0)); //No contribution, if 'point' is located in shadow } //Pathcontribution from Lightsource-Sampling float cosAtPoint = Math.Max(0, Vector.Dot(point.Normal, directionToLight)); float cosAtLight = Math.Max(0, Vector.Dot(lightPoint.Normal, -directionToLight)); float geometryFactor = cosAtPoint * cosAtLight / (lightPoint.Position - point.Position).SqrLength(); float pdfAFromLightSourceSampling = data.LightSource.PdfA; //This is the PdfA for sampling the lightPoint on the Position lightPoint.Position Vector contributionFromLightSampling = Vector.Mult(pathWeight, DiffuseBrdf.Evaluate(point)) * geometryFactor * data.LightSource.EmissionPerArea / pdfAFromLightSourceSampling; //Get PdfA from Brdf-Sampling. float pdfW = DiffuseBrdf.PdfW(point.Normal, directionToLight); float continuationPdf = Math.Min(1, point.Color.Max()); //This is the PdfA, to hit the LightSource with Brdf-Sampling and hit the Lightsource on the Position lightPoint.Position //The Factor "cosAtLight / (lightPoint.Position - point.Position).SqrLength()" is the pdfW to PdfA-Conversionfactor. //This means, you project to Solid Angle Measure from the Brdf to the surface area measure on the Point on the Light float pdfAFromBrdfSampling = pdfW * continuationPdf * cosAtLight / (lightPoint.Position - point.Position).SqrLength(); //Heare we have used LightSource-Sampling for the Creation of the Point on the LightSource. So we use pdfAFromLightSourceSampling in the numerator float misFactor = pdfAFromLightSourceSampling / (pdfAFromLightSourceSampling + pdfAFromBrdfSampling); contributionFromLightSampling *= misFactor; return(contributionFromLightSampling); }
private List <Photon> TracePhoton(Random rand) { var lightPoint = this.lightSource.GetRandomPointOnLightSource(rand); Vector direction = DiffuseBrdf.SampleDirection(lightPoint.Normal, rand); float pdfW = DiffuseBrdf.PdfW(lightPoint.Normal, direction); float lambda = Vector.Dot(lightPoint.Normal, direction); Vector pathWeight = lightPoint.Color * lambda / (lightPoint.PdfA * pdfW); Ray ray = new Ray(lightPoint.Position, direction); //PhotonType type = PhotonType.None; int maxPathLength = 5; List <Photon> photons = new List <Photon>(); for (int i = 0; i < maxPathLength; i++) { var point = this.intersectionFinder.GetIntersectionPoint(ray); if (point == null) { return(photons); } photons.Add(new Photon(point.Position, point.Normal, pathWeight / this.photonCount, ray.Direction)); //Abbruch mit Russia Rollete float continuationPdf = Math.Min(1, point.Color.Max()); if (rand.NextDouble() >= continuationPdf) { return(photons); // Absorbation } Vector newDirection = DiffuseBrdf.SampleDirection(point.Normal, rand); pathWeight = Vector.Mult(pathWeight * Vector.Dot(point.Normal, newDirection) / DiffuseBrdf.PdfW(point.Normal, newDirection), DiffuseBrdf.Evaluate(point)) / continuationPdf; ray = new Ray(point.Position, newDirection); } return(photons); }
private Vector[,] EstimateFrameWithLightracing(int width, int height, Random rand) { int lightPathsPerIteration = width * height; int maxPathLength = 5; Vector[,] frame = new Vector[width, height]; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { frame[x, y] = new Vector(0, 0, 0); } } for (int j = 0; j < lightPathsPerIteration; j++) { //Sample Position on Lightsource var point = data.LightSource.SampleRandomPointOnLightSource(rand); //Pathweight Vector pathWeight = new Vector(1, 1, 1) * data.LightSource.EmissionPerArea / data.LightSource.PdfA; //Connect Point on Lightsource with Camera var c = TryToConnectPointWithCamera(point, pathWeight, lightPathsPerIteration); if (c != null) { frame[c.PixelX, c.PixelY] += c.PathContribution; } //Sample Direction from Point on LightSource into scene. Use the diffuse Brdf Vector direction = DiffuseBrdf.SampleDirection(point.Normal, rand); //Direct vom Point on Light into some point in scene float pdfW = DiffuseBrdf.PdfW(point.Normal, direction); //PDF with Respect to Solid Angle from 'direction' //New Pathweight after sampling direction float cosAtPoint = Math.Max(0, Vector.Dot(point.Normal, direction)); pathWeight *= cosAtPoint / pdfW; Ray ray = new Ray(point.Position, direction); for (int k = 1; k < maxPathLength; k++) { //Get next intersectionpoint with scene starting from old point-Position point = this.intersectionFinder.GetIntersectionPoint(ray); if (point == null) { break; //Break Light-Path-Creation } //Connect Point in scene with Camera c = TryToConnectPointWithCamera(point, pathWeight, lightPathsPerIteration); if (c != null) { frame[c.PixelX, c.PixelY] += c.PathContribution; } //The Lightsource dosn't reflect light if (point.IsLocatedOnLightSource) { break; } //Break with Russia Rollete float continuationPdf = Math.Min(1, point.Color.Max()); if (rand.NextDouble() >= continuationPdf) { break; // Absorbation } //Go ahead with lighttracing after connection with camera direction = DiffuseBrdf.SampleDirection(point.Normal, rand); pdfW = DiffuseBrdf.PdfW(point.Normal, direction); cosAtPoint = Math.Max(0, Vector.Dot(point.Normal, direction)); pathWeight = Vector.Mult(pathWeight, DiffuseBrdf.Evaluate(point)) * cosAtPoint / (pdfW * continuationPdf); ray = new Ray(point.Position, direction); } } return(frame); }
private Vector EstimateColorWithPathtracing(int x, int y, Random rand) { Ray primaryRay = data.Camera.GetPrimaryRay(x, y); float cosAtCamera = Vector.Dot(primaryRay.Direction, this.data.Camera.Forward); Vector pathWeight = new Vector(1, 1, 1) * cosAtCamera; Ray ray = primaryRay; int maxPathLength = 5; for (int i = 0; i < maxPathLength; i++) { var point = this.intersectionFinder.GetIntersectionPoint(ray); if (point == null) { return(new Vector(0, 0, 0)); } if (point.IsLocatedOnLightSource && Vector.Dot(point.Normal, -ray.Direction) > 0) { pathWeight = Vector.Mult(pathWeight, point.Emission); return(pathWeight); } //Abbruch mit Russia Rollete float continuationPdf = Math.Min(1, point.Color.Max()); if (rand.NextDouble() >= continuationPdf) { return(new Vector(0, 0, 0)); // Absorbation } Vector newDirection = DiffuseBrdf.SampleDirection(point.Normal, rand); pathWeight = Vector.Mult(pathWeight * Vector.Dot(point.Normal, newDirection) / DiffuseBrdf.PdfW(point.Normal, newDirection), DiffuseBrdf.Evaluate(point)) / continuationPdf; ray = new Ray(point.Position, newDirection); } return(new Vector(0, 0, 0)); }
private Vector EstimateColorWithPathtracingWithNextEventEstimation(int x, int y, Random rand) { //This is the sum from all Pathcontributions from all Pathlenghts up to maxPathLength //This means Contribution(C L) + Contribution(C D L) + Contribution(C D D L) + Contribution(C D D D L) + Contribution(C D D D D L) //For Each Pathlength-Step, the Contribution from Brdf-Sampling and Lightsource-Sampling is added but only one from this two Sampling-Methods //will create a Contribution != 0. If you hit the Lightsource, then you only get the BrdfSampling-Contribution. The LightSource-Sampling-Contribution //will be zero because if your running point is on the light and the light don't reflect any light, then you don't can create any more Lightpoints //If you are on a Point in the Scene (Not Lightsoure) then only the Contribution from Lightsource-Sampling can be greater zero. The Brdf-Sampling //Contribution (Pathtracing) will be zero. Vector contributionSum = new Vector(0, 0, 0); Ray primaryRay = data.Camera.GetPrimaryRay(x, y); float cosAtCamera = Vector.Dot(primaryRay.Direction, this.data.Camera.Forward); Vector pathWeight = new Vector(1, 1, 1) * cosAtCamera; Ray ray = primaryRay; float pdfW = data.Camera.PdfWForPrimaryRayDirectionSampling(ray.Direction); //This will store the PdfW and Contination Pdf, which was used for Brdf-Sampling int maxPathLength = 5; for (int i = 0; i < maxPathLength; i++) { IntersectionPoint point = this.intersectionFinder.GetIntersectionPoint(ray); if (point == null) { break; //Ray leave the scene } //Try to add Contribution from Brdf-Sampling (This Brdf-Sampling is also called Pathtracing because you do this for every Pathpoint) if (point.IsLocatedOnLightSource && Vector.Dot(point.Normal, -ray.Direction) > 0) { //This is the PdfA on the LightPoint, if you would use LightSource-Sampling, to reach from lastPoint(ray.Origin) to current point 'point' float pdfAFromLightSourceSampling = data.LightSource.PdfA; //This is the PdfA on the LightPoint, which you get from BrdfSampling to reach rom lastPoint(ray.Origin) to current point 'point' float pdfAFromBrdfSampling = pdfW * Vector.Dot(point.Normal, -ray.Direction) / (ray.Origin - point.Position).SqrLength(); //We have used Brdf-Sampling. So the pdfAFromBrdfSampling is in the numerator float misFactor = pdfAFromBrdfSampling / (pdfAFromLightSourceSampling + pdfAFromBrdfSampling); Vector contributionFromBrdfSampling = Vector.Mult(pathWeight, point.Emission) * misFactor; contributionSum += contributionFromBrdfSampling; break; //The light don't reflect any light. So stop here with Pathtracing } //Try to add Contribution from Lightsource-Sampling (This is the Next Event Estimation-Sampling) contributionSum += GetContributionFromLightSourceSampling(point, rand, pathWeight); //Stop with Russia Rollete float continuationPdf = Math.Min(1, point.Color.Max()); if (rand.NextDouble() >= continuationPdf) { break; // Absorbation } //Sample Direction and try to hit to lightSource Vector direction = DiffuseBrdf.SampleDirection(point.Normal, rand); pdfW = DiffuseBrdf.PdfW(point.Normal, direction) * continuationPdf; float cosAtPoint = Math.Max(0, Vector.Dot(point.Normal, direction)); pathWeight = Vector.Mult(pathWeight, DiffuseBrdf.Evaluate(point)) * cosAtPoint / pdfW; //New Pathweight after Brdf-Sampling ray = new Ray(point.Position, direction); } return(contributionSum); }
private Vector EstimateColorWithPhotonmapping(int x, int y, Random rand, Photonmap photonmap) { Ray primaryRay = data.Camera.GetPrimaryRay(x, y); float cosAtCamera = Vector.Dot(primaryRay.Direction, this.data.Camera.Forward); Vector pathWeight = new Vector(1, 1, 1) * cosAtCamera; var eyePoint = this.intersectionFinder.GetIntersectionPoint(primaryRay); Vector pixelColor = new Vector(0, 0, 0); if (eyePoint != null) { if (eyePoint.IsLocatedOnLightSource) { return(eyePoint.Emission); } pathWeight = Vector.Mult(pathWeight, DiffuseBrdf.Evaluate(eyePoint)); //Direct Lighting var lightPoint = data.LightSource.GetRandomPointOnLightSource(rand); if (IsVisible(eyePoint.Position, lightPoint.Position)) { pixelColor += Vector.Mult(pathWeight, lightPoint.Color * GeometryTerm(eyePoint, lightPoint) / lightPoint.PdfA); } //Final Gathering Vector newDirection = DiffuseBrdf.SampleDirection(eyePoint.Normal, rand); pathWeight = pathWeight * Vector.Dot(eyePoint.Normal, newDirection) / DiffuseBrdf.PdfW(eyePoint.Normal, newDirection); var finalGatherPoint = this.intersectionFinder.GetIntersectionPoint(new Ray(eyePoint.Position, newDirection)); if (finalGatherPoint != null) { //100000 3000 1000 float searchRadius = 0.00634257728f * 2;//0.0383904837f;//0.065260686f; var photons = photonmap.SearchPhotons(finalGatherPoint, searchRadius); float kernelFunction = 1.0f / (searchRadius * searchRadius * (float)Math.PI); foreach (var photon in photons) { pixelColor += Vector.Mult(pathWeight, Vector.Mult(DiffuseBrdf.Evaluate(finalGatherPoint), photon.PathWeight) * kernelFunction); } } } return(pixelColor); }