From be86ba90c4ec5bfcc70cdfb57198f73c7b47c309 Mon Sep 17 00:00:00 2001
From: duv <duv@opencascade.com>
Date: Tue, 25 Oct 2016 11:21:17 +0300
Subject: [PATCH] 0025221: Visualization - Depth test errors in ray-tracing
 scene containing face outlines

Calculation of polygon offset for ray tracing has been changed.
Issues with wrong data in FBO depth buffer has been resolved.
---
 src/Shaders/PathtraceBase.fs  | 13 ++-----
 src/Shaders/RaytraceBase.fs   | 38 +++++++++++++-----
 src/Shaders/RaytraceRender.fs |  9 ++++-
 tests/v3d/raytrace/bug25221   | 72 +++++++++++++++++++++++++++++++++++
 4 files changed, 111 insertions(+), 21 deletions(-)
 create mode 100644 tests/v3d/raytrace/bug25221

diff --git a/src/Shaders/PathtraceBase.fs b/src/Shaders/PathtraceBase.fs
index bf778ad5f2..09db692e99 100644
--- a/src/Shaders/PathtraceBase.fs
+++ b/src/Shaders/PathtraceBase.fs
@@ -652,17 +652,10 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
     // Evaluate depth on first hit
     if (aDepth == 0)
     {
-      // 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 * EPS_SCALE /
-        max (abs (dot (theRay.Direct, aHit.Normal)), MIN_SLOPE);
+      vec4 aNDCPoint = uViewMat * vec4 (theRay.Origin, 1.f);
 
-      // Hit point in NDC-space [-1,1] (the polygon offset is applied in the world space)
-      vec4 aNDCPoint = uViewMat * vec4 (theRay.Origin + theRay.Direct * aPolygonOffset, 1.f);
-
-      aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w) * 0.5f + 0.5f;
+      float aPolygonOffset = PolygonOffset (aHit.Normal, theRay.Origin);
+      aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w + aPolygonOffset * POLYGON_OFFSET_SCALE) * 0.5f + 0.5f;
     }
 
     // fetch material (BSDF)
diff --git a/src/Shaders/RaytraceBase.fs b/src/Shaders/RaytraceBase.fs
index 6c5f5e4692..d5f9a80063 100644
--- a/src/Shaders/RaytraceBase.fs
+++ b/src/Shaders/RaytraceBase.fs
@@ -787,6 +787,31 @@ vec3 SmoothNormal (in vec2 theUV, in ivec4 theTriangle)
                     aNormal0 * (1.0f - theUV.x - theUV.y));
 }
 
+#define POLYGON_OFFSET_UNIT 0.f
+#define POLYGON_OFFSET_FACTOR 1.f
+#define POLYGON_OFFSET_SCALE 0.006f
+
+// =======================================================================
+// function : PolygonOffset
+// purpose  : Computes OpenGL polygon offset
+// =======================================================================
+float PolygonOffset (in vec3 theNormal, in vec3 thePoint)
+{
+  vec4 aProjectedNorm = vec4 (theNormal, -dot (theNormal, thePoint)) * uUnviewMat;
+
+  float aPolygonOffset = POLYGON_OFFSET_UNIT;
+
+  if (aProjectedNorm.z * aProjectedNorm.z > 1e-20f)
+  {
+    aProjectedNorm.xy *= 1.f / aProjectedNorm.z;
+
+    aPolygonOffset += POLYGON_OFFSET_FACTOR * max (abs (aProjectedNorm.x),
+                                                   abs (aProjectedNorm.y));
+  }
+
+  return aPolygonOffset;
+}
+
 // =======================================================================
 // function : SmoothUV
 // purpose  : Interpolates UV coordinates across the triangle
@@ -908,17 +933,10 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
     // Evaluate depth on first hit
     if (aDepth == 0)
     {
-      // 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 * EPS_SCALE /
-        max (abs (dot (theRay.Direct, aHit.Normal)), MIN_SLOPE);
+      vec4 aNDCPoint = uViewMat * vec4 (theRay.Origin, 1.f);
 
-      // Hit point in NDC-space [-1,1] (the polygon offset is applied in the world space)
-      vec4 aNDCPoint = uViewMat * vec4 (theRay.Origin + theRay.Direct * aPolygonOffset, 1.f);
-
-      aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w) * 0.5f + 0.5f;
+      float aPolygonOffset = PolygonOffset (aHit.Normal, theRay.Origin);
+      aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w + aPolygonOffset * POLYGON_OFFSET_SCALE) * 0.5f + 0.5f;
     }
 
     vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
diff --git a/src/Shaders/RaytraceRender.fs b/src/Shaders/RaytraceRender.fs
index ae25d4ef95..e2e493ffce 100644
--- a/src/Shaders/RaytraceRender.fs
+++ b/src/Shaders/RaytraceRender.fs
@@ -95,7 +95,14 @@ void main (void)
 
 #else
 
-  OutColor = mix (texture2D (uAccumTexture, vPixel), aColor, uSampleWeight);
+  if (uSampleWeight >= 1.f)
+  {
+    OutColor = aColor;
+  }
+  else
+  {
+    OutColor = mix (texture2D (uAccumTexture, vPixel), aColor, uSampleWeight);
+  }
 
 #endif // ADAPTIVE_SAMPLING
 
diff --git a/tests/v3d/raytrace/bug25221 b/tests/v3d/raytrace/bug25221
new file mode 100644
index 0000000000..279cb22f97
--- /dev/null
+++ b/tests/v3d/raytrace/bug25221
@@ -0,0 +1,72 @@
+puts "========"
+puts "OCC25221"
+puts "========"
+##########################################
+## Visualization - Depth test errors in ray-tracing scene containing face outlines
+##########################################
+
+# custom shapes
+set aShape [locate_data_file occ/Bottom.brep]
+
+# setup 3D viewer content
+vinit name=View1 w=512 h=512
+
+vsetdispmode 1
+restore $aShape s
+vdisplay s
+vfit
+
+# activate ray-tracing
+vrenderparams -raytrace
+
+# highlight the shape
+vmoveto 200 200
+
+vdump $imagedir/${casename}_lines_closeup.png
+
+vzoom 0.5
+
+vdump $imagedir/${casename}_lines_far.png
+
+vfit
+
+# change camera to perspective
+vcamera -persp
+
+# change highlight display mode
+vdisplay s -highMode 1
+
+# highlight the shape again
+vmoveto 0 0
+vmoveto 200 200
+
+vdump $imagedir/${casename}_faces_closeup.png
+
+# apply transformation
+vlocrotate s 0 0 0 0 0 1 10
+vloctranslate s -30 0 0
+vmoveto 0 0
+vmoveto 200 200
+
+vdump $imagedir/${casename}_faces_closeup_rotated.png
+
+vlocreset s
+vmoveto 0 0
+vmoveto 200 200
+
+vzoom 0.5
+
+vdump $imagedir/${casename}_faces_far.png
+
+# enable Path tracing
+vrenderparams -gi
+vfit
+vfps 100
+
+vdump $imagedir/${casename}_faces_pt.png
+
+# rotate camera
+vrotate 0 0.2 0
+vfps 100
+
+vdump $imagedir/${casename}_faces_pt_rot.png