Skip to content

Commit

Permalink
fix EnableHitting MIS code
Browse files Browse the repository at this point in the history
  • Loading branch information
pgrit committed Mar 27, 2024
1 parent c877531 commit 0ce7730
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 55 deletions.
45 changes: 20 additions & 25 deletions SeeSharp/Integrators/Bidir/BidirBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -390,12 +390,6 @@ void ConnectLightVertexToCamera(in PathVertex vertex, in PathVertex ancestor, Ve
if (ancestor.Point.Mesh != null)
pdfReverse *= SampleWarp.SurfaceAreaToSolidAngle(vertex.Point, ancestor.Point);

// Account for next event estimation
float pdfNextEvent = 0.0f;
if (vertex.Depth == 1) {
pdfNextEvent = NextEventPdf(vertex.Point, ancestor.Point);
}

// Gather the PDFs for MIS computation
int numPdfs = vertex.Depth + 1;
int lastCameraVertexIdx = -1;
Expand All @@ -404,7 +398,9 @@ void ConnectLightVertexToCamera(in PathVertex vertex, in PathVertex ancestor, Ve
var pathPdfs = new BidirPathPdfs(LightPaths.PathCache, lightToCam, camToLight);
pathPdfs.GatherLightPdfs(vertex, lastCameraVertexIdx);
pathPdfs.PdfsCameraToLight[0] = response.PdfEmit;
pathPdfs.PdfsCameraToLight[1] = pdfReverse + pdfNextEvent;
pathPdfs.PdfsCameraToLight[1] = pdfReverse;
if (vertex.Depth == 1)
pathPdfs.PdfNextEvent = NextEventPdf(vertex.Point, ancestor.Point);

float misWeight = LightTracerMis(vertex, pathPdfs, response.Pixel, distToCam);

Expand Down Expand Up @@ -481,11 +477,6 @@ RgbColor Connect(in SurfaceShader shader, PathVertex vertex, PathVertex ancestor
pdfLightReverse *= SampleWarp.SurfaceAreaToSolidAngle(vertex.Point, ancestor.Point);
pdfLightToCamera *= SampleWarp.SurfaceAreaToSolidAngle(vertex.Point, shader.Point);

float pdfNextEvent = 0.0f;
if (vertex.Depth == 1) {
pdfNextEvent = NextEventPdf(vertex.Point, ancestor.Point);
}

// Gather all PDFs for MIS compuation
int numPdfs = path.Vertices.Count + vertex.Depth + 1;
int lastCameraVertexIdx = path.Vertices.Count - 1;
Expand All @@ -495,14 +486,16 @@ RgbColor Connect(in SurfaceShader shader, PathVertex vertex, PathVertex ancestor
var pathPdfs = new BidirPathPdfs(LightPaths.PathCache, lightToCam, camToLight);
pathPdfs.GatherCameraPdfs(path, lastCameraVertexIdx);
pathPdfs.GatherLightPdfs(vertex, lastCameraVertexIdx);
if (vertex.Depth == 1)
pathPdfs.PdfNextEvent = NextEventPdf(vertex.Point, ancestor.Point);

// 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.PdfsCameraToLight[lastCameraVertexIdx] = path.Vertices[^1].PdfFromAncestor;
pathPdfs.PdfsLightToCamera[lastCameraVertexIdx] = pdfLightToCamera;
pathPdfs.PdfsCameraToLight[lastCameraVertexIdx + 1] = pdfCameraToLight;
pathPdfs.PdfsCameraToLight[lastCameraVertexIdx + 2] = pdfLightReverse + pdfNextEvent;
pathPdfs.PdfsCameraToLight[lastCameraVertexIdx + 2] = pdfLightReverse;

float misWeight = BidirConnectMis(path, vertex, pathPdfs);
float distanceSqr = (shader.Point.Position - vertex.Point.Position).LengthSquared();
Expand Down Expand Up @@ -567,15 +560,10 @@ protected virtual RgbColor BidirConnections(in SurfaceShader shader, ref RNG rng
/// Computes the MIS weight for next event estimation along a camera path
/// </summary>
/// <param name="cameraPath">The camera path</param>
/// <param name="pdfNextEvent">Surface area pdf of sampling the light vertex via next event</param>
/// <param name="pdfHit">
/// Surface area pdf of sampling the light vertex by continuing the camera path instead
/// </param>
/// <param name="pathPdfs">Surface area pdfs of all sampling techniques. </param>
/// <param name="isBackground">True if the path was connected to the background, false if its an area light</param>
/// <returns>MIS weight</returns>
public abstract float NextEventMis(in CameraPath cameraPath, float pdfNextEvent, float pdfHit,
in BidirPathPdfs pathPdfs, bool isBackground);
public abstract float NextEventMis(in CameraPath cameraPath, in BidirPathPdfs pathPdfs, bool isBackground);

/// <summary>
/// Samples an emitter and a point on its surface for next event estimation
Expand Down Expand Up @@ -667,7 +655,9 @@ protected virtual RgbColor PerformNextEventEstimation(in SurfaceShader shader, r
pathPdfs.PdfsLightToCamera[^2] = pdfEmit;
if (numPdfs > 2) // not for direct illumination
pathPdfs.PdfsLightToCamera[^3] = bsdfReversePdf;
float misWeight = NextEventMis(path, sample.Pdf, bsdfForwardPdf, pathPdfs, true);
pathPdfs.PdfNextEvent = sample.Pdf;
pathPdfs.PdfsCameraToLight[^1] = bsdfForwardPdf;
float misWeight = NextEventMis(path, pathPdfs, true);

// Compute and log the final sample weight
var weight = sample.Weight * bsdfTimesCosine;
Expand Down Expand Up @@ -718,8 +708,10 @@ protected virtual RgbColor PerformNextEventEstimation(in SurfaceShader shader, r
pathPdfs.PdfsLightToCamera[^2] = pdfEmit;
if (numPdfs > 2) // not for direct illumination
pathPdfs.PdfsLightToCamera[^3] = bsdfReversePdf;
pathPdfs.PdfNextEvent = lightSample.Pdf;
pathPdfs.PdfsCameraToLight[^1] = bsdfForwardPdf;

float misWeight = NextEventMis(path, lightSample.Pdf, bsdfForwardPdf, pathPdfs, false);
float misWeight = NextEventMis(path, pathPdfs, false);

var weight = emission * bsdfTimesCosine * (jacobian / lightSample.Pdf);
RegisterSample(weight * path.Throughput, misWeight, path.Pixel,
Expand All @@ -737,10 +729,9 @@ protected virtual RgbColor PerformNextEventEstimation(in SurfaceShader shader, r
/// Computes the MIS weight of randomly hitting an emitter
/// </summary>
/// <param name="cameraPath">The camera path that hit an emitter</param>
/// <param name="pdfNextEvent">Surface area pdf of sampling the point on the emitter via next event</param>
/// <param name="pathPdfs">Surface area pdfs of all sampling techniques. </param>
/// <returns>MIS weight</returns>
public abstract float EmitterHitMis(in CameraPath cameraPath, float pdfNextEvent, in BidirPathPdfs pathPdfs);
public abstract float EmitterHitMis(in CameraPath cameraPath, in BidirPathPdfs pathPdfs);

/// <summary>
/// Called when a camera path directly intersected an emitter
Expand Down Expand Up @@ -770,8 +761,10 @@ protected virtual RgbColor OnEmitterHit(Emitter emitter, SurfacePoint hit, Vecto
pathPdfs.GatherCameraPdfs(path, lastCameraVertexIdx);
if (numPdfs > 1)
pathPdfs.PdfsLightToCamera[^2] = pdfEmit;
pathPdfs.PdfNextEvent = pdfNextEvent;
pathPdfs.PdfsCameraToLight[^1] = path.Vertices[^1].PdfFromAncestor;

float misWeight = numPdfs == 1 ? 1.0f : EmitterHitMis(path, pdfNextEvent, pathPdfs);
float misWeight = numPdfs == 1 ? 1.0f : EmitterHitMis(path, pathPdfs);
RegisterSample(emission * path.Throughput, misWeight, path.Pixel,
path.Vertices.Count, 0, path.Vertices.Count);
OnEmitterHitSample(emission * path.Throughput, misWeight, path, pdfNextEvent, pathPdfs, emitter, outDir, hit);
Expand Down Expand Up @@ -804,8 +797,10 @@ protected virtual RgbColor OnBackgroundHit(Ray ray, in CameraPath path) {
pathPdfs.GatherCameraPdfs(path, lastCameraVertexIdx);
if (numPdfs > 1)
pathPdfs.PdfsLightToCamera[^2] = pdfEmit;
pathPdfs.PdfNextEvent = pdfNextEvent;
pathPdfs.PdfsCameraToLight[^1] = path.Vertices[^1].PdfFromAncestor;

float misWeight = numPdfs == 1 ? 1.0f : EmitterHitMis(path, pdfNextEvent, pathPdfs);
float misWeight = numPdfs == 1 ? 1.0f : EmitterHitMis(path, pathPdfs);
var emission = Scene.Background.EmittedRadiance(ray.Direction);
RegisterSample(emission * path.Throughput, misWeight, path.Pixel,
path.Vertices.Count, 0, path.Vertices.Count);
Expand Down
9 changes: 8 additions & 1 deletion SeeSharp/Integrators/Bidir/BidirPathPdfs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ public ref struct BidirPathPdfs {
/// </summary>
public readonly Span<float> PdfsCameraToLight;

/// <summary>
/// PDF of doing next event estimation at the final vertex. Tracked separately so we can separately enable
/// or disable BSDF light hits and next event
/// </summary>
public float PdfNextEvent;

/// <summary>
/// Prepares <see langword="this"/> object to compute the pdf values into two preallocated arrays.
/// </summary>
Expand Down Expand Up @@ -68,7 +74,8 @@ public void GatherLightPdfs(in PathVertex lightVertex, int lastCameraVertexIdx)
var nextVert = lightVertex;
for (int i = lastCameraVertexIdx + 1; i < NumPdfs - 2; ++i) {
PdfsLightToCamera[i] = nextVert.PdfFromAncestor;
PdfsCameraToLight[i + 2] = nextVert.PdfReverseAncestor + nextVert.PdfNextEventAncestor;
PdfsCameraToLight[i + 2] = nextVert.PdfReverseAncestor;
PdfNextEvent += nextVert.PdfNextEventAncestor; // All but one are zero, so we are lazy and add them up instead of picking the correct one
nextVert = lightPathCache[nextVert.AncestorId];
}
PdfsLightToCamera[^2] = nextVert.PdfFromAncestor;
Expand Down
14 changes: 7 additions & 7 deletions SeeSharp/Integrators/Bidir/ClassicBidir.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ protected override RgbColor OnCameraHit(in CameraPath path, ref RNG rng, in Surf
}

/// <inheritdoc />
public override float EmitterHitMis(in CameraPath cameraPath, float pdfNextEvent, in BidirPathPdfs pathPdfs) {
public override float EmitterHitMis(in CameraPath cameraPath, in BidirPathPdfs pathPdfs) {
float pdfThis = cameraPath.Vertices[^1].PdfFromAncestor;

float sumReciprocals = 1.0f;
sumReciprocals += pdfNextEvent / pdfThis;
sumReciprocals += pathPdfs.PdfNextEvent / pdfThis;
sumReciprocals +=
CameraPathReciprocals(cameraPath.Vertices.Count - 2, pathPdfs, cameraPath.Pixel) / pdfThis;

Expand All @@ -138,12 +138,11 @@ public override float BidirConnectMis(in CameraPath cameraPath, PathVertex light
}

/// <inheritdoc />
public override float NextEventMis(in CameraPath cameraPath, float pdfNextEvent, float pdfHit,
in BidirPathPdfs pathPdfs, bool isBackground) {
public override float NextEventMis(in CameraPath cameraPath, in BidirPathPdfs pathPdfs, bool isBackground) {
float sumReciprocals = 1.0f;
sumReciprocals += pdfHit / pdfNextEvent;
sumReciprocals += pathPdfs.PdfsCameraToLight[^1] / pathPdfs.PdfNextEvent;
sumReciprocals +=
CameraPathReciprocals(cameraPath.Vertices.Count - 1, pathPdfs, cameraPath.Pixel) / pdfNextEvent;
CameraPathReciprocals(cameraPath.Vertices.Count - 1, pathPdfs, cameraPath.Pixel) / pathPdfs.PdfNextEvent;
return 1 / sumReciprocals;
}

Expand Down Expand Up @@ -187,7 +186,8 @@ protected virtual float LightPathReciprocals(int lastCameraVertexIdx, in BidirPa
if (EnableConnections && i < pdfs.NumPdfs - 2) // Next event is treated separately
sumReciprocals += nextReciprocal;
}
sumReciprocals += nextReciprocal; // Next event and hitting the emitter directly
sumReciprocals += nextReciprocal; // Hitting the emitter directly
sumReciprocals += pdfs.PdfNextEvent / pdfs.PdfsLightToCamera[^1];
return sumReciprocals;
}
}
21 changes: 11 additions & 10 deletions SeeSharp/Integrators/Bidir/VertexCacheBidir.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,11 @@ protected override RgbColor OnCameraHit(in CameraPath path, ref RNG rng, in Surf
}

/// <inheritdoc />
public override float EmitterHitMis(in CameraPath cameraPath, float pdfNextEvent, in BidirPathPdfs pathPdfs) {
float pdfThis = cameraPath.Vertices[^1].PdfFromAncestor;
public override float EmitterHitMis(in CameraPath cameraPath, in BidirPathPdfs pathPdfs) {
float pdfThis = pathPdfs.PdfsCameraToLight[^1];

float sumReciprocals = 1.0f;
sumReciprocals += pdfNextEvent / pdfThis;
sumReciprocals += pathPdfs.PdfNextEvent / pdfThis;
sumReciprocals +=
CameraPathReciprocals(cameraPath.Vertices.Count - 2, pathPdfs, cameraPath.Pixel) / pdfThis;

Expand All @@ -168,19 +168,19 @@ public override float BidirConnectMis(in CameraPath cameraPath, PathVertex light
float sumReciprocals = 1.0f;
int lastCameraVertexIdx = cameraPath.Vertices.Count - 1;
sumReciprocals += CameraPathReciprocals(lastCameraVertexIdx, pathPdfs, cameraPath.Pixel)
/ BidirSelectDensity(cameraPath.Pixel);;
/ BidirSelectDensity(cameraPath.Pixel);
sumReciprocals += LightPathReciprocals(lastCameraVertexIdx, pathPdfs, cameraPath.Pixel)
/ BidirSelectDensity(cameraPath.Pixel);;
/ BidirSelectDensity(cameraPath.Pixel);
return 1 / sumReciprocals;
}

/// <inheritdoc />
public override float NextEventMis(in CameraPath cameraPath, float pdfNextEvent, float pdfHit,
in BidirPathPdfs pathPdfs, bool isBackground) {
public override float NextEventMis(in CameraPath cameraPath, in BidirPathPdfs pathPdfs, bool isBackground) {
float sumReciprocals = 1.0f;
sumReciprocals += pdfHit / pdfNextEvent;
if (EnableHitting)
sumReciprocals += pathPdfs.PdfsCameraToLight[^1] / pathPdfs.PdfNextEvent;
sumReciprocals +=
CameraPathReciprocals(cameraPath.Vertices.Count - 1, pathPdfs, cameraPath.Pixel) / pdfNextEvent;
CameraPathReciprocals(cameraPath.Vertices.Count - 1, pathPdfs, cameraPath.Pixel) / pathPdfs.PdfNextEvent;
return 1 / sumReciprocals;
}

Expand Down Expand Up @@ -208,7 +208,8 @@ protected virtual float LightPathReciprocals(int lastCameraVertexIdx, in BidirPa
if (i < pdfs.NumPdfs - 2 && NumConnections > 0) // Connections to the emitter (next event) are treated separately
sumReciprocals += nextReciprocal * BidirSelectDensity(pixel);
}
sumReciprocals += nextReciprocal; // Next event and hitting the emitter directly
if (EnableHitting) sumReciprocals += nextReciprocal; // Hitting the emitter directly
sumReciprocals += pdfs.PdfNextEvent * nextReciprocal / pdfs.PdfsCameraToLight[^1];
return sumReciprocals;
}
}
24 changes: 12 additions & 12 deletions SeeSharp/Integrators/Bidir/VertexConnectionAndMerging.cs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,6 @@ protected virtual RgbColor Merge(in CameraPath path, float cameraJacobian, in Su
? 1.0f
: SampleWarp.SurfaceAreaToSolidAngle(shader.Point, ancestor.Point);
pdfLightReverse *= jacobian;
float pdfNextEvent = (photon.Depth == 1) ? NextEventPdf(shader.Point, ancestor.Point) : 0;

int numPdfs = path.Vertices.Count + photon.Depth;
int lastCameraVertexIdx = path.Vertices.Count - 1;
Expand All @@ -300,7 +299,9 @@ protected virtual RgbColor Merge(in CameraPath path, float cameraJacobian, in Su
pathPdfs.PdfsLightToCamera[lastCameraVertexIdx - 1] = pdfCameraReverse;
pathPdfs.PdfsLightToCamera[lastCameraVertexIdx] = photon.PdfFromAncestor;
pathPdfs.PdfsCameraToLight[lastCameraVertexIdx] = path.Vertices[^1].PdfFromAncestor;
pathPdfs.PdfsCameraToLight[lastCameraVertexIdx + 1] = pdfLightReverse + pdfNextEvent;
pathPdfs.PdfsCameraToLight[lastCameraVertexIdx + 1] = pdfLightReverse;
if (photon.Depth == 1)
pathPdfs.PdfNextEvent = NextEventPdf(shader.Point, ancestor.Point);

float misWeight = MergeMis(path, photon, pathPdfs);

Expand Down Expand Up @@ -494,14 +495,14 @@ public virtual float MergeMis(in CameraPath cameraPath, in PathVertex lightVerte
}

/// <inheritdoc />
public override float EmitterHitMis(in CameraPath cameraPath, float pdfNextEvent, in BidirPathPdfs pathPdfs) {
public override float EmitterHitMis(in CameraPath cameraPath, in BidirPathPdfs pathPdfs) {
var correlRatio = new CorrelAwareRatios(pathPdfs, cameraPath.Distances[0], false);

float sumReciprocals = 1.0f;

// Next event estimation
float pdfThis = cameraPath.Vertices[^1].PdfFromAncestor;
sumReciprocals += pdfNextEvent / pdfThis;
float pdfThis = pathPdfs.PdfsCameraToLight[^1];
sumReciprocals += pathPdfs.PdfNextEvent / pdfThis;

// All connections along the camera path
float radius = ComputeLocalMergeRadius(cameraPath.Distances[0]);
Expand Down Expand Up @@ -540,20 +541,20 @@ public override float BidirConnectMis(in CameraPath cameraPath, PathVertex light
}

/// <inheritdoc />
public override float NextEventMis(in CameraPath cameraPath, float pdfNextEvent, float pdfHit,
in BidirPathPdfs pathPdfs, bool isBackground) {
public override float NextEventMis(in CameraPath cameraPath, in BidirPathPdfs pathPdfs, bool isBackground) {
var correlRatio = new CorrelAwareRatios(pathPdfs, cameraPath.Distances[0], isBackground);

float sumReciprocals = 1.0f;

// Hitting the light source
if (EnableHitting) sumReciprocals += pdfHit / pdfNextEvent;
if (EnableHitting)
sumReciprocals += pathPdfs.PdfsCameraToLight[^1] / pathPdfs.PdfNextEvent;

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

return 1 / sumReciprocals;
}
Expand Down Expand Up @@ -615,9 +616,8 @@ protected virtual float LightPathReciprocals(int lastCameraVertexIdx, in BidirPa
if (i < pdfs.NumPdfs - 2) // Connections to the emitter (next event) are treated separately
if (NumConnections > 0) sumReciprocals += nextReciprocal * BidirSelectDensity(pixel);
}
if (EnableHitting || NumShadowRays != 0)
sumReciprocals += nextReciprocal; // Next event and hitting the emitter directly
// TODO / FIXME Bsdf and Nee can only be disabled jointly here: needs proper handling when assembling pdfs
if (EnableHitting) sumReciprocals += nextReciprocal; // Hitting the emitter directly
sumReciprocals += pdfs.PdfNextEvent * nextReciprocal / pdfs.PdfsCameraToLight[^1];
return sumReciprocals;
}
}

0 comments on commit 0ce7730

Please sign in to comment.