Skip to content

Commit

Permalink
tune PM radius
Browse files Browse the repository at this point in the history
  • Loading branch information
pgrit committed Sep 3, 2024
1 parent 613f345 commit 2ef6955
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 11 deletions.
11 changes: 11 additions & 0 deletions SeeSharp/Integrators/Bidir/BidirBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ public struct CameraPath {
public SurfacePoint CurrentPoint;
public SurfacePoint PreviousPoint;

/// <summary>
/// Approximated radius of the pixel footprint, i.e., the projection of the pixel this path started in
/// onto the visible surface.
/// </summary>
public float FootprintRadius;

public CameraPayloadType Payload;
}

Expand Down Expand Up @@ -869,6 +875,11 @@ public override RgbColor OnHit(ref RandomWalk<CameraPath> walk, in SurfaceShader
integrator.DenoiseBuffers.LogPrimaryHit(walk.Payload.Pixel, albedo, shader.Context.Normal);
}

if (depth == 1) {
// Compute the pixel footprint (ignoring aspect ratios, approximated based on the camera Jacobian)
walk.Payload.FootprintRadius = float.Sqrt(1 / pdfFromAncestor);
}

walk.Payload.Vertices.Add(new PathPdfPair {
PdfFromAncestor = pdfFromAncestor,
PdfToAncestor = 0
Expand Down
7 changes: 6 additions & 1 deletion SeeSharp/Integrators/Bidir/LightPathCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ protected virtual void TraceEmitterPath(ref RNG rng, Emitter emitter, float sele
// Account for the light selection probability in the MIS weights
emitterSample.Pdf *= selectProb;

if (emitterSample.Pdf == 0 || emitterSample.Weight == RgbColor.Black) { // Avoid NaNs and terminate early
PathCache.Commit(idx, []);
return;
}

var walk = new Walk(Scene, ref rng, MaxDepth, walkModifier);
walk.StartFromEmitter(emitterSample, emitterSample.Weight / selectProb, new() { PathIdx = idx });
}
Expand All @@ -213,7 +218,7 @@ protected virtual void TraceBackgroundPath(ref RNG rng, float selectProb, int id
pdf *= selectProb;
weight /= selectProb;

if (pdf == 0) { // Avoid NaNs
if (pdf == 0 || weight == RgbColor.Black) { // Avoid NaNs and terminate early
PathCache.Commit(idx, []);
return;
}
Expand Down
13 changes: 13 additions & 0 deletions SeeSharp/Integrators/Bidir/VertexCacheBidir.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,25 @@ public override void Render(Scene scene) {
}
}

/// <summary>
/// Fraction of light paths that never properly started because their initial ray sampling failed
/// </summary>
public float InvalidLightPathFraction { get; private set; }

/// <summary>
/// Creates the vertex resampler and computes the light tracing contribution.
/// </summary>
protected override void ProcessPathCache() {
if (NumConnections > 0) vertexSelector = new VertexSelector(LightPaths);
if (EnableLightTracer) SplatLightVertices();

// For debug purposes: count the number of paths that never started
int numEmpty = 0;
for (int i = 0; i < LightPaths.NumPaths; ++i) {
if (LightPaths.Length(i) == 0)
numEmpty++;
}
InvalidLightPathFraction = numEmpty / (float)LightPaths.NumPaths;
}

/// <inheritdoc />
Expand Down
21 changes: 11 additions & 10 deletions SeeSharp/Integrators/Bidir/VertexConnectionAndMerging.cs
Original file line number Diff line number Diff line change
Expand Up @@ -328,11 +328,10 @@ protected virtual RgbColor Merge(in CameraPath path, float cameraJacobian, in Su
/// <summary>
/// Shrinks the global maximum radius based on the current camera path.
/// </summary>
/// <param name="primaryDistance">Distance between the camera and the primary hit point</param>
/// <param name="pixelFootprint">Radius of the pixel footprint at the primary hit point</param>
/// <returns>The shrunk radius</returns>
protected virtual float ComputeLocalMergeRadius(float primaryDistance) {
float footprint = primaryDistance * MathF.Tan(0.1f * MathF.PI / 180);
return MathF.Min(footprint, MaximumRadius);
protected virtual float ComputeLocalMergeRadius(float pixelFootprint) {
return pixelFootprint;
}

struct MergeState {
Expand Down Expand Up @@ -364,7 +363,7 @@ protected virtual RgbColor PerformMerging(in SurfaceShader shader, ref RNG rng,
if (path.Vertices.Count == 1 && !MergePrimary) return RgbColor.Black;
if (!EnableMerging) return RgbColor.Black;
if (!MergePrimary && path.Depth == 1) return RgbColor.Black;
float localRadius = ComputeLocalMergeRadius(path.Distances[0]);
float localRadius = ComputeLocalMergeRadius(path.FootprintRadius);

var state = new MergeState(cameraJacobian, localRadius * localRadius, path, shader);
photonMap.ForAllNearest(shader.Point.Position, MaxNumPhotons, localRadius, MergeHelper, ref state);
Expand Down Expand Up @@ -475,7 +474,7 @@ public virtual float MergeMis(in CameraPath cameraPath, in PathVertex lightVerte

// Compute the acceptance probability approximation
int lastCameraVertexIdx = cameraPath.Vertices.Count - 1;
float radius = ComputeLocalMergeRadius(cameraPath.Distances[0]);
float radius = ComputeLocalMergeRadius(cameraPath.FootprintRadius);
float mergeApproximation = pathPdfs.PdfsLightToCamera[lastCameraVertexIdx]
* MathF.PI * radius * radius * NumLightPaths.Value;

Expand Down Expand Up @@ -511,7 +510,7 @@ public override float EmitterHitMis(in CameraPath cameraPath, in BidirPathPdfs p
sumReciprocals += pathPdfs.PdfNextEvent / pdfThis;

// All connections along the camera path
float radius = ComputeLocalMergeRadius(cameraPath.Distances[0]);
float radius = ComputeLocalMergeRadius(cameraPath.FootprintRadius);
sumReciprocals +=
CameraPathReciprocals(cameraPath.Vertices.Count - 2, pathPdfs, cameraPath.Pixel, radius, correlRatio)
/ pdfThis;
Expand All @@ -523,7 +522,9 @@ public override float EmitterHitMis(in CameraPath cameraPath, in BidirPathPdfs p
public override float LightTracerMis(PathVertex lightVertex, in BidirPathPdfs pathPdfs, Pixel pixel, float distToCam) {
var correlRatio = new CorrelAwareRatios(pathPdfs, distToCam, lightVertex.FromBackground);

float radius = ComputeLocalMergeRadius(distToCam);
float footprintRadius = float.Sqrt(1.0f / pathPdfs.PdfsCameraToLight[0]);

float radius = ComputeLocalMergeRadius(footprintRadius);
float sumReciprocals = LightPathReciprocals(-1, pathPdfs, pixel, radius, correlRatio);
sumReciprocals /= NumLightPaths.Value;
sumReciprocals += 1;
Expand All @@ -535,7 +536,7 @@ public override float LightTracerMis(PathVertex lightVertex, in BidirPathPdfs pa
public override float BidirConnectMis(in CameraPath cameraPath, PathVertex lightVertex, in BidirPathPdfs pathPdfs) {
var correlRatio = new CorrelAwareRatios(pathPdfs, cameraPath.Distances[0], lightVertex.FromBackground);

float radius = ComputeLocalMergeRadius(cameraPath.Distances[0]);
float radius = ComputeLocalMergeRadius(cameraPath.FootprintRadius);
float sumReciprocals = 1.0f;
int lastCameraVertexIdx = cameraPath.Vertices.Count - 1;
sumReciprocals += CameraPathReciprocals(lastCameraVertexIdx, pathPdfs, cameraPath.Pixel, radius, correlRatio)
Expand All @@ -557,7 +558,7 @@ public override float NextEventMis(in CameraPath cameraPath, in BidirPathPdfs pa
sumReciprocals += pathPdfs.PdfsCameraToLight[^1] / pathPdfs.PdfNextEvent;

// All bidirectional connections
float radius = ComputeLocalMergeRadius(cameraPath.Distances[0]);
float radius = ComputeLocalMergeRadius(cameraPath.FootprintRadius);
sumReciprocals +=
CameraPathReciprocals(cameraPath.Vertices.Count - 1, pathPdfs, cameraPath.Pixel, radius, correlRatio)
/ pathPdfs.PdfNextEvent;
Expand Down

0 comments on commit 2ef6955

Please sign in to comment.