public PdfRatio(BidirPathPdfs pdfs, float radius, int numPaths, JendersieFootprint parent)
            {
                this.numPaths = numPaths;
                this.parent   = parent;
                int numSurfaceVertices = pdfs.PdfsCameraToLight.Length - 1;

                cameraToLight = new float[numSurfaceVertices];
                lightToCamera = new float[numSurfaceVertices];

                float offset = 0.01f;

                // gather camera "footprint"
                float sum = 1 / (offset + MathF.Sqrt(pdfs.PdfsCameraToLight[0]));

                cameraToLight[0] = sum;
                for (int i = 1; i < numSurfaceVertices; ++i)
                {
                    float next = pdfs.PdfsCameraToLight[i];
                    sum += 1 / (offset + MathF.Sqrt(next));
                    cameraToLight[i] = sum;
                }

                // gather light "footprint"
                sum = 1 / (offset + MathF.Sqrt(pdfs.PdfsLightToCamera[numSurfaceVertices - 1]));
                lightToCamera[numSurfaceVertices - 1] = sum;
                for (int i = numSurfaceVertices - 2; i >= 0; --i)
                {
                    float next = pdfs.PdfsLightToCamera[i];
                    sum += 1 / (offset + MathF.Sqrt(next));
                    lightToCamera[i] = sum;
                }
            }
Esempio n. 2
0
            public PdfRatio(BidirPathPdfs pdfs, float radius, int numPaths, PdfRatioVcm parent,
                            float distToCam)
            {
                this.numPaths = numPaths;
                this.parent   = parent;

                if (parent.RadiusInitializer == null)
                {
                    Debug.Assert(parent.UseUpperBound);
                    cameraToLight = null;
                    lightToCamera = null;
                    return;
                }

                radius = parent.RadiusInitializer.ComputeRadius(parent.scene.Radius,
                                                                pdfs.PdfsCameraToLight[0], distToCam);

                int numSurfaceVertices = pdfs.PdfsCameraToLight.Length - 1;

                cameraToLight = new float[numSurfaceVertices];
                lightToCamera = new float[numSurfaceVertices];

                float acceptArea = radius * radius * MathF.PI;

                // Gather camera probability
                float product = 1.0f;

                for (int i = 0; i < numSurfaceVertices; ++i)
                {
                    float next = pdfs.PdfsCameraToLight[i] * acceptArea;
                    next             = MathF.Min(next, 1.0f);
                    product         *= next;
                    cameraToLight[i] = product;
                }

                // Gather light probability
                product = 1.0f;
                for (int i = numSurfaceVertices - 1; i >= 0; --i)
                {
                    float next = pdfs.PdfsLightToCamera[i] * acceptArea;

                    if (i == numSurfaceVertices - 1)
                    {
                        next *= acceptArea; // TODO unless environment map! (in that case: different radius approach)
                    }
                    next             = MathF.Min(next, 1.0f);
                    product         *= next;
                    lightToCamera[i] = product;
                }
            }
Esempio n. 3
0
        public override float EmitterHitMis(CameraPath cameraPath, float pdfEmit, float pdfNextEvent)
        {
            int          numPdfs             = cameraPath.Vertices.Count;
            int          lastCameraVertexIdx = numPdfs - 1;
            Span <float> camToLight          = stackalloc float[numPdfs];
            Span <float> lightToCam          = stackalloc float[numPdfs];

            if (numPdfs == 1)
            {
                return(1.0f);              // sole technique for rendering directly visible lights.
            }
            var pathPdfs = new BidirPathPdfs(LightPaths.PathCache, lightToCam, camToLight);

            pathPdfs.GatherCameraPdfs(cameraPath, lastCameraVertexIdx);

            pathPdfs.PdfsLightToCamera[^ 2] = pdfEmit;
        public float ComputeNeeFactor(BidirPathPdfs pdfs, PathVertex?lightVertex, int numPdfs,
                                      int lastCameraVertexIdx, float pdfNextEvent, float distToCam)
        {
            if (numPdfs <= 2)
            {
                return(1); // Direct illumination has no correlation
            }

            // Set a radius for the probability approximations.
            float radius     = RadiusInitializer.ComputeRadius(scene.Radius, pdfs.PdfsCameraToLight[0], distToCam);
            float acceptArea = radius * radius * MathF.PI;

            // Compute the camera path determinism up until the last vertex
            int   numSurfaceVertices = pdfs.PdfsCameraToLight.Length - 1;
            float cameraProbability  = 1.0f;

            for (int i = 0; i < numSurfaceVertices; ++i)
            {
                float next = pdfs.PdfsCameraToLight[i] * acceptArea;
                next = MathF.Min(next, 1.0f);
                cameraProbability *= next;
            }

            // Retrieve the next event pdf from the second to last light path vertex (if it exists)
            while (lightVertex?.Depth > 2)
            {
                var ancestor = lightPaths.PathCache[lightVertex.Value.PathId, lightVertex.Value.AncestorId];
                lightVertex = ancestor;
            }
            if (lightVertex?.Depth == 2)
            {
                pdfNextEvent = lightVertex.Value.PdfNextEventAncestor;
            }
            float nextEventProbability = acceptArea * pdfNextEvent / NumShadowRays;

            nextEventProbability = MathF.Min(nextEventProbability, 1.0f);

            float denom  = cameraProbability + nextEventProbability - cameraProbability * nextEventProbability;
            float factor = cameraProbability / denom;

            // Make sure that we only ever increase the weight, going below the provable upper bound
            // will always hurt the outcome!
            factor = MathF.Max(factor, 1.0f / NumShadowRays);

            // Compute the new joint pdf of BSDF and next event sampling
            float pdfBsdf = pdfs.PdfsCameraToLight[^ 1] - pdfNextEvent;
        public override float MergeMis(CameraPath cameraPath, PathVertex lightVertex, float pdfCameraReverse,
                                       float pdfLightReverse, float pdfNextEvent)
        {
            int          numPdfs             = cameraPath.Vertices.Count + lightVertex.Depth;
            int          lastCameraVertexIdx = cameraPath.Vertices.Count - 1;
            Span <float> camToLight          = stackalloc float[numPdfs];
            Span <float> lightToCam          = stackalloc float[numPdfs];
            var          pathPdfs            = new BidirPathPdfs(lightPaths.PathCache, lightToCam, camToLight);

            pathPdfs.GatherCameraPdfs(cameraPath, lastCameraVertexIdx);
            pathPdfs.GatherLightPdfs(lightVertex, lastCameraVertexIdx - 1, numPdfs);

            // Set the pdf values that are unique to this combination of paths
            if (lastCameraVertexIdx > 0) // only if this is not the primary hit point
            {
                pathPdfs.PdfsLightToCamera[lastCameraVertexIdx - 1] = pdfCameraReverse;
            }
            pathPdfs.PdfsLightToCamera[lastCameraVertexIdx]     = lightVertex.PdfFromAncestor;
            pathPdfs.PdfsCameraToLight[lastCameraVertexIdx]     = cameraPath.Vertices[^ 1].PdfFromAncestor;
        public float ComputeNeeFactor(BidirPathPdfs pdfs, PathVertex?lightVertex, int numPdfs,
                                      int lastCameraVertexIdx, float pdfNextEvent, Vector2 pixel)
        {
            if (numPdfs <= 2)
            {
                return(1); // Direct illumination has no correlation
            }

            float factor = varianceFactors.Get(numPdfs - 2, pixel);

            // Retrieve the next event pdf from the second to last light path vertex (if it exists)
            while (lightVertex?.Depth > 2)
            {
                var ancestor = lightPaths.PathCache[lightVertex.Value.PathId, lightVertex.Value.AncestorId];
                lightVertex = ancestor;
            }
            if (lightVertex?.Depth == 2)
            {
                pdfNextEvent = lightVertex.Value.PdfNextEventAncestor;
            }

            // Compute the new joint pdf of BSDF and next event sampling
            float pdfBsdf = pdfs.PdfsCameraToLight[^ 1] - pdfNextEvent;