Exemple #1
0
        public override (Ray, RgbColor, float) SampleRay(Vector2 primaryPos, Vector2 primaryDir)
        {
            // Sample a direction from the scene to the background
            var dirSample = SampleDirection(primaryDir);

            // Sample a point on the unit disc
            var unitDiscPoint = SampleWarp.ToConcentricDisc(primaryPos);

            // And transform it to the scene spanning disc orthogonal to the selected direction
            Vector3 tangent, binormal;

            ShadingSpace.ComputeBasisVectors(dirSample.Direction, out tangent, out binormal);
            var pos = SceneCenter + SceneRadius * (dirSample.Direction            // offset outside of the scene
                                                   + tangent * unitDiscPoint.X    // remap unit disc x coordinate
                                                   + binormal * unitDiscPoint.Y); // remap unit disc y coordinate

            // Compute the pdf: uniform sampling of a disc with radius "SceneRadius"
            float discJacobian = SampleWarp.ToConcentricDiscJacobian();
            float posPdf       = discJacobian / (SceneRadius * SceneRadius);

            // Compute the final result
            var ray = new Ray {
                Origin = pos, Direction = -dirSample.Direction, MinDistance = 0
            };
            var weight = dirSample.Weight / posPdf;
            var pdf    = posPdf * dirSample.Pdf;

            return(ray, weight, pdf);
        }
Exemple #2
0
        /// <summary>
        /// Generates a ray from a position in the image into the scene
        /// </summary>
        /// <param name="filmPos">
        ///     Position on the film plane: integer pixel coordinates and fractional position within
        /// </param>
        /// <param name="rng">
        ///     Random number generator used to sample additional decisions (lens position for depth of field)
        /// </param>
        /// <returns>The sampled camera ray and related information like PDF and contribution</returns>
        public override CameraRaySample GenerateRay(Vector2 filmPos, RNG rng)
        {
            Debug.Assert(Width != 0 && Height != 0);

            // Transform the direction from film to world space.
            // The view space is vertically flipped compared to the film.
            var view     = new Vector3(2 * filmPos.X / Width - 1, 1 - 2 * filmPos.Y / Height, 0);
            var localDir = Vector3.Transform(view, viewToCamera);
            var dirHomo  = Vector4.Transform(new Vector4(localDir, 0), cameraToWorld);
            var dir      = new Vector3(dirHomo.X, dirHomo.Y, dirHomo.Z);

            // Compute the camera position
            var pos = Vector3.Transform(new Vector3(0, 0, 0), cameraToWorld);

            var ray = new Ray {
                Direction = Vector3.Normalize(dir), MinDistance = 0, Origin = pos
            };

            // Sample depth of field
            float pdfLens = 1;

            if (lensRadius > 0)
            {
                var lensSample = rng.NextFloat2D();
                var lensPos    = lensRadius * SampleWarp.ToConcentricDisc(lensSample);

                // Intersect ray with focal plane
                var focalPoint = ray.ComputePoint(focalDistance / ray.Direction.Z);

                // Update the ray
                ray.Origin    = new Vector3(lensPos, 0);
                ray.Direction = Vector3.Normalize(focalPoint - ray.Origin);

                pdfLens = 1 / (MathF.PI * lensRadius * lensRadius);
            }

            return(new CameraRaySample {
                Ray = ray,
                Weight = RgbColor.White,
                Point = new SurfacePoint {
                    Position = Position, Normal = Direction
                },
                PdfRay = SolidAngleToPixelJacobian(pos + dir) * pdfLens,
                PdfConnect = pdfLens
            });
        }
Exemple #3
0
        /// <summary>
        /// Samples a point on the camera lens that sees the given surface point. Returns an invalid
        /// sample if there is no such point.
        /// </summary>
        /// <param name="scenePoint">A point on a scene surface that might be seen by the camera</param>
        /// <param name="rng">RNG used to sample the lens. Can be null if the lens radius is zero.</param>
        /// <returns>The pixel coordinates and weights, or an invalid sample</returns>
        public override CameraResponseSample SampleResponse(SurfacePoint scenePoint, RNG rng)
        {
            Debug.Assert(Width != 0 && Height != 0);

            // Sample a point on the lens
            Vector3 lensPoint = Position;

            if (lensRadius > 0)
            {
                var lensSample   = rng.NextFloat2D();
                var lensPosCam   = lensRadius * SampleWarp.ToConcentricDisc(lensSample);
                var lensPosWorld = Vector4.Transform(new Vector4(lensPosCam.X, lensPosCam.Y, 0, 1), cameraToWorld);
                lensPoint = new(lensPosWorld.X, lensPosWorld.Y, lensPosWorld.Z);
            }

            // Map the scene point to the film
            var filmPos = WorldToFilm(scenePoint.Position);

            if (!filmPos.HasValue)
            {
                return(CameraResponseSample.Invalid);
            }

            // Compute the change of variables from scene surface to pixel area
            float jacobian = SolidAngleToPixelJacobian(scenePoint.Position);

            jacobian *= SurfaceAreaToSolidAngleJacobian(scenePoint.Position, scenePoint.Normal);

            // Compute the pdfs
            float invLensArea = 1;

            if (lensRadius > 0)
            {
                invLensArea = 1 / (MathF.PI * lensRadius * lensRadius);
            }
            float pdfConnect = invLensArea;
            float pdfEmit    = invLensArea * jacobian;

            return(new CameraResponseSample {
                Pixel = new(filmPos.Value.X, filmPos.Value.Y),
                Position = lensPoint,
                Weight = jacobian * RgbColor.White,
                PdfConnect = pdfConnect,
                PdfEmit = pdfEmit
            });