[Bf-blender-cvs] [57f46b9d5f3] master: Fix T92036: `Magic Texture` in Volumetric World Shaders render differently with the CPU and GPU

William Leeson noreply at git.blender.org
Fri Dec 10 09:12:17 CET 2021


Commit: 57f46b9d5f370dfacc92786dab596060400a21a8
Author: William Leeson
Date:   Fri Dec 10 09:02:55 2021 +0100
Branches: master
https://developer.blender.org/rB57f46b9d5f370dfacc92786dab596060400a21a8

Fix T92036: `Magic Texture` in Volumetric World Shaders render differently with the CPU and GPU

When rendering volume surfaces in unbounded worlds the volume stepping can produce large values. If used with a magic texture node the values can results in a Inf float which when used in a sin or cos produces a NaN.

To fix this the input values are mapped into the periodic range of the sin and cos functions (-2*PI 2*PI) this stops the possibility of a Inf occurring and thus the NaN. It also improves the accuracy and smoothness of the result due to loss of precision when large values are summed with smaller ones effectively removing the parts of the smaller number (i.e. those in the -2PI to 2PI range) that result in variation of the output of sin and cos.

Reviewed By: brecht

Maniphest Tasks: T92036

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

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

M	intern/cycles/kernel/osl/shaders/node_magic_texture.osl
M	intern/cycles/kernel/svm/magic.h
M	source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl

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

diff --git a/intern/cycles/kernel/osl/shaders/node_magic_texture.osl b/intern/cycles/kernel/osl/shaders/node_magic_texture.osl
index 476c6895f05..0ed83aae3b8 100644
--- a/intern/cycles/kernel/osl/shaders/node_magic_texture.osl
+++ b/intern/cycles/kernel/osl/shaders/node_magic_texture.osl
@@ -17,14 +17,17 @@
 #include "stdcycles.h"
 
 /* Magic */
-
-color magic(point p, int n, float distortion)
+color magic(point p, float scale, int n, float distortion)
 {
   float dist = distortion;
 
-  float x = sin((p[0] + p[1] + p[2]) * 5.0);
-  float y = cos((-p[0] + p[1] - p[2]) * 5.0);
-  float z = -cos((-p[0] - p[1] + p[2]) * 5.0);
+  float a = mod(p.x * scale, M_2PI);
+  float b = mod(p.y * scale, M_2PI);
+  float c = mod(p.z * scale, M_2PI);
+
+  float x = sin((a + b + c) * 5.0);
+  float y = cos((-a + b - c) * 5.0);
+  float z = -cos((-a - b + c) * 5.0);
 
   if (n > 0) {
     x *= dist;
@@ -103,6 +106,6 @@ shader node_magic_texture(int use_mapping = 0,
   if (use_mapping)
     p = transform(mapping, p);
 
-  Color = magic(p * Scale, depth, Distortion);
+  Color = magic(p, Scale, depth, Distortion);
   Fac = (Color[0] + Color[1] + Color[2]) * (1.0 / 3.0);
 }
diff --git a/intern/cycles/kernel/svm/magic.h b/intern/cycles/kernel/svm/magic.h
index f103a8eebcc..715a47d88cf 100644
--- a/intern/cycles/kernel/svm/magic.h
+++ b/intern/cycles/kernel/svm/magic.h
@@ -20,11 +20,27 @@ CCL_NAMESPACE_BEGIN
 
 /* Magic */
 
-ccl_device_noinline_cpu float3 svm_magic(float3 p, int n, float distortion)
+ccl_device_noinline_cpu float3 svm_magic(float3 p, float scale, int n, float distortion)
 {
-  float x = sinf((p.x + p.y + p.z) * 5.0f);
-  float y = cosf((-p.x + p.y - p.z) * 5.0f);
-  float z = -cosf((-p.x - p.y + p.z) * 5.0f);
+  /*
+   * Prevent NaNs due to input p
+   * Sin and Cosine are periodic about [0 2*PI) so the following
+   * will yeild a more accurate result. As it stops the input values
+   * going out of range for floats which caused a NaN. The
+   * calculation of (px + py + pz)*5 can cause an Inf when one or more
+   * values are very large the cos or sin of this results in a NaN
+   * It also addresses the case where one dimension is large relative
+   * to another which caused banding due to the loss of precision in the
+   * smaller value. This is due to the value in the -2*PI to 2*PI range
+   * effectively being lost due to floating point precision.
+   */
+  float px = fmodf(p.x, M_2PI_F);
+  float py = fmodf(p.y, M_2PI_F);
+  float pz = fmodf(p.z, M_2PI_F);
+
+  float x = sinf((px + py + pz) * 5.0f * scale);
+  float y = cosf((-px + py - pz) * 5.0f * scale);
+  float z = -cosf((-px - py + pz) * 5.0f * scale);
 
   if (n > 0) {
     x *= distortion;
@@ -103,7 +119,7 @@ ccl_device_noinline int svm_node_tex_magic(
   float scale = stack_load_float_default(stack, scale_offset, node2.x);
   float distortion = stack_load_float_default(stack, distortion_offset, node2.y);
 
-  float3 color = svm_magic(co * scale, depth, distortion);
+  float3 color = svm_magic(co, scale, depth, distortion);
 
   if (stack_valid(fac_offset))
     stack_store_float(stack, fac_offset, average(color));
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl
index 942c507cc38..1dc5ff433a8 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl
@@ -1,7 +1,8 @@
 void node_tex_magic(
     vec3 co, float scale, float distortion, float depth, out vec4 color, out float fac)
 {
-  vec3 p = co * scale;
+  vec3 p = mod(co * scale, 2.0 * M_PI);
+
   float x = sin((p.x + p.y + p.z) * 5.0);
   float y = cos((-p.x + p.y - p.z) * 5.0);
   float z = -cos((-p.x - p.y + p.z) * 5.0);



More information about the Bf-blender-cvs mailing list