Skip to content

Commit

Permalink
shading normals
Browse files Browse the repository at this point in the history
  • Loading branch information
pgrit committed Jan 17, 2025
1 parent 637d406 commit dd8e0e1
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 3 deletions.
10 changes: 9 additions & 1 deletion SeeSharp/Integrators/Bidir/BidirBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,11 @@ void ConnectLightVertexToCamera(in PathVertex vertex, in PathVertex ancestor, Ve
if (bsdfValue == RgbColor.Black)
return;

// The shading cosine only cancels out with the Jacobian if the geometry aligns with the shading geometry
bsdfValue *=
float.Abs(Vector3.Dot(vertex.Point.ShadingNormal, dirToAncestor)) /
float.Abs(Vector3.Dot(vertex.Point.Normal, dirToAncestor));

// Compute the surface area pdf of sampling the previous vertex instead
var (pdfReverse, _) = shader.Pdf(dirToAncestor);
if (ancestor.Point.Mesh != null)
Expand Down Expand Up @@ -468,8 +473,11 @@ RgbColor Connect(in SurfaceShader shader, PathVertex vertex, PathVertex ancestor
var dirFromCamToLight = Vector3.Normalize(vertex.Point.Position - shader.Point.Position);

SurfaceShader lightShader = new(vertex.Point, dirToAncestor, true);
var bsdfWeightLight = lightShader.Evaluate(-dirFromCamToLight) * float.Abs(Vector3.Dot(vertex.Point.Normal, -dirFromCamToLight));
bsdfWeightLight *=
float.Abs(Vector3.Dot(vertex.Point.ShadingNormal, dirToAncestor)) /
float.Abs(Vector3.Dot(vertex.Point.Normal, dirToAncestor));

var bsdfWeightLight = lightShader.EvaluateWithCosine(-dirFromCamToLight);
var bsdfWeightCam = shader.EvaluateWithCosine(dirFromCamToLight);

if (bsdfWeightCam == RgbColor.Black || bsdfWeightLight == RgbColor.Black)
Expand Down
11 changes: 9 additions & 2 deletions SeeSharp/Integrators/Bidir/VertexConnectionAndMerging.cs
Original file line number Diff line number Diff line change
Expand Up @@ -271,16 +271,23 @@ protected virtual RgbColor Merge(in CameraPath path, float cameraJacobian, in Su
if (depth > MaxDepth || depth < MinDepth)
return RgbColor.Black;

// Discard photons on (almost) perpendicular surfaces. This avoids outliers and somewhat reduces
// light leaks, but slightly amplifies darkening from kernel estimation bias.
if (float.Abs(Vector3.Dot(shader.Point.Normal, photon.Point.Normal)) < 0.4f) {
return RgbColor.Black;
}

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

// Early exit + prevent NaN / Inf
if (photonContrib == RgbColor.Black) return RgbColor.Black;
// 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
var (pdfLightReverse, pdfCameraReverse) = shader.Pdf(dirToAncestor);
Expand Down
14 changes: 14 additions & 0 deletions SeeSharp/Integrators/Common/RandomWalk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,20 @@ RgbColor ContinueWalk(Ray ray, SurfacePoint previousPoint, float pdfDirection, R
if (dirSample.PdfForward == 0 || dirSample.Weight == RgbColor.Black)
break;

if (isOnLightSubpath) {
// The direction sample is multiplied by the shading cosine, but we need the geometric one
dirSample.Weight *=
float.Abs(Vector3.Dot(hit.Normal, dirSample.Direction)) /
float.Abs(Vector3.Dot(hit.ShadingNormal, dirSample.Direction));

// Rendering equation cosine cancels with the Jacobian, but only if geometry and shading geometry align
dirSample.Weight *=
float.Abs(Vector3.Dot(hit.ShadingNormal, -ray.Direction)) /
float.Abs(Vector3.Dot(hit.Normal, -ray.Direction));

SanityChecks.IsNormalized(ray.Direction);
}

// Continue the path with the next ray
prefixWeight *= dirSample.Weight / survivalProb;
depth++;
Expand Down

0 comments on commit dd8e0e1

Please sign in to comment.