0028129: Visualization, Path Tracing - Improve interactivity in "steady" rendering...
authordbp <dbp@opencascade.com>
Thu, 26 Jan 2017 09:56:13 +0000 (12:56 +0300)
committerapn <apn@opencascade.com>
Thu, 26 Jan 2017 09:57:02 +0000 (12:57 +0300)
Re-basing the patch on current master.

13 files changed:
src/Graphic3d/Graphic3d_RenderingParams.hxx
src/OpenGl/OpenGl_TileSampler.cxx
src/OpenGl/OpenGl_TileSampler.hxx
src/OpenGl/OpenGl_View.hxx
src/OpenGl/OpenGl_View_Raytrace.cxx
src/Shaders/Display.fs
src/Shaders/PathtraceBase.fs
src/Shaders/RaytraceRender.fs
src/Shaders/Shaders_Display_fs.pxx
src/Shaders/Shaders_PathtraceBase_fs.pxx
src/Shaders/Shaders_RaytraceRender_fs.pxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx
tests/v3d/raytrace/sample_ball_iss [new file with mode: 0644]

index b264d44..33ca9e3 100644 (file)
@@ -62,6 +62,7 @@ public:
     TwoSidedBsdfModels          (Standard_False),
     RadianceClampingValue       (30.0),
     RebuildRayTracingShaders    (Standard_False),
+    NbRayTracingTiles           (16 * 16),
     // stereoscopic parameters
     StereoMode (Graphic3d_StereoMode_QuadBuffer),
     AnaglyphFilter (Anaglyph_RedCyan_Optimized),
@@ -105,6 +106,7 @@ public:
   Standard_Boolean        TwoSidedBsdfModels;          //!< forces path tracing to use two-sided versions of original one-sided scattering models
   Standard_ShortReal      RadianceClampingValue;       //!< maximum radiance value used for clamping radiance estimation.
   Standard_Boolean        RebuildRayTracingShaders;    //!< forces rebuilding ray tracing shaders at the next frame
+  Standard_Integer        NbRayTracingTiles;           //!< total number of screen tiles used in adaptive sampling mode (PT only)
 
   Graphic3d_StereoMode    StereoMode;                  //!< stereoscopic output mode, Graphic3d_StereoMode_QuadBuffer by default
   Anaglyph                AnaglyphFilter;              //!< filter for anaglyph output, Anaglyph_RedCyan_Optimized by default
index 6e8a1dc..c9b9b88 100644 (file)
@@ -150,36 +150,45 @@ void OpenGl_TileSampler::SetSize (const int theSizeX,
 //=======================================================================
 void OpenGl_TileSampler::Upload (const Handle(OpenGl_Context)& theContext,
                                  const Handle(OpenGl_Texture)& theTexture,
-                                 bool theAdaptive)
+                                 const int                     theNbTilesX,
+                                 const int                     theNbTilesY,
+                                 const bool                    theAdaptive)
 {
   if (theTexture.IsNull())
   {
     return;
   }
 
-  std::vector<GLint> aData (myTilesX * myTilesY * 2);
-  for (int aX = 0; aX < myTilesX; ++aX)
+  const int aNbTilesX = theAdaptive ? theNbTilesX : myTilesX;
+  const int aNbTilesY = theAdaptive ? theNbTilesY : myTilesY;
+
+  Standard_ASSERT_RAISE (aNbTilesX * aNbTilesY > 0,
+    "Error! Number of sampling tiles should be positive");
+
+  std::vector<GLint> aData (aNbTilesX * aNbTilesY * 2);
+
+  for (int aX = 0; aX < aNbTilesX; ++aX)
   {
-    for (int aY = 0; aY < myTilesY; ++aY)
+    for (int aY = 0; aY < aNbTilesY; ++aY)
     {
       if (!theAdaptive)
       {
-        aData[(aY * myTilesX + aX) * 2 + 0] = aX * TileSize();
-        aData[(aY * myTilesX + aX) * 2 + 1] = aY * TileSize();
+        aData[(aY * aNbTilesX + aX) * 2 + 0] = aX * TileSize();
+        aData[(aY * aNbTilesX + aX) * 2 + 1] = aY * TileSize();
       }
       else
       {
-        Sample (aData[(aY * myTilesX + aX) * 2 + 0],
-                aData[(aY * myTilesX + aX) * 2 + 1]);
+        Sample (aData[(aY * aNbTilesX + aX) * 2 + 0],
+                aData[(aY * aNbTilesX + aX) * 2 + 1]);
       }
     }
   }
 
   theTexture->Bind (theContext);
 
-  theContext->core11fwd->glTexImage2D (GL_TEXTURE_2D, 0, GL_RG32I, myTilesX, myTilesY, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, &aData.front());
-  const GLenum anErr = theContext->core11fwd->glGetError();
-  if (anErr != GL_NO_ERROR)
+  theContext->core11fwd->glTexImage2D (GL_TEXTURE_2D, 0, GL_RG32I, aNbTilesX, aNbTilesY, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, &aData.front());
+
+  if (theContext->core11fwd->glGetError() != GL_NO_ERROR)
   {
     theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_MEDIUM,
                              "Error! Failed to upload tile offset map on the GPU");
index 4f27293..9fc9753 100644 (file)
 #include <vector>
 
 //! Tool object used for sampling screen tiles according to estimated pixel variance (used in path tracing engine).
-//! To improve GPU thread coherency, render window is split into pixel blocks or tiles.
+//! To improve GPU thread coherency, rendering window is split into pixel blocks or tiles. The important feature of
+//! this approach is that it is possible to keep the same number of tiles for any screen resolution (e.g. 256 tiles
+//! can be used for both 512 x 512 window and 1920 x 1080 window). So, a smaller number of tiles allows to increase
+//! interactivity (FPS), but at the cost of higher per-frame variance ('noise'). On the contrary a larger number of
+//! tiles decrease interactivity, but leads to lower per-frame variance. Note that the total time needed to produce
+//! final final image is the same for both cases.
 class OpenGl_TileSampler
 {
 public:
@@ -76,7 +81,9 @@ public:
   //! Uploads offsets of sampled tiles to the given OpenGL texture.
   Standard_EXPORT void Upload (const Handle(OpenGl_Context)& theContext,
                                const Handle(OpenGl_Texture)& theTexture,
-                               bool theAdaptive);
+                               const int                     theNbTilesX,
+                               const int                     theNbTilesY,
+                               const bool                    theAdaptive);
 
 protected:
 
index 45f44cc..7eaadd2 100644 (file)
@@ -711,6 +711,12 @@ protected: //! @name data types related to ray-tracing
     //! Maximum radiance value used for clamping radiance estimation.
     Standard_ShortReal RadianceClampingValue;
 
+    //! Number of tiles in X dimension (in adaptive sampling mode).
+    Standard_Integer NbTilesX;
+    
+    //! Number of tiles in Y dimension (in adaptive sampling mode).
+    Standard_Integer NbTilesY;
+
     //! Creates default compile-time ray-tracing parameters.
     RaytracingParams()
     : StackSize              (THE_DEFAULT_STACK_SIZE),
@@ -721,7 +727,9 @@ protected: //! @name data types related to ray-tracing
       TwoSidedBsdfModels     (Standard_False),
       AdaptiveScreenSampling (Standard_False),
       UseEnvMapForBackground (Standard_False),
-      RadianceClampingValue  (30.0)            { }
+      RadianceClampingValue  (30.0),
+      NbTilesX               (16),
+      NbTilesY               (16) { }
   };
 
   //! Describes state of OpenGL structure.
@@ -897,9 +905,11 @@ protected: //! @name methods related to ray-tracing
                                 const Handle(OpenGl_Context)& theGlContext);
 
   //! Runs path tracing (global illumination) kernel.
-  Standard_Boolean runPathtrace (const Graphic3d_Camera::Projection theProjection,
-                                 OpenGl_FrameBuffer*                theReadDrawFbo,
-                                 const Handle(OpenGl_Context)&      theGlContext);
+  Standard_Boolean runPathtrace (const Standard_Integer        theSizeX,
+                                 const Standard_Integer        theSizeY,
+                                 Graphic3d_Camera::Projection  theProjection,
+                                 OpenGl_FrameBuffer*           theReadDrawFbo,
+                                 const Handle(OpenGl_Context)& theGlContext);
 
   //! Redraws the window using OpenGL/GLSL ray-tracing or path tracing.
   Standard_Boolean raytrace (const Standard_Integer        theSizeX,
index 54494ef..c078c54 100644 (file)
@@ -1359,11 +1359,21 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Handle(OpenGl_Context
       }
     }
 
+    Standard_Integer aNbTilesX = 8;
+    Standard_Integer aNbTilesY = 8;
+
+    for (Standard_Integer anIdx = 0; aNbTilesX * aNbTilesY < myRenderParams.NbRayTracingTiles; ++anIdx)
+    {
+      (anIdx % 2 == 0 ? aNbTilesX : aNbTilesY) <<= 1;
+    }
+
     if (myRenderParams.RaytracingDepth             != myRaytraceParameters.NbBounces
      || myRenderParams.IsTransparentShadowEnabled  != myRaytraceParameters.TransparentShadows
      || myRenderParams.IsGlobalIlluminationEnabled != myRaytraceParameters.GlobalIllumination
      || myRenderParams.TwoSidedBsdfModels          != myRaytraceParameters.TwoSidedBsdfModels
-     || myRaytraceGeometry.HasTextures()           != myRaytraceParameters.UseBindlessTextures)
+     || myRaytraceGeometry.HasTextures()           != myRaytraceParameters.UseBindlessTextures
+     || aNbTilesX                                  != myRaytraceParameters.NbTilesX
+     || aNbTilesY                                  != myRaytraceParameters.NbTilesY)
     {
       myRaytraceParameters.NbBounces           = myRenderParams.RaytracingDepth;
       myRaytraceParameters.TransparentShadows  = myRenderParams.IsTransparentShadowEnabled;
@@ -1371,6 +1381,18 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Handle(OpenGl_Context
       myRaytraceParameters.TwoSidedBsdfModels  = myRenderParams.TwoSidedBsdfModels;
       myRaytraceParameters.UseBindlessTextures = myRaytraceGeometry.HasTextures();
 
+#ifdef RAY_TRACE_PRINT_INFO
+      if (aNbTilesX != myRaytraceParameters.NbTilesX
+       || aNbTilesY != myRaytraceParameters.NbTilesY)
+      {
+        std::cout << "Number of tiles X: " << aNbTilesX << "\n";
+        std::cout << "Number of tiles Y: " << aNbTilesY << "\n";
+      }
+#endif
+
+      myRaytraceParameters.NbTilesX = aNbTilesX;
+      myRaytraceParameters.NbTilesY = aNbTilesY;
+
       aToRebuildShaders = Standard_True;
     }
 
@@ -1848,25 +1870,42 @@ Standard_Boolean OpenGl_View::updateRaytraceBuffers (const Standard_Integer
     return Standard_True;
   }
 
-  if (myRaytraceFBO1[0]->GetSizeX() != theSizeX
-   || myRaytraceFBO1[0]->GetSizeY() != theSizeY)
+  if (myRaytraceParameters.AdaptiveScreenSampling)
   {
-    myAccumFrames = 0;
-  }
+    const Standard_Integer aSizeX = std::max (myRaytraceParameters.NbTilesX * 64, theSizeX);
+    const Standard_Integer aSizeY = std::max (myRaytraceParameters.NbTilesY * 64, theSizeY);
 
-  myRaytraceFBO1[0]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
-  myRaytraceFBO2[0]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
+    myRaytraceFBO1[0]->InitLazy (theGlContext, aSizeX, aSizeY, GL_RGBA32F, myFboDepthFormat);
+    myRaytraceFBO2[0]->InitLazy (theGlContext, aSizeX, aSizeY, GL_RGBA32F, myFboDepthFormat);
 
-  // Init second set of buffers for stereographic rendering.
-  if (myCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
-  {
-    myRaytraceFBO1[1]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
-    myRaytraceFBO2[1]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
+    if (myRaytraceFBO1[1]->IsValid()) // second FBO not needed
+    {
+      myRaytraceFBO1[1]->Release (theGlContext.operator->());
+      myRaytraceFBO2[1]->Release (theGlContext.operator->());
+    }
   }
-  else
+  else // non-adaptive mode
   {
-    myRaytraceFBO1[1]->Release (theGlContext.operator->());
-    myRaytraceFBO2[1]->Release (theGlContext.operator->());
+    if (myRaytraceFBO1[0]->GetSizeX() != theSizeX
+     || myRaytraceFBO1[0]->GetSizeY() != theSizeY)
+    {
+      myAccumFrames = 0; // accumulation should be restarted
+    }
+
+    myRaytraceFBO1[0]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
+    myRaytraceFBO2[0]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
+
+    // Init second set of buffers for stereographic rendering
+    if (myCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
+    {
+      myRaytraceFBO1[1]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
+      myRaytraceFBO2[1]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
+    }
+    else if (myRaytraceFBO1[1]->IsValid()) // second FBO not needed
+    {
+      myRaytraceFBO1[1]->Release (theGlContext.operator->());
+      myRaytraceFBO2[1]->Release (theGlContext.operator->());
+    }
   }
 
   myTileSampler.SetSize (theSizeX, theSizeY);
@@ -1883,6 +1922,8 @@ Standard_Boolean OpenGl_View::updateRaytraceBuffers (const Standard_Integer
   if (myRaytraceOutputTexture[0]->SizeX() / 3 != theSizeX
    || myRaytraceOutputTexture[0]->SizeY() / 2 != theSizeY)
   {
+    myAccumFrames = 0;
+
     // Due to limitations of OpenGL image load-store extension
     // atomic operations are supported only for single-channel
     // images, so we define GL_R32F image. It is used as array
@@ -2634,7 +2675,7 @@ Standard_Boolean OpenGl_View::runRaytraceShaders (const Standard_Integer
 
   if (myRaytraceParameters.GlobalIllumination) // path tracing
   {
-    aResult &= runPathtrace (theProjection, theReadDrawFbo, theGlContext);
+    aResult &= runPathtrace (theSizeX, theSizeY, theProjection, theReadDrawFbo, theGlContext);
   }
   else // Whitted-style ray-tracing
   {
@@ -2775,7 +2816,9 @@ Standard_Boolean OpenGl_View::runRaytrace (const Standard_Integer        theSize
 // function : runPathtrace
 // purpose  : Runs path tracing shader
 // =======================================================================
-Standard_Boolean OpenGl_View::runPathtrace (const Graphic3d_Camera::Projection  theProjection,
+Standard_Boolean OpenGl_View::runPathtrace (const Standard_Integer              theSizeX,
+                                            const Standard_Integer              theSizeY,
+                                            const Graphic3d_Camera::Projection  theProjection,
                                             OpenGl_FrameBuffer*                 theReadDrawFbo,
                                             const Handle(OpenGl_Context)&       theGlContext)
 {
@@ -2793,13 +2836,12 @@ Standard_Boolean OpenGl_View::runPathtrace (const Graphic3d_Camera::Projection
       myTileSampler.Reset(); // reset tile sampler to its initial state
     }
 
-    // We upload tile offset texture each 4 frames in order
-    // to minimize overhead of additional memory bandwidth.
-    // Adaptive sampling is starting after first 30 frames.
-    if (myAccumFrames % 4 == 0)
-    {
-      myTileSampler.Upload (theGlContext, myRaytraceTileOffsetsTexture, myAccumFrames > 30);
-    }
+    // Adaptive sampling is starting at the second frame
+    myTileSampler.Upload (theGlContext,
+                          myRaytraceTileOffsetsTexture,
+                          myRaytraceParameters.NbTilesX,
+                          myRaytraceParameters.NbTilesY,
+                          myAccumFrames > 0);
   }
 
   bindRaytraceTextures (theGlContext);
@@ -2859,9 +2901,25 @@ Standard_Boolean OpenGl_View::runPathtrace (const Graphic3d_Camera::Projection
 
   glDisable (GL_DEPTH_TEST);
 
+  if (myRaytraceParameters.AdaptiveScreenSampling && myAccumFrames > 0)
+  {
+    glViewport (0,
+                0,
+                myTileSampler.TileSize() * myRaytraceParameters.NbTilesX,
+                myTileSampler.TileSize() * myRaytraceParameters.NbTilesY);
+  }
+
   // Generate for the given RNG seed
   theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6);
 
+  if (myRaytraceParameters.AdaptiveScreenSampling && myAccumFrames > 0)
+  {
+    glViewport (0,
+                0,
+                theSizeX,
+                theSizeY);
+  }
+
   // Output accumulated path traced image
   theGlContext->BindProgram (myOutImageProgram);
 
index c4f9faa..6aff9c1 100644 (file)
@@ -2,6 +2,8 @@
 
   #extension GL_ARB_shader_image_load_store : require
 
+  #extension GL_ARB_shader_image_size : enable
+
   //! OpenGL image used for accumulating rendering result.
   volatile restrict layout(size1x32) uniform image2D uRenderImage;
 
@@ -87,8 +89,9 @@ void main (void)
   // calculate visual error
   float anError = (aAverRad - aHalfRad) * (aAverRad - aHalfRad);
 
-  // accumulate visual error to current block
-  imageAtomicAdd (uVarianceImage, ivec2 (aPixel / vec2 (BLOCK_SIZE)), int (anError * SCALE_FACTOR));
+  // accumulate visual error to current block; estimated error is written only
+  // after the first 40 samples and path length has reached 10 bounces or more
+  imageAtomicAdd (uVarianceImage, ivec2 (aPixel / vec2 (BLOCK_SIZE)), int (mix (SCALE_FACTOR, anError * SCALE_FACTOR, aColor.w > 40.f)));
 
   if (uDebugAdaptive == 0) // normal rendering
   {
@@ -96,7 +99,13 @@ void main (void)
   }
   else // showing number of samples
   {
-    aColor = vec4 (0.5f * aColor.rgb * aSampleWeight + vec3 (0.f, aColor.w / uAccumFrames * 0.35f, 0.f), 1.0);
+    vec2 aRatio = vec2 (1.f, 1.f);
+
+#ifdef GL_ARB_shader_image_size
+    aRatio = vec2 (imageSize (uRenderImage)) / vec2 (3.f * 512.f, 2.f * 512.f);
+#endif
+
+    aColor = vec4 (0.5f * aColor.rgb * aSampleWeight + vec3 (0.f, sqrt (aRatio.x * aRatio.y) * aColor.w / uAccumFrames * 0.35f, 0.f), 1.0);
   }
 
 #endif // ADAPTIVE_SAMPLING
index 76b44e8..7088826 100644 (file)
@@ -12,9 +12,6 @@
 
 #ifdef PATH_TRACING
 
-//! Number of previously rendered frames.
-uniform int uAccumSamples;
-
 ///////////////////////////////////////////////////////////////////////////////////////
 // Specific data types
 
@@ -700,17 +697,26 @@ vec3 IntersectLight (in SRay theRay, in int theDepth, in float theHitDistance, o
 #define MATERIAL_FRESNEL(index) (18 * index + 16)
 #define MATERIAL_ABSORPT(index) (18 * index + 17)
 
-// Enables expiremental russian roulette sampling
+//! Enables experimental russian roulette sampling path termination.
+//! In most cases, it provides faster image convergence with minimal
+//! bias, so it is enabled by default.
 #define RUSSIAN_ROULETTE
 
-//! Frame step to increase number of bounces
-#define FRAME_STEP 5
+//! Frame step to increase number of bounces. This mode is used
+//! for interaction with the model, when path length is limited
+//! for the first samples, and gradually increasing when camera
+//! is stabilizing.
+#ifdef ADAPTIVE_SAMPLING
+  #define FRAME_STEP 4
+#else
+  #define FRAME_STEP 5
+#endif
 
 //=======================================================================
 // function : PathTrace
 // purpose  : Calculates radiance along the given ray
 //=======================================================================
-vec4 PathTrace (in SRay theRay, in vec3 theInverse)
+vec4 PathTrace (in SRay theRay, in vec3 theInverse, in int theNbSamples)
 {
   float aRaytraceDepth = MAXFLOAT;
 
@@ -867,7 +873,8 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
     aSurvive = aDepth < 3 ? 1.f : min (dot (LUMA, aThroughput), 0.95f);
 #endif
 
-    if (RandFloat() > aSurvive || all (lessThan (aThroughput, MIN_THROUGHPUT)) || aDepth >= uAccumSamples / FRAME_STEP + step (1.f / M_PI, aImpPDF))
+    // here, we additionally increase path length for non-diffuse bounces
+    if (RandFloat() > aSurvive || all (lessThan (aThroughput, MIN_THROUGHPUT)) || aDepth >= theNbSamples / FRAME_STEP + step (1.f / M_PI, aImpPDF))
     {
       aDepth = INVALID_BOUNCES; // terminate path
     }
index 15ed8d8..e3937ff 100644 (file)
@@ -8,6 +8,9 @@ uniform int uFrameRndSeed;
 //! become structured. Can be used fo final rendering.
 uniform int uBlockedRngEnabled;
 
+//! Number of previously rendered frames (used in non-ISS mode).
+uniform int uAccumSamples;
+
 #ifndef ADAPTIVE_SAMPLING
   //! Input image with previously accumulated samples.
   uniform sampler2D uAccumTexture;
@@ -57,7 +60,18 @@ void main (void)
 
 #ifdef PATH_TRACING
 
-  vec4 aColor = PathTrace (aRay, aInvDirect);
+#ifndef ADAPTIVE_SAMPLING
+
+  vec4 aColor = PathTrace (aRay, aInvDirect, uAccumSamples);
+
+#else
+
+  float aNbSamples = imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 0,
+                                                          2 * aFragCoord.y + 1), 1.0);
+
+  vec4 aColor = PathTrace (aRay, aInvDirect, int (aNbSamples));
+
+#endif
 
   if (any (isnan (aColor.rgb)))
   {
@@ -78,18 +92,12 @@ void main (void)
   imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 2,
                                        2 * aFragCoord.y + 1), aColor.w);
 
-  // accumulate number of samples
-  float aNbSamples = imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 0,
-                                                          2 * aFragCoord.y + 1), 1.0);
-
   if (int (aNbSamples) % 2 == 0) // accumulate luminance for even samples only
   {
     imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 2,
                                          2 * aFragCoord.y + 0), dot (LUMA, aColor.rgb));
   }
 
-  discard; // fragment should not be written to frame buffer
-
 #else
 
   if (uAccumSamples == 0)
index 2685179..80e1cba 100644 (file)
@@ -5,6 +5,8 @@ static const char Shaders_Display_fs[] =
   "\n"
   "  #extension GL_ARB_shader_image_load_store : require\n"
   "\n"
+  "  #extension GL_ARB_shader_image_size : enable\n"
+  "\n"
   "  //! OpenGL image used for accumulating rendering result.\n"
   "  volatile restrict layout(size1x32) uniform image2D uRenderImage;\n"
   "\n"
@@ -90,8 +92,9 @@ static const char Shaders_Display_fs[] =
   "  // calculate visual error\n"
   "  float anError = (aAverRad - aHalfRad) * (aAverRad - aHalfRad);\n"
   "\n"
-  "  // accumulate visual error to current block\n"
-  "  imageAtomicAdd (uVarianceImage, ivec2 (aPixel / vec2 (BLOCK_SIZE)), int (anError * SCALE_FACTOR));\n"
+  "  // accumulate visual error to current block; estimated error is written only\n"
+  "  // after the first 40 samples and path length has reached 10 bounces or more\n"
+  "  imageAtomicAdd (uVarianceImage, ivec2 (aPixel / vec2 (BLOCK_SIZE)), int (mix (SCALE_FACTOR, anError * SCALE_FACTOR, aColor.w > 40.f)));\n"
   "\n"
   "  if (uDebugAdaptive == 0) // normal rendering\n"
   "  {\n"
@@ -99,7 +102,13 @@ static const char Shaders_Display_fs[] =
   "  }\n"
   "  else // showing number of samples\n"
   "  {\n"
-  "    aColor = vec4 (0.5f * aColor.rgb * aSampleWeight + vec3 (0.f, aColor.w / uAccumFrames * 0.35f, 0.f), 1.0);\n"
+  "    vec2 aRatio = vec2 (1.f, 1.f);\n"
+  "\n"
+  "#ifdef GL_ARB_shader_image_size\n"
+  "    aRatio = vec2 (imageSize (uRenderImage)) / vec2 (3.f * 512.f, 2.f * 512.f);\n"
+  "#endif\n"
+  "\n"
+  "    aColor = vec4 (0.5f * aColor.rgb * aSampleWeight + vec3 (0.f, sqrt (aRatio.x * aRatio.y) * aColor.w / uAccumFrames * 0.35f, 0.f), 1.0);\n"
   "  }\n"
   "\n"
   "#endif // ADAPTIVE_SAMPLING\n"
index fb1746c..04cd95a 100644 (file)
@@ -15,9 +15,6 @@ static const char Shaders_PathtraceBase_fs[] =
   "\n"
   "#ifdef PATH_TRACING\n"
   "\n"
-  "//! Number of previously rendered frames.\n"
-  "uniform int uAccumSamples;\n"
-  "\n"
   "///////////////////////////////////////////////////////////////////////////////////////\n"
   "// Specific data types\n"
   "\n"
@@ -703,17 +700,26 @@ static const char Shaders_PathtraceBase_fs[] =
   "#define MATERIAL_FRESNEL(index) (18 * index + 16)\n"
   "#define MATERIAL_ABSORPT(index) (18 * index + 17)\n"
   "\n"
-  "// Enables expiremental russian roulette sampling\n"
+  "//! Enables experimental russian roulette sampling path termination.\n"
+  "//! In most cases, it provides faster image convergence with minimal\n"
+  "//! bias, so it is enabled by default.\n"
   "#define RUSSIAN_ROULETTE\n"
   "\n"
-  "//! Frame step to increase number of bounces\n"
-  "#define FRAME_STEP 5\n"
+  "//! Frame step to increase number of bounces. This mode is used\n"
+  "//! for interaction with the model, when path length is limited\n"
+  "//! for the first samples, and gradually increasing when camera\n"
+  "//! is stabilizing.\n"
+  "#ifdef ADAPTIVE_SAMPLING\n"
+  "  #define FRAME_STEP 4\n"
+  "#else\n"
+  "  #define FRAME_STEP 5\n"
+  "#endif\n"
   "\n"
   "//=======================================================================\n"
   "// function : PathTrace\n"
   "// purpose  : Calculates radiance along the given ray\n"
   "//=======================================================================\n"
-  "vec4 PathTrace (in SRay theRay, in vec3 theInverse)\n"
+  "vec4 PathTrace (in SRay theRay, in vec3 theInverse, in int theNbSamples)\n"
   "{\n"
   "  float aRaytraceDepth = MAXFLOAT;\n"
   "\n"
@@ -870,7 +876,8 @@ static const char Shaders_PathtraceBase_fs[] =
   "    aSurvive = aDepth < 3 ? 1.f : min (dot (LUMA, aThroughput), 0.95f);\n"
   "#endif\n"
   "\n"
-  "    if (RandFloat() > aSurvive || all (lessThan (aThroughput, MIN_THROUGHPUT)) || aDepth >= uAccumSamples / FRAME_STEP + step (1.f / M_PI, aImpPDF))\n"
+  "    // here, we additionally increase path length for non-diffuse bounces\n"
+  "    if (RandFloat() > aSurvive || all (lessThan (aThroughput, MIN_THROUGHPUT)) || aDepth >= theNbSamples / FRAME_STEP + step (1.f / M_PI, aImpPDF))\n"
   "    {\n"
   "      aDepth = INVALID_BOUNCES; // terminate path\n"
   "    }\n"
index 46afbe0..1d6e5bd 100644 (file)
@@ -11,6 +11,9 @@ static const char Shaders_RaytraceRender_fs[] =
   "//! become structured. Can be used fo final rendering.\n"
   "uniform int uBlockedRngEnabled;\n"
   "\n"
+  "//! Number of previously rendered frames (used in non-ISS mode).\n"
+  "uniform int uAccumSamples;\n"
+  "\n"
   "#ifndef ADAPTIVE_SAMPLING\n"
   "  //! Input image with previously accumulated samples.\n"
   "  uniform sampler2D uAccumTexture;\n"
@@ -60,7 +63,18 @@ static const char Shaders_RaytraceRender_fs[] =
   "\n"
   "#ifdef PATH_TRACING\n"
   "\n"
-  "  vec4 aColor = PathTrace (aRay, aInvDirect);\n"
+  "#ifndef ADAPTIVE_SAMPLING\n"
+  "\n"
+  "  vec4 aColor = PathTrace (aRay, aInvDirect, uAccumSamples);\n"
+  "\n"
+  "#else\n"
+  "\n"
+  "  float aNbSamples = imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 0,\n"
+  "                                                          2 * aFragCoord.y + 1), 1.0);\n"
+  "\n"
+  "  vec4 aColor = PathTrace (aRay, aInvDirect, int (aNbSamples));\n"
+  "\n"
+  "#endif\n"
   "\n"
   "  if (any (isnan (aColor.rgb)))\n"
   "  {\n"
@@ -81,18 +95,12 @@ static const char Shaders_RaytraceRender_fs[] =
   "  imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 2,\n"
   "                                       2 * aFragCoord.y + 1), aColor.w);\n"
   "\n"
-  "  // accumulate number of samples\n"
-  "  float aNbSamples = imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 0,\n"
-  "                                                          2 * aFragCoord.y + 1), 1.0);\n"
-  "\n"
   "  if (int (aNbSamples) % 2 == 0) // accumulate luminance for even samples only\n"
   "  {\n"
   "    imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 2,\n"
   "                                         2 * aFragCoord.y + 0), dot (LUMA, aColor.rgb));\n"
   "  }\n"
   "\n"
-  "  discard; // fragment should not be written to frame buffer\n"
-  "\n"
   "#else\n"
   "\n"
   "  if (uAccumSamples == 0)\n"
index ce91b42..5572280 100644 (file)
@@ -9076,6 +9076,7 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
     theDI << "iss debug:      " << (aParams.ShowSamplingTiles           ? "on" : "off") << "\n";
     theDI << "two-sided BSDF: " << (aParams.TwoSidedBsdfModels          ? "on" : "off") << "\n";
     theDI << "max radiance:   " <<  aParams.RadianceClampingValue                       << "\n";
+    theDI << "nb tiles (iss): " <<  aParams.NbRayTracingTiles                           << "\n";
     theDI << "shadingModel: ";
     switch (aView->ShadingModel())
     {
@@ -9364,6 +9365,32 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
       }
       aParams.ShowSamplingTiles = toEnable;
     }
+    else if (aFlag == "-nbtiles")
+    {
+      if (toPrint)
+      {
+        theDI << aParams.NbRayTracingTiles << " ";
+        continue;
+      }
+      else if (++anArgIter >= theArgNb)
+      {
+        std::cerr << "Error: wrong syntax at argument '" << anArg << "'\n";
+        return 1;
+      }
+
+      const Standard_Integer aNbTiles = Draw::Atoi (theArgVec[anArgIter]);
+
+      if (aNbTiles < 64)
+      {
+        std::cerr << "Error: invalid number of ISS tiles " << aNbTiles << ".\n";
+        std::cerr << "Specify value in range [64, 1024].\n";
+        return 1;
+      }
+      else
+      {
+        aParams.NbRayTracingTiles = aNbTiles;
+      }
+    }
     else if (aFlag == "-env")
     {
       if (toPrint)
@@ -10924,25 +10951,26 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     __FILE__, VRenderParams, group);
   theCommands.Add("vrenderparams",
     "\n    Manages rendering parameters: "
-    "\n      '-raster'               Disables GPU ray-tracing"
-    "\n      '-msaa         0..4'    Specifies number of samples for MSAA"
-    "\n      '-rayTrace'             Enables  GPU ray-tracing"
-    "\n      '-rayDepth     0..10'   Defines maximum ray-tracing depth"
-    "\n      '-shadows      on|off'  Enables/disables shadows rendering"
-    "\n      '-reflections  on|off'  Enables/disables specular reflections"
-    "\n      '-fsaa         on|off'  Enables/disables adaptive anti-aliasing"
-    "\n      '-gleam        on|off'  Enables/disables transparency shadow effects"
-    "\n      '-gi           on|off'  Enables/disables global illumination effects"
-    "\n      '-brng         on|off'  Enables/disables blocked RNG (fast coherent PT)"
-    "\n      '-env          on|off'  Enables/disables environment map background"
-    "\n      '-twoside      on|off'  Enables/disables two-sided BSDF models (PT mode)"
-    "\n      '-iss          on|off'  Enables/disables adaptive screen sampling (PT mode)"
-    "\n      '-issd         on|off'  Shows screen sampling distribution in ISS mode"
-    "\n      '-maxrad       > 0.0'   Value used for clamping radiance estimation (PT mode)"
-    "\n      '-rebuildGlsl  on|off'  Rebuild Ray-Tracing GLSL programs (for debugging)"
-    "\n      '-shadingModel model'   Controls shading model from enumeration"
-    "\n                              color, flat, gouraud, phong"
-    "\n      '-resolution   value'   Sets a new pixels density (PPI), defines scaling factor for parameters like text size"
+    "\n      '-raster'                Disables GPU ray-tracing"
+    "\n      '-msaa         0..4'     Specifies number of samples for MSAA"
+    "\n      '-rayTrace'              Enables  GPU ray-tracing"
+    "\n      '-rayDepth     0..10'    Defines maximum ray-tracing depth"
+    "\n      '-shadows      on|off'   Enables/disables shadows rendering"
+    "\n      '-reflections  on|off'   Enables/disables specular reflections"
+    "\n      '-fsaa         on|off'   Enables/disables adaptive anti-aliasing"
+    "\n      '-gleam        on|off'   Enables/disables transparency shadow effects"
+    "\n      '-gi           on|off'   Enables/disables global illumination effects"
+    "\n      '-brng         on|off'   Enables/disables blocked RNG (fast coherent PT)"
+    "\n      '-env          on|off'   Enables/disables environment map background"
+    "\n      '-twoside      on|off'   Enables/disables two-sided BSDF models (PT mode)"
+    "\n      '-iss          on|off'   Enables/disables adaptive screen sampling (PT mode)"
+    "\n      '-issd         on|off'   Shows screen sampling distribution in ISS mode"
+    "\n      '-maxrad       > 0.0'    Value used for clamping radiance estimation (PT mode)"
+    "\n      '-nbtiles      64..1024' Specifies number of screen tiles in ISS mode"
+    "\n      '-rebuildGlsl  on|off'   Rebuild Ray-Tracing GLSL programs (for debugging)"
+    "\n      '-shadingModel model'    Controls shading model from enumeration"
+    "\n                               color, flat, gouraud, phong"
+    "\n      '-resolution   value'    Sets a new pixels density (PPI), defines scaling factor for parameters like text size"
     "\n    Unlike vcaps, these parameters dramatically change visual properties."
     "\n    Command is intended to control presentation quality depending on"
     "\n    hardware capabilities and performance.",
diff --git a/tests/v3d/raytrace/sample_ball_iss b/tests/v3d/raytrace/sample_ball_iss
new file mode 100644 (file)
index 0000000..32b9d31
--- /dev/null
@@ -0,0 +1,20 @@
+puts "============"
+puts "Visualization - Path Tracing, Ball sample (ISS mode)"
+puts "============"
+puts ""
+
+cpulimit 1000
+
+source $env(CSF_OCCTSamplesPath)/tcl/pathtrace_ball.tcl
+
+vrenderparams -iss -nbtiles 64
+vfps 1024
+vdump $imagedir/${casename}_iss_64.png
+
+vrenderparams -iss -nbtiles 256
+vfps 256
+vdump $imagedir/${casename}_iss_256.png
+
+vrenderparams -iss -nbtiles 1024
+vfps 64
+vdump $imagedir/${casename}_iss_1024.png