[Bf-blender-cvs] [c41601becd7] master: Fix T89037: Cycles: Backfacing node can be wrong for lights with negative scale

Lukas Stockner noreply at git.blender.org
Tue Jan 10 02:56:20 CET 2023


Commit: c41601becd73ef67d041ed9cbb9b189fddd183d0
Author: Lukas Stockner
Date:   Tue Jan 10 02:32:16 2023 +0100
Branches: master
https://developer.blender.org/rBc41601becd73ef67d041ed9cbb9b189fddd183d0

Fix T89037: Cycles: Backfacing node can be wrong for lights with negative scale

When rendering in the viewport (or probably on instanced objects, but I didn't
test that), emissive objects whose scale is negative give the wrong value on the
"backfacing" input when multiple sampling is enabled.

The underlying problem was a corner case in how normal transformation is handled,
which is generally a bit messy.

>From what I can tell, the pattern appears to be:
- If you first transform vertices to world space and then compute the normal from
  them (as triangle light samping, MNEE and light tree do), you need to flip
  whenever the transform has negative scale regardless of whether the transform
  has been applied
- If you compute the normal in object space and then transform it to world space
  (as the regular shader_setup_from_ray path does), you only need to flip if the
  transform was already applied and was negative
- If you get the normal from a local intersection result (as bevel and SSS do),
  you only need to flip if the transform was already applied and was negative
- If you get the normal from vertex normals, you don't need to do anything since
  the host-side code does the flip for you (arguably it'd be more consistent to
  do this in the kernel as well, but meh, not worth the potential slowdown)

So, this patch fixes the logic in the triangle emission code.

Also, turns out that the MNEE code had the same problem and was also having
problems in the viewport on negative-scale objects, this is also fixed now.

Differential Revision: https://developer.blender.org/D16952

===================================================================

M	intern/cycles/kernel/geom/motion_triangle_shader.h
M	intern/cycles/kernel/geom/object.h
M	intern/cycles/kernel/geom/triangle.h
M	intern/cycles/kernel/integrator/mnee.h
M	intern/cycles/kernel/integrator/subsurface_disk.h
M	intern/cycles/kernel/light/triangle.h
M	intern/cycles/kernel/svm/bevel.h
M	intern/cycles/kernel/types.h
M	intern/cycles/scene/object.cpp

===================================================================

diff --git a/intern/cycles/kernel/geom/motion_triangle_shader.h b/intern/cycles/kernel/geom/motion_triangle_shader.h
index 413a61b380a..0ec5e29f480 100644
--- a/intern/cycles/kernel/geom/motion_triangle_shader.h
+++ b/intern/cycles/kernel/geom/motion_triangle_shader.h
@@ -58,7 +58,7 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals kg,
   sd->P = motion_triangle_point_from_uv(kg, sd, isect_object, isect_prim, sd->u, sd->v, verts);
   /* Compute face normal. */
   float3 Ng;
-  if (sd->object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
+  if (object_negative_scale_applied(sd->object_flag)) {
     Ng = normalize(cross(verts[2] - verts[0], verts[1] - verts[0]));
   }
   else {
diff --git a/intern/cycles/kernel/geom/object.h b/intern/cycles/kernel/geom/object.h
index 14ceb636e2e..f5f3c36f208 100644
--- a/intern/cycles/kernel/geom/object.h
+++ b/intern/cycles/kernel/geom/object.h
@@ -201,6 +201,11 @@ ccl_device_inline void object_normal_transform(KernelGlobals kg,
   *N = normalize(transform_direction_transposed(&tfm, *N));
 }
 
+ccl_device_inline bool object_negative_scale_applied(const int object_flag)
+{
+  return ((object_flag & SD_OBJECT_NEGATIVE_SCALE) && (object_flag & SD_OBJECT_TRANSFORM_APPLIED));
+}
+
 /* Transform direction vector from object to world space */
 
 ccl_device_inline void object_dir_transform(KernelGlobals kg,
diff --git a/intern/cycles/kernel/geom/triangle.h b/intern/cycles/kernel/geom/triangle.h
index 6b9450d59ef..b5fb67260a9 100644
--- a/intern/cycles/kernel/geom/triangle.h
+++ b/intern/cycles/kernel/geom/triangle.h
@@ -21,7 +21,7 @@ ccl_device_inline float3 triangle_normal(KernelGlobals kg, ccl_private ShaderDat
   const float3 v2 = kernel_data_fetch(tri_verts, tri_vindex.w + 2);
 
   /* return normal */
-  if (sd->object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
+  if (object_negative_scale_applied(sd->object_flag)) {
     return normalize(cross(v2 - v0, v1 - v0));
   }
   else {
@@ -50,7 +50,7 @@ ccl_device_inline void triangle_point_normal(KernelGlobals kg,
   /* get object flags */
   int object_flag = kernel_data_fetch(object_flag, object);
   /* compute normal */
-  if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
+  if (object_negative_scale_applied(object_flag)) {
     *Ng = normalize(cross(v2 - v0, v1 - v0));
   }
   else {
diff --git a/intern/cycles/kernel/integrator/mnee.h b/intern/cycles/kernel/integrator/mnee.h
index 7f5f2c97497..debbce497dc 100644
--- a/intern/cycles/kernel/integrator/mnee.h
+++ b/intern/cycles/kernel/integrator/mnee.h
@@ -176,8 +176,9 @@ ccl_device_forceinline void mnee_setup_manifold_vertex(KernelGlobals kg,
 
   /* Geometric normal. */
   vtx->ng = normalize(cross(dp_du, dp_dv));
-  if (sd_vtx->object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED)
+  if (sd_vtx->object_flag & SD_OBJECT_NEGATIVE_SCALE) {
     vtx->ng = -vtx->ng;
+  }
 
   /* Shading normals: Interpolate normals between vertices. */
   float n_len;
diff --git a/intern/cycles/kernel/integrator/subsurface_disk.h b/intern/cycles/kernel/integrator/subsurface_disk.h
index 16fb45392f4..083834a87da 100644
--- a/intern/cycles/kernel/integrator/subsurface_disk.h
+++ b/intern/cycles/kernel/integrator/subsurface_disk.h
@@ -120,7 +120,7 @@ ccl_device_inline bool subsurface_disk(KernelGlobals kg,
     if (path_flag & PATH_RAY_SUBSURFACE_BACKFACING) {
       hit_Ng = -hit_Ng;
     }
-    if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
+    if (object_negative_scale_applied(object_flag)) {
       hit_Ng = -hit_Ng;
     }
 
diff --git a/intern/cycles/kernel/light/triangle.h b/intern/cycles/kernel/light/triangle.h
index 829bacb31f3..7a9a395c2b6 100644
--- a/intern/cycles/kernel/light/triangle.h
+++ b/intern/cycles/kernel/light/triangle.h
@@ -146,7 +146,7 @@ ccl_device_forceinline bool triangle_light_sample(KernelGlobals kg,
 
   /* flip normal if necessary */
   const int object_flag = kernel_data_fetch(object_flag, object);
-  if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
+  if (object_flag & SD_OBJECT_NEGATIVE_SCALE) {
     ls->Ng = -ls->Ng;
   }
   ls->eval_fac = 1.0f;
diff --git a/intern/cycles/kernel/svm/bevel.h b/intern/cycles/kernel/svm/bevel.h
index c1e227959f8..736ea9b80c1 100644
--- a/intern/cycles/kernel/svm/bevel.h
+++ b/intern/cycles/kernel/svm/bevel.h
@@ -224,7 +224,7 @@ ccl_device float3 svm_bevel(
       float3 hit_Ng = isect.Ng[hit];
       int object = isect.hits[hit].object;
       int object_flag = kernel_data_fetch(object_flag, object);
-      if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
+      if (object_negative_scale_applied(object_flag)) {
         hit_Ng = -hit_Ng;
       }
 
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
index 69b73d78417..ff75e70ba6b 100644
--- a/intern/cycles/kernel/types.h
+++ b/intern/cycles/kernel/types.h
@@ -850,8 +850,8 @@ enum ShaderDataObjectFlag {
   SD_OBJECT_MOTION = (1 << 1),
   /* Vertices have transform applied. */
   SD_OBJECT_TRANSFORM_APPLIED = (1 << 2),
-  /* Vertices have negative scale applied. */
-  SD_OBJECT_NEGATIVE_SCALE_APPLIED = (1 << 3),
+  /* The object's transform applies a negative scale. */
+  SD_OBJECT_NEGATIVE_SCALE = (1 << 3),
   /* Object has a volume shader. */
   SD_OBJECT_HAS_VOLUME = (1 << 4),
   /* Object intersects AABB of an object with volume shader. */
@@ -873,7 +873,7 @@ enum ShaderDataObjectFlag {
   SD_OBJECT_CAUSTICS = (SD_OBJECT_CAUSTICS_CASTER | SD_OBJECT_CAUSTICS_RECEIVER),
 
   SD_OBJECT_FLAGS = (SD_OBJECT_HOLDOUT_MASK | SD_OBJECT_MOTION | SD_OBJECT_TRANSFORM_APPLIED |
-                     SD_OBJECT_NEGATIVE_SCALE_APPLIED | SD_OBJECT_HAS_VOLUME |
+                     SD_OBJECT_NEGATIVE_SCALE | SD_OBJECT_HAS_VOLUME |
                      SD_OBJECT_INTERSECTS_VOLUME | SD_OBJECT_SHADOW_CATCHER |
                      SD_OBJECT_HAS_VOLUME_ATTRIBUTES | SD_OBJECT_CAUSTICS |
                      SD_OBJECT_HAS_VOLUME_MOTION)
diff --git a/intern/cycles/scene/object.cpp b/intern/cycles/scene/object.cpp
index 898e161f832..c788c6f4a8c 100644
--- a/intern/cycles/scene/object.cpp
+++ b/intern/cycles/scene/object.cpp
@@ -435,6 +435,10 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
     state->have_motion = true;
   }
 
+  if (transform_negative_scale(tfm)) {
+    flag |= SD_OBJECT_NEGATIVE_SCALE;
+  }
+
   if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::POINTCLOUD) {
     /* TODO: why only mesh? */
     Mesh *mesh = static_cast<Mesh *>(geom);
@@ -970,8 +974,6 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, P
         }
 
         object_flag[i] |= SD_OBJECT_TRANSFORM_APPLIED;
-        if (geom->transform_negative_scaled)
-          object_flag[i] |= SD_OBJECT_NEGATIVE_SCALE_APPLIED;
       }
     }



More information about the Bf-blender-cvs mailing list