public IntersectionPoint GetIntersectionPoint(Ray ray) { float currentMinDistance = float.MaxValue; IntersectionPoint resultPoint = null; foreach (var triangle in this.triangles) { var point = triangle.Intersect(ray); if (point != null && point.DistanceToRayOrigin < currentMinDistance) { resultPoint = point; currentMinDistance = point.DistanceToRayOrigin; } } return(resultPoint); }
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 ConnectionData TryToConnectPointWithCamera(IntersectionPoint point, Vector pathWeight, int lightPathsPerIteration) { Vector2D pixelPosition = GetPixelPositionForScenePoint(point.Position); if (pixelPosition != null) { //GeometryTerm Vector cameraToLightPointDirection = (point.Position - data.Camera.Position).Normalize(); float cosAtCamera = Vector.Dot(cameraToLightPointDirection, data.Camera.Forward); float cosAtPoint = Vector.Dot(-cameraToLightPointDirection, point.Normal); float geomertryFaktor = (cosAtCamera * cosAtPoint) / (point.Position - data.Camera.Position).SqrLength(); //Brdf (Inputdirection is Direction from preceeding point to 'point' and Outgoingdirection is direction from 'point' to Camera-Point //In this case its a Diffuse Brdf and no Input- or Outputdirection is needed Vector brdf = DiffuseBrdf.Evaluate(point); //If you use Pathtracing and don't divide the Pathweight with the PdfW from the Camera, then you implicite multiply the Pathweight with (1 / CameraPdfW) //To get with Lightracing the same Results as with Pathtracing, you have to multipli the PathWeight with the cameraPdfW, which is also called PixelFilter float cameraPdfW = data.Camera.PdfWForPrimaryRayDirectionSampling(cameraToLightPointDirection); //cameraPdfW == PixelFilter Vector pathContribution = Vector.Mult(pathWeight, brdf) * geomertryFaktor / lightPathsPerIteration * cameraPdfW; int x = (int)pixelPosition.X; int y = (int)pixelPosition.Y; if (x >= 0 && x < width && y >= 0 && y < height) { return(new ConnectionData() { PixelX = x, PixelY = y, PathContribution = pathContribution, }); } } return(null); }
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); }
public static Vector Evaluate(IntersectionPoint point) { return(point.Color / (float)Math.PI); }
public List <Photon> SearchPhotons(IntersectionPoint searchPoint, float searchRadius) { float rSqr = searchRadius * searchRadius; return(this.kdTree.FixedRadiusSearch(searchPoint.Position, searchRadius).Cast <Photon>().Where(x => Vector.Dot(x.Normal, searchPoint.Normal) > 0).ToList()); }