Skip to content

Commit

Permalink
faster merging
Browse files Browse the repository at this point in the history
  • Loading branch information
pgrit committed Dec 6, 2024
1 parent 8245c42 commit 04bbed6
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 22 deletions.
2 changes: 1 addition & 1 deletion SeeSharp/Integrators/Bidir/BidirBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ protected virtual RgbColor BidirConnections(in SurfaceShader shader, ref RNG rng

if (lightVertIdx > 0) {
// specific vertex selected
var vertex = LightPaths[lightVertIdx];
var vertex = LightPaths[lightVertIdx]; // TODO-PERFORMANCE this is an expensive binary search ATM --> should we instead pick a random path and vertex within? Or precompute a lookup table for this mapping?
if (vertex.Depth < 1)
return result;
var ancestor = LightPaths[lightVertIdx - 1];
Expand Down
2 changes: 1 addition & 1 deletion SeeSharp/Integrators/Bidir/PhotonMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class PhotonMapper : Integrator {
/// </summary>
protected LightPathCache lightPaths;

TinyEmbree.NearestNeighborSearch photonMap;
NearestNeighborSearch<int> photonMap;

/// <inheritdoc />
public override void Render(Scene scene) {
Expand Down
50 changes: 31 additions & 19 deletions SeeSharp/Integrators/Bidir/VertexConnectionAndMerging.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class VertexConnectionAndMergingBase<CameraPayloadType> : VertexCacheBidi
/// <summary>
/// Acceleration structure to query photons in the scene.
/// </summary>
protected NearestNeighborSearch photonMap;
protected NearestNeighborSearch<(int, int)> photonMap;

ThreadLocal<ulong> totalCamPathLen;
ThreadLocal<ulong> totalMergeOps;
Expand Down Expand Up @@ -223,10 +223,11 @@ protected override void ProcessPathCache() {
mergeBuildTimer.Start();

photonMap.Clear();
for (int i = 0; i < LightPaths.NumVertices; ++i) {
var vertex = LightPaths[i];
if (vertex.PathId >= 0 && vertex.Depth >= 1 && vertex.Weight != RgbColor.Black) {
photonMap.AddPoint(vertex.Point.Position, i);
for (int pathIdx = 0; pathIdx < NumLightPaths.Value; ++pathIdx) {
for (int vertIdx = 1; vertIdx < LightPaths.Length(pathIdx); ++vertIdx) {
ref var vertex = ref LightPaths[pathIdx, vertIdx];
if (vertex.Weight != RgbColor.Black)
photonMap.AddPoint(vertex.Point.Position, (pathIdx, vertIdx));
}
}
photonMap.Build();
Expand Down Expand Up @@ -262,23 +263,23 @@ protected virtual void OnCombinedMergeSample(in SurfaceShader shader, ref RNG rn
=> totalMergeOps.Value++;

protected virtual RgbColor Merge(in CameraPath path, float cameraJacobian, in SurfaceShader shader,
int vertexIdx, float distSqr, float radiusSquared) {
var photon = LightPaths[vertexIdx];
(int pathIdx, int vertexIdx) idx, float distSqr, float radiusSquared) {
var photon = LightPaths[idx.pathIdx, idx.vertexIdx];

// Check that the path does not exceed the maximum length
var depth = path.Vertices.Count + photon.Depth;
if (depth > MaxDepth || depth < MinDepth)
return RgbColor.Black;

// Compute the contribution of the photon
var ancestor = LightPaths[vertexIdx - 1];
var ancestor = LightPaths[idx.pathIdx, idx.vertexIdx - 1];
var dirToAncestor = Vector3.Normalize(ancestor.Point.Position - shader.Point.Position);
var bsdfValue = shader.Evaluate(dirToAncestor);
var photonContrib = photon.Weight * bsdfValue / NumLightPaths.Value;

// Early exit + prevent NaN / Inf
if (photonContrib == RgbColor.Black) return RgbColor.Black;
// Prevent outliers du to numerical issues with photons arriving almost parallel to the surface
// Prevent outliers due to numerical issues with photons arriving almost parallel to the surface
if (Math.Abs(Vector3.Dot(dirToAncestor, shader.Point.Normal)) < 1e-4f) return RgbColor.Black;

// Compute the missing pdf terms and the MIS weight
Expand Down Expand Up @@ -371,7 +372,7 @@ protected virtual RgbColor PerformMerging(in SurfaceShader shader, ref RNG rng,
return state.Estimate;
}

void MergeHelper(Vector3 position, int idx, float distance, int numFound, float distToFurthest, ref MergeState userData) {
void MergeHelper(Vector3 position, (int, int) idx, float distance, int numFound, float distToFurthest, ref MergeState userData) {
float radiusSquared = numFound == MaxNumPhotons
? distToFurthest * distToFurthest
: userData.LocalRadiusSquared;
Expand Down Expand Up @@ -419,13 +420,14 @@ protected override RgbColor OnCameraHit(in CameraPath path, ref RNG rng, in Surf
public readonly ref struct CorrelAwareRatios {
readonly Span<float> cameraToLight;
readonly Span<float> lightToCamera;
public CorrelAwareRatios(BidirPathPdfs pdfs, float distToCam, bool fromBackground) {

public CorrelAwareRatios(BidirPathPdfs pdfs, float distToCam, bool fromBackground, Span<float> cameraToLight, Span<float> lightToCamera) {
float radius = distToCam * 0.0174550649f; // distance * tan(1°)
float acceptArea = radius * radius * MathF.PI;

int numSurfaceVertices = pdfs.PdfsCameraToLight.Length - 1;
cameraToLight = new float[numSurfaceVertices];
lightToCamera = new float[numSurfaceVertices];

this.cameraToLight = cameraToLight;
this.lightToCamera = lightToCamera;

// Gather camera probability
float product = 1.0f;
Expand Down Expand Up @@ -478,7 +480,9 @@ public virtual float MergeMis(in CameraPath cameraPath, in PathVertex lightVerte
float mergeApproximation = pathPdfs.PdfsLightToCamera[lastCameraVertexIdx]
* MathF.PI * radius * radius * NumLightPaths.Value;

var correlRatio = new CorrelAwareRatios(pathPdfs, cameraPath.Distances[0], lightVertex.FromBackground);
Span<float> bufA = stackalloc float[pathPdfs.PdfsCameraToLight.Length - 1];
Span<float> bufB = stackalloc float[pathPdfs.PdfsCameraToLight.Length - 1];
var correlRatio = new CorrelAwareRatios(pathPdfs, cameraPath.Distances[0], lightVertex.FromBackground, bufA, bufB);
if (!DisableCorrelAwareMIS) mergeApproximation *= correlRatio[lastCameraVertexIdx];

if (mergeApproximation == 0.0f) return 0.0f;
Expand All @@ -501,7 +505,9 @@ public virtual float MergeMis(in CameraPath cameraPath, in PathVertex lightVerte

/// <inheritdoc />
public override float EmitterHitMis(in CameraPath cameraPath, in BidirPathPdfs pathPdfs) {
var correlRatio = new CorrelAwareRatios(pathPdfs, cameraPath.Distances[0], false);
Span<float> bufA = stackalloc float[pathPdfs.PdfsCameraToLight.Length - 1];
Span<float> bufB = stackalloc float[pathPdfs.PdfsCameraToLight.Length - 1];
var correlRatio = new CorrelAwareRatios(pathPdfs, cameraPath.Distances[0], false, bufA, bufB);

float sumReciprocals = 1.0f;

Expand All @@ -520,7 +526,9 @@ public override float EmitterHitMis(in CameraPath cameraPath, in BidirPathPdfs p

/// <inheritdoc />
public override float LightTracerMis(PathVertex lightVertex, in BidirPathPdfs pathPdfs, Pixel pixel, float distToCam) {
var correlRatio = new CorrelAwareRatios(pathPdfs, distToCam, lightVertex.FromBackground);
Span<float> bufA = stackalloc float[pathPdfs.PdfsCameraToLight.Length - 1];
Span<float> bufB = stackalloc float[pathPdfs.PdfsCameraToLight.Length - 1];
var correlRatio = new CorrelAwareRatios(pathPdfs, distToCam, lightVertex.FromBackground, bufA, bufB);

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

Expand All @@ -534,7 +542,9 @@ public override float LightTracerMis(PathVertex lightVertex, in BidirPathPdfs pa

/// <inheritdoc />
public override float BidirConnectMis(in CameraPath cameraPath, PathVertex lightVertex, in BidirPathPdfs pathPdfs) {
var correlRatio = new CorrelAwareRatios(pathPdfs, cameraPath.Distances[0], lightVertex.FromBackground);
Span<float> bufA = stackalloc float[pathPdfs.PdfsCameraToLight.Length - 1];
Span<float> bufB = stackalloc float[pathPdfs.PdfsCameraToLight.Length - 1];
var correlRatio = new CorrelAwareRatios(pathPdfs, cameraPath.Distances[0], lightVertex.FromBackground, bufA, bufB);

float radius = ComputeLocalMergeRadius(cameraPath.FootprintRadius);
float sumReciprocals = 1.0f;
Expand All @@ -549,7 +559,9 @@ public override float BidirConnectMis(in CameraPath cameraPath, PathVertex light

/// <inheritdoc />
public override float NextEventMis(in CameraPath cameraPath, in BidirPathPdfs pathPdfs, bool isBackground) {
var correlRatio = new CorrelAwareRatios(pathPdfs, cameraPath.Distances[0], isBackground);
Span<float> bufA = stackalloc float[pathPdfs.PdfsCameraToLight.Length - 1];
Span<float> bufB = stackalloc float[pathPdfs.PdfsCameraToLight.Length - 1];
var correlRatio = new CorrelAwareRatios(pathPdfs, cameraPath.Distances[0], isBackground, bufA, bufB);

float sumReciprocals = 1.0f;

Expand Down
2 changes: 1 addition & 1 deletion SeeSharp/SeeSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
<PackageReference Include="Markdig" Version="0.37.0" />
<PackageReference Include="SimpleImageIO" Version="1.7.0" />
<!-- <ProjectReference Include="../../SimpleImageIO/SimpleImageIO/SimpleImageIO.csproj" /> -->
<PackageReference Include="TinyEmbree" Version="1.0.3" />
<PackageReference Include="TinyEmbree" Version="1.1.0" />
<!-- <ProjectReference Include="../../TinyEmbree/TinyEmbree/TinyEmbree.csproj" /> -->
</ItemGroup>

Expand Down

0 comments on commit 04bbed6

Please sign in to comment.