[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