Cycles and surface normals (normalmap shading)

Somebody else had a very similar complaint/observation to this thread.

Various parts of Cycles will use the geometric normals (or smoothed geometric normals depending on settings), not the shader normals, to make decisions about various things. This leads to the issue obvserved.

A simple “fix” is to just overwrite these geometric normals with your shader normals. Here’s example of this:

EEVEE (“Desired”) result:

Stock Cycles (Has the shading issue):

Overwriten geometric normals:

Code change:

--- a/intern/cycles/kernel/svm/closure.h
+++ b/intern/cycles/kernel/svm/closure.h
@@ -448,7 +448,8 @@ ccl_device
 
       if (bsdf) {
         bsdf->N = N;
+        sd->N = N;
+        sd->Ng = N;
         float roughness = param1;
 
         if (roughness == 0.0f) {

You might be wondering, if the fix is so simple (Basically 2 lines of code), then why isn’t it done.

  • This specific code change only works for the diffuse BSDF. Although it’s easy to expand to other BSDFs.
  • This method is extremely hacky and probably has some knock on issues.
  • And most importantly. It doesn’t work if you have more than one shader. And the Principled BSDF is made up of multiple shaders meaning this method is incompatble with it.

I’ve had ideas on how to resolve this (Instead of overwriting the geometric normals, just use the shader normals in the various areas that use geometric normals and lead to the observed issue), but I’ve always been concerned of introducing bias if different parts of the rendering don’t match up. An example being this bug report: #120119 - 4.1 Regression: Cycles: Area lamp artifacts - blender - Blender Projects

This bug occured because the normals during Next Event Estimation did not match the normals during forward path tracing, meaning any light that was large enough to be “commonly sampled via forward path tracing” ended up rendering incorrectly.

9 Likes