0026437: Visualization - Improve path tracing rendering engine
authordbp <dbp@opencascade.com>
Thu, 30 Jul 2015 09:49:43 +0000 (12:49 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 30 Jul 2015 09:50:41 +0000 (12:50 +0300)
Fix compile warnings.

samples/tcl/pathtrace.tcl [new file with mode: 0644]
src/Graphic3d/Graphic3d_RenderingParams.hxx
src/OpenGl/OpenGl_View.hxx
src/OpenGl/OpenGl_View_Raytrace.cxx
src/Shaders/PathtraceBase.fs
src/Shaders/RaytraceBase.fs
src/Shaders/RaytraceRender.fs
src/ViewerTest/ViewerTest_ViewerCommands.cxx

diff --git a/samples/tcl/pathtrace.tcl b/samples/tcl/pathtrace.tcl
new file mode 100644 (file)
index 0000000..82abdc3
--- /dev/null
@@ -0,0 +1,78 @@
+#########################################################################
+# 26437: Visualization - Improve path tracing rendering engine
+#########################################################################
+
+pload ALL
+
+# setup 3D viewer content
+vinit name=View1 w=512 h=512
+vglinfo
+
+vvbo 0
+vsetdispmode 1
+vcamera -persp
+
+box b 1 1 1 
+explode b FACE 
+vdisplay b_1 b_2 b_3 b_5 b_6
+
+vright
+vfit
+
+vsetmaterial b_1 plastic
+vsetmaterial b_2 plastic
+vsetmaterial b_3 plastic
+vsetmaterial b_5 plastic
+vsetmaterial b_6 plastic
+
+vbsdf b_1 -kd 1 -ks 0
+vbsdf b_2 -kd 1 -ks 0
+vbsdf b_3 -kd 1 -ks 0
+vbsdf b_5 -kd 1 -ks 0
+vbsdf b_6 -kd 1 -ks 0
+
+vbsdf b_2 -kd 0.3 0.5 1
+vbsdf b_1 -kd 1 0.3 0.3
+
+vsetlocation b_1  1  0  0
+vsetlocation b_2 -1  0  0
+vsetlocation b_5  0  0  1
+vsetlocation b_6  0  0 -1
+vsetlocation b_3  0  1  0
+
+vlight del 0
+vlight del 1
+vlight add positional head 0 pos 0.5 0.5 0.85
+vlight change 0 sm 0.06
+vlight change 0 int 60.0
+
+psphere s 0.2
+vdisplay s
+vsetlocation s 0.21 0.3 0.2
+vsetmaterial s glass
+vbsdf s -absorpcolor 0.8 0.8 1.0
+vbsdf s -absorpcoeff 6
+
+box c 0.3 0.3 0.2
+vdisplay c
+vsetlocation c 0.55 0.3 0.0
+vlocrotate c 0 0 0 0 0 1 -30
+vsetmaterial c plastic
+vbsdf c -kd 1.0 0.8 0.2 -ks 0.3 -n
+
+box g 0.15 0.15 0.3
+vdisplay g
+vsetlocation g 0.7 0.25 0.2
+vlocrotate g 0 0 0 0 0 1 10
+vsetmaterial g glass
+vbsdf g -absorpcolor 0.8 1.0 0.8
+vbsdf g -absorpcoeff 6
+
+psphere r 0.1
+vdisplay r
+vsetmaterial r plastic
+vbsdf r -kd 0.5 0.9 0.3 -ks 0.0 -kr 0.3 -n
+vbsdf r -fresnel Constant 1.0
+vsetlocation r 0.5 0.65 0.1
+
+vrenderparams -ray -gi -rayDepth 8
index 5222741..1ee0e65 100644 (file)
@@ -55,8 +55,9 @@ public:
     IsReflectionEnabled         (Standard_False),
     IsAntialiasingEnabled       (Standard_False),
     IsTransparentShadowEnabled  (Standard_False),
-
     UseEnvironmentMapBackground (Standard_False),
+    CoherentPathTracingMode     (Standard_False),
+
     StereoMode (Graphic3d_StereoMode_QuadBuffer),
     AnaglyphFilter (Anaglyph_RedCyan_Optimized),
     ToReverseStereo (Standard_False)
@@ -84,6 +85,7 @@ public:
   Standard_Boolean        IsAntialiasingEnabled;       //!< enables/disables adaptive anti-aliasing, False by default
   Standard_Boolean        IsTransparentShadowEnabled;  //!< enables/disables light propagation through transparent media, False by default
   Standard_Boolean        UseEnvironmentMapBackground; //!< enables/disables environment map background
+  Standard_Boolean        CoherentPathTracingMode;     //!< enables/disables 'coherent' tracing mode (single RNG seed within 16x16 image blocks)
 
   Graphic3d_StereoMode    StereoMode;                  //!< stereoscopic output mode, Graphic3d_StereoMode_QuadBuffer by default
   Anaglyph                AnaglyphFilter;              //!< filter for anaglyph output, Anaglyph_RedCyan_Optimized by default
index f5d5176..af8c704 100644 (file)
@@ -170,7 +170,6 @@ class OpenGl_View : public MMgt_TShared
                const Aspect_CLayer2d&               theCOverLayer,
                const Standard_Boolean               theToDrawImmediate);
 
-
   void DrawBackground (const Handle(OpenGl_Workspace)& theWorkspace);
 
   //! Returns list of OpenGL Z-layers.
@@ -334,6 +333,7 @@ protected: //! @name data types related to ray-tracing
     OpenGl_RT_uSphereMapEnabled,
     OpenGl_RT_uSphereMapForBack,
     OpenGl_RT_uTexSamplersArray,
+    OpenGl_RT_uBlockedRngEnabled,
 
     // sampled frame params
     OpenGl_RT_uSampleWeight,
@@ -502,10 +502,10 @@ protected: //! @name methods related to ray-tracing
                                          const Handle(OpenGl_Context)& theGlContext);
 
   //! Adds OpenGL groups to ray-traced scene geometry.
-  Standard_Boolean addRaytraceGroups (const OpenGl_Structure*       theStructure,
-                                      const Standard_Integer        theStructMat,
-                                      const Standard_ShortReal*     theTransform,
-                                      const Handle(OpenGl_Context)& theGlContext);
+  Standard_Boolean addRaytraceGroups (const OpenGl_Structure*        theStructure,
+                                      const OpenGl_RaytraceMaterial& theStructMat,
+                                      const Standard_ShortReal*      theTransform,
+                                      const Handle(OpenGl_Context)&  theGlContext);
 
   //! Creates ray-tracing material properties.
   OpenGl_RaytraceMaterial convertMaterial (const OpenGl_AspectFace*      theAspect,
index 4072437..f7bd08b 100644 (file)
@@ -407,15 +407,11 @@ Standard_Boolean OpenGl_View::addRaytraceStructure (const OpenGl_Structure*
   }
 
   // Get structure material
-  Standard_Integer aStructMatID = -1;
+  OpenGl_RaytraceMaterial aStructMaterial;
 
   if (theStructure->AspectFace() != NULL)
   {
-    aStructMatID = static_cast<Standard_Integer> (myRaytraceGeometry.Materials.size());
-
-    OpenGl_RaytraceMaterial aStructMaterial = convertMaterial (theStructure->AspectFace(), theGlContext);
-
-    myRaytraceGeometry.Materials.push_back (aStructMaterial);
+    aStructMaterial = convertMaterial (theStructure->AspectFace(), theGlContext);
   }
 
   Standard_ShortReal aStructTransform[16];
@@ -431,7 +427,7 @@ Standard_Boolean OpenGl_View::addRaytraceStructure (const OpenGl_Structure*
     }
   }
 
-  Standard_Boolean aResult = addRaytraceGroups (theStructure, aStructMatID,
+  Standard_Boolean aResult = addRaytraceGroups (theStructure, aStructMaterial,
     theStructure->Transformation()->mat ? aStructTransform : NULL, theGlContext);
 
   // Process all connected OpenGL structures
@@ -439,7 +435,7 @@ Standard_Boolean OpenGl_View::addRaytraceStructure (const OpenGl_Structure*
 
   if (anInstanced != NULL && anInstanced->IsRaytracable())
   {
-    aResult &= addRaytraceGroups (anInstanced, aStructMatID,
+    aResult &= addRaytraceGroups (anInstanced, aStructMaterial,
       theStructure->Transformation()->mat ? aStructTransform : NULL, theGlContext);
   }
 
@@ -452,32 +448,26 @@ Standard_Boolean OpenGl_View::addRaytraceStructure (const OpenGl_Structure*
 // function : addRaytraceGroups
 // purpose  : Adds OpenGL groups to ray-traced scene geometry
 // =======================================================================
-Standard_Boolean OpenGl_View::addRaytraceGroups (const OpenGl_Structure*       theStructure,
-                                                 const Standard_Integer        theStructMat,
-                                                 const Standard_ShortReal*     theTransform,
-                                                 const Handle(OpenGl_Context)& theGlContext)
+Standard_Boolean OpenGl_View::addRaytraceGroups (const OpenGl_Structure*        theStructure,
+                                                 const OpenGl_RaytraceMaterial& theStructMat,
+                                                 const Standard_ShortReal*      theTransform,
+                                                 const Handle(OpenGl_Context)&  theGlContext)
 {
   for (OpenGl_Structure::GroupIterator aGroupIter (theStructure->DrawGroups()); aGroupIter.More(); aGroupIter.Next())
   {
     // Get group material
-    Standard_Integer aGroupMatID = -1;
+    OpenGl_RaytraceMaterial aGroupMaterial;
     if (aGroupIter.Value()->AspectFace() != NULL)
     {
-      aGroupMatID = static_cast<Standard_Integer> (myRaytraceGeometry.Materials.size());
-
-      OpenGl_RaytraceMaterial aGroupMaterial = convertMaterial (
+      aGroupMaterial = convertMaterial (
         aGroupIter.Value()->AspectFace(), theGlContext);
-
-      myRaytraceGeometry.Materials.push_back (aGroupMaterial);
     }
 
-    Standard_Integer aMatID = aGroupMatID < 0 ? theStructMat : aGroupMatID;
-    if (aMatID < 0)
-    {
-      aMatID = static_cast<Standard_Integer> (myRaytraceGeometry.Materials.size());
+    Standard_Integer aMatID = static_cast<Standard_Integer> (myRaytraceGeometry.Materials.size());
 
-      myRaytraceGeometry.Materials.push_back (OpenGl_RaytraceMaterial());
-    }
+    // Use group material if available, otherwise use structure material
+    myRaytraceGeometry.Materials.push_back (
+      aGroupIter.Value()->AspectFace() != NULL ? aGroupMaterial : theStructMat);
 
     // Add OpenGL elements from group (extract primitives arrays and aspects)
     for (const OpenGl_ElementNode* aNode = aGroupIter.Value()->FirstNode(); aNode != NULL; aNode = aNode->next)
@@ -1573,6 +1563,8 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Graphic3d_CView& theC
         aShaderProgram->GetUniformLocation (theGlContext, "uSphereMapEnabled");
       myUniformLocations[anIndex][OpenGl_RT_uSphereMapForBack] =
         aShaderProgram->GetUniformLocation (theGlContext, "uSphereMapForBack");
+      myUniformLocations[anIndex][OpenGl_RT_uBlockedRngEnabled] =
+        aShaderProgram->GetUniformLocation (theGlContext, "uBlockedRngEnabled");
 
       myUniformLocations[anIndex][OpenGl_RT_uSampleWeight] =
         aShaderProgram->GetUniformLocation (theGlContext, "uSampleWeight");
@@ -2256,6 +2248,12 @@ Standard_Boolean OpenGl_View::setUniformState (const Graphic3d_CView&        the
   theProgram->SetUniform (theGlContext,
     myUniformLocations[theProgramId][OpenGl_RT_uReflectEnabled], theCView.RenderParams.IsReflectionEnabled ?  1 : 0);
 
+  if (theCView.RenderParams.IsGlobalIlluminationEnabled)
+  {
+    theProgram->SetUniform (theGlContext,
+      myUniformLocations[theProgramId][OpenGl_RT_uBlockedRngEnabled], theCView.RenderParams.CoherentPathTracingMode ?  1 : 0);
+  }
+
   // Set array of 64-bit texture handles
   if (theGlContext->arbTexBindless != NULL && myRaytraceGeometry.HasTextures())
   {
index 03f43ec..d7e799e 100644 (file)
@@ -302,17 +302,6 @@ vec3 handleMaterial (in SMaterial theMaterial, in vec3 theInput, in vec3 theOutp
 }
 
 //=======================================================================
-// function : sampleSpecularReflection
-// purpose  : Samples specular BRDF, W = BRDF * cos(N, PSI) / PDF(PSI)
-//=======================================================================
-void sampleSpecularReflection (in vec3 theOutput, out vec3 theInput)
-{
-  theInput = vec3 (-theOutput.x,
-                   -theOutput.y,
-                    theOutput.z);
-}
-
-//=======================================================================
 // function : sampleLambertianReflection
 // purpose  : Samples Lambertian BRDF, W = BRDF * cos(N, PSI) / PDF(PSI)
 //=======================================================================
@@ -327,38 +316,51 @@ void sampleLambertianReflection (in vec3 theOutput, out vec3 theInput)
                    aTemp * sin (2.f * M_PI * aKsi1),
                    sqrt (1.f - aKsi2));
 
-  if (theOutput.z < 0.f)
-    theInput.z = -theInput.z;
+  theInput.z = mix (-theInput.z, theInput.z, step (0.f, theOutput.z));
 }
 
+// Types of bounces
+#define NON_SPECULAR_BOUNCE 0
+#define SPEC_REFLECT_BOUNCE 1
+#define SPEC_REFRACT_BOUNCE 2
+
+#define IS_NON_SPEC_BOUNCE(theBounce) (theBounce == 0)
+#define IS_ANY_SPEC_BOUNCE(theBounce) (theBounce != 0)
+#define IS_REFL_SPEC_BOUNCE(theBounce) (theBounce == 1)
+#define IS_REFR_SPEC_BOUNCE(theBounce) (theBounce == 2)
+
 //=======================================================================
 // function : sampleSpecularTransmission
 // purpose  : Samples specular BTDF, W = BRDF * cos(N, PSI) / PDF(PSI)
 //=======================================================================
 vec3 sampleSpecularTransmission (in vec3 theOutput, out vec3 theInput,
-  out bool isTransmit, in vec3 theThroughput, in vec3 theFresnelCoeffs)
+  out int theBounce, in vec3 theWeight, in vec3 theFresnelCoeffs)
 {
   vec3 aFresnel = fresnelMedia (theOutput.z, theFresnelCoeffs);
 
-  float aProbability = convolve (aFresnel, theThroughput);
+  float aProbability = convolve (aFresnel, theWeight);
+
+  // Check if transmission takes place
+  theBounce = RandFloat() <= aProbability ?
+    SPEC_REFLECT_BOUNCE : SPEC_REFRACT_BOUNCE;
 
   // Sample input direction
-  if (RandFloat() <= aProbability)
+  if (theBounce == SPEC_REFLECT_BOUNCE)
   {
     theInput = vec3 (-theOutput.x,
                      -theOutput.y,
                       theOutput.z);
 
-    isTransmit = false;
-
-    return aFresnel * (1.f / aProbability);
+    theWeight = aFresnel * (1.f / aProbability);
   }
+  else
+  {
+    transmitted (theFresnelCoeffs.y, theOutput, theInput);
 
-  transmitted (theFresnelCoeffs.y, theOutput, theInput);
-
-  isTransmit = true;
+    theWeight = (UNIT - aFresnel) * (1.f / (1.f - aProbability));
+  }
 
-  return (UNIT - aFresnel) * (1.f / (1.f - aProbability));
+  return theWeight;
 }
 
 //=======================================================================
@@ -430,98 +432,55 @@ vec3 sampleBlinnReflection (in vec3 theOutput, out vec3 theInput, in vec3 theFre
   return aFresnel * ((theExponent + 2.f) / (theExponent + 1.f) * aGeom / aCosThetaO);
 }
 
-// Enables expiremental russian roulette sampling
-// #define RUSSIAN_ROULETTE
-
 //=======================================================================
 // function : sampleMaterial
 // purpose  : Samples specified composite material (BSDF)
 //=======================================================================
-bool sampleMaterial (in SMaterial theMaterial,
+void sampleMaterial (in SMaterial theMaterial,
                      in vec3      theOutput,
-                     in vec3      theFactor,
                      out vec3     theInput,
-                     out vec3     theWeight,
-                     inout bool   isTransmit)
+                     inout vec3   theWeight,
+                     inout int    theBounce)
 {
-  theWeight = ZERO;
-
   // Compute the probability of ray reflection
-  float aPd = convolve (theMaterial.Kd.rgb, theFactor);
-  float aPs = convolve (theMaterial.Ks.rgb, theFactor);
-  float aPr = convolve (theMaterial.Kr.rgb, theFactor);
-  float aPt = convolve (theMaterial.Kt.rgb, theFactor);
+  float aPd = convolve (theMaterial.Kd.rgb, theWeight);
+  float aPs = convolve (theMaterial.Ks.rgb, theWeight);
+  float aPr = convolve (theMaterial.Kr.rgb, theWeight);
+  float aPt = convolve (theMaterial.Kt.rgb, theWeight);
 
   float aReflection = aPd + aPs + aPr + aPt;
 
-#ifndef RUSSIAN_ROULETTE
-  if (aReflection < 1e-2f)
-  {
-    return false; // path termination
-  }
-#else
-  float aSurvival = max (dot (theFactor, LUMA), 0.1f);
-
-  if (RandFloat() > aSurvival)
-  {
-    return false; // path termination
-  }
-#endif
-
-  isTransmit = false;
-
   // Choose BSDF component to sample
   float aKsi = aReflection * RandFloat();
 
+  theBounce = NON_SPECULAR_BOUNCE;
+
   if (aKsi < aPd) // diffuse reflection
   {
     sampleLambertianReflection (theOutput, theInput);
 
-#ifndef RUSSIAN_ROULETTE
-    theWeight = theMaterial.Kd.rgb * (aReflection / aPd);
-#else
-    theWeight = theMaterial.Kd.rgb * (aReflection / aPd / aSurvival);
-#endif
-
-    return false; // non-specular bounce
+    theWeight *= theMaterial.Kd.rgb * (aReflection / aPd);
   }
   else if (aKsi < aPd + aPs) //  glossy reflection
   {
-    theWeight = sampleBlinnReflection (theOutput, theInput, theMaterial.Fresnel, theMaterial.Ks.w);
-
-#ifndef RUSSIAN_ROULETTE
-    theWeight *= theMaterial.Ks.rgb * (aReflection / aPs);
-#else
-    theWeight *= theMaterial.Ks.rgb * (aReflection / aPs / aSurvival);
-#endif
-
-    return false; // non-specular bounce
+    theWeight *= theMaterial.Ks.rgb * (aReflection / aPs) *
+      sampleBlinnReflection (theOutput, theInput, theMaterial.Fresnel, theMaterial.Ks.w);
   }
   else if (aKsi < aPd + aPs + aPr) //  specular reflection
   {
-    theWeight = sampleSpecularReflection (theOutput, theInput, theMaterial.Fresnel);
-
-#ifndef RUSSIAN_ROULETTE
-    theWeight *= theMaterial.Kr.rgb * (aReflection / aPr);
-#else
-    theWeight *= theMaterial.Kr.rgb * (aReflection / aPr / aSurvival);
-#endif
+    theWeight *= theMaterial.Kr.rgb * (aReflection / aPr) *
+      sampleSpecularReflection (theOutput, theInput, theMaterial.Fresnel);
 
-    return true; // specular bounce
+    theBounce = SPEC_REFLECT_BOUNCE; // specular bounce
   }
   else //  specular transmission
   {
-    theWeight = sampleSpecularTransmission (theOutput, theInput,
-      isTransmit, theFactor, theMaterial.Fresnel);
-
-#ifndef RUSSIAN_ROULETTE
-    theWeight *= theMaterial.Kt.rgb * (aReflection / aPt);
-#else
-    theWeight *= theMaterial.Kt.rgb * (aReflection / aPt / aSurvival);
-#endif
-
-    return true; // specular bounce
+    theWeight *= theMaterial.Kt.rgb * (aReflection / aPt) *
+      sampleSpecularTransmission (theOutput, theInput, theBounce, theWeight, theMaterial.Fresnel);
   }
+
+  // path termination for extra small weights
+  theWeight = mix (theWeight, ZERO, float (aReflection < 1e-3f));
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////////
@@ -532,11 +491,14 @@ bool sampleMaterial (in SMaterial theMaterial,
 // function : handlePointLight
 // purpose  :
 //=======================================================================
-float handlePointLight (in vec3 theInput, in vec3 theToLight, in float theRadius)
+float handlePointLight (in vec3 theInput, in vec3 theToLight, in float theRadius, in float theDistance)
 {
-  float aCosMax = sqrt (1.f - theRadius * theRadius / dot (theToLight, theToLight));
+  float aDistance = dot (theToLight, theToLight);
+
+  float aCosMax = inversesqrt (1.f + theRadius * theRadius / aDistance);
 
-  return step (aCosMax, dot (theInput, theToLight));
+  return float (aDistance < theDistance * theDistance) *
+    step (aCosMax, dot (theToLight, theInput) * inversesqrt (aDistance));
 }
 
 //=======================================================================
@@ -549,47 +511,29 @@ float handleDirectLight (in vec3 theInput, in vec3 theToLight, in float theCosMa
 }
 
 //=======================================================================
-// function : samplePointLight
-// purpose  :
+// function : sampleLight
+// purpose  : general sampling function for directional and point lights
 //=======================================================================
-vec3 samplePointLight (in vec3 theToLight, in float theRadius, inout float thePDF)
+vec3 sampleLight (in vec3 theToLight, in bool isDirectional, in float theSmoothness, inout float thePDF)
 {
   SLocalSpace aSpace = LocalSpace (theToLight);
 
-  float aCosMax = sqrt (1.f - theRadius * theRadius / dot (theToLight, theToLight));
+  // for point lights smoothness defines radius
+  float aCosMax = isDirectional ? theSmoothness :
+    inversesqrt (1.f + theSmoothness * theSmoothness / dot (theToLight, theToLight));
 
   float aKsi1 = RandFloat();
   float aKsi2 = RandFloat();
 
   float aTmp = 1.f - aKsi2 * (1.f - aCosMax);
 
-  vec3 anInput = vec3 (sqrt (1.f - aTmp * aTmp) * cos (2.f * M_PI * aKsi1),
-                       sqrt (1.f - aTmp * aTmp) * sin (2.f * M_PI * aKsi1),
+  vec3 anInput = vec3 (cos (2.f * M_PI * aKsi1),
+                       sin (2.f * M_PI * aKsi1),
                        aTmp);
 
-  thePDF *= (theRadius > 0.f) ? 1.f / (2.f * M_PI) / (1.f - aCosMax) : 1.f;
-
-  return normalize (fromLocalSpace (anInput, aSpace));
-}
-
-//=======================================================================
-// function : sampleDirectLight
-// purpose  :
-//=======================================================================
-vec3 sampleDirectLight (in vec3 theToLight, in float theCosMax, inout float thePDF)
-{
-  SLocalSpace aSpace = LocalSpace (theToLight);
-
-  float aKsi1 = RandFloat();
-  float aKsi2 = RandFloat();
+  anInput.xy *= sqrt (1.f - aTmp * aTmp);
 
-  float aTmp = 1.f - aKsi2 * (1.f - theCosMax);
-
-  vec3 anInput = vec3 (sqrt (1.f - aTmp * aTmp) * cos (2.f * M_PI * aKsi1),
-                       sqrt (1.f - aTmp * aTmp) * sin (2.f * M_PI * aKsi1),
-                       aTmp);
-
-  thePDF *= (theCosMax < 1.f) ? 1.f / (2.f * M_PI) / (1.f - theCosMax) : 1.f;
+  thePDF *= (aCosMax < 1.f) ? 1.f / (2.f * M_PI) / (1.f - aCosMax) : 1.f;
 
   return normalize (fromLocalSpace (anInput, aSpace));
 }
@@ -609,26 +553,26 @@ vec2 Latlong (in vec3 thePoint)
 }
 
 // =======================================================================
-// function : EnvironmentRadiance
-// purpose  :
+// function: intersectLight
+// purpose : Checks intersections with light sources
 // =======================================================================
-vec3 EnvironmentRadiance (in SRay theRay, in bool isSpecular, in bool isBackground)
+vec3 intersectLight (in SRay theRay, in bool isViewRay, in int theBounce, in float theDistance)
 {
   vec3 aRadiance = ZERO;
 
-  if (uSphereMapForBack != 0 || !isBackground)
+  if ((isViewRay || IS_REFR_SPEC_BOUNCE(theBounce)) && uSphereMapForBack == 0)
   {
-    aRadiance += FetchEnvironment (Latlong (theRay.Direct)).xyz;
+    aRadiance = BackgroundColor().xyz;
   }
   else
   {
-    aRadiance += BackgroundColor().xyz;
+    aRadiance = FetchEnvironment (Latlong (theRay.Direct)).xyz;
   }
 
   // Apply gamma correction (gamma is 2)
-  aRadiance *= aRadiance;
+  aRadiance = aRadiance * aRadiance * float (theDistance == MAXFLOAT);
 
-  for (int aLightIdx = 0; aLightIdx < uLightCount && isSpecular; ++aLightIdx)
+  for (int aLightIdx = 0; aLightIdx < uLightCount && (isViewRay || IS_ANY_SPEC_BOUNCE(theBounce)); ++aLightIdx)
   {
     vec4 aLight = texelFetch (
       uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));
@@ -637,9 +581,10 @@ vec3 EnvironmentRadiance (in SRay theRay, in bool isSpecular, in bool isBackgrou
 
     if (aLight.w != 0.f) // point light source
     {
-      aRadiance += aParam.rgb * handlePointLight (theRay.Direct, aLight.xyz - theRay.Origin, aParam.w /* radius */);
+      aRadiance += aParam.rgb * handlePointLight (
+        theRay.Direct, aLight.xyz - theRay.Origin, aParam.w /* radius */, theDistance);
     }
-    else // directional light source
+    else if (theDistance == MAXFLOAT) // directional light source
     {
       aRadiance += aParam.rgb * handleDirectLight (theRay.Direct, aLight.xyz, aParam.w /* angle cosine */);
     }
@@ -659,6 +604,9 @@ vec3 EnvironmentRadiance (in SRay theRay, in bool isSpecular, in bool isBackgrou
 #define MATERIAL_FRESNEL(index) (18 * index + 16)
 #define MATERIAL_ABSORPT(index) (18 * index + 17)
 
+// Enables expiremental russian roulette sampling
+#define RUSSIAN_ROULETTE
+
 //=======================================================================
 // function : PathTrace
 // purpose  : Calculates radiance along the given ray
@@ -670,28 +618,31 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
   vec3 aRadiance   = ZERO;
   vec3 aThroughput = UNIT;
 
-  bool isInMedium = false;
-  bool isSpecular = false;
-  bool isTransmit = false;
+  int aBounce = 0; // type of previous hit point
+  int aTrsfId = 0; // offset of object transform
 
-  int anObjectId; // ID of intersected triangle
+  bool isInMedium = false;
 
   for (int aDepth = 0; aDepth < NB_BOUNCES; ++aDepth)
   {
     SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);
 
-    ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, anObjectId);
+    ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTrsfId);
+
+    // check implicit path
+    vec3 aLe = intersectLight (theRay,
+      aDepth == 0 /* is view ray */, aBounce, aHit.Time);
 
-    if (aTriIndex.x == -1)
+    if (any (greaterThan (aLe, ZERO)) || aTriIndex.x == -1)
     {
-      return vec4 (aRadiance + aThroughput *
-        EnvironmentRadiance (theRay, isSpecular, aDepth == 0 || isTransmit), 0.f);
+      aRadiance += aThroughput * aLe; break; // terminate path
     }
 
-    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 aInvTransf0 = texelFetch (uSceneTransformTexture, aTrsfId + 0).xyz;
+    vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, aTrsfId + 1).xyz;
+    vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, aTrsfId + 2).xyz;
 
+    // compute geometrical normal
     aHit.Normal = normalize (vec3 (dot (aInvTransf0, aHit.Normal),
                                    dot (aInvTransf1, aHit.Normal),
                                    dot (aInvTransf2, aHit.Normal)));
@@ -711,9 +662,9 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
       aThroughput *= aSrcColorRGBA.w;
     }
 
-    theRay.Origin += theRay.Direct * aHit.Time; // intersection point
+    theRay.Origin += theRay.Direct * aHit.Time; // get new intersection point
 
-    // Fetch material (BSDF)
+    // fetch material (BSDF)
     SMaterial aMaterial = SMaterial (
       vec4 (texelFetch (uRaytraceMaterialTexture, MATERIAL_KD      (aTriIndex.w))),
       vec3 (texelFetch (uRaytraceMaterialTexture, MATERIAL_KR      (aTriIndex.w))),
@@ -742,6 +693,7 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
     }
 #endif
 
+    // compute smooth normal
     vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
 
     aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),
@@ -750,7 +702,7 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
 
     SLocalSpace aSpace = LocalSpace (aNormal);
 
-    // Account for self-emission (not stored in the material)
+    // account for self-emission (not stored in the material)
     aRadiance += aThroughput * texelFetch (
       uRaytraceMaterialTexture, MATERIAL_LE (aTriIndex.w)).rgb;
 
@@ -763,18 +715,13 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
       vec4 aParam = texelFetch (
         uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx));
 
-      float aPDF = 1.f / uLightCount, aDistance = MAXFLOAT;
+      // 'w' component is 0 for infinite light and 1 for point light
+      aLight.xyz -= mix (ZERO, theRay.Origin, aLight.w);
 
-      if (aLight.w != 0.f) // point light source
-      {
-        aDistance = length (aLight.xyz -= theRay.Origin);
+      float aPDF = 1.f / uLightCount, aDistance = length (aLight.xyz);
 
-        aLight.xyz = samplePointLight (aLight.xyz, aParam.w /* radius */, aPDF);
-      }
-      else // directional light source
-      {
-        aLight.xyz = sampleDirectLight (aLight.xyz, aParam.w /* angle cosine */, aPDF);
-      }
+      aLight.xyz = sampleLight (aLight.xyz * (1.f / aDistance),
+        aLight.w == 0.f /* is infinite */, aParam.w /* angle cosine */, aPDF);
 
       vec3 aContrib = (1.f / aPDF) * aParam.rgb /* Le */ * handleMaterial (
           aMaterial, toLocalSpace (aLight.xyz, aSpace), toLocalSpace (-theRay.Direct, aSpace));
@@ -787,17 +734,16 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
           -uSceneEpsilon, uSceneEpsilon, step (0.f, dot (aHit.Normal, aLight.xyz)));
 
         float aVisibility = SceneAnyHit (aShadow,
-          InverseDirection (aLight.xyz), aDistance);
+          InverseDirection (aLight.xyz), aLight.w == 0.f ? MAXFLOAT : aDistance);
 
         aRadiance += aVisibility * aThroughput * aContrib;
       }
     }
 
     vec3 anInput;
-    vec3 aWeight;
 
-    isSpecular = sampleMaterial (aMaterial,
-      toLocalSpace (-theRay.Direct, aSpace), aThroughput, anInput, aWeight, isTransmit);
+    sampleMaterial (aMaterial,
+      toLocalSpace (-theRay.Direct, aSpace), anInput, aThroughput, aBounce);
 
     if (isInMedium)
     {
@@ -805,15 +751,24 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
         aMaterial.Absorption.w * (UNIT - aMaterial.Absorption.rgb));
     }
 
-    isInMedium = isTransmit ? !isInMedium : isInMedium;
-
-    aThroughput *= aWeight;
+    isInMedium = IS_REFR_SPEC_BOUNCE(aBounce) ? !isInMedium : isInMedium;
 
+#ifndef RUSSIAN_ROULETTE
     if (all (lessThan (aThroughput, MIN_THROUGHPUT)))
     {
-      return vec4 (aRadiance, 0.f);
+      aDepth = INVALID_BOUNCES; // terminate path
+    }
+#else
+    float aSurvive = aDepth < 3 ? 1.f : min (dot (LUMA, aThroughput), 0.95f);
+
+    if (RandFloat() > aSurvive)
+    {
+      aDepth = INVALID_BOUNCES; // terminate path
     }
 
+    aThroughput /= aSurvive;
+#endif
+
     anInput = normalize (fromLocalSpace (anInput, aSpace));
 
     theRay = SRay (theRay.Origin + anInput * uSceneEpsilon +
index 92bf755..8e62c41 100644 (file)
@@ -158,9 +158,9 @@ uint RandState;
 // purpose  : Applies hash function by Thomas Wang to randomize seeds
 //            (see http://www.burtleburtle.net/bob/hash/integer.html)
 // =======================================================================
-void SeedRand (in int theSeed, in int theSizeX)
+void SeedRand (in int theSeed, in int theSizeX, in int theRadius)
 {
-  RandState = uint (int (gl_FragCoord.y) * theSizeX + int (gl_FragCoord.x) + theSeed);
+  RandState = uint (int (gl_FragCoord.y) / theRadius * theSizeX + int (gl_FragCoord.x) / theRadius + theSeed);
 
   RandState = (RandState + 0x479ab41du) + (RandState <<  8);
   RandState = (RandState ^ 0xe4aa10ceu) ^ (RandState >>  5);
@@ -365,9 +365,7 @@ ivec4 ObjectNearestHit (in int theBVHOffset, in int theVrtOffset, in int theTrgO
 
   ivec4 aTriIndex = INALID_HIT;
 
-  bool toContinue = true;
-
-  while (toContinue)
+  for (bool toContinue = true; toContinue;)
   {
     ivec3 aData = texelFetch (uSceneNodeInfoTexture, aNode).xyz;
 
@@ -487,11 +485,9 @@ float ObjectAnyHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffse
   int aHead = theSentinel;  // stack pointer
   int aNode = theBVHOffset; // node to visit
 
-#ifdef TRANSPARENT_SHADOWS
-  float aFactor = 1.0f;
-#endif
+  float aFactor = 1.f;
 
-  while (true)
+  for (bool toContinue = true; toContinue;)
   {
     ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
 
@@ -545,15 +541,10 @@ float ObjectAnyHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffse
         }
         else
         {
-#ifdef TRANSPARENT_SHADOWS
-          if (aHead == theSentinel)
-            return aFactor;
-#else
-          if (aHead == theSentinel)
-            return 1.0f;
-#endif
+          toContinue = (aHead != theSentinel);
 
-          aNode = Stack[aHead--];
+          if (toContinue)
+            aNode = Stack[aHead--];
         }
       }
     }
@@ -580,45 +571,38 @@ float ObjectAnyHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffse
 #ifdef TRANSPARENT_SHADOWS
         if (aTime < theDistance)
         {
-          aFactor *= 1.0f - texelFetch (uRaytraceMaterialTexture, MATERIAL_TRAN (aTriangle.w)).x;
+          aFactor *= 1.f - texelFetch (uRaytraceMaterialTexture, MATERIAL_TRAN (aTriangle.w)).x;
         }
 #else
         if (aTime < theDistance)
-          return 0.0f;
+        {
+          aFactor = 0.f;
+        }
 #endif
       }
 
-#ifdef TRANSPARENT_SHADOWS
-      if (aHead == theSentinel || aFactor < 0.1f)
-        return aFactor;
-#else
-      if (aHead == theSentinel)
-        return 1.0f;
-#endif
+      toContinue = (aHead != theSentinel) && (aFactor > 0.1f);
 
-      aNode = Stack[aHead--];
+      if (toContinue)
+        aNode = Stack[aHead--];
     }
   }
 
-#ifdef TRANSPARENT_SHADOWS
   return aFactor;
-#else
-  return 1.0f;
-#endif
 }
 
 // =======================================================================
 // function : SceneNearestHit
 // purpose  : Finds intersection with nearest scene triangle
 // =======================================================================
-ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theObjectId)
+ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theTrsfId)
 {
   int aHead = -1; // stack pointer
   int aNode =  0; // node to visit
 
   ivec4 aHitObject = INALID_HIT;
 
-  while (true)
+  for (bool toContinue = true; toContinue;)
   {
     ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
 
@@ -635,12 +619,12 @@ ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theH
       if (max (aTimes.x, max (aTimes.y, aTimes.z)) < theHit.Time)
       {
         // fetch object transformation
-        int anObjectId = aData.x - 1;
+        int aTrsfId = (aData.x - 1) * 4;
 
-        vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
-        vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
-        vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
-        vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 3);
+        vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, aTrsfId + 0);
+        vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, aTrsfId + 1);
+        vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, aTrsfId + 2);
+        vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, aTrsfId + 3);
 
         SRay aTrsfRay = SRay (
           MatrixColMultiplyPnt (theRay.Origin, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3),
@@ -660,14 +644,14 @@ ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theH
                               aTriIndex.z,  // vertex 2
                               aTriIndex.w); // material
 
-          theObjectId = anObjectId;
+          theTrsfId = aTrsfId;
         }
       }
 
-      if (aHead < 0)
-        return aHitObject;
+      toContinue = aHead >= 0;
 
-      aNode = Stack[aHead--];
+      if (toContinue)
+        aNode = Stack[aHead--];
     }
     else // if inner node
     {
@@ -716,10 +700,10 @@ ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theH
         }
         else
         {
-          if (aHead < 0)
-            return aHitObject;
+          toContinue = aHead >= 0;
 
-          aNode = Stack[aHead--];
+          if (toContinue)
+            aNode = Stack[aHead--];
         }
       }
     }
@@ -737,23 +721,21 @@ float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
   int aHead = -1; // stack pointer
   int aNode =  0; // node to visit
 
-#ifdef TRANSPARENT_SHADOWS
-  float aFactor = 1.0f;
-#endif
+  float aFactor = 1.f;
 
-  while (true)
+  for (bool toContinue = true; toContinue;)
   {
     ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
 
     if (aData.x != 0) // if leaf node
     {
       // fetch object transformation
-      int anObjectId = aData.x - 1;
+      int aTrsfId = (aData.x - 1) * 4;
 
-      vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
-      vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
-      vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
-      vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 3);
+      vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, aTrsfId + 0);
+      vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, aTrsfId + 1);
+      vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, aTrsfId + 2);
+      vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, aTrsfId + 3);
 
       SRay aTrsfRay = SRay (
         MatrixColMultiplyPnt (theRay.Origin, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3),
@@ -767,17 +749,16 @@ float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
       aFactor *= ObjectAnyHit (
         aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theDistance, aHead);
 
-      if (aHead < 0 || aFactor < 0.1f)
-        return aFactor;
+      toContinue = aHead >= 0 && aFactor >= 0.1f;
 #else
-      bool isShadow = 0.0f == ObjectAnyHit (
+      aFactor = ObjectAnyHit (
         aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theDistance, aHead);
 
-      if (aHead < 0 || isShadow)
-        return isShadow ? 0.0f : 1.0f;
+      toContinue = aHead >= 0 && aFactor != 0.0f;
 #endif
 
-      aNode = Stack[aHead--];
+      if (toContinue)
+        aNode = Stack[aHead--];
     }
     else // if inner node
     {
@@ -789,7 +770,7 @@ float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
       vec3 aNodeMaxLft = texelFetch (uSceneMaxPointTexture, aData.y).xyz;
       vec3 aNodeMinRgh = texelFetch (uSceneMinPointTexture, aData.z).xyz;
       vec3 aNodeMaxRgh = texelFetch (uSceneMaxPointTexture, aData.z).xyz;
-      
+
       vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
       vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
 
@@ -800,7 +781,7 @@ float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
       aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
 
       int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theDistance);
-      
+
       aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
       aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
 
@@ -809,7 +790,7 @@ float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
 
       aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
       aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
-      
+
       int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theDistance);
 
       if (bool(aHitLft & aHitRgh))
@@ -826,25 +807,16 @@ float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
         }
         else
         {
-#ifdef TRANSPARENT_SHADOWS
-          if (aHead < 0)
-            return aFactor;
-#else
-          if (aHead < 0)
-            return 1.0f;
-#endif
+          toContinue = aHead >= 0;
 
-          aNode = Stack[aHead--];
+          if (toContinue)
+            aNode = Stack[aHead--];
         }
       }
     }
   }
 
-#ifdef TRANSPARENT_SHADOWS
   return aFactor;
-#else
-  return 1.0f;
-#endif
 }
 
 #define PI 3.1415926f
@@ -955,7 +927,7 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
   vec3 aResult = vec3 (0.0f);
   vec4 aWeight = vec4 (1.0f);
 
-  int anObjectId;
+  int aTrsfId;
 
   float anOpenGlDepth = ComputeOpenGlDepth (theRay);
 
@@ -963,7 +935,7 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
   {
     SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);
 
-    ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, anObjectId);
+    ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTrsfId);
 
     if (aTriIndex.x == -1)
     {
@@ -982,12 +954,14 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
         aColor = vec4 (BackgroundColor().rgb * aGlColor.w + ComputeOpenGlColor().rgb, aGlColor.w);
       }
 
-      return vec4 (aResult.xyz + aWeight.xyz * aColor.xyz, aWeight.w * aColor.w);
+      aResult += aWeight.xyz * aColor.xyz; aWeight.w *= aColor.w;
+
+      break; // terminate path
     }
 
-    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 aInvTransf0 = texelFetch (uSceneTransformTexture, aTrsfId + 0).xyz;
+    vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, aTrsfId + 1).xyz;
+    vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, aTrsfId + 2).xyz;
 
     aHit.Normal = normalize (vec3 (dot (aInvTransf0, aHit.Normal),
                                    dot (aInvTransf1, aHit.Normal),
index a15ddd2..25c9bbe 100644 (file)
@@ -9,6 +9,12 @@ uniform float uSampleWeight;
 //! Input accumulated image.
 uniform sampler2D uAccumTexture;
 
+//! Enabled/disbales using of single RNG seed for image 16x16 blocks.
+//! Increases performance up to 4 times, but noise becomes structured.
+uniform int uBlockedRngEnabled;
+
+#define MAX_RADIANCE vec3 (10.f)
+
 // =======================================================================
 // function : main
 // purpose  :
@@ -20,7 +26,7 @@ void main (void)
 #else
   ivec2 aWinSize = textureSize (uAccumTexture, 0);
 
-  SeedRand (uFrameRndSeed, aWinSize.x);
+  SeedRand (uFrameRndSeed, aWinSize.x, uBlockedRngEnabled == 0 ? 1 : 16);
 
   SRay aRay = GenerateRay (vPixel +
     vec2 (RandFloat() + 1.f, RandFloat() + 1.f) / vec2 (aWinSize));
@@ -33,19 +39,17 @@ void main (void)
                      aRay.Direct.z < 0.f ? -aInvDirect.z : aInvDirect.z);
 
 #ifdef PATH_TRACING
-
   vec4 aColor = PathTrace (aRay, aInvDirect);
 
   if (any (isnan (aColor.xyz)))
   {
-    aColor.xyz = ZERO;
+    aColor.rgb = ZERO;
   }
 
-  OutColor = mix (texture2D (uAccumTexture, vPixel), aColor, uSampleWeight);
+  aColor.rgb = min (aColor.rgb, MAX_RADIANCE);
 
+  OutColor = mix (texture2D (uAccumTexture, vPixel), aColor, uSampleWeight);
 #else
-
   OutColor = clamp (Radiance (aRay, aInvDirect), 0.f, 1.f);
-
 #endif
 }
\ No newline at end of file
index 3bfc9cf..a3ebb4b 100644 (file)
@@ -5320,6 +5320,22 @@ static int VFps (Draw_Interpretor& theDI,
   theDI << "FPS: " << aFpsAver << "\n"
         << "CPU: " << (1000.0 * aCpuAver) << " msec\n";
 
+  // compute additional statistics in ray-tracing mode
+  Graphic3d_RenderingParams& aParams = aView->ChangeRenderingParams();
+
+  if (aParams.Method == Graphic3d_RM_RAYTRACING)
+  {
+    Standard_Integer aSizeX;
+    Standard_Integer aSizeY;
+
+    aView->Window()->Size (aSizeX, aSizeY);
+
+    // 1 shadow ray and 1 secondary ray pew each bounce
+    const Standard_Real aMRays = aSizeX * aSizeY * aFpsAver * aParams.RaytracingDepth * 2 / 1.0e6f;
+
+    theDI << "MRays/sec (upper bound): " << aMRays << "\n";
+  }
+
   return 0;
 }
 
@@ -8389,6 +8405,7 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
     theDI << "rayDepth:     " <<  aParams.RaytracingDepth                             << "\n";
     theDI << "gleam:        " << (aParams.IsTransparentShadowEnabled  ? "on" : "off") << "\n";
     theDI << "GI:           " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
+    theDI << "blocked RNG:  " << (aParams.CoherentPathTracingMode     ? "on" : "off") << "\n";
     theDI << "shadingModel: ";
     switch (aView->ShadingModel())
     {
@@ -8573,6 +8590,23 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
         aParams.RaytracingDepth = Min (aParams.RaytracingDepth, 10);
       }
     }
+    else if (aFlag == "-blockedrng"
+          || aFlag == "-brng")
+    {
+      if (toPrint)
+      {
+        theDI << (aParams.CoherentPathTracingMode ? "on" : "off") << " ";
+        continue;
+      }
+
+      Standard_Boolean toEnable = Standard_True;
+      if (++anArgIter < theArgNb
+        && !parseOnOff (theArgVec[anArgIter], toEnable))
+      {
+        --anArgIter;
+      }
+      aParams.CoherentPathTracingMode = toEnable;
+    }
     else if (aFlag == "-env")
     {
       if (toPrint)
@@ -9360,6 +9394,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "\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      '-shadingModel model'   Controls shading model from enumeration"
     "\n                              color, flat, gouraud, phong"