0025833: Visualization, ray tracing - Problems with the backside of triangles
authordbp <dbp@opencascade.com>
Thu, 2 Apr 2015 11:27:16 +0000 (14:27 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 2 Apr 2015 11:38:42 +0000 (14:38 +0300)
Backside triangles are handled correctly by implementing two-sided lighting model. Ray-tracing shader was optimized (up to 25% performance increase).

Test case for CR25833

src/Shaders/RaytraceBase.fs
tests/v3d/raytrace/bug25833 [new file with mode: 0755]

index a300273..2cc2df9 100644 (file)
@@ -125,20 +125,6 @@ struct SIntersect
 #define AXIS_Y vec3 (0.0f, 1.0f, 0.0f)
 #define AXIS_Z vec3 (0.0f, 0.0f, 1.0f)
 
-// =======================================================================
-// function : MatrixRowMultiplyDir
-// purpose  : Multiplies a vector by matrix
-// =======================================================================
-vec3 MatrixRowMultiplyDir (in vec3 v,
-                           in vec4 m0,
-                           in vec4 m1,
-                           in vec4 m2)
-{
-  return vec3 (dot (m0.xyz, v),
-               dot (m1.xyz, v),
-               dot (m2.xyz, v));
-}
-
 //! 32-bit state of random number generator.
 uint RandState;
 
@@ -897,6 +883,8 @@ vec3 Refract (in vec3 theInput,
 
 #define THRESHOLD vec3 (0.1f)
 
+#define INVALID_BOUNCES 1000
+
 #define LIGHT_POS(index) (2 * index + 1)
 #define LIGHT_PWR(index) (2 * index + 0)
 
@@ -921,12 +909,12 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
 
     if (aTriIndex.x == -1)
     {
-      vec4 aColor = vec4 (0.0f, 0.0f, 0.0f, 1.0f);
+      vec4 aColor = vec4 (0.0f);
 
       if (aWeight.w != 0.0f)
       {
-        if (anOpenGlDepth != MAXFLOAT)
-          aColor = ComputeOpenGlColor (theRay);
+        aColor = anOpenGlDepth != MAXFLOAT ?
+          ComputeOpenGlColor (theRay) : vec4 (0.0f, 0.0f, 0.0f, 1.0f);
       }
       else if (bool(uEnvironmentEnable))
       {
@@ -940,23 +928,33 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
     }
 
     aHit.Normal = normalize (aHit.Normal);
-    
+
     // For polygons that are parallel to the screen plane, the depth slope
     // is equal to 1, resulting in small polygon offset. For polygons that
     // that are at a large angle to the screen, the depth slope tends to 1,
     // resulting in a larger polygon offset
-    float aPolygonOffset = uSceneEpsilon * min (
-      EPS_SCALE / abs (dot (theRay.Direct, aHit.Normal)), EPS_SCALE / MIN_SLOPE);
+    float aPolygonOffset = uSceneEpsilon * EPS_SCALE /
+      max (abs (dot (theRay.Direct, aHit.Normal)), MIN_SLOPE);
 
-    if (anOpenGlDepth - aPolygonOffset < aHit.Time)
+    if (anOpenGlDepth < aHit.Time + aPolygonOffset)
     {
-      vec4 aColor = ComputeOpenGlColor (theRay);
+      vec4 aGlColor = ComputeOpenGlColor (theRay);
 
-      aResult += aWeight.xyz * aColor.xyz;
-      aWeight *= aColor.w;
+      aResult += aWeight.xyz * aGlColor.xyz;
+      aWeight *= aGlColor.w;
     }
 
-    vec3 aPoint = theRay.Direct * aHit.Time + theRay.Origin;
+    theRay.Origin += theRay.Direct * aHit.Time; // intersection point
+
+    vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0).xyz;
+    vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1).xyz;
+    vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2).xyz;
+
+    vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
+
+    aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),
+                               dot (aInvTransf1, aNormal),
+                               dot (aInvTransf2, aNormal)));
 
     vec3 aAmbient  = texelFetch (
       uRaytraceMaterialTexture, MATERIAL_AMBN (aTriIndex.w)).rgb;
@@ -966,8 +964,6 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
       uRaytraceMaterialTexture, MATERIAL_SPEC (aTriIndex.w));
     vec4 aOpacity  = texelFetch (
       uRaytraceMaterialTexture, MATERIAL_TRAN (aTriIndex.w));
-    vec3 aEmission = texelFetch (
-      uRaytraceMaterialTexture, MATERIAL_EMIS (aTriIndex.w)).rgb;
 
 #ifdef USE_TEXTURES
     if (aDiffuse.w >= 0.f)
@@ -990,14 +986,15 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
     }
 #endif
 
-    vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
-    vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
-    vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
+    vec3 aEmission = texelFetch (
+      uRaytraceMaterialTexture, MATERIAL_EMIS (aTriIndex.w)).rgb;
 
-    vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
+    float aGeomFactor = dot (aNormal, theRay.Direct);
+
+    aResult.xyz += aWeight.xyz * aOpacity.x * (
+      uGlobalAmbient.xyz * aAmbient * max (abs (aGeomFactor), 0.5f) + aEmission);
 
-    aNormal = normalize (MatrixRowMultiplyDir (
-      aNormal, aInvTransf0, aInvTransf1, aInvTransf2));
+    vec3 aSidedNormal = mix (aNormal, -aNormal, step (0.0f, aGeomFactor));
 
     for (int aLightIdx = 0; aLightIdx < uLightCount; ++aLightIdx)
     {
@@ -1008,49 +1005,43 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
 
       if (aLight.w != 0.0f) // point light source
       {
-        aDistance = length (aLight.xyz -= aPoint);
+        aDistance = length (aLight.xyz -= theRay.Origin);
 
         aLight.xyz *= 1.0f / aDistance;
       }
 
-      SRay aShadow = SRay (aPoint + aLight.xyz * uSceneEpsilon, aLight.xyz);
-
-      aShadow.Origin += aHit.Normal * uSceneEpsilon *
-        (dot (aHit.Normal, aLight.xyz) >= 0.0f ? 1.0f : -1.0f);
-
-      float aVisibility = 1.0f;
+      float aLdotN = dot (aLight.xyz, aSidedNormal);
 
-      if (bool(uShadowsEnable))
+      if (aLdotN > 0.0f) // first check if light source is important
       {
-        vec3 aInverse = 1.0f / max (abs (aLight.xyz), SMALL);
+        float aVisibility = 1.0f;
 
-        aVisibility = SceneAnyHit (
-          aShadow, mix (-aInverse, aInverse, step (ZERO, aLight.xyz)), aDistance);
-      }
+        if (bool(uShadowsEnable))
+        {
+          SRay aShadow = SRay (theRay.Origin, aLight.xyz);
 
-      if (aVisibility > 0.0f)
-      {
-        vec3 aIntensity = vec3 (texelFetch (
-          uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx)));
+          aShadow.Origin += uSceneEpsilon * (aLight.xyz +
+            mix (-aHit.Normal, aHit.Normal, step (0.0f, dot (aHit.Normal, aLight.xyz))));
 
-        float aLdotN = dot (aShadow.Direct, aNormal);
+          vec3 aInverse = 1.0f / max (abs (aLight.xyz), SMALL);
 
-        if (aOpacity.y > 0.0f)   // force two-sided lighting
-          aLdotN = abs (aLdotN); // for transparent surfaces
+          aVisibility = SceneAnyHit (
+            aShadow, mix (-aInverse, aInverse, step (ZERO, aLight.xyz)), aDistance);
+        }
 
-        if (aLdotN > 0.0f)
+        if (aVisibility > 0.0f)
         {
-          float aRdotV = dot (reflect (aShadow.Direct, aNormal), theRay.Direct);
+          vec3 aIntensity = vec3 (texelFetch (
+            uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx)));
+
+          float aRdotV = dot (reflect (aLight.xyz, aSidedNormal), theRay.Direct);
 
           aResult.xyz += aWeight.xyz * (aOpacity.x * aVisibility) * aIntensity *
-            (aDiffuse.rgb * aLdotN + aSpecular.xyz * pow (max (0.0f, aRdotV), aSpecular.w));
+            (aDiffuse.xyz * aLdotN + aSpecular.xyz * pow (max (0.f, aRdotV), aSpecular.w));
         }
       }
     }
 
-    aResult.xyz += aWeight.xyz * aOpacity.x * (uGlobalAmbient.xyz *
-      aAmbient * max (abs (dot (aNormal, theRay.Direct)), 0.5f) + aEmission);
-
     if (aOpacity.x != 1.0f)
     {
       aWeight *= aOpacity.y;
@@ -1058,15 +1049,6 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
       if (aOpacity.z != 1.0f)
       {
         theRay.Direct = Refract (theRay.Direct, aNormal, aOpacity.z, aOpacity.w);
-
-        theInverse = 1.0f / max (abs (theRay.Direct), SMALL);
-
-        theInverse = mix (-theInverse, theInverse, step (ZERO, theRay.Direct));
-
-        aPoint += aHit.Normal * (dot (aHit.Normal, theRay.Direct) >= 0.0f ? uSceneEpsilon : -uSceneEpsilon);
-
-        // Disable combining image with OpenGL output
-        anOpenGlDepth = MAXFLOAT;
       }
       else
       {
@@ -1078,32 +1060,33 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
       aWeight *= bool(uReflectionsEnable) ?
         texelFetch (uRaytraceMaterialTexture, MATERIAL_REFL (aTriIndex.w)) : vec4 (0.0f);
 
-      theRay.Direct = reflect (theRay.Direct, aNormal);
+      vec3 aReflect = reflect (theRay.Direct, aNormal);
 
-      if (dot (theRay.Direct, aHit.Normal) < 0.0f)
+      if (dot (aReflect, aHit.Normal) * dot (theRay.Direct, aHit.Normal) > 0.0f)
       {
-        theRay.Direct = reflect (theRay.Direct, aHit.Normal);
+        aReflect = reflect (theRay.Direct, aHit.Normal);
       }
 
-      theInverse = 1.0f / max (abs (theRay.Direct), SMALL);
-
-      theInverse = mix (-theInverse, theInverse, step (ZERO, theRay.Direct));
-
-      aPoint += aHit.Normal * (dot (aHit.Normal, theRay.Direct) >= 0.0f ? uSceneEpsilon : -uSceneEpsilon);
-
-      // Disable combining image with OpenGL output
-      anOpenGlDepth = MAXFLOAT;
+      theRay.Direct = aReflect;
     }
 
     if (all (lessThanEqual (aWeight.xyz, THRESHOLD)))
     {
-      return vec4 (aResult.x,
-                   aResult.y,
-                   aResult.z,
-                   aWeight.w);
+      aDepth = INVALID_BOUNCES;
+    }
+    else if (aOpacity.x == 1.0f || aOpacity.z != 1.0f) // if no simple transparency
+    {
+      theRay.Origin += aHit.Normal * mix (
+        -uSceneEpsilon, uSceneEpsilon, step (0.0f, dot (aHit.Normal, theRay.Direct)));
+
+      theInverse = 1.0f / max (abs (theRay.Direct), SMALL);
+
+      theInverse = mix (-theInverse, theInverse, step (ZERO, theRay.Direct));
+
+      anOpenGlDepth = MAXFLOAT; // disable combining image with OpenGL output
     }
 
-    theRay.Origin = theRay.Direct * uSceneEpsilon + aPoint;
+    theRay.Origin += theRay.Direct * uSceneEpsilon;
   }
 
   return vec4 (aResult.x,
diff --git a/tests/v3d/raytrace/bug25833 b/tests/v3d/raytrace/bug25833
new file mode 100755 (executable)
index 0000000..46eafc8
--- /dev/null
@@ -0,0 +1,47 @@
+puts "========"
+puts "OCC25833"
+puts "========"
+puts ""
+##########################################
+## Visualization, Ray Tracing - fix problems with the backside of triangles
+##########################################
+
+box b1 100 100 100
+explode b1 Fa
+box b2 10 10 -20 10 10 10
+
+vsetdispmode 1
+vdisplay b1_5 b1_6 b2
+vsetmaterial b1_5 steel
+vsetmaterial b1_6 steel
+vfit
+
+# Problem 1: b1_5 (grey) becomes semi-transparent after the next line,
+# compare it with b1_6 visible from the frontside
+vrenderparams -rayTrace
+vdump ${imagedir}/${test_image}_1.png
+checkcolor 100 300 0.37647059559822083 0.3803921639919281 0.40392157435417175
+if { ${stat} != 1 } {
+   puts "Error : bad color (case 1)"
+}
+
+# Problem 2: The small box shows through b1_5
+vrenderparams -reflections
+vdump ${imagedir}/${test_image}_2.png
+checkcolor 190 250 0.37647059559822083 0.3803921639919281 0.40392157435417175
+if { ${stat} != 1 } {
+   puts "Error : bad color (case 2)"
+}
+
+ttranslate b2 30 30 30
+# Problem 3: The small box is not reflected from the backface of b1_5
+vdisplay b2
+vdump ${imagedir}/${test_image}_3.png
+checkcolor 190 260 0.79607844352722168 0.60784316062927246 0.21960784494876862
+if { ${stat} != 1 } {
+   puts "Error : bad color (case 3)"
+}
+checkcolor 190 310 0.61960786581039429 0.56078433990478516 0.43529412150382996
+if { ${stat} != 1 } {
+   puts "Error : bad color (case 4)"
+}