[Bf-blender-cvs] [58be9708bfa] master: Cycles: removed UV requirement for MNEE, along with fixes and cleanups

Olivier Maury noreply at git.blender.org
Fri Apr 22 18:45:46 CEST 2022


Commit: 58be9708bfa069df2db7415a64ec76c3fc012868
Author: Olivier Maury
Date:   Fri Apr 22 18:25:18 2022 +0200
Branches: master
https://developer.blender.org/rB58be9708bfa069df2db7415a64ec76c3fc012868

Cycles: removed UV requirement for MNEE, along with fixes and cleanups

Remove need for shadow caustic caster geometry to have a UV layout. UVs were
useful to maintain a consistent tangent frame across the surface while
performing the walk. A consistent tangent frame is necessary for rough
surfaces where a normal offset encodes the sampled h, which should point
towards the same direction across the mesh.

In order to get a continuous surface parametrization without UVs, the
technique described in this paper was implemented:

"The Natural-Constraint Representation of the Path Space for Efficient
 Light Transport Simulation" (Supplementary Material), SIGGRAPH 2014.

In addition to implementing this feature:
* Shadow caustic casters without smooth normals are now ignored (triggered
  some refactoring and cleaning).
* Hit point calculation was refactored using existing utils functions,
  simplifying the code.
* The max number of solver iterations was reduced to 32, a solution is
  usually found by then.
* Added generalized geometry term clamping (transfer matrix calculation can
  sometimes get unstable).
* Add stop condition to Newton solver for more consistent CPU and GPU result.
* Add support for multi scatter GGX refraction.

Fixes T96990, T96991

Ref T94120

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

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

M	intern/cycles/kernel/integrator/mnee.h

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

diff --git a/intern/cycles/kernel/integrator/mnee.h b/intern/cycles/kernel/integrator/mnee.h
index 7218165c67c..6eee597a0a1 100644
--- a/intern/cycles/kernel/integrator/mnee.h
+++ b/intern/cycles/kernel/integrator/mnee.h
@@ -36,11 +36,13 @@
  *  https://cg.ivd.kit.edu/english/HSLT.php
  */
 
-#  define MNEE_MAX_ITERATIONS 50
+#  define MNEE_MAX_ITERATIONS 32
 #  define MNEE_MAX_INTERSECTION_COUNT 10
 #  define MNEE_SOLVER_THRESHOLD 0.001f
+#  define MNEE_MINIMUM_STEP_SIZE 0.0001f
 #  define MNEE_MAX_CAUSTIC_CASTERS 6
 #  define MNEE_MIN_DISTANCE 0.001f
+#  define MNEE_MIN_PROGRESS_DISTANCE 0.0001f
 #  define MNEE_MIN_DETERMINANT 0.0001f
 #  define MNEE_PROJECTION_DISTANCE_MULTIPLIER 2.f
 
@@ -168,7 +170,8 @@ ccl_device_forceinline void mnee_setup_manifold_vertex(KernelGlobals kg,
                                                        const float2 n_offset,
                                                        ccl_private const Ray *ray,
                                                        ccl_private const Intersection *isect,
-                                                       ccl_private ShaderData *sd_vtx)
+                                                       ccl_private ShaderData *sd_vtx,
+                                                       bool seed)
 {
   sd_vtx->object = (isect->object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, isect->prim) :
                                                     isect->object;
@@ -177,7 +180,7 @@ ccl_device_forceinline void mnee_setup_manifold_vertex(KernelGlobals kg,
   sd_vtx->flag = 0;
   sd_vtx->object_flag = kernel_tex_fetch(__object_flag, sd_vtx->object);
 
-  /* matrices and time */
+  /* Matrices and time. */
   shader_setup_object_transforms(kg, sd_vtx, ray->time);
   sd_vtx->time = ray->time;
 
@@ -191,83 +194,29 @@ ccl_device_forceinline void mnee_setup_manifold_vertex(KernelGlobals kg,
 
   float3 verts[3];
   float3 normals[3];
-  uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd_vtx->prim);
-
   if (sd_vtx->type & PRIMITIVE_TRIANGLE) {
-    /* Static triangle. */
-
-    /* Load triangle vertices. */
-    verts[0] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0);
-    verts[1] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1);
-    verts[2] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2);
-
-    /* Vectors. */
-    sd_vtx->P = triangle_point_from_uv(kg, sd_vtx, isect->object, isect->prim, isect->u, isect->v);
-
-    /* Smooth normal. */
-    if (sd_vtx->shader & SHADER_SMOOTH_NORMAL) {
-      /* Load triangle vertices. */
-      normals[0] = kernel_tex_fetch(__tri_vnormal, tri_vindex.x);
-      normals[1] = kernel_tex_fetch(__tri_vnormal, tri_vindex.y);
-      normals[2] = kernel_tex_fetch(__tri_vnormal, tri_vindex.z);
+    /* Load triangle vertices and normals. */
+    triangle_vertices_and_normals(kg, sd_vtx->prim, verts, normals);
+
+    /* Compute refined position (same code as in triangle_point_from_uv). */
+    sd_vtx->P = isect->u * verts[0] + isect->v * verts[1] + (1.f - isect->u - isect->v) * verts[2];
+    if (!(sd_vtx->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+      const Transform tfm = object_get_transform(kg, sd_vtx);
+      sd_vtx->P = transform_point(&tfm, sd_vtx->P);
     }
   }
   else { /* if (sd_vtx->type & PRIMITIVE_MOTION_TRIANGLE) */
-    /* Motion triangle. */
-
-    /* Get motion info. */
-    int numsteps, numverts;
-    object_motion_info(kg, sd_vtx->object, &numsteps, &numverts, NULL);
-
-    /* Figure out which steps we need to fetch and their interpolation factor. */
-    int maxstep = numsteps * 2;
-    int step = min((int)(sd_vtx->time * maxstep), maxstep - 1);
-    float t = sd_vtx->time * maxstep - step;
-
-    /* Find attribute. */
-    int offset = intersection_find_attribute(kg, sd_vtx->object, ATTR_STD_MOTION_VERTEX_POSITION);
-    kernel_assert(offset != ATTR_STD_NOT_FOUND);
-
-    /* Fetch vertex coordinates. */
-    float3 next_verts[3];
-    uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd_vtx->prim);
-    motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts);
-    motion_triangle_verts_for_step(
-        kg, tri_vindex, offset, numverts, numsteps, step + 1, next_verts);
-
-    /* Interpolate between steps. */
-    verts[0] = (1.0f - t) * verts[0] + t * next_verts[0];
-    verts[1] = (1.0f - t) * verts[1] + t * next_verts[1];
-    verts[2] = (1.0f - t) * verts[2] + t * next_verts[2];
+    /* Load triangle vertices and normals. */
+    motion_triangle_vertices_and_normals(
+        kg, sd_vtx->object, sd_vtx->prim, sd_vtx->time, verts, normals);
 
     /* Compute refined position. */
     sd_vtx->P = motion_triangle_point_from_uv(
         kg, sd_vtx, isect->object, isect->prim, isect->u, isect->v, verts);
-
-    /* Compute smooth normal. */
-    if (sd_vtx->shader & SHADER_SMOOTH_NORMAL) {
-      /* Find attribute. */
-      int offset = intersection_find_attribute(kg, sd_vtx->object, ATTR_STD_MOTION_VERTEX_NORMAL);
-      kernel_assert(offset != ATTR_STD_NOT_FOUND);
-
-      /* Fetch vertex coordinates. */
-      float3 next_normals[3];
-      motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step, normals);
-      motion_triangle_normals_for_step(
-          kg, tri_vindex, offset, numverts, numsteps, step + 1, next_normals);
-
-      /* Interpolate between steps. */
-      normals[0] = (1.0f - t) * normals[0] + t * next_normals[0];
-      normals[1] = (1.0f - t) * normals[1] + t * next_normals[1];
-      normals[2] = (1.0f - t) * normals[2] + t * next_normals[2];
-    }
   }
 
-  /* manifold vertex position */
-  vtx->p = sd_vtx->P;
-
+  /* Instance transform. */
   if (!(sd_vtx->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
-    /* Instance transform. */
     object_position_transform_auto(kg, sd_vtx, &verts[0]);
     object_position_transform_auto(kg, sd_vtx, &verts[1]);
     object_position_transform_auto(kg, sd_vtx, &verts[2]);
@@ -277,94 +226,70 @@ ccl_device_forceinline void mnee_setup_manifold_vertex(KernelGlobals kg,
   }
 
   /* Tangent space (position derivatives) WRT barycentric (u, v). */
-  vtx->dp_du = verts[0] - verts[2];
-  vtx->dp_dv = verts[1] - verts[2];
+  float3 dp_du = verts[0] - verts[2];
+  float3 dp_dv = verts[1] - verts[2];
 
   /* Geometric normal. */
-  vtx->ng = normalize(cross(vtx->dp_du, vtx->dp_dv));
+  vtx->ng = normalize(cross(dp_du, dp_dv));
   if (sd_vtx->object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED)
     vtx->ng = -vtx->ng;
 
-  /* Shading normal. */
-  if (!(sd_vtx->shader & SHADER_SMOOTH_NORMAL)) {
-    vtx->n = vtx->ng;
-    vtx->dn_du = vtx->dn_dv = zero_float3();
-  }
-  else {
-    /* Interpolate normals between vertices. */
-    float n_len;
-    vtx->n = normalize_len(normals[0] * sd_vtx->u + normals[1] * sd_vtx->v +
-                               normals[2] * (1.0f - sd_vtx->u - sd_vtx->v),
-                           &n_len);
-
-    /* Shading normal derivatives WRT barycentric (u, v)
-     * we calculate the derivative of n = |u*n0 + v*n1 + (1-u-v)*n2| using:
-     * d/du [f(u)/|f(u)|] = [d/du f(u)]/|f(u)| - f(u)/|f(u)|^3 <f(u), d/du f(u)>. */
-    const float inv_n_len = 1.f / n_len;
-    vtx->dn_du = inv_n_len * (normals[0] - normals[2]);
-    vtx->dn_dv = inv_n_len * (normals[1] - normals[2]);
-    vtx->dn_du -= vtx->n * dot(vtx->n, vtx->dn_du);
-    vtx->dn_dv -= vtx->n * dot(vtx->n, vtx->dn_dv);
-  }
+  /* Shading normals: Interpolate normals between vertices. */
+  float n_len;
+  vtx->n = normalize_len(normals[0] * sd_vtx->u + normals[1] * sd_vtx->v +
+                             normals[2] * (1.0f - sd_vtx->u - sd_vtx->v),
+                         &n_len);
+
+  /* Shading normal derivatives WRT barycentric (u, v)
+   * we calculate the derivative of n = |u*n0 + v*n1 + (1-u-v)*n2| using:
+   * d/du [f(u)/|f(u)|] = [d/du f(u)]/|f(u)| - f(u)/|f(u)|^3 <f(u), d/du f(u)>. */
+  const float inv_n_len = 1.f / n_len;
+  float3 dn_du = inv_n_len * (normals[0] - normals[2]);
+  float3 dn_dv = inv_n_len * (normals[1] - normals[2]);
+  dn_du -= vtx->n * dot(vtx->n, dn_du);
+  dn_dv -= vtx->n * dot(vtx->n, dn_dv);
 
-  /* dp_du and dp_dv need to be continuous across triangles for the h normal
-   * offset to yield a consistent halfvector while walking on the manifold.
-   * It's usually best to rely on the mesh uv layout, which is assumed to be
-   * continuous across the mesh. */
-  float2 duv0, duv1;
-  bool found_uv = false;
-  AttributeDescriptor uv_desc = find_attribute(kg, sd_vtx, ATTR_STD_GENERATED);
-  if (uv_desc.offset != ATTR_STD_NOT_FOUND) {
-    float3 uvs[3];
-    uvs[0] = kernel_tex_fetch(__attributes_float3, uv_desc.offset + tri_vindex.x);
-    uvs[1] = kernel_tex_fetch(__attributes_float3, uv_desc.offset + tri_vindex.y);
-    uvs[2] = kernel_tex_fetch(__attributes_float3, uv_desc.offset + tri_vindex.z);
-    duv0 = make_float2(uvs[0].x - uvs[2].x, uvs[0].y - uvs[2].y);
-    duv1 = make_float2(uvs[1].x - uvs[2].x, uvs[1].y - uvs[2].y);
-    found_uv = true;
+  /* Orthonormalize (dp_du,dp_dv) using a linear transformation, which
+   * we use on (dn_du,dn_dv) as well so the new (u,v) are consistent. */
+  const float inv_len_dp_du = 1.f / len(dp_du);
+  dp_du *= inv_len_dp_du;
+  dn_du *= inv_len_dp_du;
+
+  const float dpdu_dot_dpdv = dot(dp_du, dp_dv);
+  dp_dv -= dpdu_dot_dpdv * dp_du;
+  dn_dv -= dpdu_dot_dpdv * dn_du;
+
+  const float inv_len_dp_dv = 1.f / len(dp_dv);
+  dp_dv *= inv_len_dp_dv;
+  dn_dv *= inv_len_dp_dv;
+
+  /* Final local differential geometry. */
+  if (seed) {
+    vtx->dp_du = dp_du;
+    vtx->dp_dv = dp_dv;
+    vtx->dn_du = dn_du;
+    vtx->dn_dv = dn_dv;
   }
   else {
-    uv_desc = find_attribute(kg, sd_vtx, ATTR_STD_UV);
-    if (uv_desc.offset != ATTR_STD_NOT_FOUND) {
-      float2 uvs[3];
-      uvs[0] = kernel_tex_fetch(__attributes_float2, uv_desc.offset + tri_vindex.x);
-      uvs[1] = kernel_tex_fetch(__attributes_float2, uv_desc.offset + tri_vindex.y);
-      uvs[2] = kernel_tex_fetch(__attributes_float2, uv_desc.offset + tri_vindex.z);
-      duv0 = make_float2(uvs[0].x - uvs[2].x, uvs[0].y - uvs[2].y);
-      duv1 = make_float2(uvs[1].x - uvs[2].x, uvs[1].y - uvs[2].y);
-      found_uv = true;
-    }
-  }
-  if (found_uv) {
-    const float det = duv

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list