0025201: Visualization - Implementing soft shadows and ambient occlusion in OCCT...
authordbp <dbp@opencascade.com>
Mon, 20 Apr 2015 07:15:34 +0000 (10:15 +0300)
committerbugmaster <bugmaster@opencascade.com>
Wed, 10 Jun 2015 07:56:24 +0000 (10:56 +0300)
41 files changed:
src/AIS/AIS_InteractiveObject.cdl
src/AIS/AIS_InteractiveObject.cxx
src/Graphic3d/FILES
src/Graphic3d/Graphic3d.cdl
src/Graphic3d/Graphic3d_BSDF.cxx [new file with mode: 0644]
src/Graphic3d/Graphic3d_BSDF.hxx [new file with mode: 0644]
src/Graphic3d/Graphic3d_CLight.hxx
src/Graphic3d/Graphic3d_Group.cxx
src/Graphic3d/Graphic3d_MaterialAspect.cdl
src/Graphic3d/Graphic3d_MaterialAspect.cxx
src/Graphic3d/Graphic3d_RenderingParams.hxx
src/Graphic3d/Graphic3d_Structure.cxx
src/InterfaceGraphic/InterfaceGraphic_Graphic3d.hxx
src/OpenGl/OpenGl_AspectFace.cxx
src/OpenGl/OpenGl_AspectFace.hxx
src/OpenGl/OpenGl_BackgroundArray.hxx
src/OpenGl/OpenGl_FrameBuffer.cxx
src/OpenGl/OpenGl_SceneGeometry.hxx
src/OpenGl/OpenGl_Structure.hxx
src/OpenGl/OpenGl_View.cxx
src/OpenGl/OpenGl_View.hxx
src/OpenGl/OpenGl_View_Raytrace.cxx
src/Shaders/Display.fs [new file with mode: 0644]
src/Shaders/PathtraceBase.fs [new file with mode: 0644]
src/Shaders/RaytraceBase.fs
src/Shaders/RaytraceRender.fs
src/Shaders/RaytraceSmooth.fs
src/V3d/V3d_DirectionalLight.cdl
src/V3d/V3d_DirectionalLight.cxx
src/V3d/V3d_Light.cdl
src/V3d/V3d_Light.cxx
src/V3d/V3d_PositionalLight.cdl
src/V3d/V3d_PositionalLight.cxx
src/ViewerTest/FILES
src/ViewerTest/ViewerTest.cxx
src/ViewerTest/ViewerTest_CmdParser.cxx [new file with mode: 0644]
src/ViewerTest/ViewerTest_CmdParser.hxx [new file with mode: 0644]
src/ViewerTest/ViewerTest_ViewerCommands.cxx
src/Visual3d/Visual3d_Light.cdl
src/Visual3d/Visual3d_Light.cxx
tests/v3d/raytrace/bug25201 [new file with mode: 0644]

index 601a008..235a468 100644 (file)
@@ -454,7 +454,7 @@ is
        -- -   Pewter
        -- -   Silver
        -- -   Stone.
-    
+
     SetMaterial(me:mutable;aName:NameOfMaterial from Graphic3d) is virtual; 
        ---Purpose: Sets the name aName for material defining this
        -- display attribute for the interactive object.
index cc4dad7..0b52a52 100644 (file)
@@ -276,9 +276,7 @@ void AIS_InteractiveObject::UnsetWidth()
 //function : 
 //purpose  : 
 //=======================================================================
-//POP pour K4L
 void AIS_InteractiveObject::SetMaterial(const Graphic3d_NameOfMaterial aName)
-//void AIS_InteractiveObject::SetMaterial(const Graphic3d_NameOfPhysicalMaterial aName)
 {
   if( HasColor() || IsTransparent() || HasMaterial() )
   {
@@ -292,44 +290,57 @@ void AIS_InteractiveObject::SetMaterial(const Graphic3d_NameOfMaterial aName)
   myOwnMaterial  = aName;
   hasOwnMaterial = Standard_True;
 }
+
 //=======================================================================
 //function : SetMaterial
 //purpose  : 
 //=======================================================================
-
-void AIS_InteractiveObject::SetMaterial(const Graphic3d_MaterialAspect& aMat)
+void AIS_InteractiveObject::SetMaterial (const Graphic3d_MaterialAspect& theMaterial)
 {
-  if (HasColor() || IsTransparent() || HasMaterial())
+  if (!HasColor() && !IsTransparent() && !HasMaterial())
   {
-    myDrawer->ShadingAspect()->SetMaterial(aMat);
-  }
-  else
-  {
-    myDrawer->SetShadingAspect(new Prs3d_ShadingAspect());
-    myDrawer->ShadingAspect()->SetMaterial(aMat);
+    myDrawer->SetShadingAspect (new Prs3d_ShadingAspect);
   }
+
+  myDrawer->ShadingAspect()->SetMaterial (theMaterial);
+
   hasOwnMaterial = Standard_True;
 }
+
 //=======================================================================
-//function : 
-//purpose  : 
+//function : UnsetMaterial
+//purpose  :
 //=======================================================================
 void AIS_InteractiveObject::UnsetMaterial()
 {
-  if( !HasMaterial() ) return;
+  if (!HasMaterial())
+  {
+    return;
+  }
+
   if (HasColor() || IsTransparent())
   {
     if(myDrawer->HasLink())
     {
       myDrawer->ShadingAspect()->SetMaterial (AIS_GraphicTool::GetMaterial (myDrawer->Link()));
     }
-    if (HasColor()) SetColor (myOwnColor);
-    if (IsTransparent()) SetTransparency (myTransparency);
+
+    if (HasColor())
+    {
+      SetColor (myOwnColor);
+    }
+
+    if (IsTransparent())
+    {
+      SetTransparency (myTransparency);
+    }
   }
-  else{
-    Handle(Prs3d_ShadingAspect) SA;
-    myDrawer->SetShadingAspect(SA);
+  else
+  {
+    Handle(Prs3d_ShadingAspect) anAspect;
+    myDrawer->SetShadingAspect (anAspect);
   }
+
   hasOwnMaterial = Standard_False;
 }
 
index 14f6e96..d7ad4df 100755 (executable)
@@ -65,3 +65,5 @@ Graphic3d_Camera.cxx
 Graphic3d_Camera.hxx
 Graphic3d_RenderingParams.hxx
 Graphic3d_NMapOfTransient.hxx
+Graphic3d_BSDF.hxx
+Graphic3d_BSDF.cxx
index 7ed61e2..9b7db76 100644 (file)
@@ -362,6 +362,8 @@ is
     imported BndBox4d;
     imported BufferType;
 
+    imported BSDF;
+
     imported CBitFields20;
     ---Category: Imported types
 
diff --git a/src/Graphic3d/Graphic3d_BSDF.cxx b/src/Graphic3d/Graphic3d_BSDF.cxx
new file mode 100644 (file)
index 0000000..5784008
--- /dev/null
@@ -0,0 +1,159 @@
+// Created on: 2015-01-19
+// Created by: Denis BOGOLEPOV
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <Graphic3d_BSDF.hxx>
+
+#include <algorithm>
+
+// =======================================================================
+// function : Serialize
+// purpose  :
+// =======================================================================
+Graphic3d_Vec4 Graphic3d_Fresnel::Serialize() const
+{
+  Graphic3d_Vec4 aData = Graphic3d_Vec4 (myFresnelData, 0.f);
+
+  if (myFresnelType != Graphic3d_FM_SCHLICK)
+  {
+    aData.x() = -static_cast<Standard_ShortReal> (myFresnelType);
+  }
+
+  return aData;
+}
+
+// =======================================================================
+// function : fresnelNormal
+// purpose  :
+// =======================================================================
+inline Standard_ShortReal fresnelNormal (Standard_ShortReal theN,
+                                         Standard_ShortReal theK)
+{
+  return ((theN - 1.f) * (theN - 1.f) + theK * theK) /
+         ((theN + 1.f) * (theN + 1.f) + theK * theK);
+}
+
+// =======================================================================
+// function : CreateConductor
+// purpose  :
+// =======================================================================
+Graphic3d_Fresnel Graphic3d_Fresnel::CreateConductor (const Graphic3d_Vec3& theRefractionIndex,
+                                                      const Graphic3d_Vec3& theAbsorptionIndex)
+{
+  return Graphic3d_Fresnel (Graphic3d_FM_SCHLICK,
+    Graphic3d_Vec3 (fresnelNormal (theRefractionIndex.x(), theAbsorptionIndex.x()),
+                    fresnelNormal (theRefractionIndex.y(), theAbsorptionIndex.y()),
+                    fresnelNormal (theRefractionIndex.z(), theAbsorptionIndex.z())));
+}
+
+// =======================================================================
+// function : Normalize
+// purpose  :
+// =======================================================================
+void Graphic3d_BSDF::Normalize()
+{
+  Standard_ShortReal aMax = std::max (Kd.x() + Ks.x() + Kr.x() + Kt.x(),
+                            std::max (Kd.y() + Ks.y() + Kr.y() + Kt.y(),
+                                      Kd.z() + Ks.z() + Kr.z() + Kt.z()));
+
+  if (aMax > 1.f)
+  {
+    Kd /= aMax;
+    Ks /= aMax;
+    Kr /= aMax;
+    Ks /= aMax;
+  }
+}
+
+// =======================================================================
+// function : CreateDiffuse
+// purpose  :
+// =======================================================================
+Graphic3d_BSDF Graphic3d_BSDF::CreateDiffuse (const Graphic3d_Vec3& theWeight)
+{
+  Graphic3d_BSDF aBSDF;
+
+  aBSDF.Kd = theWeight;
+
+  return aBSDF;
+}
+
+// =======================================================================
+// function : CreateMetallic
+// purpose  :
+// =======================================================================
+Graphic3d_BSDF Graphic3d_BSDF::CreateMetallic (const Graphic3d_Vec3&    theWeight,
+                                               const Graphic3d_Fresnel& theFresnel,
+                                               const Standard_ShortReal theRoughness)
+{
+  Graphic3d_BSDF aBSDF;
+
+  aBSDF.Roughness = theRoughness;
+
+  // Selecting between specular and glossy
+  // BRDF depending on the given roughness
+  if (aBSDF.Roughness > 0.f)
+  {
+    aBSDF.Ks = theWeight;
+  }
+  else
+  {
+    aBSDF.Kr = theWeight;
+  }
+
+  aBSDF.Fresnel = theFresnel;
+
+  return aBSDF;
+}
+
+// =======================================================================
+// function : CreateTransparent
+// purpose  :
+// =======================================================================
+Graphic3d_BSDF Graphic3d_BSDF::CreateTransparent (const Graphic3d_Vec3&    theWeight,
+                                                  const Graphic3d_Vec3&    theAbsorptionColor,
+                                                  const Standard_ShortReal theAbsorptionCoeff)
+{
+  Graphic3d_BSDF aBSDF;
+
+  aBSDF.Kt = theWeight;
+
+  aBSDF.AbsorptionColor = theAbsorptionColor;
+  aBSDF.AbsorptionCoeff = theAbsorptionCoeff;
+
+  aBSDF.Fresnel = Graphic3d_Fresnel::CreateConstant (0.f);
+
+  return aBSDF;
+}
+
+// =======================================================================
+// function : CreateGlass
+// purpose  :
+// =======================================================================
+Graphic3d_BSDF Graphic3d_BSDF::CreateGlass (const Graphic3d_Vec3&    theWeight,
+                                            const Graphic3d_Vec3&    theAbsorptionColor,
+                                            const Standard_ShortReal theAbsorptionCoeff,
+                                            const Standard_ShortReal theRefractionIndex)
+{
+  Graphic3d_BSDF aBSDF;
+
+  aBSDF.Kt = theWeight;
+
+  aBSDF.AbsorptionColor = theAbsorptionColor;
+  aBSDF.AbsorptionCoeff = theAbsorptionCoeff;
+
+  aBSDF.Fresnel = Graphic3d_Fresnel::CreateDielectric (theRefractionIndex);
+
+  return aBSDF;
+}
\ No newline at end of file
diff --git a/src/Graphic3d/Graphic3d_BSDF.hxx b/src/Graphic3d/Graphic3d_BSDF.hxx
new file mode 100644 (file)
index 0000000..8256a18
--- /dev/null
@@ -0,0 +1,203 @@
+// Created on: 2015-01-15
+// Created by: Danila ULYANOV
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Graphic3d_BSDF_HeaderFile
+#define _Graphic3d_BSDF_HeaderFile
+
+#include <Graphic3d_Vec3.hxx>
+#include <Graphic3d_Vec4.hxx>
+
+//! Type of the Fresnel model.
+enum Graphic3d_FresnelModel
+{
+  Graphic3d_FM_SCHLICK    = 0,
+  Graphic3d_FM_CONSTANT   = 1,
+  Graphic3d_FM_CONDUCTOR  = 2,
+  Graphic3d_FM_DIELECTRIC = 3
+};
+
+//! Describes Fresnel reflectance parameters.
+class Graphic3d_Fresnel
+{
+public:
+
+  //! Creates uninitialized Fresnel factor.
+  Graphic3d_Fresnel()
+  : myFresnelType (Graphic3d_FM_CONSTANT)
+  {
+    // ideal specular reflector
+    myFresnelData = Graphic3d_Vec3 (0.f, 1.f, 0.f);
+  }
+
+  //! Creates Schlick's approximation of Fresnel factor.
+  static Graphic3d_Fresnel CreateSchlick (const Graphic3d_Vec3& theSpecularColor)
+  {
+    return Graphic3d_Fresnel (Graphic3d_FM_SCHLICK, theSpecularColor);
+  }
+
+  //! Creates Fresnel factor for constant reflection.
+  static Graphic3d_Fresnel CreateConstant (const Standard_ShortReal theReflection)
+  {
+    return Graphic3d_Fresnel (Graphic3d_FM_CONSTANT, Graphic3d_Vec3 (0.f, 1.f, theReflection));
+  }
+
+  //! Creates Fresnel factor for physical-based dielectric model.
+  static Graphic3d_Fresnel CreateDielectric (Standard_ShortReal theRefractionIndex)
+  {
+    return Graphic3d_Fresnel (Graphic3d_FM_DIELECTRIC, Graphic3d_Vec3 (0.f, theRefractionIndex, 0.f));
+  }
+
+  //! Creates Fresnel factor for physical-based conductor model.
+  static Graphic3d_Fresnel CreateConductor (Standard_ShortReal theRefractionIndex,
+                                            Standard_ShortReal theAbsorptionIndex)
+  {
+    return Graphic3d_Fresnel (Graphic3d_FM_CONDUCTOR, Graphic3d_Vec3 (0.f, theRefractionIndex, theAbsorptionIndex));
+  }
+
+  //! Creates Fresnel factor for physical-based conductor model (spectral version).
+  Standard_EXPORT static Graphic3d_Fresnel CreateConductor (const Graphic3d_Vec3& theRefractionIndex,
+                                                            const Graphic3d_Vec3& theAbsorptionIndex);
+
+public:
+
+  //! Returns serialized representation of Fresnel factor.
+  Standard_EXPORT Graphic3d_Vec4 Serialize() const;
+
+  //! Performs comparison of two objects describing Fresnel factor.
+  bool operator== (const Graphic3d_Fresnel& theOther) const
+  {
+    return myFresnelType == theOther.myFresnelType
+        && myFresnelData == theOther.myFresnelData;
+  }
+
+protected:
+
+  //! Creates new Fresnel reflectance factor.
+  Graphic3d_Fresnel (Graphic3d_FresnelModel theType, const Graphic3d_Vec3& theData)
+  : myFresnelType (theType),
+    myFresnelData (theData)
+  {
+    //
+  }
+
+private:
+
+  //! Type of Fresnel approximation.
+  Graphic3d_FresnelModel myFresnelType;
+
+  //! Serialized parameters of specific approximation.
+  Graphic3d_Vec3 myFresnelData;
+};
+
+//! Describes material's BSDF (Bidirectional Scattering Distribution Function) used
+//! for physically-based rendering (in path tracing engine). BSDF is represented as
+//! weighted mixture of basic BRDFs/BTDFs (Bidirectional Reflectance (Transmittance)
+//! Distribution Functions).
+class Graphic3d_BSDF
+{
+public:
+
+  //! Weight of the Lambertian BRDF.
+  Graphic3d_Vec3 Kd;
+
+  //! Weight of the reflection BRDF.
+  Graphic3d_Vec3 Kr;
+
+  //! Weight of the transmission BTDF.
+  Graphic3d_Vec3 Kt;
+
+  //! Weight of the Blinn's glossy BRDF.
+  Graphic3d_Vec3 Ks;
+
+  //! Self-emitted radiance.
+  Graphic3d_Vec3 Le;
+
+  //! Parameters of Fresnel reflectance.
+  Graphic3d_Fresnel Fresnel;
+
+  //! Roughness (exponent) of Blinn's BRDF.
+  Standard_ShortReal Roughness;
+
+  //! Absorption color of transparent media.
+  Graphic3d_Vec3 AbsorptionColor;
+
+  //! Absorption intensity of transparent media.
+  Standard_ShortReal AbsorptionCoeff;
+
+public:
+
+  //! Creates BSDF describing diffuse (Lambertian) surface.
+  static Standard_EXPORT Graphic3d_BSDF CreateDiffuse (const Graphic3d_Vec3& theWeight);
+
+  //! Creates BSDF describing polished metallic-like surface.
+  static Standard_EXPORT Graphic3d_BSDF CreateMetallic (const Graphic3d_Vec3&    theWeight,
+                                                        const Graphic3d_Fresnel& theFresnel,
+                                                        const Standard_ShortReal theRoughness);
+
+  //! Creates BSDF describing transparent object.
+  //! Transparent BSDF models simple transparency without
+  //! refraction (the ray passes straight through the surface).
+  static Standard_EXPORT Graphic3d_BSDF CreateTransparent (const Graphic3d_Vec3&    theWeight,
+                                                           const Graphic3d_Vec3&    theAbsorptionColor,
+                                                           const Standard_ShortReal theAbsorptionCoeff);
+
+  //! Creates BSDF describing glass-like object.
+  //! Glass-like BSDF mixes refraction and reflection effects at
+  //! grazing angles using physically-based Fresnel dielectric model.
+  static Standard_EXPORT Graphic3d_BSDF CreateGlass (const Graphic3d_Vec3&    theWeight,
+                                                     const Graphic3d_Vec3&    theAbsorptionColor,
+                                                     const Standard_ShortReal theAbsorptionCoeff,
+                                                     const Standard_ShortReal theRefractionIndex);
+
+public:
+
+  //! Creates uninitialized BSDF.
+  Graphic3d_BSDF()
+  {
+    Roughness = AbsorptionCoeff = 0.f;
+  }
+
+  //! Normalizes BSDF components.
+  Standard_EXPORT void Normalize();
+
+  //! Performs mixing of two BSDFs.
+  Graphic3d_BSDF& operator+ (const Graphic3d_BSDF& theOther)
+  {
+    Kd += theOther.Kd;
+    Kr += theOther.Kr;
+    Kt += theOther.Kt;
+    Ks += theOther.Ks;
+    Le += theOther.Le;
+
+    return *this;
+  }
+
+  //! Performs comparison of two BSDFs.
+  bool operator== (const Graphic3d_BSDF& theOther) const
+  {
+    return Kd              == theOther.Kd
+        && Kr              == theOther.Kr
+        && Kt              == theOther.Kt
+        && Ks              == theOther.Ks
+        && Le              == theOther.Le
+        && Fresnel         == theOther.Fresnel
+        && Roughness       == theOther.Roughness
+        && AbsorptionCoeff == theOther.AbsorptionCoeff
+        && AbsorptionColor == theOther.AbsorptionColor;
+  }
+
+};
+
+#endif // _Graphic3d_BSDF_HeaderFile
index 3854072..bc8646f 100644 (file)
@@ -30,6 +30,8 @@ public:
   Graphic3d_Vec4     Params;      //!< packed light parameters
   Standard_Integer   Type;        //!< Visual3d_TypeOfLightSource enumeration
   Standard_Boolean   IsHeadlight; //!< flag to mark head light
+  Standard_ShortReal Smoothness;  //!< radius (cone angle) for point (directional) light
+  Standard_ShortReal Intensity;   //!< intensity multiplier for light
 
   //! Const attenuation factor of positional light source
   Standard_ShortReal  ConstAttenuation()  const { return Params.x();  }
@@ -61,7 +63,9 @@ public:
     Direction     (0.0f, 0.0f, 0.0f, 0.0f),
     Params        (0.0f, 0.0f, 0.0f, 0.0f),
     Type          (0),
-    IsHeadlight   (Standard_False)
+    IsHeadlight   (Standard_False),
+    Smoothness    (0.0f),
+    Intensity     (1.0f)
   {
     //
   }
index 62a4ded..4552746 100644 (file)
@@ -336,14 +336,15 @@ void Graphic3d_Group::SetGroupPrimitivesAspect (const Handle(Graphic3d_AspectFil
   // Back Material
   const Graphic3d_MaterialAspect& aBack = theAspFill->BackMaterial();
 
-  // Light specificity
-  ContextFillArea.Back.Shininess    = float (aBack.Shininess());
-  ContextFillArea.Back.Ambient      = float (aBack.Ambient());
-  ContextFillArea.Back.Diffuse      = float (aBack.Diffuse());
-  ContextFillArea.Back.Specular     = float (aBack.Specular());
-  ContextFillArea.Back.Transparency = float (aBack.Transparency());
-  ContextFillArea.Back.Emission     = float (aBack.Emissive());
+  // Material properties
+  ContextFillArea.Back.Shininess       = float (aBack.Shininess());
+  ContextFillArea.Back.Ambient         = float (aBack.Ambient());
+  ContextFillArea.Back.Diffuse         = float (aBack.Diffuse());
+  ContextFillArea.Back.Specular        = float (aBack.Specular());
+  ContextFillArea.Back.Transparency    = float (aBack.Transparency());
+  ContextFillArea.Back.Emission        = float (aBack.Emissive());
   ContextFillArea.Back.RefractionIndex = float (aBack.RefractionIndex());
+  ContextFillArea.Back.BSDF            = aBack.BSDF();
 
   // Reflection mode
   ContextFillArea.Back.IsAmbient    = aBack.ReflectionMode (Graphic3d_TOR_AMBIENT)  ? 1 : 0;
@@ -378,14 +379,16 @@ void Graphic3d_Group::SetGroupPrimitivesAspect (const Handle(Graphic3d_AspectFil
 
   // Front Material
   const Graphic3d_MaterialAspect& aFront = theAspFill->FrontMaterial();
-  // Light specificity
-  ContextFillArea.Front.Shininess     = float (aFront.Shininess());
-  ContextFillArea.Front.Ambient       = float (aFront.Ambient());
-  ContextFillArea.Front.Diffuse       = float (aFront.Diffuse());
-  ContextFillArea.Front.Specular      = float (aFront.Specular());
-  ContextFillArea.Front.Transparency  = float (aFront.Transparency());
-  ContextFillArea.Front.Emission      = float (aFront.Emissive());
+
+  // Material properties
+  ContextFillArea.Front.Shininess       = float (aFront.Shininess());
+  ContextFillArea.Front.Ambient         = float (aFront.Ambient());
+  ContextFillArea.Front.Diffuse         = float (aFront.Diffuse());
+  ContextFillArea.Front.Specular        = float (aFront.Specular());
+  ContextFillArea.Front.Transparency    = float (aFront.Transparency());
+  ContextFillArea.Front.Emission        = float (aFront.Emissive());
   ContextFillArea.Front.RefractionIndex = float (aFront.RefractionIndex());
+  ContextFillArea.Front.BSDF            = aFront.BSDF();
 
   // Reflection mode
   ContextFillArea.Front.IsAmbient     = aFront.ReflectionMode (Graphic3d_TOR_AMBIENT)  ? 1 : 0;
@@ -636,6 +639,9 @@ void Graphic3d_Group::SetPrimitivesAspect (const Handle(Graphic3d_AspectFillArea
 
   ContextFillArea.Back.EnvReflexion = float (aBack.EnvReflexion());
 
+  ContextFillArea.Back.RefractionIndex = float (aBack.RefractionIndex());
+  ContextFillArea.Back.BSDF = aBack.BSDF();
+
   // Front Material
   const Graphic3d_MaterialAspect& aFront = theAspFill->FrontMaterial();
   // Light specificity
@@ -677,6 +683,9 @@ void Graphic3d_Group::SetPrimitivesAspect (const Handle(Graphic3d_AspectFillArea
 
   ContextFillArea.Front.EnvReflexion  = float (aFront.EnvReflexion());
 
+  ContextFillArea.Front.RefractionIndex = float (aFront.RefractionIndex());
+  ContextFillArea.Front.BSDF = aFront.BSDF();
+
   ContextFillArea.IsDef = 1; // Material definition ok
 
   ContextFillArea.Texture.TextureMap   = theAspFill->TextureMap();
@@ -892,6 +901,9 @@ void Graphic3d_Group::GroupPrimitivesAspect (const Handle(Graphic3d_AspectLine3d
 
   aBack.SetEnvReflexion (anAspFill.Back.EnvReflexion);
 
+  aBack.SetRefractionIndex (Standard_Real (anAspFill.Back.RefractionIndex));
+  aBack.SetBSDF (anAspFill.Back.BSDF);
+
   // Front Material
   aFront.SetShininess    (Standard_Real (anAspFill.Front.Shininess));
   aFront.SetAmbient      (Standard_Real (anAspFill.Front.Ambient));
@@ -926,6 +938,9 @@ void Graphic3d_Group::GroupPrimitivesAspect (const Handle(Graphic3d_AspectLine3d
 
   aFront.SetEnvReflexion (anAspFill.Front.EnvReflexion);
 
+  aFront.SetRefractionIndex (Standard_Real (anAspFill.Front.RefractionIndex));
+  aFront.SetBSDF (anAspFill.Front.BSDF);
+
   // Edges
   anAspFill.Edge == 1 ? theAspFill->SetEdgeOn() : theAspFill->SetEdgeOff();
   // Hatch
index e4077ee..72c6b35 100644 (file)
@@ -34,12 +34,12 @@ class MaterialAspect from Graphic3d
 
 uses
 
-       Color                   from Quantity,
-
-       NameOfMaterial          from Graphic3d,
-       TypeOfReflection        from Graphic3d,
-       TypeOfMaterial          from Graphic3d,
-       AsciiString             from TCollection
+  Color             from Quantity,
+  NameOfMaterial    from Graphic3d,
+  TypeOfReflection  from Graphic3d,
+  TypeOfMaterial    from Graphic3d,
+  BSDF              from Graphic3d,
+  AsciiString       from TCollection
 
 raises
 
@@ -148,6 +148,13 @@ is
        --          lesser than 1.0.
        raises MaterialDefinitionError from Graphic3d is static;
 
+  SetBSDF ( me : in out;
+            theBSDF  : BSDF from Graphic3d )
+          is static;
+  ---Level: Public
+  ---Purpose: Modifies the BSDF (bidirectional scattering distribution function).
+  --  Category: Methods to modify the class definition
+
        SetColor ( me           : in out;
                   AColor       : Color from Quantity )
                is static;
@@ -325,6 +332,14 @@ is
        ---Purpose: Returns the refraction index of the material
        ---Category: Inquire methods
 
+  BSDF ( me )
+    returns BSDF from Graphic3d
+    is static;
+  ---C++: return const&
+  ---Level: Public
+  ---Purpose: Returns BSDF (bidirectional scattering distribution function).
+  ---Category: Inquire methods
+
   Emissive ( me )
                returns Real from Standard
                is static;
@@ -485,6 +500,9 @@ fields
   myTransparencyCoef  : ShortReal from Standard;
   myRefractionIndex   : ShortReal from Standard;
 
+  -- BSDF (bidirectional scattering distribution function). Physically based material represented as weighted mixture of BxDFs (BRDFs and BTDFs) and its parameters.
+  myBSDF              : BSDF from Graphic3d;
+
   -- the specular exponent
   myShininess    : ShortReal from Standard;
 
@@ -501,4 +519,4 @@ fields
   -- the string name of the material
   myStringName : AsciiString from TCollection;
 
-end MaterialAspect;
+end MaterialAspect;
\ No newline at end of file
index 12c3181..97d847d 100644 (file)
@@ -62,6 +62,8 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
   mySpecularColor.SetValues (1.0, 1.0, 1.0, Quantity_TOC_RGB);
   myMaterialName     = theName;
 
+  myBSDF = Graphic3d_BSDF::CreateDiffuse (Graphic3d_Vec3 (0.2f, 0.2f, 0.2f));
+
   Standard_Integer index = Standard_Integer (theName);
   if (index < NumberOfMaterials())
   {
@@ -70,23 +72,44 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
 
   switch (theName)
   {
-    case Graphic3d_NOM_PLASTIC:       // Blue plastic
+    case Graphic3d_NOM_PLASTIC:
       myShininess    = Standard_ShortReal (0.0078125);
       myAmbientCoef  = Standard_ShortReal (0.5);
       myDiffuseCoef  = Standard_ShortReal (0.24);
       mySpecularCoef = Standard_ShortReal (0.06);
+
+      myBSDF.Kd = Graphic3d_Vec3 (static_cast<Standard_ShortReal> (myDiffuseColor.Red()),
+                                  static_cast<Standard_ShortReal> (myDiffuseColor.Green()),
+                                  static_cast<Standard_ShortReal> (myDiffuseColor.Blue()));
+      myBSDF.Ks = Graphic3d_Vec3 (0.00784314f, 0.00784314f, 0.00784314f);
+      myBSDF.Normalize();
+      myBSDF.Roughness = 32;
       break;
-    case Graphic3d_NOM_SHINY_PLASTIC: // black plastic
+    case Graphic3d_NOM_SHINY_PLASTIC:
       myShininess    = Standard_ShortReal (1.0);
       myAmbientCoef  = Standard_ShortReal (0.44);
       myDiffuseCoef  = Standard_ShortReal (0.5);
       mySpecularCoef = Standard_ShortReal (1.0);
+
+      myBSDF.Kd = Graphic3d_Vec3 (static_cast<Standard_ShortReal> (myDiffuseColor.Red()),
+                                  static_cast<Standard_ShortReal> (myDiffuseColor.Green()),
+                                  static_cast<Standard_ShortReal> (myDiffuseColor.Blue()));
+      myBSDF.Ks = Graphic3d_Vec3 (0.0156863f, 0.0156863f, 0.0156863f);
+      myBSDF.Normalize();
+      myBSDF.Roughness = 64.f;
       break;
     case Graphic3d_NOM_SATIN :
       myShininess    = Standard_ShortReal (0.09375);
       myAmbientCoef  = Standard_ShortReal (0.33);
       myDiffuseCoef  = Standard_ShortReal (0.4);
       mySpecularCoef = Standard_ShortReal (0.44);
+
+      myBSDF.Kd = Graphic3d_Vec3 (static_cast<Standard_ShortReal> (myDiffuseColor.Red()),
+                                  static_cast<Standard_ShortReal> (myDiffuseColor.Green()),
+                                  static_cast<Standard_ShortReal> (myDiffuseColor.Blue()));
+      myBSDF.Ks = Graphic3d_Vec3 (0.0313726f, 0.0313726f, 0.0313726f);
+      myBSDF.Roughness = 16.f;
+      myBSDF.Normalize();
       break;
     case Graphic3d_NOM_NEON_GNC:
       myShininess    = Standard_ShortReal (0.05);
@@ -96,6 +119,12 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myEmissiveCoef = Standard_ShortReal (1.0);
       myEmissiveActivity = Standard_True;
       myAmbientActivity  = Standard_False;
+
+      myBSDF.Kr = Graphic3d_Vec3 (0.207843f, 0.207843f, 0.207843f);
+      myBSDF.Le = Graphic3d_Vec3 (static_cast<Standard_ShortReal> (myDiffuseColor.Red()),
+                                  static_cast<Standard_ShortReal> (myDiffuseColor.Green()),
+                                  static_cast<Standard_ShortReal> (myDiffuseColor.Blue()));
+      myBSDF.Fresnel == Graphic3d_Fresnel::CreateSchlick (Graphic3d_Vec3 (0.3f, 0.3f, 0.3f));
       break;
     case Graphic3d_NOM_METALIZED:
       myShininess    = Standard_ShortReal (0.13);
@@ -104,10 +133,14 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       mySpecularCoef = Standard_ShortReal (0.45);
       myAmbientActivity  = Standard_False;
 
-      // Color resulting from dispersed
-      //myDiffuseColor .SetValues (0.87, 0.96,  1.0, Quantity_TOC_RGB);
-      // Color resulting from specular
-      //mySpecularColor.SetValues (0.93, 0.95, 0.78, Quantity_TOC_RGB);
+      {
+        Graphic3d_Vec3 aColor (static_cast<Standard_ShortReal> (myDiffuseColor.Red()),
+                               static_cast<Standard_ShortReal> (myDiffuseColor.Green()),
+                               static_cast<Standard_ShortReal> (myDiffuseColor.Blue()));
+
+        myBSDF = Graphic3d_BSDF::CreateMetallic (Graphic3d_Vec3 (0.985f, 0.985f, 0.985f),
+          Graphic3d_Fresnel::CreateSchlick (aColor), 1024.f);
+      }
       break;
     // Ascending Compatibility physical materials. The same definition is taken as in the next constructor.
     case Graphic3d_NOM_BRASS:
@@ -118,6 +151,9 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myDiffuseCoef  = 1.00f;
       mySpecularCoef = 1.00f;
 
+      myBSDF = Graphic3d_BSDF::CreateMetallic (Graphic3d_Vec3 (0.985f, 0.985f, 0.985f),
+        Graphic3d_Fresnel::CreateSchlick (Graphic3d_Vec3 (0.58f, 0.42f, 0.20f)), 1024.f);
+
       // Color resulting from ambient
       myAmbientColor .SetValues (0.329f, 0.224f, 0.027f, Quantity_TOC_RGB);
       // Color resulting from dispersed
@@ -133,6 +169,9 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myDiffuseCoef  = 1.00f;
       mySpecularCoef = 1.00f;
 
+      myBSDF = Graphic3d_BSDF::CreateMetallic (Graphic3d_Vec3 (0.985f, 0.985f, 0.985f),
+        Graphic3d_Fresnel::CreateSchlick (Graphic3d_Vec3 (0.65f, 0.35f, 0.15f)), 1024.f);
+
       // Color resulting from ambient
       myAmbientColor .SetValues (0.213f, 0.128f, 0.054f, Quantity_TOC_RGB);
       // Color resulting from dispersed
@@ -148,6 +187,9 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myDiffuseCoef  = 1.00f;
       mySpecularCoef = 1.00f;
 
+      myBSDF = Graphic3d_BSDF::CreateMetallic (Graphic3d_Vec3 (0.985f, 0.985f, 0.985f),
+        Graphic3d_Fresnel::CreateSchlick (Graphic3d_Vec3 (0.955008f, 0.637427f, 0.538163f)), 1024.f);
+
       // Color resulting from ambient
       myAmbientColor .SetValues (0.191f, 0.074f, 0.023f, Quantity_TOC_RGB);
       // Color resulting from dispersed
@@ -163,6 +205,9 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myDiffuseCoef  = 1.00f;
       mySpecularCoef = 1.00f;
 
+      myBSDF = Graphic3d_BSDF::CreateMetallic (Graphic3d_Vec3 (0.985f, 0.985f, 0.985f),
+        Graphic3d_Fresnel::CreateSchlick (Graphic3d_Vec3 (1.000000f, 0.765557f, 0.336057f)), 1024.f);
+
       // Color resulting from ambient
       myAmbientColor .SetValues (0.300f, 0.230f, 0.095f, Quantity_TOC_RGB);
       // Color resulting from dispersed
@@ -178,6 +223,9 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myDiffuseCoef  = 1.00f;
       mySpecularCoef = 1.00f;
 
+      myBSDF = Graphic3d_BSDF::CreateMetallic (Graphic3d_Vec3 (0.985f, 0.985f, 0.985f),
+        Graphic3d_Fresnel::CreateConductor (1.8800f, 3.4900f), 1024.f);
+
       // Color resulting from ambient
       myAmbientColor .SetValues (0.106f, 0.059f, 0.114f, Quantity_TOC_RGB);
       // Color resulting from dispersed
@@ -197,6 +245,9 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myDiffuseColor .SetValues (0.508f, 0.508f, 0.508f, Quantity_TOC_RGB);
       // Color resulting from specular
       mySpecularColor.SetValues (0.508f, 0.508f, 0.508f, Quantity_TOC_RGB);
+
+      myBSDF.Kd = Graphic3d_Vec3 (0.482353f, 0.482353f, 0.482353f);
+
       break;
     case Graphic3d_NOM_SILVER:
       myMaterialType = Graphic3d_MATERIAL_PHYSIC;
@@ -206,6 +257,9 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myDiffuseCoef  = 1.00f;
       mySpecularCoef = 1.00f;
 
+      myBSDF = Graphic3d_BSDF::CreateMetallic (Graphic3d_Vec3 (0.985f, 0.985f, 0.985f),
+        Graphic3d_Fresnel::CreateSchlick (Graphic3d_Vec3 (0.971519f, 0.959915f, 0.915324f)), 1024.f);
+
       // Color resulting from ambient
       myAmbientColor .SetValues (0.275f, 0.275f, 0.250f, Quantity_TOC_RGB);
       // Color resulting from dispersed
@@ -221,6 +275,9 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myDiffuseCoef  = 1.00f;
       mySpecularCoef = 1.00f;
 
+      myBSDF = Graphic3d_BSDF::CreateMetallic (Graphic3d_Vec3 (0.985f, 0.985f, 0.985f),
+        Graphic3d_Fresnel::CreateConductor (Graphic3d_Vec3 (2.90f, 2.80f, 2.53f), Graphic3d_Vec3 (3.08f, 2.90f, 2.74f)), 1024.f);
+
       // Color resulting from ambient
       myAmbientColor .SetValues (0.150f, 0.150f, 0.180f, Quantity_TOC_RGB);
       // Color resulting from dispersed
@@ -242,6 +299,10 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myDiffuseColor .SetValues (1.0,  0.8, 0.62, Quantity_TOC_RGB);
       // Color resulting from specular
       mySpecularColor.SetValues (0.98, 1.0, 0.60, Quantity_TOC_RGB);
+
+      myBSDF.Kd = Graphic3d_Vec3 (0.243137f, 0.243137f, 0.243137f);
+      myBSDF.Ks = Graphic3d_Vec3 (0.00392157f, 0.00392157f, 0.00392157f);
+
       break;
     // Ascending Compatibility of physical materials. Takes the same definition as in the next constructor. New materials
     case Graphic3d_NOM_CHROME:
@@ -252,6 +313,9 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myDiffuseCoef  = 1.00f;
       mySpecularCoef = 1.00f;
 
+      myBSDF = Graphic3d_BSDF::CreateMetallic (Graphic3d_Vec3 (0.985f, 0.985f, 0.985f),
+        Graphic3d_Fresnel::CreateSchlick (Graphic3d_Vec3 (0.549585f, 0.556114f, 0.554256f)), 1024.f);
+
       // Color resulting from ambient
       myAmbientColor .SetValues (0.200f, 0.200f, 0.225f, Quantity_TOC_RGB);
       // Color resulting from dispersed
@@ -267,6 +331,9 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myDiffuseCoef  = 1.00f;
       mySpecularCoef = 1.00f;
 
+      myBSDF = Graphic3d_BSDF::CreateMetallic (Graphic3d_Vec3 (0.985f, 0.985f, 0.985f),
+        Graphic3d_Fresnel::CreateSchlick (Graphic3d_Vec3 (0.913183f, 0.921494f, 0.924524f)), 1024.f);
+
       // Color resulting from ambient
       myAmbientColor .SetValues (0.300f, 0.300f, 0.300f, Quantity_TOC_RGB);
       // Color resulting from dispersed
@@ -294,6 +361,10 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       mySpecularColor.SetValues (1.0, 1.0, 1.0,  Quantity_TOC_RGB);
       // Color resulting from specular
       myEmissiveColor.SetValues (0.0, 1.0, 0.46, Quantity_TOC_RGB);
+
+      myBSDF.Kr = Graphic3d_Vec3 (0.207843f, 0.207843f, 0.207843f);
+      myBSDF.Le = Graphic3d_Vec3 (0.0f, 1.0f, 0.46f);
+      myBSDF.Fresnel == Graphic3d_Fresnel::CreateSchlick (Graphic3d_Vec3 (0.3f, 0.3f, 0.3f));
       break;
     case Graphic3d_NOM_OBSIDIAN:
       myMaterialType = Graphic3d_MATERIAL_PHYSIC;
@@ -309,6 +380,10 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myDiffuseColor .SetValues (0.183f, 0.170f, 0.225f, Quantity_TOC_RGB);
       // Color resulting from specular
       mySpecularColor.SetValues (0.333f, 0.329f, 0.346f, Quantity_TOC_RGB);
+
+      myBSDF.Kd = Graphic3d_Vec3 (0.0156863f, 0.f, 0.0155017f);
+      myBSDF.Ks = Graphic3d_Vec3 (0.0156863f, 0.0156863f, 0.0156863f);
+      myBSDF.Roughness = 1024.f;
       break;
     case Graphic3d_NOM_JADE:
       myMaterialType = Graphic3d_MATERIAL_PHYSIC;
@@ -324,6 +399,11 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myDiffuseColor .SetValues (0.540f, 0.890f, 0.630f, Quantity_TOC_RGB);
       // Color resulting from specular
       mySpecularColor.SetValues (0.316f, 0.316f, 0.316f, Quantity_TOC_RGB);
+
+      myBSDF.Fresnel = Graphic3d_Fresnel::CreateDielectric (1.5f);
+      myBSDF.Kd = Graphic3d_Vec3 (0.208658f, 0.415686f, 0.218401f);
+      myBSDF.Ks = Graphic3d_Vec3 (0.611765f, 0.611765f, 0.611765f);
+      myBSDF.Roughness = 512.f;
       break;
     case Graphic3d_NOM_CHARCOAL:
       myMaterialType = Graphic3d_MATERIAL_PHYSIC;
@@ -339,6 +419,10 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myDiffuseColor .SetValues (0.150f, 0.150f, 0.150f, Quantity_TOC_RGB);
       // Color resulting from specular
       mySpecularColor.SetValues (0.000f, 0.000f, 0.000f, Quantity_TOC_RGB);
+
+      myBSDF.Kd = Graphic3d_Vec3 (0.0196078f, 0.0196078f, 0.0196078f);
+      myBSDF.Ks = Graphic3d_Vec3 (0.0196078f, 0.0196078f, 0.0196078f);
+      myBSDF.Roughness = 8;
       break;
     case Graphic3d_NOM_WATER:
       myMaterialType = Graphic3d_MATERIAL_PHYSIC;
@@ -348,6 +432,10 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myDiffuseCoef  = 1.00f;
       mySpecularCoef = 1.00f;
       myRefractionIndex  = 1.33f;
+      myBSDF             = Graphic3d_BSDF::CreateGlass (Graphic3d_Vec3 (1.f),
+                                                        Graphic3d_Vec3 (0.7f, 0.75f, 0.85f),
+                                                        0.05f,
+                                                        myRefractionIndex);
       myTransparencyCoef = 0.80f;
 
       // Color resulting from ambient
@@ -365,6 +453,10 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myDiffuseCoef  = 1.00f;
       mySpecularCoef = 1.00f;
       myRefractionIndex  = 1.62f;
+      myBSDF             = Graphic3d_BSDF::CreateGlass (Graphic3d_Vec3 (1.f),
+                                                        Graphic3d_Vec3 (0.75f, 0.95f, 0.9f),
+                                                        0.05f,
+                                                        myRefractionIndex);
       myTransparencyCoef = 0.80f;
 
       // Color resulting from ambient
@@ -382,6 +474,10 @@ void Graphic3d_MaterialAspect::Init (const Graphic3d_NameOfMaterial theName)
       myDiffuseCoef  = 1.00f;
       mySpecularCoef = 1.00f;
       myRefractionIndex  = 2.42f;
+      myBSDF             = Graphic3d_BSDF::CreateGlass (Graphic3d_Vec3 (1.f),
+                                                        Graphic3d_Vec3 (0.95f, 0.95f, 0.95f),
+                                                        0.05f,
+                                                        myRefractionIndex);
       myTransparencyCoef = 0.80f;
 
       // Color resulting from ambient
@@ -665,6 +761,15 @@ void Graphic3d_MaterialAspect::SetRefractionIndex (const Standard_Real theValue)
 }
 
 // =======================================================================
+// function : SetBSDF
+// purpose  :
+// =======================================================================
+void Graphic3d_MaterialAspect::SetBSDF (const Graphic3d_BSDF& theBSDF)
+{
+  myBSDF = theBSDF;
+}
+
+// =======================================================================
 // function : Color
 // purpose  :
 // =======================================================================
@@ -791,6 +896,15 @@ Standard_Real Graphic3d_MaterialAspect::RefractionIndex() const
 }
 
 // =======================================================================
+// function : BSDF
+// purpose  :
+// =======================================================================
+const Graphic3d_BSDF& Graphic3d_MaterialAspect::BSDF() const
+{
+  return myBSDF;
+}
+
+// =======================================================================
 // function : Shininess
 // purpose  :
 // =======================================================================
@@ -863,6 +977,7 @@ Standard_Boolean Graphic3d_MaterialAspect::IsEqual (const Graphic3d_MaterialAspe
       && myEmissiveCoef     == theOther.myEmissiveCoef
       && myTransparencyCoef == theOther.myTransparencyCoef
       && myRefractionIndex  == theOther.myRefractionIndex
+      && myBSDF             == theOther.myBSDF
       && myShininess        == theOther.myShininess
       && myEnvReflexion     == theOther.myEnvReflexion
       && myAmbientColor     == theOther.myAmbientColor
index 12d1fd0..6f8478f 100644 (file)
@@ -23,6 +23,9 @@ class Graphic3d_RenderingParams
 {
 public:
 
+  //! Default number of samples per pixel.
+  static const Standard_Integer THE_DEFAULT_SPP = 1;
+
   //! Default ray-tracing depth.
   static const Standard_Integer THE_DEFAULT_DEPTH = 3;
 
@@ -30,12 +33,15 @@ public:
 
   //! Creates default rendering parameters.
   Graphic3d_RenderingParams()
-  : Method (Graphic3d_RM_RASTERIZATION),
-    RaytracingDepth (THE_DEFAULT_DEPTH),
-    IsShadowEnabled (Standard_True),
-    IsReflectionEnabled (Standard_False),
-    IsAntialiasingEnabled (Standard_False),
-    IsTransparentShadowEnabled (Standard_False)
+  : Method                      (Graphic3d_RM_RASTERIZATION),
+    RaytracingDepth             (THE_DEFAULT_DEPTH),
+    SamplesPerPixel             (THE_DEFAULT_SPP),
+    IsShadowEnabled             (Standard_True),
+    IsReflectionEnabled         (Standard_False),
+    IsAntialiasingEnabled       (Standard_False),
+    IsTransparentShadowEnabled  (Standard_False),
+    IsGlobalIlluminationEnabled (Standard_False),
+    UseEnvironmentMapBackground (Standard_False)
   {
     //
   }
@@ -48,6 +54,9 @@ public:
   //! Maximum ray-tracing depth.
   Standard_Integer RaytracingDepth;
 
+  //! Number of samples per pixel (SPP).
+  Standard_Integer SamplesPerPixel;
+
   //! Enables/disables shadows rendering.
   Standard_Boolean IsShadowEnabled;
 
@@ -60,6 +69,12 @@ public:
   //! Enables/disables light propagation through transparent media.
   Standard_Boolean IsTransparentShadowEnabled;
 
+  //! Enables/disables global illumination effects (uses path tracing).
+  Standard_Boolean IsGlobalIlluminationEnabled;
+
+  //! Enables/disables environment map background (instead of OCCT background).
+  Standard_Boolean UseEnvironmentMapBackground;
+
 };
 
 #endif // _Graphic3d_RenderingParams_HeaderFile
index befdb95..b834e93 100644 (file)
@@ -807,6 +807,9 @@ Handle(Graphic3d_AspectFillArea3d) Graphic3d_Structure::FillArea3dAspect() const
   aBack.SetEnvReflexion (myCStructure->ContextFillArea.Back.EnvReflexion);
   aBack.SetMaterialType (myCStructure->ContextFillArea.Back.IsPhysic ? Graphic3d_MATERIAL_PHYSIC : Graphic3d_MATERIAL_ASPECT);
 
+  aBack.SetRefractionIndex (Standard_Real (myCStructure->ContextFillArea.Back.RefractionIndex));
+  aBack.SetBSDF (myCStructure->ContextFillArea.Back.BSDF);
+
   // Front Material
   Graphic3d_MaterialAspect aFront;
   aFront.SetShininess    (Standard_Real (myCStructure->ContextFillArea.Front.Shininess));
@@ -855,6 +858,9 @@ Handle(Graphic3d_AspectFillArea3d) Graphic3d_Structure::FillArea3dAspect() const
   aFront.SetEnvReflexion (myCStructure->ContextFillArea.Front.EnvReflexion);
   aFront.SetMaterialType (myCStructure->ContextFillArea.Front.IsPhysic ? Graphic3d_MATERIAL_PHYSIC : Graphic3d_MATERIAL_ASPECT);
 
+  aFront.SetRefractionIndex (Standard_Real (myCStructure->ContextFillArea.Front.RefractionIndex));
+  aFront.SetBSDF (myCStructure->ContextFillArea.Front.BSDF);
+
   Quantity_Color anIntColor  (Standard_Real (myCStructure->ContextFillArea.IntColor.r),
                               Standard_Real (myCStructure->ContextFillArea.IntColor.g),
                               Standard_Real (myCStructure->ContextFillArea.IntColor.b), Quantity_TOC_RGB);
@@ -1004,6 +1010,7 @@ void Graphic3d_Structure::SetPrimitivesAspect (const Handle(Graphic3d_AspectFill
   myCStructure->ContextFillArea.Back.Specular        = float (aBack.Specular());
   myCStructure->ContextFillArea.Back.Transparency    = float (aBack.Transparency());
   myCStructure->ContextFillArea.Back.RefractionIndex = float (aBack.RefractionIndex());
+  myCStructure->ContextFillArea.Back.BSDF            = aBack.BSDF();
   myCStructure->ContextFillArea.Back.Emission        = float (aBack.Emissive());
 
   // Reflection mode
@@ -1048,6 +1055,7 @@ void Graphic3d_Structure::SetPrimitivesAspect (const Handle(Graphic3d_AspectFill
   myCStructure->ContextFillArea.Front.Specular        = float (aFront.Specular());
   myCStructure->ContextFillArea.Front.Transparency    = float (aFront.Transparency());
   myCStructure->ContextFillArea.Front.RefractionIndex = float (aFront.RefractionIndex());
+  myCStructure->ContextFillArea.Front.BSDF            = aFront.BSDF();
   myCStructure->ContextFillArea.Front.Emission        = float (aFront.Emissive());
 
   // Reflection mode
index 2e33160..9f78faa 100644 (file)
 
 #include <InterfaceGraphic_telem.hxx>
 #include <Graphic3d_BndBox4f.hxx>
+#include <Graphic3d_BSDF.hxx>
 #include <Standard_Transient.hxx>
 
 /* COULEUR */
 
 typedef struct {
 
-        float r, g, b;
+  Standard_ShortReal r;
+  Standard_ShortReal g;
+  Standard_ShortReal b;
 
 } CALL_DEF_COLOR;
 
@@ -31,7 +34,9 @@ typedef struct {
 
 typedef struct {
 
-        float x, y, z;
+  Standard_ShortReal x;
+  Standard_ShortReal y;
+  Standard_ShortReal z;
 
 } CALL_DEF_POINT;
 
@@ -39,47 +44,52 @@ typedef struct {
 
 typedef struct {
 
-        float Ambient;
-        int IsAmbient;
+  Standard_ShortReal Ambient;
+  Standard_Integer   IsAmbient;
 
-        float Diffuse;
-        int IsDiffuse;
+  Standard_ShortReal Diffuse;
+  Standard_Integer   IsDiffuse;
 
-        float Specular;
-        int IsSpecular;
+  Standard_ShortReal Specular;
+  Standard_Integer   IsSpecular;
 
-        float Emission;
-        int IsEmission;
+  Standard_ShortReal Emission;
+  Standard_Integer   IsEmission;
 
-        float Shininess;
-        float Transparency;
-        float RefractionIndex;
+  Graphic3d_BSDF     BSDF;
 
-        float EnvReflexion;
+  Standard_ShortReal Shininess;
+  Standard_ShortReal Transparency;
+  Standard_ShortReal RefractionIndex;
 
-        int IsPhysic;
+  Standard_ShortReal EnvReflexion;
 
-        /* Attribut couleur eclairage */
-        CALL_DEF_COLOR ColorAmb, ColorDif, ColorSpec, ColorEms, Color;
+  Standard_Integer   IsPhysic;
 
+  /* Color attributes */
+  CALL_DEF_COLOR     ColorAmb;
+  CALL_DEF_COLOR     ColorDif;
+  CALL_DEF_COLOR     ColorSpec;
+  CALL_DEF_COLOR     ColorEms;
+  CALL_DEF_COLOR     Color;
 
 } CALL_DEF_MATERIAL;
 
 /* Transform persistence struct */
 typedef struct
 {
-        int            IsSet;
-       int            IsDef;
-       int            Flag;
-        CALL_DEF_POINT Point;
+  Standard_Integer IsSet;
+  Standard_Integer IsDef;
+  Standard_Integer Flag;
+  CALL_DEF_POINT   Point;
 } CALL_DEF_TRANSFORM_PERSISTENCE;
 
 /* USERDRAW DATA */
 
 typedef struct {
 
-        void            *Data;
-        Graphic3d_BndBox4f  *Bounds;
+  void*               Data;
+  Graphic3d_BndBox4f* Bounds;
 
 } CALL_DEF_USERDRAW;
 
index 16417be..0aa7366 100644 (file)
@@ -111,6 +111,9 @@ void OpenGl_AspectFace::convertMaterial (const CALL_DEF_MATERIAL& theMat,
   // in OpenGl it is opposite.
   theSurf.trans = 1.0f - theMat.Transparency;
   theSurf.index = theMat.RefractionIndex;
+
+  // material BSDF (for physically-based rendering)
+  theSurf.BSDF = theMat.BSDF;
 }
 
 // =======================================================================
index 45f65fb..0cafe86 100644 (file)
@@ -31,6 +31,7 @@
 #include <Graphic3d_CAspectFillArea.hxx>
 #include <Graphic3d_ShaderProgram.hxx>
 #include <Graphic3d_TextureMap.hxx>
+#include <Graphic3d_BSDF.hxx>
 
 #define OPENGL_AMBIENT_MASK  (1<<0)
 #define OPENGL_DIFFUSE_MASK  (1<<1)
@@ -41,12 +42,28 @@ static const TEL_POFFSET_PARAM THE_DEFAULT_POFFSET = { Aspect_POM_Fill, 1.0F, 0.
 
 struct OPENGL_SURF_PROP
 {
-  float        amb, diff, spec, emsv;
-  float        trans, shine, index;
-  float        env_reflexion;
-  int          isphysic;
+  Standard_ShortReal amb;
+  Standard_ShortReal diff;
+  Standard_ShortReal spec;
+  Standard_ShortReal emsv;
+
+  Standard_ShortReal trans;
+  Standard_ShortReal shine;
+  Standard_ShortReal index;
+
+  Standard_ShortReal env_reflexion;
+  Standard_Integer   isphysic;
+
   unsigned int color_mask;
-  TEL_COLOUR speccol, difcol, ambcol, emscol, matcol;
+
+  TEL_COLOUR speccol;
+  TEL_COLOUR difcol;
+  TEL_COLOUR ambcol;
+  TEL_COLOUR emscol;
+  TEL_COLOUR matcol;
+
+  Graphic3d_BSDF BSDF;
+
   DEFINE_STANDARD_ALLOC
 };
 
index ab45828..efdb1b6 100644 (file)
@@ -53,6 +53,9 @@ public:
   //! Gets background gradient fill method
   Aspect_GradientFillMethod GradientFillMethod() const { return myGradientParams.type; }
 
+  //! Returns color of gradient background for the given index.
+  const OpenGl_Vec4& GradientColor (const Standard_Integer theIndex) const { return (&myGradientParams.color1)[theIndex]; }
+
   //! Sets type of gradient fill method
   Standard_EXPORT void SetGradientFillMethod (const Aspect_GradientFillMethod theType);
 
index 2e0c192..18c21c8 100644 (file)
@@ -139,6 +139,7 @@ Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& the
 {
   if (myVPSizeX == theViewportSizeX
    && myVPSizeY == theViewportSizeY)
+
   {
     return IsValid();
   }
index 60740ae..c83f256 100755 (executable)
@@ -72,6 +72,32 @@ public:
   //! Texture transformation matrix.
   BVH_Mat4f TextureTransform;
 
+  //! Physically-based material properties (used in path tracing engine).
+  struct Physical
+  {
+    //! Weight of the diffuse BRDF.
+    BVH_Vec4f Kd;
+
+    //! Weight of the reflection BRDF.
+    BVH_Vec4f Kr;
+
+    //! Weight of the transmission BTDF.
+    BVH_Vec4f Kt;
+
+    //! Weight of the Blinn's glossy BRDF.
+    BVH_Vec4f Ks;
+
+    //! Self-emitted radiance.
+    BVH_Vec4f Le;
+
+    //! Fresnel coefficients.
+    BVH_Vec4f Fresnel;
+
+    //! Absorption color for the transmission BSDF.
+    BVH_Vec4f Absorption;
+
+  } BSDF;
+
 public:
 
   //! Creates new default material.
index ac96195..4209053 100644 (file)
@@ -190,7 +190,7 @@ public:
   //! Returns structure modification state (for ray-tracing).
   Standard_Size ModificationState() const { return myModificationState; }
 
-  //! Resets structure modification state (for ray-tracing)
+  //! Resets structure modification state (for ray-tracing).
   void ResetModificationState() const { myModificationState = 0; }
 
   //! Is the structure ray-tracable (contains ray-tracable elements)?
index 44926c3..d293880 100644 (file)
@@ -81,7 +81,7 @@ OpenGl_View::OpenGl_View (const CALL_DEF_VIEWCONTEXT &AContext,
   myIsRaytraceDataValid (Standard_False),
   myIsRaytraceWarnTextures (Standard_False),
   myToUpdateEnvironmentMap (Standard_False),
-  myLayersModificationStatus (0)
+  myLayerListState (0)
 {
   myCurrLightSourceState = myStateCounter->Increment();
 }
index aa41691..8fc9d71 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <TColStd_Array2OfReal.hxx>
 #include <NCollection_List.hxx>
+#include <math_BullardGenerator.hxx>
 
 #include <Quantity_NameOfColor.hxx>
 #include <Aspect_FillMethod.hxx>
@@ -318,6 +319,7 @@ protected: //! @name data types related to ray-tracing
   {
     OpenGl_RT_aPosition,
 
+    // camera position
     OpenGl_RT_uOriginLT,
     OpenGl_RT_uOriginLB,
     OpenGl_RT_uOriginRT,
@@ -328,22 +330,31 @@ protected: //! @name data types related to ray-tracing
     OpenGl_RT_uDirectRB,
     OpenGl_RT_uUnviewMat,
 
+    // 3D scene params
     OpenGl_RT_uSceneRad,
     OpenGl_RT_uSceneEps,
     OpenGl_RT_uLightAmbnt,
     OpenGl_RT_uLightCount,
 
-    OpenGl_RT_uShadEnabled,
-    OpenGl_RT_uReflEnabled,
-    OpenGl_RT_uEnvMapEnable,
+    // background params
+    OpenGl_RT_uBackColorTop,
+    OpenGl_RT_uBackColorBot,
 
+    // ray-tracing params
+    OpenGl_RT_uShadowsEnabled,
+    OpenGl_RT_uReflectEnabled,
+    OpenGl_RT_uSphereMapEnabled,
+    OpenGl_RT_uSphereMapForBack,
+    OpenGl_RT_uTexSamplersArray,
+
+    // sampled frame params
+    OpenGl_RT_uSampleWeight,
+    OpenGl_RT_uFrameRndSeed,
+
+    // adaptive FSAA params
     OpenGl_RT_uOffsetX,
     OpenGl_RT_uOffsetY,
     OpenGl_RT_uSamples,
-    OpenGl_RT_uWinSizeX,
-    OpenGl_RT_uWinSizeY,
-
-    OpenGl_RT_uTextures,
 
     OpenGl_RT_NbVariables // special field
   };
@@ -366,10 +377,11 @@ protected: //! @name data types related to ray-tracing
     OpenGl_RT_RaytraceMaterialTexture = 9,
     OpenGl_RT_RaytraceLightSrcTexture = 10,
 
-    OpenGl_RT_FSAAInputTexture = 11,
+    OpenGl_RT_FsaaInputTexture = 11,
+    OpenGl_RT_PrevAccumTexture = 12,
 
-    OpenGl_RT_OpenGlColorTexture = 12,
-    OpenGl_RT_OpenGlDepthTexture = 13
+    OpenGl_RT_OpenGlColorTexture = 13,
+    OpenGl_RT_OpenGlDepthTexture = 14
   };
 
   //! Tool class for management of shader sources.
@@ -377,6 +389,9 @@ protected: //! @name data types related to ray-tracing
   {
   public:
 
+    //! Default shader prefix - empty string.
+    static const TCollection_AsciiString EMPTY_PREFIX;
+
     //! Creates new uninitialized shader source.
     ShaderSource()
     {
@@ -384,9 +399,11 @@ protected: //! @name data types related to ray-tracing
     }
 
     //! Creates new shader source from specified file.
-    ShaderSource (const TCollection_AsciiString& theFileName)
+    ShaderSource (const TCollection_AsciiString& theFileName, const TCollection_AsciiString& thePrefix = EMPTY_PREFIX)
     {
-      Load (&theFileName, 1);
+      TCollection_AsciiString aFileNames[] = { theFileName, "" };
+
+      Load (aFileNames, thePrefix);
     }
 
   public:
@@ -407,7 +424,7 @@ protected: //! @name data types related to ray-tracing
     TCollection_AsciiString Source() const;
 
     //! Loads shader source from specified files.
-    void Load (const TCollection_AsciiString* theFileNames, const Standard_Integer theCount);
+    void Load (const TCollection_AsciiString* theFileNames, const TCollection_AsciiString& thePrefix = EMPTY_PREFIX);
 
   private:
 
@@ -434,6 +451,9 @@ protected: //! @name data types related to ray-tracing
     //! Enables/disables light propagation through transparent media.
     Standard_Boolean TransparentShadows;
 
+    //! Enables/disables global illumination (GI) effects.
+    Standard_Boolean GlobalIllumination;
+
     //! Enables/disables the use of OpenGL bindless textures.
     Standard_Boolean UseBindlessTextures;
 
@@ -442,6 +462,7 @@ protected: //! @name data types related to ray-tracing
     : StackSize (THE_DEFAULT_STACK_SIZE),
       NbBounces (THE_DEFAULT_NB_BOUNCES),
       TransparentShadows (Standard_False),
+      GlobalIllumination  (Standard_False),
       UseBindlessTextures (Standard_False)
     {
       //
@@ -572,6 +593,11 @@ protected: //! @name methods related to ray-tracing
                                           const ShaderSource&           theSource,
                                           const Handle(OpenGl_Context)& theGlContext);
 
+  //! Creates shader program from the given vertex and fragment shaders.
+  Handle(OpenGl_ShaderProgram) initProgram (const Handle(OpenGl_Context)&      theGlContext,
+                                            const Handle(OpenGl_ShaderObject)& theVertShader,
+                                            const Handle(OpenGl_ShaderObject)& theFragShader);
+
   //! Initializes OpenGL/GLSL shader programs.
   Standard_Boolean initRaytraceResources (const Graphic3d_CView&        theCView,
                                           const Handle(OpenGl_Context)& theGlContext);
@@ -658,6 +684,8 @@ protected: //! @name fields related to ray-tracing
   Handle(OpenGl_ShaderProgram) myRaytraceProgram;
   //! OpenGL/GLSL adaptive-AA shader program.
   Handle(OpenGl_ShaderProgram) myPostFSAAProgram;
+  //! OpenGL/GLSL program for displaying texture.
+  Handle(OpenGl_ShaderProgram) myOutImageProgram;
 
   //! Texture buffer of data records of bottom-level BVH nodes.
   Handle(OpenGl_TextureBufferArb) mySceneNodeInfoTexture;
@@ -701,14 +729,26 @@ protected: //! @name fields related to ray-tracing
   //! PrimitiveArray to TriangleSet map for scene partial update.
   std::map<Standard_Size, OpenGl_TriangleSet*> myArrayToTrianglesMap;
 
-  //! Graphical ray-tracing filter to filter out all raytracable structures.
+  //! Set of IDs of non-raytracable elements (to detect updates).
+  std::set<Standard_Integer> myNonRaytraceStructureIDs;
+
+  //! Render filter to filter out all raytracable structures.
   Handle(OpenGl_RaytraceFilter) myRaytraceFilter;
 
   //! Marks if environment map should be updated.
   Standard_Boolean myToUpdateEnvironmentMap;
 
   //! State of OpenGL layer list.
-  Standard_Size myLayersModificationStatus;
+  Standard_Size myLayerListState;
+
+  //! Number of accumulated frames (for progressive rendering).
+  Standard_Integer myAccumFrames;
+
+  //! Stored ray origins used for detection of camera movements.
+  OpenGl_Vec3 myPreviousOrigins[3];
+
+  //! Bullard RNG to produce random sequence.
+  math_BullardGenerator myRNG;
 
 public:
 
index 728c98c..b51d479 100644 (file)
@@ -33,7 +33,7 @@ using namespace OpenGl_Raytrace;
 #endif
 
 // =======================================================================
-// function : UpdateRaytraceGeometry
+// function : updateRaytraceGeometry
 // purpose  : Updates 3D scene geometry for ray-tracing
 // =======================================================================
 Standard_Boolean OpenGl_View::updateRaytraceGeometry (const RaytraceUpdateMode      theMode,
@@ -44,7 +44,7 @@ Standard_Boolean OpenGl_View::updateRaytraceGeometry (const RaytraceUpdateMode
   // modifications. This is light-weight procedure performed on each frame
   if (theMode == OpenGl_GUM_CHECK)
   {
-    if (myLayersModificationStatus != myZLayers.ModificationState())
+    if (myLayerListState != myZLayers.ModificationState())
     {
       return updateRaytraceGeometry (OpenGl_GUM_PREPARE, theViewId, theGlContext);
     }
@@ -67,6 +67,10 @@ Standard_Boolean OpenGl_View::updateRaytraceGeometry (const RaytraceUpdateMode
   // applicable for ray-tracing
   std::set<Standard_Size> anArrayIDs;
 
+  // Set to store all non-raytracable elements allowing tracking
+  // of changes in OpenGL scene (only for path tracing)
+  std::set<Standard_Integer> aNonRaytraceIDs;
+
   const OpenGl_Layer& aLayer = myZLayers.Layer (Graphic3d_ZLayerId_Default);
 
   if (aLayer.NbStructures() != 0)
@@ -85,6 +89,10 @@ Standard_Boolean OpenGl_View::updateRaytraceGeometry (const RaytraceUpdateMode
           {
             return updateRaytraceGeometry (OpenGl_GUM_PREPARE, theViewId, theGlContext);
           }
+          else if (aStructure->IsVisible() && myRaytraceParameters.GlobalIllumination)
+          {
+            aNonRaytraceIDs.insert (aStructure->highlight ? aStructure->Id : -aStructure->Id);
+          }
         }
         else if (theMode == OpenGl_GUM_PREPARE)
         {
@@ -172,7 +180,7 @@ Standard_Boolean OpenGl_View::updateRaytraceGeometry (const RaytraceUpdateMode
     }
 
     // Actualize OpenGL layer list state
-    myLayersModificationStatus = myZLayers.ModificationState();
+    myLayerListState = myZLayers.ModificationState();
 
     // Rebuild two-level acceleration structure
     myRaytraceGeometry.ProcessAcceleration();
@@ -188,11 +196,30 @@ Standard_Boolean OpenGl_View::updateRaytraceGeometry (const RaytraceUpdateMode
     return uploadRaytraceData (theGlContext);
   }
 
+  if (myRaytraceParameters.GlobalIllumination)
+  {
+    Standard_Boolean toRestart =
+      aNonRaytraceIDs.size() != myNonRaytraceStructureIDs.size();
+
+    for (std::set<Standard_Integer>::iterator anID = aNonRaytraceIDs.begin(); anID != aNonRaytraceIDs.end() && !toRestart; ++anID)
+    {
+      if (myNonRaytraceStructureIDs.find (*anID) == myNonRaytraceStructureIDs.end())
+      {
+        toRestart = Standard_True;
+      }
+    }
+
+    if (toRestart)
+      myAccumFrames = 0;
+
+    myNonRaytraceStructureIDs = aNonRaytraceIDs;
+  }
+
   return Standard_True;
 }
 
 // =======================================================================
-// function : ToUpdateStructure
+// function : toUpdateStructure
 // purpose  : Checks to see if the structure is modified
 // =======================================================================
 Standard_Boolean OpenGl_View::toUpdateStructure (const OpenGl_Structure* theStructure)
@@ -224,10 +251,10 @@ Standard_Boolean OpenGl_View::toUpdateStructure (const OpenGl_Structure* theStru
 }
 
 // =======================================================================
-// function : BuildTextureTransform
+// function : buildTextureTransform
 // purpose  : Constructs texture transformation matrix
 // =======================================================================
-void BuildTextureTransform (const Handle(Graphic3d_TextureParams)& theParams, BVH_Mat4f& theMatrix)
+void buildTextureTransform (const Handle(Graphic3d_TextureParams)& theParams, BVH_Mat4f& theMatrix)
 {
   theMatrix.InitIdentity();
 
@@ -272,7 +299,7 @@ void BuildTextureTransform (const Handle(Graphic3d_TextureParams)& theParams, BV
 }
 
 // =======================================================================
-// function : ConvertMaterial
+// function : convertMaterial
 // purpose  : Creates ray-tracing material properties
 // =======================================================================
 OpenGl_RaytraceMaterial OpenGl_View::convertMaterial (const OpenGl_AspectFace*      theAspect,
@@ -323,15 +350,30 @@ OpenGl_RaytraceMaterial OpenGl_View::convertMaterial (const OpenGl_AspectFace*
     aProperties.speccol.rgb[2] * aProperties.spec * aReflectionScale,
     0.f);
 
+  // Serialize physically-based material properties
+  const Graphic3d_BSDF& aBSDF = aProperties.BSDF;
+
+  theMaterial.BSDF.Le = BVH_Vec4f (aBSDF.Le,               0.f);
+  theMaterial.BSDF.Kd = BVH_Vec4f (aBSDF.Kd, -1.f /* no tex */);
+  theMaterial.BSDF.Kr = BVH_Vec4f (aBSDF.Kr,               0.f);
+  theMaterial.BSDF.Kt = BVH_Vec4f (aBSDF.Kt,               0.f);
+  theMaterial.BSDF.Ks = BVH_Vec4f (aBSDF.Ks,   aBSDF.Roughness);
+
+  theMaterial.BSDF.Fresnel = aBSDF.Fresnel.Serialize();
+
+  theMaterial.BSDF.Absorption = BVH_Vec4f (aBSDF.AbsorptionColor,
+                                           aBSDF.AbsorptionCoeff);
+
+  // Handle material textures
   if (theAspect->DoTextureMap())
   {
     if (theGlContext->arbTexBindless != NULL)
     {
-      BuildTextureTransform (theAspect->TextureParams(), theMaterial.TextureTransform);
+      buildTextureTransform (theAspect->TextureParams(), theMaterial.TextureTransform);
 
-      // write texture ID in the w-component
-      theMaterial.Diffuse.w() = static_cast<Standard_ShortReal> (
-        myRaytraceGeometry.AddTexture (theAspect->TextureRes (theGlContext)));
+      // write texture ID to diffuse w-component
+      theMaterial.Diffuse.w() = theMaterial.BSDF.Kd.w() =
+        static_cast<Standard_ShortReal> (myRaytraceGeometry.AddTexture (theAspect->TextureRes (theGlContext)));
     }
     else if (!myIsRaytraceWarnTextures)
     {
@@ -350,7 +392,7 @@ OpenGl_RaytraceMaterial OpenGl_View::convertMaterial (const OpenGl_AspectFace*
 }
 
 // =======================================================================
-// function : AddRaytraceStructure
+// function : addRaytraceStructure
 // purpose  : Adds OpenGL structure to ray-traced scene geometry
 // =======================================================================
 Standard_Boolean OpenGl_View::addRaytraceStructure (const OpenGl_Structure*       theStructure,
@@ -406,7 +448,7 @@ Standard_Boolean OpenGl_View::addRaytraceStructure (const OpenGl_Structure*
 }
 
 // =======================================================================
-// function : AddRaytraceGroups
+// function : addRaytraceGroups
 // purpose  : Adds OpenGL groups to ray-traced scene geometry
 // =======================================================================
 Standard_Boolean OpenGl_View::addRaytraceGroups (const OpenGl_Structure*       theStructure,
@@ -503,7 +545,7 @@ Standard_Boolean OpenGl_View::addRaytraceGroups (const OpenGl_Structure*       t
 }
 
 // =======================================================================
-// function : AddRaytracePrimitiveArray
+// function : addRaytracePrimitiveArray
 // purpose  : Adds OpenGL primitive array to ray-traced scene geometry
 // =======================================================================
 OpenGl_TriangleSet* OpenGl_View::addRaytracePrimitiveArray (const OpenGl_PrimitiveArray* theArray,
@@ -668,7 +710,7 @@ OpenGl_TriangleSet* OpenGl_View::addRaytracePrimitiveArray (const OpenGl_Primiti
 }
 
 // =======================================================================
-// function : AddRaytraceVertexIndices
+// function : addRaytraceVertexIndices
 // purpose  : Adds vertex indices to ray-traced scene geometry
 // =======================================================================
 Standard_Boolean OpenGl_View::addRaytraceVertexIndices (OpenGl_TriangleSet&                  theSet,
@@ -693,7 +735,7 @@ Standard_Boolean OpenGl_View::addRaytraceVertexIndices (OpenGl_TriangleSet&
 }
 
 // =======================================================================
-// function : AddRaytraceTriangleArray
+// function : addRaytraceTriangleArray
 // purpose  : Adds OpenGL triangle array to ray-traced scene geometry
 // =======================================================================
 Standard_Boolean OpenGl_View::addRaytraceTriangleArray (OpenGl_TriangleSet&                  theSet,
@@ -731,7 +773,7 @@ Standard_Boolean OpenGl_View::addRaytraceTriangleArray (OpenGl_TriangleSet&
 }
 
 // =======================================================================
-// function : AddRaytraceTriangleFanArray
+// function : addRaytraceTriangleFanArray
 // purpose  : Adds OpenGL triangle fan array to ray-traced scene geometry
 // =======================================================================
 Standard_Boolean OpenGl_View::addRaytraceTriangleFanArray (OpenGl_TriangleSet&                  theSet,
@@ -772,7 +814,7 @@ Standard_Boolean OpenGl_View::addRaytraceTriangleFanArray (OpenGl_TriangleSet&
 }
 
 // =======================================================================
-// function : AddRaytraceTriangleStripArray
+// function : addRaytraceTriangleStripArray
 // purpose  : Adds OpenGL triangle strip array to ray-traced scene geometry
 // =======================================================================
 Standard_Boolean OpenGl_View::addRaytraceTriangleStripArray (OpenGl_TriangleSet&                  theSet,
@@ -813,7 +855,7 @@ Standard_Boolean OpenGl_View::addRaytraceTriangleStripArray (OpenGl_TriangleSet&
 }
 
 // =======================================================================
-// function : AddRaytraceQuadrangleArray
+// function : addRaytraceQuadrangleArray
 // purpose  : Adds OpenGL quad array to ray-traced scene geometry
 // =======================================================================
 Standard_Boolean OpenGl_View::addRaytraceQuadrangleArray (OpenGl_TriangleSet&                  theSet,
@@ -858,7 +900,7 @@ Standard_Boolean OpenGl_View::addRaytraceQuadrangleArray (OpenGl_TriangleSet&
 }
 
 // =======================================================================
-// function : AddRaytraceQuadrangleStripArray
+// function : addRaytraceQuadrangleStripArray
 // purpose  : Adds OpenGL quad strip array to ray-traced scene geometry
 // =======================================================================
 Standard_Boolean OpenGl_View::addRaytraceQuadrangleStripArray (OpenGl_TriangleSet&                  theSet,
@@ -909,7 +951,7 @@ Standard_Boolean OpenGl_View::addRaytraceQuadrangleStripArray (OpenGl_TriangleSe
 }
 
 // =======================================================================
-// function : AddRaytracePolygonArray
+// function : addRaytracePolygonArray
 // purpose  : Adds OpenGL polygon array to ray-traced scene geometry
 // =======================================================================
 Standard_Boolean OpenGl_View::addRaytracePolygonArray (OpenGl_TriangleSet&                  theSet,
@@ -949,6 +991,8 @@ Standard_Boolean OpenGl_View::addRaytracePolygonArray (OpenGl_TriangleSet&
   return Standard_True;
 }
 
+const TCollection_AsciiString OpenGl_View::ShaderSource::EMPTY_PREFIX;
+
 // =======================================================================
 // function : Source
 // purpose  : Returns shader source combined with prefix
@@ -970,11 +1014,11 @@ TCollection_AsciiString OpenGl_View::ShaderSource::Source() const
 // purpose  : Loads shader source from specified files
 // =======================================================================
 void OpenGl_View::ShaderSource::Load (const TCollection_AsciiString* theFileNames,
-                                      const Standard_Integer         theCount)
+                                      const TCollection_AsciiString& thePrefix)
 {
   mySource.Clear();
 
-  for (Standard_Integer anIndex = 0; anIndex < theCount; ++anIndex)
+  for (Standard_Integer anIndex = 0; !theFileNames[anIndex].IsEmpty(); ++anIndex)
   {
     OSD_File aFile (theFileNames[anIndex]);
 
@@ -997,10 +1041,12 @@ void OpenGl_View::ShaderSource::Load (const TCollection_AsciiString* theFileName
 
     aFile.Close();
   }
+
+  myPrefix = thePrefix;
 }
 
 // =======================================================================
-// function : GenerateShaderPrefix
+// function : generateShaderPrefix
 // purpose  : Generates shader prefix based on current ray-tracing options
 // =======================================================================
 TCollection_AsciiString OpenGl_View::generateShaderPrefix (const Handle(OpenGl_Context)& theGlContext) const
@@ -1022,11 +1068,16 @@ TCollection_AsciiString OpenGl_View::generateShaderPrefix (const Handle(OpenGl_C
       TCollection_AsciiString ("\n#define MAX_TEX_NUMBER ") + TCollection_AsciiString (OpenGl_RaytraceGeometry::MAX_TEX_NUMBER);
   }
 
+  if (myRaytraceParameters.GlobalIllumination)
+  {
+    aPrefixString += TCollection_AsciiString ("\n#define PATH_TRACING");
+  }
+
   return aPrefixString;
 }
 
 // =======================================================================
-// function : SafeFailBack
+// function : safeFailBack
 // purpose  : Performs safe exit when shaders initialization fails
 // =======================================================================
 Standard_Boolean OpenGl_View::safeFailBack (const TCollection_ExtendedString& theMessage,
@@ -1043,7 +1094,7 @@ Standard_Boolean OpenGl_View::safeFailBack (const TCollection_ExtendedString& th
 }
 
 // =======================================================================
-// function : InitShader
+// function : initShader
 // purpose  : Creates new shader object with specified source
 // =======================================================================
 Handle(OpenGl_ShaderObject) OpenGl_View::initShader (const GLenum                  theType,
@@ -1112,7 +1163,71 @@ Handle(OpenGl_ShaderObject) OpenGl_View::initShader (const GLenum
 }
 
 // =======================================================================
-// function : InitRaytraceResources
+// function : initProgram
+// purpose  : Creates GLSL program from the given shader objects
+// =======================================================================
+Handle(OpenGl_ShaderProgram) OpenGl_View::initProgram (const Handle(OpenGl_Context)&      theGlContext,
+                                                       const Handle(OpenGl_ShaderObject)& theVertShader,
+                                                       const Handle(OpenGl_ShaderObject)& theFragShader)
+{
+  Handle(OpenGl_ShaderProgram) aProgram = new OpenGl_ShaderProgram;
+
+  if (!aProgram->Create (theGlContext))
+  {
+    theVertShader->Release (theGlContext.operator->());
+
+    theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
+      GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, "Failed to create shader program");
+
+    return Handle(OpenGl_ShaderProgram)();
+  }
+
+  if (!aProgram->AttachShader (theGlContext, theVertShader)
+   || !aProgram->AttachShader (theGlContext, theFragShader))
+  {
+    theVertShader->Release (theGlContext.operator->());
+
+    theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
+      GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, "Failed to attach shader objects");
+
+    return Handle(OpenGl_ShaderProgram)();
+  }
+
+  aProgram->SetAttributeName (theGlContext, Graphic3d_TOA_POS, "occVertex");
+
+  TCollection_AsciiString aLinkLog;
+
+  if (!aProgram->Link (theGlContext))
+  {
+    aProgram->FetchInfoLog (theGlContext, aLinkLog);
+
+    const TCollection_ExtendedString aMessage = TCollection_ExtendedString (
+      "Failed to link shader program:\n") + aLinkLog;
+
+    theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
+      GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMessage);
+
+    return Handle(OpenGl_ShaderProgram)();
+  }
+  else if (theGlContext->caps->glslWarnings)
+  {
+    myRaytraceProgram->FetchInfoLog (theGlContext, aLinkLog);
+
+    if (!aLinkLog.IsEmpty() && !aLinkLog.IsEqual ("No errors.\n"))
+    {
+      const TCollection_ExtendedString aMessage = TCollection_ExtendedString (
+        "Shader program was linked with following warnings:\n") + aLinkLog;
+
+      theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
+        GL_DEBUG_TYPE_PORTABILITY_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, aMessage);
+    }
+  }
+
+  return aProgram;
+}
+
+// =======================================================================
+// function : initRaytraceResources
 // purpose  : Initializes OpenGL/GLSL shader programs
 // =======================================================================
 Standard_Boolean OpenGl_View::initRaytraceResources (const Graphic3d_CView& theCView, const Handle(OpenGl_Context)& theGlContext)
@@ -1168,13 +1283,18 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Graphic3d_CView& theC
       aToRebuildShaders = Standard_True;
     }
 
+    if (theCView.RenderParams.IsGlobalIlluminationEnabled != myRaytraceParameters.GlobalIllumination)
+    {
+      myRaytraceParameters.GlobalIllumination = theCView.RenderParams.IsGlobalIlluminationEnabled;
+      aToRebuildShaders = Standard_True;
+    }
+
     if (aToRebuildShaders)
     {
-#ifdef RAY_TRACE_PRINT_INFO
-      std::cout << "Info: Rebuild shaders with stack size: " << myRaytraceParameters.StackSize << std::endl;
-#endif
+      // Reject accumulated frames
+      myAccumFrames = 0;
 
-      // Change state to force update all uniforms
+      // We need to update environment texture
       myToUpdateEnvironmentMap = Standard_True;
 
       TCollection_AsciiString aPrefixString = generateShaderPrefix (theGlContext);
@@ -1254,11 +1374,11 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Graphic3d_CView& theC
       }
 
       TCollection_AsciiString aFiles[] = { aFolder + "/RaytraceBase.fs",
-                                           aFolder + "/RaytraceRender.fs" };
-
-      myRaytraceShaderSource.Load (aFiles, 2);
+                                           aFolder + "/PathtraceBase.fs",
+                                           aFolder + "/RaytraceRender.fs",
+                                           "" };
 
-      myRaytraceShaderSource.SetPrefix (aPrefixString);
+      myRaytraceShaderSource.Load (aFiles, aPrefixString);
 
       myRaytraceShader = initShader (GL_FRAGMENT_SHADER, myRaytraceShaderSource, theGlContext);
 
@@ -1269,46 +1389,11 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Graphic3d_CView& theC
         return safeFailBack ("Failed to initialize ray-trace fragment shader", theGlContext);
       }
 
-      myRaytraceProgram = new OpenGl_ShaderProgram;
+      myRaytraceProgram = initProgram (theGlContext, aBasicVertShader, myRaytraceShader);
 
-      if (!myRaytraceProgram->Create (theGlContext))
+      if (myRaytraceProgram.IsNull())
       {
-        aBasicVertShader->Release (theGlContext.operator->());
-
-        return safeFailBack ("Failed to create ray-trace shader program", theGlContext);
-      }
-
-      if (!myRaytraceProgram->AttachShader (theGlContext, aBasicVertShader)
-       || !myRaytraceProgram->AttachShader (theGlContext, myRaytraceShader))
-      {
-        aBasicVertShader->Release (theGlContext.operator->());
-
-        return safeFailBack ("Failed to attach ray-trace shader objects", theGlContext);
-      }
-
-      myRaytraceProgram->SetAttributeName (theGlContext, Graphic3d_TOA_POS, "occVertex");
-
-      TCollection_AsciiString aLinkLog;
-
-      if (!myRaytraceProgram->Link (theGlContext))
-      {
-        myRaytraceProgram->FetchInfoLog (theGlContext, aLinkLog);
-
-        return safeFailBack (TCollection_ExtendedString (
-          "Failed to link ray-trace shader program:\n") + aLinkLog, theGlContext);
-      }
-      else if (theGlContext->caps->glslWarnings)
-      {
-        myRaytraceProgram->FetchInfoLog (theGlContext, aLinkLog);
-
-        if (!aLinkLog.IsEmpty() && !aLinkLog.IsEqual ("No errors.\n"))
-        {
-          const TCollection_ExtendedString aMessage = TCollection_ExtendedString (
-            "Ray-trace shader program was linked with following warnings:\n") + aLinkLog;
-
-          theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
-            GL_DEBUG_TYPE_PORTABILITY_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, aMessage);
-        }
+        return safeFailBack ("Failed to initialize ray-trace shader program", theGlContext);
       }
     }
 
@@ -1322,12 +1407,11 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Graphic3d_CView& theC
       }
 
       TCollection_AsciiString aFiles[] = { aFolder + "/RaytraceBase.fs",
-                                           aFolder + "/RaytraceSmooth.fs" };
+                                           aFolder + "/RaytraceSmooth.fs",
+                                           "" };
 
-      myPostFSAAShaderSource.Load (aFiles, 2);
+      myPostFSAAShaderSource.Load (aFiles, aPrefixString);
 
-      myPostFSAAShaderSource.SetPrefix (aPrefixString);
-    
       myPostFSAAShader = initShader (GL_FRAGMENT_SHADER, myPostFSAAShaderSource, theGlContext);
 
       if (myPostFSAAShader.IsNull())
@@ -1337,46 +1421,38 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Graphic3d_CView& theC
         return safeFailBack ("Failed to initialize FSAA fragment shader", theGlContext);
       }
 
-      myPostFSAAProgram = new OpenGl_ShaderProgram;
+      myPostFSAAProgram = initProgram (theGlContext, aBasicVertShader, myPostFSAAShader);
 
-      if (!myPostFSAAProgram->Create (theGlContext))
+      if (myPostFSAAProgram.IsNull())
       {
-        aBasicVertShader->Release (theGlContext.operator->());
-
-        return safeFailBack ("Failed to create FSAA shader program", theGlContext);
+        return safeFailBack ("Failed to initialize FSAA shader program", theGlContext);
       }
+    }
 
-      if (!myPostFSAAProgram->AttachShader (theGlContext, aBasicVertShader)
-       || !myPostFSAAProgram->AttachShader (theGlContext, myPostFSAAShader))
-      {
-        aBasicVertShader->Release (theGlContext.operator->());
+    {
+      Handle(OpenGl_ShaderObject) aBasicVertShader = initShader (
+        GL_VERTEX_SHADER, ShaderSource (aFolder + "/RaytraceBase.vs"), theGlContext);
 
-        return safeFailBack ("Failed to attach FSAA shader objects", theGlContext);
+      if (aBasicVertShader.IsNull())
+      {
+        return safeFailBack ("Failed to set vertex shader source", theGlContext);
       }
 
-      myPostFSAAProgram->SetAttributeName (theGlContext, Graphic3d_TOA_POS, "occVertex");
-
-      TCollection_AsciiString aLinkLog;
+      Handle(OpenGl_ShaderObject) aDisplayShader = initShader (
+        GL_FRAGMENT_SHADER, ShaderSource (aFolder + "/Display.fs", aPrefixString), theGlContext);
 
-      if (!myPostFSAAProgram->Link (theGlContext))
+      if (aDisplayShader.IsNull())
       {
-        myPostFSAAProgram->FetchInfoLog (theGlContext, aLinkLog);
-      
-        return safeFailBack (TCollection_ExtendedString (
-          "Failed to link FSAA shader program:\n") + aLinkLog, theGlContext);
+        aBasicVertShader->Release (theGlContext.operator->());
+
+        return safeFailBack ("Failed to set display fragment shader source", theGlContext);
       }
-      else if (theGlContext->caps->glslWarnings)
-      {
-        myPostFSAAProgram->FetchInfoLog (theGlContext, aLinkLog);
 
-        if (!aLinkLog.IsEmpty() && !aLinkLog.IsEqual ("No errors.\n"))
-        {
-          const TCollection_ExtendedString aMessage = TCollection_ExtendedString (
-            "FSAA shader program was linked with following warnings:\n") + aLinkLog;
+      myOutImageProgram = initProgram (theGlContext, aBasicVertShader, aDisplayShader);
 
-          theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
-            GL_DEBUG_TYPE_PORTABILITY_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, aMessage);
-        }
+      if (myOutImageProgram.IsNull())
+      {
+        return safeFailBack ("Failed to initialize output shader program", theGlContext);
       }
     }
   }
@@ -1421,7 +1497,12 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Graphic3d_CView& theC
       if (anIndex == 1)
       {
         aShaderProgram->SetSampler (theGlContext,
-          "uFSAAInputTexture", OpenGl_RT_FSAAInputTexture);
+          "uFSAAInputTexture", OpenGl_RT_FsaaInputTexture);
+      }
+      else
+      {
+        aShaderProgram->SetSampler (theGlContext,
+          "uAccumTexture", OpenGl_RT_PrevAccumTexture);
       }
 
       myUniformLocations[anIndex][OpenGl_RT_aPosition] =
@@ -1461,22 +1542,35 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Graphic3d_CView& theC
         aShaderProgram->GetUniformLocation (theGlContext, "uOffsetY");
       myUniformLocations[anIndex][OpenGl_RT_uSamples] =
         aShaderProgram->GetUniformLocation (theGlContext, "uSamples");
-      myUniformLocations[anIndex][OpenGl_RT_uWinSizeX] =
-        aShaderProgram->GetUniformLocation (theGlContext, "uWinSizeX");
-      myUniformLocations[anIndex][OpenGl_RT_uWinSizeY] =
-        aShaderProgram->GetUniformLocation (theGlContext, "uWinSizeY");
 
-      myUniformLocations[anIndex][OpenGl_RT_uTextures] =
+      myUniformLocations[anIndex][OpenGl_RT_uTexSamplersArray] =
         aShaderProgram->GetUniformLocation (theGlContext, "uTextureSamplers");
 
-      myUniformLocations[anIndex][OpenGl_RT_uShadEnabled] =
-        aShaderProgram->GetUniformLocation (theGlContext, "uShadowsEnable");
-      myUniformLocations[anIndex][OpenGl_RT_uReflEnabled] =
-        aShaderProgram->GetUniformLocation (theGlContext, "uReflectionsEnable");
-      myUniformLocations[anIndex][OpenGl_RT_uEnvMapEnable] =
-        aShaderProgram->GetUniformLocation (theGlContext, "uEnvironmentEnable");
+      myUniformLocations[anIndex][OpenGl_RT_uShadowsEnabled] =
+        aShaderProgram->GetUniformLocation (theGlContext, "uShadowsEnabled");
+      myUniformLocations[anIndex][OpenGl_RT_uReflectEnabled] =
+        aShaderProgram->GetUniformLocation (theGlContext, "uReflectEnabled");
+      myUniformLocations[anIndex][OpenGl_RT_uSphereMapEnabled] =
+        aShaderProgram->GetUniformLocation (theGlContext, "uSphereMapEnabled");
+      myUniformLocations[anIndex][OpenGl_RT_uSphereMapForBack] =
+        aShaderProgram->GetUniformLocation (theGlContext, "uSphereMapForBack");
+
+      myUniformLocations[anIndex][OpenGl_RT_uSampleWeight] =
+        aShaderProgram->GetUniformLocation (theGlContext, "uSampleWeight");
+      myUniformLocations[anIndex][OpenGl_RT_uFrameRndSeed] =
+        aShaderProgram->GetUniformLocation (theGlContext, "uFrameRndSeed");
+
+      myUniformLocations[anIndex][OpenGl_RT_uBackColorTop] =
+        aShaderProgram->GetUniformLocation (theGlContext, "uBackColorTop");
+      myUniformLocations[anIndex][OpenGl_RT_uBackColorBot] =
+        aShaderProgram->GetUniformLocation (theGlContext, "uBackColorBot");
     }
 
+    theGlContext->BindProgram (myOutImageProgram);
+
+    myOutImageProgram->SetSampler (theGlContext,
+      "uInputTexture", OpenGl_RT_PrevAccumTexture);
+
     theGlContext->BindProgram (NULL);
   }
 
@@ -1487,12 +1581,12 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Graphic3d_CView& theC
 
   if (myRaytraceFBO1.IsNull())
   {
-    myRaytraceFBO1 = new OpenGl_FrameBuffer;
+    myRaytraceFBO1 = new OpenGl_FrameBuffer (GL_RGBA32F);
   }
 
   if (myRaytraceFBO2.IsNull())
   {
-    myRaytraceFBO2 = new OpenGl_FrameBuffer;
+    myRaytraceFBO2 = new OpenGl_FrameBuffer (GL_RGBA32F);
   }
 
   const GLfloat aVertices[] = { -1.f, -1.f,  0.f,
@@ -1510,10 +1604,10 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Graphic3d_CView& theC
 }
 
 // =======================================================================
-// function : NullifyResource
+// function : nullifyResource
 // purpose  :
 // =======================================================================
-inline void NullifyResource (const Handle(OpenGl_Context)& theGlContext,
+inline void nullifyResource (const Handle(OpenGl_Context)& theGlContext,
                              Handle(OpenGl_Resource)&      theResource)
 {
   if (!theResource.IsNull())
@@ -1524,40 +1618,41 @@ inline void NullifyResource (const Handle(OpenGl_Context)& theGlContext,
 }
 
 // =======================================================================
-// function : ReleaseRaytraceResources
+// function : releaseRaytraceResources
 // purpose  : Releases OpenGL/GLSL shader programs
 // =======================================================================
 void OpenGl_View::releaseRaytraceResources (const Handle(OpenGl_Context)& theGlContext)
 {
-  NullifyResource (theGlContext, myOpenGlFBO);
-  NullifyResource (theGlContext, myRaytraceFBO1);
-  NullifyResource (theGlContext, myRaytraceFBO2);
+  nullifyResource (theGlContext, myOpenGlFBO);
+  nullifyResource (theGlContext, myRaytraceFBO1);
+  nullifyResource (theGlContext, myRaytraceFBO2);
 
-  NullifyResource (theGlContext, myRaytraceShader);
-  NullifyResource (theGlContext, myPostFSAAShader);
+  nullifyResource (theGlContext, myRaytraceShader);
+  nullifyResource (theGlContext, myPostFSAAShader);
 
-  NullifyResource (theGlContext, myRaytraceProgram);
-  NullifyResource (theGlContext, myPostFSAAProgram);
+  nullifyResource (theGlContext, myRaytraceProgram);
+  nullifyResource (theGlContext, myPostFSAAProgram);
+  nullifyResource (theGlContext, myOutImageProgram);
 
-  NullifyResource (theGlContext, mySceneNodeInfoTexture);
-  NullifyResource (theGlContext, mySceneMinPointTexture);
-  NullifyResource (theGlContext, mySceneMaxPointTexture);
+  nullifyResource (theGlContext, mySceneNodeInfoTexture);
+  nullifyResource (theGlContext, mySceneMinPointTexture);
+  nullifyResource (theGlContext, mySceneMaxPointTexture);
 
-  NullifyResource (theGlContext, myGeometryVertexTexture);
-  NullifyResource (theGlContext, myGeometryNormalTexture);
-  NullifyResource (theGlContext, myGeometryTexCrdTexture);
-  NullifyResource (theGlContext, myGeometryTriangTexture);
-  NullifyResource (theGlContext, mySceneTransformTexture);
+  nullifyResource (theGlContext, myGeometryVertexTexture);
+  nullifyResource (theGlContext, myGeometryNormalTexture);
+  nullifyResource (theGlContext, myGeometryTexCrdTexture);
+  nullifyResource (theGlContext, myGeometryTriangTexture);
+  nullifyResource (theGlContext, mySceneTransformTexture);
 
-  NullifyResource (theGlContext, myRaytraceLightSrcTexture);
-  NullifyResource (theGlContext, myRaytraceMaterialTexture);
+  nullifyResource (theGlContext, myRaytraceLightSrcTexture);
+  nullifyResource (theGlContext, myRaytraceMaterialTexture);
 
   if (myRaytraceScreenQuad.IsValid())
     myRaytraceScreenQuad.Release (theGlContext.operator->());
 }
 
 // =======================================================================
-// function : ResizeRaytraceBuffers
+// function : resizeRaytraceBuffers
 // purpose  : Resizes OpenGL frame buffers
 // =======================================================================
 Standard_Boolean OpenGl_View::resizeRaytraceBuffers (const Standard_Integer        theSizeX,
@@ -1575,7 +1670,7 @@ Standard_Boolean OpenGl_View::resizeRaytraceBuffers (const Standard_Integer
 }
 
 // =======================================================================
-// function : UpdateCamera
+// function : updateCamera
 // purpose  : Generates viewing rays for corners of screen quad
 // =======================================================================
 void OpenGl_View::updateCamera (const OpenGl_Mat4& theOrientation,
@@ -1634,7 +1729,7 @@ void OpenGl_View::updateCamera (const OpenGl_Mat4& theOrientation,
 }
 
 // =======================================================================
-// function : UploadRaytraceData
+// function : uploadRaytraceData
 // purpose  : Uploads ray-trace data to the GPU
 // =======================================================================
 Standard_Boolean OpenGl_View::uploadRaytraceData (const Handle(OpenGl_Context)& theGlContext)
@@ -1647,6 +1742,8 @@ Standard_Boolean OpenGl_View::uploadRaytraceData (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
+  myAccumFrames = 0; // accumulation should be restarted
+
   /////////////////////////////////////////////////////////////////////////////
   // Prepare OpenGL textures
 
@@ -1899,7 +1996,7 @@ Standard_Boolean OpenGl_View::uploadRaytraceData (const Handle(OpenGl_Context)&
   if (myRaytraceGeometry.Materials.size() != 0)
   {
     aResult &= myRaytraceMaterialTexture->Init (theGlContext, 4,
-      GLsizei (myRaytraceGeometry.Materials.size() * 11),  myRaytraceGeometry.Materials.front().Packed());
+      GLsizei (myRaytraceGeometry.Materials.size() * 18), myRaytraceGeometry.Materials.front().Packed());
 
     if (!aResult)
     {
@@ -1953,7 +2050,7 @@ Standard_Boolean OpenGl_View::uploadRaytraceData (const Handle(OpenGl_Context)&
 }
 
 // =======================================================================
-// function : UpdateRaytraceLightSources
+// function : updateRaytraceLightSources
 // purpose  : Updates 3D scene light sources for ray-tracing
 // =======================================================================
 Standard_Boolean OpenGl_View::updateRaytraceLightSources (const OpenGl_Mat4& theInvModelView, const Handle(OpenGl_Context)& theGlContext)
@@ -1962,22 +2059,22 @@ Standard_Boolean OpenGl_View::updateRaytraceLightSources (const OpenGl_Mat4& the
 
   myRaytraceGeometry.Ambient = BVH_Vec4f (0.0f, 0.0f, 0.0f, 0.0f);
 
-  for (OpenGl_ListOfLight::Iterator anItl (LightList()); anItl.More(); anItl.Next())
+  for (OpenGl_ListOfLight::Iterator aLightIter (myLights); aLightIter.More(); aLightIter.Next())
   {
-    const OpenGl_Light& aLight = anItl.Value();
+    const OpenGl_Light& aLight = aLightIter.Value();
 
     if (aLight.Type == Visual3d_TOLS_AMBIENT)
     {
-      myRaytraceGeometry.Ambient += BVH_Vec4f (aLight.Color.r(),
-                                               aLight.Color.g(),
-                                               aLight.Color.b(),
+      myRaytraceGeometry.Ambient += BVH_Vec4f (aLight.Color.r() * aLight.Intensity,
+                                               aLight.Color.g() * aLight.Intensity,
+                                               aLight.Color.b() * aLight.Intensity,
                                                0.0f);
       continue;
     }
 
-    BVH_Vec4f aDiffuse  (aLight.Color.r(),
-                         aLight.Color.g(),
-                         aLight.Color.b(),
+    BVH_Vec4f aDiffuse  (aLight.Color.r() * aLight.Intensity,
+                         aLight.Color.g() * aLight.Intensity,
+                         aLight.Color.b() * aLight.Intensity,
                          1.0f);
 
     BVH_Vec4f aPosition (-aLight.Direction.x(),
@@ -1991,6 +2088,14 @@ Standard_Boolean OpenGl_View::updateRaytraceLightSources (const OpenGl_Mat4& the
                              aLight.Position.y(),
                              aLight.Position.z(),
                              1.0f);
+
+      // store smoothing radius in w-component
+      aDiffuse.w() = Max (aLight.Smoothness, 0.f);
+    }
+    else
+    {
+      // store cosine of smoothing angle in w-component
+      aDiffuse.w() = cosf (Min (Max (aLight.Smoothness, 0.f), static_cast<Standard_ShortReal> (M_PI / 2.0)));
     }
 
     if (aLight.IsHeadlight)
@@ -2013,7 +2118,7 @@ Standard_Boolean OpenGl_View::updateRaytraceLightSources (const OpenGl_Mat4& the
       return Standard_False;
     }
   }
-  
+
   if (myRaytraceGeometry.Sources.size() != 0)
   {
     const GLfloat* aDataPtr = myRaytraceGeometry.Sources.front().Packed();
@@ -2030,7 +2135,7 @@ Standard_Boolean OpenGl_View::updateRaytraceLightSources (const OpenGl_Mat4& the
 }
 
 // =======================================================================
-// function : UpdateRaytraceEnvironmentMap
+// function : updateRaytraceEnvironmentMap
 // purpose  : Updates environment map for ray-tracing
 // =======================================================================
 Standard_Boolean OpenGl_View::updateRaytraceEnvironmentMap (const Handle(OpenGl_Context)& theGlContext)
@@ -2057,12 +2162,12 @@ Standard_Boolean OpenGl_View::updateRaytraceEnvironmentMap (const Handle(OpenGl_
           GL_TEXTURE0 + OpenGl_RT_EnvironmentMapTexture);
 
         aResult &= aProgram->SetUniform (theGlContext,
-          myUniformLocations[anIdx][OpenGl_RT_uEnvMapEnable], 1);
+          myUniformLocations[anIdx][OpenGl_RT_uSphereMapEnabled], 1);
       }
       else
       {
         aResult &= aProgram->SetUniform (theGlContext,
-          myUniformLocations[anIdx][OpenGl_RT_uEnvMapEnable], 0);
+          myUniformLocations[anIdx][OpenGl_RT_uSphereMapEnabled], 0);
       }
     }
   }
@@ -2075,7 +2180,7 @@ Standard_Boolean OpenGl_View::updateRaytraceEnvironmentMap (const Handle(OpenGl_
 }
 
 // =======================================================================
-// function : SetUniformState
+// function : setUniformState
 // purpose  : Sets uniform state for the given ray-tracing shader program
 // =======================================================================
 Standard_Boolean OpenGl_View::setUniformState (const Graphic3d_CView&        theCView,
@@ -2093,66 +2198,69 @@ Standard_Boolean OpenGl_View::setUniformState (const Graphic3d_CView&        the
     return Standard_False;
   }
 
-  Standard_Boolean aResult = Standard_True;
-
   const Standard_Integer aLightSourceBufferSize =
     static_cast<Standard_Integer> (myRaytraceGeometry.Sources.size());
 
   // Set camera state
-  aResult &= theProgram->SetUniform (theGlContext,
+  theProgram->SetUniform (theGlContext,
     myUniformLocations[theProgramId][OpenGl_RT_uOriginLB], theOrigins[0]);
-  aResult &= theProgram->SetUniform (theGlContext,
+  theProgram->SetUniform (theGlContext,
     myUniformLocations[theProgramId][OpenGl_RT_uOriginRB], theOrigins[1]);
-  aResult &= theProgram->SetUniform (theGlContext,
+  theProgram->SetUniform (theGlContext,
     myUniformLocations[theProgramId][OpenGl_RT_uOriginLT], theOrigins[2]);
-  aResult &= theProgram->SetUniform (theGlContext,
+  theProgram->SetUniform (theGlContext,
     myUniformLocations[theProgramId][OpenGl_RT_uOriginRT], theOrigins[3]);
-  aResult &= theProgram->SetUniform (theGlContext,
+  theProgram->SetUniform (theGlContext,
     myUniformLocations[theProgramId][OpenGl_RT_uDirectLB], theDirects[0]);
-  aResult &= theProgram->SetUniform (theGlContext,
+  theProgram->SetUniform (theGlContext,
     myUniformLocations[theProgramId][OpenGl_RT_uDirectRB], theDirects[1]);
-  aResult &= theProgram->SetUniform (theGlContext,
+  theProgram->SetUniform (theGlContext,
     myUniformLocations[theProgramId][OpenGl_RT_uDirectLT], theDirects[2]);
-  aResult &= theProgram->SetUniform (theGlContext,
+  theProgram->SetUniform (theGlContext,
     myUniformLocations[theProgramId][OpenGl_RT_uDirectRT], theDirects[3]);
-  aResult &= theProgram->SetUniform (theGlContext,
+  theProgram->SetUniform (theGlContext,
     myUniformLocations[theProgramId][OpenGl_RT_uUnviewMat], theUnviewMat);
 
   // Set scene parameters
-  aResult &= theProgram->SetUniform (theGlContext,
+  theProgram->SetUniform (theGlContext,
     myUniformLocations[theProgramId][OpenGl_RT_uSceneRad], myRaytraceSceneRadius);
-  aResult &= theProgram->SetUniform (theGlContext,
+  theProgram->SetUniform (theGlContext,
     myUniformLocations[theProgramId][OpenGl_RT_uSceneEps], myRaytraceSceneEpsilon);
-  aResult &= theProgram->SetUniform (theGlContext,
+  theProgram->SetUniform (theGlContext,
     myUniformLocations[theProgramId][OpenGl_RT_uLightCount], aLightSourceBufferSize);
-  aResult &= theProgram->SetUniform (theGlContext,
+  theProgram->SetUniform (theGlContext,
     myUniformLocations[theProgramId][OpenGl_RT_uLightAmbnt], myRaytraceGeometry.Ambient);
 
   // Set run-time rendering options
-  aResult &= theProgram->SetUniform (theGlContext,
-    myUniformLocations[theProgramId][OpenGl_RT_uShadEnabled], theCView.RenderParams.IsShadowEnabled ? 1 : 0);
-  aResult &= theProgram->SetUniform (theGlContext,
-    myUniformLocations[theProgramId][OpenGl_RT_uReflEnabled], theCView.RenderParams.IsReflectionEnabled ? 1 : 0);
+  theProgram->SetUniform (theGlContext,
+    myUniformLocations[theProgramId][OpenGl_RT_uShadowsEnabled], theCView.RenderParams.IsShadowEnabled ?  1 : 0);
+  theProgram->SetUniform (theGlContext,
+    myUniformLocations[theProgramId][OpenGl_RT_uReflectEnabled], theCView.RenderParams.IsReflectionEnabled ?  1 : 0);
 
   // Set array of 64-bit texture handles
   if (theGlContext->arbTexBindless != NULL && myRaytraceGeometry.HasTextures())
   {
-    aResult &= theProgram->SetUniform (theGlContext, "uTextureSamplers", static_cast<GLsizei> (
-      myRaytraceGeometry.TextureHandles().size()), &myRaytraceGeometry.TextureHandles()[0]);
+    theProgram->SetUniform (theGlContext, myUniformLocations[theProgramId][OpenGl_RT_uTexSamplersArray],
+      static_cast<GLsizei> (myRaytraceGeometry.TextureHandles().size()), &myRaytraceGeometry.TextureHandles()[0]);
   }
 
-  if (!aResult)
+  // Set background colors (only gradient background supported)
+  if (myBgGradientArray != NULL)
   {
-#ifdef RAY_TRACE_PRINT_INFO
-    std::cout << "Info: Not all uniforms were detected for program " << theProgramId << std::endl;
-#endif
+    theProgram->SetUniform (theGlContext,
+      myUniformLocations[theProgramId][OpenGl_RT_uBackColorTop], myBgGradientArray->GradientColor (0));
+    theProgram->SetUniform (theGlContext,
+      myUniformLocations[theProgramId][OpenGl_RT_uBackColorBot], myBgGradientArray->GradientColor (1));
   }
 
-  return aResult;
+  theProgram->SetUniform (theGlContext,
+    myUniformLocations[theProgramId][OpenGl_RT_uSphereMapForBack], theCView.RenderParams.UseEnvironmentMapBackground ?  1 : 0);
+
+  return Standard_True;
 }
 
 // =======================================================================
-// function : BindRaytraceTextures
+// function : bindRaytraceTextures
 // purpose  : Binds ray-trace textures to corresponding texture units
 // =======================================================================
 void OpenGl_View::bindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext)
@@ -2176,7 +2284,7 @@ void OpenGl_View::bindRaytraceTextures (const Handle(OpenGl_Context)& theGlConte
 }
 
 // =======================================================================
-// function : UnbindRaytraceTextures
+// function : unbindRaytraceTextures
 // purpose  : Unbinds ray-trace textures from corresponding texture units
 // =======================================================================
 void OpenGl_View::unbindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext)
@@ -2202,7 +2310,7 @@ void OpenGl_View::unbindRaytraceTextures (const Handle(OpenGl_Context)& theGlCon
 }
 
 // =======================================================================
-// function : RunRaytraceShaders
+// function : runRaytraceShaders
 // purpose  : Runs ray-tracing shader programs
 // =======================================================================
 Standard_Boolean OpenGl_View::runRaytraceShaders (const Graphic3d_CView&        theCView,
@@ -2216,7 +2324,32 @@ Standard_Boolean OpenGl_View::runRaytraceShaders (const Graphic3d_CView&
 {
   bindRaytraceTextures (theGlContext);
 
-  if (theCView.RenderParams.IsAntialiasingEnabled) // render source image to FBO
+  Handle(OpenGl_FrameBuffer) aRenderFramebuffer;
+  Handle(OpenGl_FrameBuffer) anAccumFramebuffer;
+
+  if (myRaytraceParameters.GlobalIllumination) // if path-tracing is used
+  {
+    for (int anIdx = 0; anIdx < 3; ++anIdx)
+    {
+      if  (fabsf (theOrigins[anIdx].x() - myPreviousOrigins[anIdx].x()) > std::numeric_limits<Standard_ShortReal>::epsilon()
+        || fabsf (theOrigins[anIdx].y() - myPreviousOrigins[anIdx].y()) > std::numeric_limits<Standard_ShortReal>::epsilon()
+        || fabsf (theOrigins[anIdx].z() - myPreviousOrigins[anIdx].z()) > std::numeric_limits<Standard_ShortReal>::epsilon())
+      {
+        myAccumFrames = 0; // camera has been moved
+      }
+
+      myPreviousOrigins[anIdx] = theOrigins[anIdx];
+    }
+
+    aRenderFramebuffer = myAccumFrames % 2 ? myRaytraceFBO1 : myRaytraceFBO2;
+    anAccumFramebuffer = myAccumFrames % 2 ? myRaytraceFBO2 : myRaytraceFBO1;
+
+    anAccumFramebuffer->ColorTexture()->Bind (
+      theGlContext, GL_TEXTURE0 + OpenGl_RT_PrevAccumTexture);
+
+    aRenderFramebuffer->BindBuffer (theGlContext);
+  }
+  else if (theCView.RenderParams.IsAntialiasingEnabled) // if 2-pass ray-tracing is used
   {
     myRaytraceFBO1->BindBuffer (theGlContext);
 
@@ -2232,35 +2365,55 @@ Standard_Boolean OpenGl_View::runRaytraceShaders (const Graphic3d_CView&
                               0, // ID of RT program
                               theGlContext);
 
-  myRaytraceScreenQuad.BindVertexAttrib (theGlContext, Graphic3d_TOA_POS);
+  if (myRaytraceParameters.GlobalIllumination)
   {
-    if (aResult)
-      theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6);
+    // Set frame accumulation weight
+    myRaytraceProgram->SetUniform (theGlContext,
+      myUniformLocations[0][OpenGl_RT_uSampleWeight], 1.f / (myAccumFrames + 1));
+
+    // Set random number generator seed
+    myRaytraceProgram->SetUniform (theGlContext,
+      myUniformLocations[0][OpenGl_RT_uFrameRndSeed], static_cast<Standard_Integer> (myRNG.NextInt() >> 2));
   }
-  myRaytraceScreenQuad.UnbindVertexAttrib (theGlContext, Graphic3d_TOA_POS);
 
-  if (!theCView.RenderParams.IsAntialiasingEnabled || !aResult)
-  {
-    unbindRaytraceTextures (theGlContext);
+  theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6);
 
-    theGlContext->BindProgram (NULL);
+  if (myRaytraceParameters.GlobalIllumination)
+  {
+    // Output accumulated image
+    glDisable (GL_BLEND);
 
-    return aResult;
-  }
+    theGlContext->BindProgram (myOutImageProgram);
 
-  myRaytraceFBO1->ColorTexture()->Bind (theGlContext, GL_TEXTURE0 + OpenGl_RT_FSAAInputTexture);
+    if (theReadDrawFbo != NULL)
+    {
+      theReadDrawFbo->BindBuffer (theGlContext);
+    }
+    else
+    {
+      aRenderFramebuffer->UnbindBuffer (theGlContext);
+    }
 
-  aResult &= theGlContext->BindProgram (myPostFSAAProgram);
+    aRenderFramebuffer->ColorTexture()->Bind (
+      theGlContext, GL_TEXTURE0 + OpenGl_RT_PrevAccumTexture);
 
-  aResult &= setUniformState (theCView,
-                              theOrigins,
-                              theDirects,
-                              theUnviewMat,
-                              1, // ID of FSAA program
-                              theGlContext);
+    theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6);
 
-  myRaytraceScreenQuad.BindVertexAttrib (theGlContext, Graphic3d_TOA_POS);
+    ++myAccumFrames;
+  }
+  else if (theCView.RenderParams.IsAntialiasingEnabled)
   {
+    myRaytraceFBO1->ColorTexture()->Bind (theGlContext, GL_TEXTURE0 + OpenGl_RT_FsaaInputTexture);
+
+    aResult &= theGlContext->BindProgram (myPostFSAAProgram);
+
+    aResult &= setUniformState (theCView,
+                                theOrigins,
+                                theDirects,
+                                theUnviewMat,
+                                1, // ID of FSAA program
+                                theGlContext);
+
     // Perform multi-pass adaptive FSAA using ping-pong technique.
     // We use 'FLIPTRI' sampling pattern changing for every pixel
     // (3 additional samples per pixel, the 1st sample is already
@@ -2297,10 +2450,14 @@ Standard_Boolean OpenGl_View::runRaytraceShaders (const Graphic3d_CView&
 
       if (anIt == 3) // disable FBO on last iteration
       {
-        glEnable (GL_BLEND);
-
         if (theReadDrawFbo != NULL)
+        {
           theReadDrawFbo->BindBuffer (theGlContext);
+        }
+        else
+        {
+          aFramebuffer->UnbindBuffer (theGlContext);
+        }
       }
       else
       {
@@ -2311,11 +2468,10 @@ Standard_Boolean OpenGl_View::runRaytraceShaders (const Graphic3d_CView&
 
       if (anIt != 3) // set input for the next pass
       {
-        aFramebuffer->ColorTexture()->Bind (theGlContext, GL_TEXTURE0 + OpenGl_RT_FSAAInputTexture);
+        aFramebuffer->ColorTexture()->Bind (theGlContext, GL_TEXTURE0 + OpenGl_RT_FsaaInputTexture);
       }
     }
   }
-  myRaytraceScreenQuad.UnbindVertexAttrib (theGlContext, Graphic3d_TOA_POS);
 
   unbindRaytraceTextures (theGlContext);
 
@@ -2325,7 +2481,7 @@ Standard_Boolean OpenGl_View::runRaytraceShaders (const Graphic3d_CView&
 }
 
 // =======================================================================
-// function : Raytrace
+// function : raytrace
 // purpose  : Redraws the window using OpenGL/GLSL ray-tracing
 // =======================================================================
 Standard_Boolean OpenGl_View::raytrace (const Graphic3d_CView&        theCView,
@@ -2370,9 +2526,8 @@ Standard_Boolean OpenGl_View::raytrace (const Graphic3d_CView&        theCView,
                 aDirects,
                 anUnviewMat);
 
-  glEnable (GL_BLEND);
+  glDisable (GL_BLEND);
   glDisable (GL_DEPTH_TEST);
-  glBlendFunc (GL_ONE, GL_SRC_ALPHA);
 
   if (theReadDrawFbo != NULL)
   {
@@ -2382,7 +2537,7 @@ Standard_Boolean OpenGl_View::raytrace (const Graphic3d_CView&        theCView,
   // Generate ray-traced image
   if (myIsRaytraceDataValid)
   {
-    myRaytraceScreenQuad.Bind (theGlContext);
+    myRaytraceScreenQuad.BindVertexAttrib (theGlContext, Graphic3d_TOA_POS);
 
     if (!myRaytraceGeometry.AcquireTextures (theGlContext))
     {
@@ -2411,7 +2566,7 @@ Standard_Boolean OpenGl_View::raytrace (const Graphic3d_CView&        theCView,
         0, GL_DEBUG_SEVERITY_MEDIUM_ARB, "Error: Failed to release OpenGL image textures");
     }
 
-    myRaytraceScreenQuad.Unbind (theGlContext);
+    myRaytraceScreenQuad.UnbindVertexAttrib (theGlContext, Graphic3d_TOA_POS);
   }
 
   glDisable (GL_BLEND);
diff --git a/src/Shaders/Display.fs b/src/Shaders/Display.fs
new file mode 100644 (file)
index 0000000..b6ac211
--- /dev/null
@@ -0,0 +1,13 @@
+//! Input image.
+uniform sampler2D uInputTexture;
+
+//! Output pixel color.
+out vec4 OutColor;
+
+void main (void)
+{
+  vec4 aColor = texelFetch (uInputTexture, ivec2 (gl_FragCoord.xy), 0);
+
+  // apply gamma correction (we use gamma = 2)
+  OutColor = vec4 (sqrt (aColor.rgb), aColor.a);
+}
diff --git a/src/Shaders/PathtraceBase.fs b/src/Shaders/PathtraceBase.fs
new file mode 100644 (file)
index 0000000..03f43ec
--- /dev/null
@@ -0,0 +1,830 @@
+#ifdef PATH_TRACING
+
+///////////////////////////////////////////////////////////////////////////////////////
+// Specific data types
+
+//! Describes local space at the hit point (visualization space).
+struct SLocalSpace
+{
+  //! Local X axis.
+  vec3 AxisX;
+
+  //! Local Y axis.
+  vec3 AxisY;
+
+  //! Local Z axis.
+  vec3 AxisZ;
+};
+
+//! Describes material properties (BSDF).
+struct SMaterial
+{
+  //! Weight of the Lambertian BRDF.
+  vec4 Kd;
+
+  //! Weight of the reflection BRDF.
+  vec3 Kr;
+
+  //! Weight of the transmission BTDF.
+  vec3 Kt;
+
+  //! Weight of the Blinn BRDF (and roughness).
+  vec4 Ks;
+
+  //! Fresnel coefficients.
+  vec3 Fresnel;
+
+  //! Absorption color and intensity of the media.
+  vec4 Absorption;
+};
+
+///////////////////////////////////////////////////////////////////////////////////////
+// Support subroutines
+
+//=======================================================================
+// function : LocalSpace
+// purpose  : Generates local space for the given normal
+//=======================================================================
+SLocalSpace LocalSpace (in vec3 theNormal)
+{
+  vec3 anAxisX = cross (vec3 (0.f, 1.f, 0.f), theNormal);
+  vec3 anAxisY = cross (vec3 (1.f, 0.f, 0.f), theNormal);
+
+  float aSqrLenX = dot (anAxisX, anAxisX);
+  float aSqrLenY = dot (anAxisY, anAxisY);
+
+  if (aSqrLenX > aSqrLenY)
+  {
+    anAxisX *= inversesqrt (aSqrLenX);
+    anAxisY = cross (anAxisX, theNormal);
+  }
+  else
+  {
+    anAxisY *= inversesqrt (aSqrLenY);
+    anAxisX = cross (anAxisY, theNormal);
+  }
+
+  return SLocalSpace (anAxisX, anAxisY, theNormal);
+}
+
+//=======================================================================
+// function : toLocalSpace
+// purpose  : Transforms the vector to local space from world space
+//=======================================================================
+vec3 toLocalSpace (in vec3 theVector, in SLocalSpace theSpace)
+{
+  return vec3 (dot (theVector, theSpace.AxisX),
+               dot (theVector, theSpace.AxisY),
+               dot (theVector, theSpace.AxisZ));
+}
+
+//=======================================================================
+// function : fromLocalSpace
+// purpose  : Transforms the vector from local space to world space
+//=======================================================================
+vec3 fromLocalSpace (in vec3 theVector, in SLocalSpace theSpace)
+{
+  return theVector.x * theSpace.AxisX +
+         theVector.y * theSpace.AxisY +
+         theVector.z * theSpace.AxisZ;
+}
+
+//=======================================================================
+// function : convolve
+// purpose  : Performs a linear convolution of the vector components
+//=======================================================================
+float convolve (in vec3 theVector, in vec3 theFactor)
+{
+  return dot (theVector, theFactor) * (1.f / max (theFactor.x + theFactor.y + theFactor.z, 1e-15f));
+}
+
+//=======================================================================
+// function : sphericalDirection
+// purpose  : Constructs vector from spherical coordinates
+//=======================================================================
+vec3 sphericalDirection (in float theCosTheta, in float thePhi)
+{
+  float aSinTheta = sqrt (1.f - theCosTheta * theCosTheta);
+
+  return vec3 (aSinTheta * cos (thePhi),
+               aSinTheta * sin (thePhi),
+               theCosTheta);
+}
+
+//=======================================================================
+// function : fresnelSchlick
+// purpose  : Computes the Fresnel reflection formula using
+//            Schlick's approximation.
+//=======================================================================
+vec3 fresnelSchlick (in float theCosI, in vec3 theSpecularColor)
+{
+  return theSpecularColor + (UNIT - theSpecularColor) * pow (1.f - theCosI, 5.f);
+}
+
+//=======================================================================
+// function : fresnelDielectric
+// purpose  : Computes the Fresnel reflection formula for dielectric in
+//            case of circularly polarized light (Based on PBRT code).
+//=======================================================================
+float fresnelDielectric (in float theCosI,
+                         in float theCosT,
+                         in float theEtaI,
+                         in float theEtaT)
+{
+  float aParl = (theEtaT * theCosI - theEtaI * theCosT) /
+                (theEtaT * theCosI + theEtaI * theCosT);
+
+  float aPerp = (theEtaI * theCosI - theEtaT * theCosT) /
+                (theEtaI * theCosI + theEtaT * theCosT);
+
+  return (aParl * aParl + aPerp * aPerp) * 0.5f;
+}
+
+#define ENVIRONMENT_IOR 1.f
+
+//=======================================================================
+// function : fresnelDielectric
+// purpose  : Computes the Fresnel reflection formula for dielectric in
+//            case of circularly polarized light (based on PBRT code)
+//=======================================================================
+float fresnelDielectric (in float theCosI, in float theIndex)
+{
+  float anEtaI = theCosI > 0.f ? 1.f : theIndex;
+  float anEtaT = theCosI > 0.f ? theIndex : 1.f;
+
+  float aSinT = (anEtaI / anEtaT) * sqrt (1.f - theCosI * theCosI);
+
+  if (aSinT >= 1.f)
+  {
+    return 1.f;
+  }
+
+  float aCosT = sqrt (1.f - aSinT * aSinT);
+
+  return fresnelDielectric (abs (theCosI), aCosT, anEtaI, anEtaT);
+}
+
+//=======================================================================
+// function : fresnelConductor
+// purpose  : Computes the Fresnel reflection formula for conductor in case
+//            of circularly polarized light (based on PBRT source code)
+//=======================================================================
+float fresnelConductor (in float theCosI, in float theEta, in float theK)
+{
+  float aTmp = 2.f * theEta * theCosI;
+
+  float aTmp1 = theEta * theEta + theK * theK;
+
+  float aSPerp = (aTmp1 - aTmp + theCosI * theCosI) /
+                 (aTmp1 + aTmp + theCosI * theCosI);
+
+  float aTmp2 = aTmp1 * theCosI * theCosI;
+
+  float aSParl = (aTmp2 - aTmp + 1.f) /
+                 (aTmp2 + aTmp + 1.f);
+
+  return (aSPerp + aSParl) * 0.5f;
+}
+
+#define FRESNEL_SCHLICK    -0.5f
+#define FRESNEL_CONSTANT   -1.5f
+#define FRESNEL_CONDUCTOR  -2.5f
+#define FRESNEL_DIELECTRIC -3.5f
+
+//=======================================================================
+// function : fresnelMedia
+// purpose  : Computes the Fresnel reflection formula for general medium
+//            in case of circularly polarized light.
+//=======================================================================
+vec3 fresnelMedia (in float theCosI, in vec3 theFresnelCoeffs)
+{
+  if (theFresnelCoeffs.x > FRESNEL_SCHLICK)
+  {
+    return fresnelSchlick (abs (theCosI), theFresnelCoeffs);
+  }
+
+  if (theFresnelCoeffs.x > FRESNEL_CONSTANT)
+  {
+    return vec3 (theFresnelCoeffs.z);
+  }
+
+  if (theFresnelCoeffs.x > FRESNEL_CONDUCTOR)
+  {
+    return vec3 (fresnelConductor (abs (theCosI), theFresnelCoeffs.y, theFresnelCoeffs.z));
+  }
+
+  return vec3 (fresnelDielectric (theCosI, theFresnelCoeffs.y));
+}
+
+//=======================================================================
+// function : transmitted
+// purpose  : Computes transmitted direction in tangent space
+//            (in case of TIR returned result is undefined!)
+//=======================================================================
+void transmitted (in float theIndex, in vec3 theIncident, out vec3 theTransmit)
+{
+  // Compute relative index of refraction
+  float anEta = (theIncident.z > 0.f) ? 1.f / theIndex : theIndex;
+
+  // Handle total internal reflection for transmission
+  float aSinT2 = anEta * anEta * (1.f - theIncident.z * theIncident.z);
+
+  // Compute transmitted ray direction
+  float aCosT = sqrt (1.f - min (aSinT2, 1.f)) * (theIncident.z > 0.f ? -1.f : 1.f);
+
+  theTransmit = normalize (vec3 (-anEta * theIncident.x,
+                                 -anEta * theIncident.y,
+                                  aCosT));
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+// Handlers and samplers for materials
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+//=======================================================================
+// function : handleLambertianReflection
+// purpose  : Handles Lambertian BRDF, with cos(N, PSI)
+//=======================================================================
+float handleLambertianReflection (in vec3 theInput, in vec3 theOutput)
+{
+  return max (0.f, theInput.z) * (1.f / M_PI);
+}
+
+//=======================================================================
+// function : handleBlinnReflection
+// purpose  : Handles Blinn glossy BRDF, with cos(N, PSI)
+//=======================================================================
+vec3 handleBlinnReflection (in vec3 theInput, in vec3 theOutput, in vec3 theFresnelCoeffs, in float theExponent)
+{
+  vec3 aWeight = ZERO;
+
+  // Compute half-angle vector
+  vec3 aHalf = theInput + theOutput;
+
+  if (aHalf.z < 0.f)
+    aHalf = -aHalf;
+
+  float aLength = dot (aHalf, aHalf);
+
+  if (aLength <= 0.f)
+    return ZERO;
+
+  aHalf *= inversesqrt (aLength);
+
+  // Compute Fresnel reflectance
+  float aCosDelta = dot (theOutput, aHalf);
+
+  vec3 aFresnel = fresnelMedia (aCosDelta, theFresnelCoeffs);
+
+  // Compute fraction of microfacets that reflect light
+  float aCosThetaH = max (0.f, aHalf.z);
+
+  float aFraction = (theExponent + 2.f) * (M_PI / 2.f) * pow (aCosThetaH, theExponent);
+
+  // Compute geometry attenuation term (already includes cos)
+  float aCosThetaI = max (0.f, theInput.z);
+  float aCosThetaO = max (0.f, theOutput.z);
+
+  float aGeom = min (1.f, 2.f * aCosThetaH / max (0.f, aCosDelta) * min (aCosThetaO, aCosThetaI));
+
+  return aCosThetaO < 1.0e-3f ? ZERO :
+    aFraction * aGeom / (4.f * aCosThetaO) * aFresnel;
+}
+
+//=======================================================================
+// function : handleMaterial
+// purpose  : Returns BSDF value for specified material, with cos(N, PSI)
+//=======================================================================
+vec3 handleMaterial (in SMaterial theMaterial, in vec3 theInput, in vec3 theOutput)
+{
+  return theMaterial.Kd.rgb * handleLambertianReflection (theInput, theOutput) +
+    theMaterial.Ks.rgb * handleBlinnReflection (theInput, theOutput, theMaterial.Fresnel, theMaterial.Ks.w);
+}
+
+//=======================================================================
+// 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)
+//=======================================================================
+void sampleLambertianReflection (in vec3 theOutput, out vec3 theInput)
+{
+  float aKsi1 = RandFloat();
+  float aKsi2 = RandFloat();
+
+  float aTemp = sqrt (aKsi2);
+
+  theInput = vec3 (aTemp * cos (2.f * M_PI * aKsi1),
+                   aTemp * sin (2.f * M_PI * aKsi1),
+                   sqrt (1.f - aKsi2));
+
+  if (theOutput.z < 0.f)
+    theInput.z = -theInput.z;
+}
+
+//=======================================================================
+// 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)
+{
+  vec3 aFresnel = fresnelMedia (theOutput.z, theFresnelCoeffs);
+
+  float aProbability = convolve (aFresnel, theThroughput);
+
+  // Sample input direction
+  if (RandFloat() <= aProbability)
+  {
+    theInput = vec3 (-theOutput.x,
+                     -theOutput.y,
+                      theOutput.z);
+
+    isTransmit = false;
+
+    return aFresnel * (1.f / aProbability);
+  }
+
+  transmitted (theFresnelCoeffs.y, theOutput, theInput);
+
+  isTransmit = true;
+
+  return (UNIT - aFresnel) * (1.f / (1.f - aProbability));
+}
+
+//=======================================================================
+// function : sampleSpecularReflection
+// purpose  : Samples specular BRDF, W = BRDF * cos(N, PSI) / PDF(PSI)
+//=======================================================================
+vec3 sampleSpecularReflection (in vec3 theOutput, out vec3 theInput, in vec3 theFresnelCoeffs)
+{
+  // Sample input direction
+  theInput = vec3 (-theOutput.x,
+                   -theOutput.y,
+                    theOutput.z);
+
+  return fresnelMedia (theOutput.z, theFresnelCoeffs);
+}
+
+#define MIN_COS 1.0e-20f
+
+//=======================================================================
+// function : sampleBlinnReflection
+// purpose  : Samples Blinn BRDF, W = BRDF * cos(N, PSI) / PDF(PSI)
+//            The BRDF is a product of three main terms, D, G, and F,
+//            which is then divided by two cosine terms. Here we perform
+//            importance sample the D part of the Blinn model; trying to
+//            develop a sampling procedure that accounted for all of the
+//            terms would be complex, and it is the D term that accounts
+//            for most of the variation.
+//=======================================================================
+vec3 sampleBlinnReflection (in vec3 theOutput, out vec3 theInput, in vec3 theFresnelCoeffs, in float theExponent)
+{
+  vec3 aWeight = ZERO;
+
+  // Generate two random variables
+  float aKsi1 = RandFloat();
+  float aKsi2 = RandFloat();
+
+  // Compute sampled half-angle vector for Blinn distribution
+  float aCosThetaH = pow (aKsi1, 1.f / (theExponent + 1.f));
+
+  vec3 aHalf = sphericalDirection (aCosThetaH, aKsi2 * 2.f * M_PI);
+
+  if (aHalf.z < 0)
+  {
+    aHalf = -aHalf;
+  }
+
+  // Compute incident direction by reflecting about half-vector
+  float aCosDelta = dot (theOutput, aHalf);
+
+  vec3 anInput = 2.f * aCosDelta * aHalf - theOutput;
+
+  if (theOutput.z * anInput.z <= 0.f)
+  {
+    return ZERO;
+  }
+
+  theInput = anInput;
+
+  // Compute Fresnel reflectance
+  vec3 aFresnel = fresnelMedia (aCosDelta, theFresnelCoeffs);
+
+  // Compute geometry attenuation term
+  float aCosThetaI = max (MIN_COS, theInput.z);
+  float aCosThetaO = max (MIN_COS, theOutput.z);
+
+  float aGeom = min (max (MIN_COS, aCosDelta), 2.f * aCosThetaH * min (aCosThetaO, aCosThetaI));
+
+  // Compute weight of the ray sample
+  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,
+                     in vec3      theOutput,
+                     in vec3      theFactor,
+                     out vec3     theInput,
+                     out vec3     theWeight,
+                     inout bool   isTransmit)
+{
+  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 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();
+
+  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
+  }
+  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
+  }
+  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
+
+    return true; // 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
+  }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+// Handlers and samplers for light sources
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+//=======================================================================
+// function : handlePointLight
+// purpose  :
+//=======================================================================
+float handlePointLight (in vec3 theInput, in vec3 theToLight, in float theRadius)
+{
+  float aCosMax = sqrt (1.f - theRadius * theRadius / dot (theToLight, theToLight));
+
+  return step (aCosMax, dot (theInput, theToLight));
+}
+
+//=======================================================================
+// function : handleDirectLight
+// purpose  :
+//=======================================================================
+float handleDirectLight (in vec3 theInput, in vec3 theToLight, in float theCosMax)
+{
+  return step (theCosMax, dot (theInput, theToLight));
+}
+
+//=======================================================================
+// function : samplePointLight
+// purpose  :
+//=======================================================================
+vec3 samplePointLight (in vec3 theToLight, in float theRadius, inout float thePDF)
+{
+  SLocalSpace aSpace = LocalSpace (theToLight);
+
+  float aCosMax = sqrt (1.f - theRadius * theRadius / 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),
+                       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();
+
+  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;
+
+  return normalize (fromLocalSpace (anInput, aSpace));
+}
+
+// =======================================================================
+// function : Latlong
+// purpose  : Converts world direction to environment texture coordinates
+// =======================================================================
+vec2 Latlong (in vec3 thePoint)
+{
+  float aPsi = acos (-thePoint.z);
+
+  float aPhi = atan (thePoint.y, thePoint.x) + M_PI;
+
+  return vec2 (aPhi * 0.1591549f,
+               aPsi * 0.3183098f);
+}
+
+// =======================================================================
+// function : EnvironmentRadiance
+// purpose  :
+// =======================================================================
+vec3 EnvironmentRadiance (in SRay theRay, in bool isSpecular, in bool isBackground)
+{
+  vec3 aRadiance = ZERO;
+
+  if (uSphereMapForBack != 0 || !isBackground)
+  {
+    aRadiance += FetchEnvironment (Latlong (theRay.Direct)).xyz;
+  }
+  else
+  {
+    aRadiance += BackgroundColor().xyz;
+  }
+
+  // Apply gamma correction (gamma is 2)
+  aRadiance *= aRadiance;
+
+  for (int aLightIdx = 0; aLightIdx < uLightCount && isSpecular; ++aLightIdx)
+  {
+    vec4 aLight = texelFetch (
+      uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));
+    vec4 aParam = texelFetch (
+      uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx));
+
+    if (aLight.w != 0.f) // point light source
+    {
+      aRadiance += aParam.rgb * handlePointLight (theRay.Direct, aLight.xyz - theRay.Origin, aParam.w /* radius */);
+    }
+    else // directional light source
+    {
+      aRadiance += aParam.rgb * handleDirectLight (theRay.Direct, aLight.xyz, aParam.w /* angle cosine */);
+    }
+  }
+
+  return aRadiance;
+}
+
+#define MIN_THROUGHPUT   vec3 (0.02f)
+#define MIN_CONTRIBUTION vec3 (0.01f)
+
+#define MATERIAL_KD(index)      (18 * index + 11)
+#define MATERIAL_KR(index)      (18 * index + 12)
+#define MATERIAL_KT(index)      (18 * index + 13)
+#define MATERIAL_KS(index)      (18 * index + 14)
+#define MATERIAL_LE(index)      (18 * index + 15)
+#define MATERIAL_FRESNEL(index) (18 * index + 16)
+#define MATERIAL_ABSORPT(index) (18 * index + 17)
+
+//=======================================================================
+// function : PathTrace
+// purpose  : Calculates radiance along the given ray
+//=======================================================================
+vec4 PathTrace (in SRay theRay, in vec3 theInverse)
+{
+  float anOpenGlDepth = ComputeOpenGlDepth (theRay);
+
+  vec3 aRadiance   = ZERO;
+  vec3 aThroughput = UNIT;
+
+  bool isInMedium = false;
+  bool isSpecular = false;
+  bool isTransmit = false;
+
+  int anObjectId; // ID of intersected triangle
+
+  for (int aDepth = 0; aDepth < NB_BOUNCES; ++aDepth)
+  {
+    SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);
+
+    ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, anObjectId);
+
+    if (aTriIndex.x == -1)
+    {
+      return vec4 (aRadiance + aThroughput *
+        EnvironmentRadiance (theRay, isSpecular, aDepth == 0 || isTransmit), 0.f);
+    }
+
+    vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0).xyz;
+    vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1).xyz;
+    vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2).xyz;
+
+    aHit.Normal = normalize (vec3 (dot (aInvTransf0, aHit.Normal),
+                                   dot (aInvTransf1, aHit.Normal),
+                                   dot (aInvTransf2, 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 * EPS_SCALE /
+      max (abs (dot (theRay.Direct, aHit.Normal)), MIN_SLOPE);
+
+    if (anOpenGlDepth < aHit.Time + aPolygonOffset)
+    {
+      vec4 aSrcColorRGBA = ComputeOpenGlColor();
+
+      aRadiance   += aThroughput.xyz * aSrcColorRGBA.xyz;
+      aThroughput *= aSrcColorRGBA.w;
+    }
+
+    theRay.Origin += theRay.Direct * aHit.Time; // intersection point
+
+    // Fetch material (BSDF)
+    SMaterial aMaterial = SMaterial (
+      vec4 (texelFetch (uRaytraceMaterialTexture, MATERIAL_KD      (aTriIndex.w))),
+      vec3 (texelFetch (uRaytraceMaterialTexture, MATERIAL_KR      (aTriIndex.w))),
+      vec3 (texelFetch (uRaytraceMaterialTexture, MATERIAL_KT      (aTriIndex.w))),
+      vec4 (texelFetch (uRaytraceMaterialTexture, MATERIAL_KS      (aTriIndex.w))),
+      vec3 (texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL (aTriIndex.w))),
+      vec4 (texelFetch (uRaytraceMaterialTexture, MATERIAL_ABSORPT (aTriIndex.w))));
+
+#ifdef USE_TEXTURES
+    if (aMaterial.Kd.w >= 0.f)
+    {
+      vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriIndex), 0.f, 1.f);
+
+      vec4 aTrsfRow1 = texelFetch (
+        uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriIndex.w));
+      vec4 aTrsfRow2 = texelFetch (
+        uRaytraceMaterialTexture, MATERIAL_TRS2 (aTriIndex.w));
+
+      aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord),
+                           dot (aTrsfRow2, aTexCoord));
+
+      vec3 aTexColor = textureLod (
+        uTextureSamplers[int (aMaterial.Kd.w)], aTexCoord.st, 0.f).rgb;
+
+      aMaterial.Kd.rgb *= aTexColor;
+    }
+#endif
+
+    vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
+
+    aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),
+                               dot (aInvTransf1, aNormal),
+                               dot (aInvTransf2, aNormal)));
+
+    SLocalSpace aSpace = LocalSpace (aNormal);
+
+    // Account for self-emission (not stored in the material)
+    aRadiance += aThroughput * texelFetch (
+      uRaytraceMaterialTexture, MATERIAL_LE (aTriIndex.w)).rgb;
+
+    if (uLightCount > 0 && convolve (aMaterial.Kd.rgb + aMaterial.Ks.rgb, aThroughput) > 0.f)
+    {
+      int aLightIdx = min (int (floor (RandFloat() * uLightCount)), uLightCount - 1);
+
+      vec4 aLight = texelFetch (
+        uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));
+      vec4 aParam = texelFetch (
+        uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx));
+
+      float aPDF = 1.f / uLightCount, aDistance = MAXFLOAT;
+
+      if (aLight.w != 0.f) // point light source
+      {
+        aDistance = length (aLight.xyz -= theRay.Origin);
+
+        aLight.xyz = samplePointLight (aLight.xyz, aParam.w /* radius */, aPDF);
+      }
+      else // directional light source
+      {
+        aLight.xyz = sampleDirectLight (aLight.xyz, aParam.w /* angle cosine */, aPDF);
+      }
+
+      vec3 aContrib = (1.f / aPDF) * aParam.rgb /* Le */ * handleMaterial (
+          aMaterial, toLocalSpace (aLight.xyz, aSpace), toLocalSpace (-theRay.Direct, aSpace));
+
+      if (any (greaterThan (aContrib, MIN_CONTRIBUTION))) // first check if light source is important
+      {
+        SRay aShadow = SRay (theRay.Origin + aLight.xyz * uSceneEpsilon, aLight.xyz);
+
+        aShadow.Origin += aHit.Normal * mix (
+          -uSceneEpsilon, uSceneEpsilon, step (0.f, dot (aHit.Normal, aLight.xyz)));
+
+        float aVisibility = SceneAnyHit (aShadow,
+          InverseDirection (aLight.xyz), aDistance);
+
+        aRadiance += aVisibility * aThroughput * aContrib;
+      }
+    }
+
+    vec3 anInput;
+    vec3 aWeight;
+
+    isSpecular = sampleMaterial (aMaterial,
+      toLocalSpace (-theRay.Direct, aSpace), aThroughput, anInput, aWeight, isTransmit);
+
+    if (isInMedium)
+    {
+      aThroughput *= exp (-aHit.Time *
+        aMaterial.Absorption.w * (UNIT - aMaterial.Absorption.rgb));
+    }
+
+    isInMedium = isTransmit ? !isInMedium : isInMedium;
+
+    aThroughput *= aWeight;
+
+    if (all (lessThan (aThroughput, MIN_THROUGHPUT)))
+    {
+      return vec4 (aRadiance, 0.f);
+    }
+
+    anInput = normalize (fromLocalSpace (anInput, aSpace));
+
+    theRay = SRay (theRay.Origin + anInput * uSceneEpsilon +
+      aHit.Normal * mix (-uSceneEpsilon, uSceneEpsilon, step (0.f, dot (aHit.Normal, anInput))), anInput);
+
+    theInverse = InverseDirection (anInput);
+
+    anOpenGlDepth = MAXFLOAT; // disable combining image with OpenGL output
+  }
+
+  return vec4 (aRadiance, 0.f);
+}
+
+#endif
index 9de6f3a..92bf755 100644 (file)
@@ -73,12 +73,14 @@ uniform int uLightCount;
 //! Intensity of global ambient light.
 uniform vec4 uGlobalAmbient;
 
-//! Enables/disables environment map.
-uniform int uEnvironmentEnable;
-//! Enables/disables computation of shadows.
-uniform int uShadowsEnable;
-//! Enables/disables computation of reflections.
-uniform int uReflectionsEnable;
+//! Enables/disables hard shadows.
+uniform int uShadowsEnabled;
+//! Enables/disables specular reflections.
+uniform int uReflectEnabled;
+//! Enables/disables spherical environment map.
+uniform int uSphereMapEnabled;
+//! Enables/disables environment map background.
+uniform int uSphereMapForBack;
 
 //! Radius of bounding sphere of the scene.
 uniform float uSceneRadius;
@@ -90,14 +92,19 @@ uniform float uSceneEpsilon;
   uniform sampler2D uTextureSamplers[MAX_TEX_NUMBER];
 #endif
 
+//! Top color of gradient background.
+uniform vec4 uBackColorTop = vec4 (0.0);
+//! Bottom color of gradient background.
+uniform vec4 uBackColorBot = vec4 (0.0);
+
 /////////////////////////////////////////////////////////////////////////////////////////
 // Specific data types
-  
+
 //! Stores ray parameters.
 struct SRay
 {
   vec3 Origin;
-  
+
   vec3 Direct;
 };
 
@@ -105,9 +112,9 @@ struct SRay
 struct SIntersect
 {
   float Time;
-  
+
   vec2 UV;
-  
+
   vec3 Normal;
 };
 
@@ -125,6 +132,24 @@ struct SIntersect
 #define AXIS_Y vec3 (0.0f, 1.0f, 0.0f)
 #define AXIS_Z vec3 (0.0f, 0.0f, 1.0f)
 
+#define M_PI 3.14159265f
+
+#define LUMA vec3 (0.2126f, 0.7152f, 0.0722f)
+
+// =======================================================================
+// 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;
 
@@ -133,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)
+void SeedRand (in int theSeed, in int theSizeX)
 {
-  RandState = uint (int (gl_FragCoord.y) * uWinSizeX + int (gl_FragCoord.x) + theSeed);
+  RandState = uint (int (gl_FragCoord.y) * theSizeX + int (gl_FragCoord.x) + theSeed);
 
   RandState = (RandState + 0x479ab41du) + (RandState <<  8);
   RandState = (RandState ^ 0xe4aa10ceu) ^ (RandState >>  5);
@@ -196,6 +221,26 @@ vec3 MatrixColMultiplyDir (in vec3 v,
                m0[2] * v.x + m1[2] * v.y + m2[2] * v.z);
 }
 
+//=======================================================================
+// function : InverseDirection
+// purpose  : Returns safely inverted direction of the given one
+//=======================================================================
+vec3 InverseDirection (in vec3 theInput)
+{
+  vec3 anInverse = 1.f / max (abs (theInput), SMALL);
+
+  return mix (-anInverse, anInverse, step (ZERO, theInput));
+}
+
+//=======================================================================
+// function : BackgroundColor
+// purpose  : Returns color of gradient background
+//=======================================================================
+vec4 BackgroundColor()
+{
+  return mix (uBackColorBot, uBackColorTop, vPixel.y);
+}
+
 /////////////////////////////////////////////////////////////////////////////////////////
 // Functions for compute ray-object intersection
 
@@ -239,7 +284,7 @@ float ComputeOpenGlDepth (in SRay theRay)
 // function : ComputeOpenGlColor
 // purpose  :
 // =======================================================================
-vec4 ComputeOpenGlColor (in SRay theRay)
+vec4 ComputeOpenGlColor()
 {
   vec4 anOpenGlColor = texelFetch (uOpenGlColorTexture, ivec2 (gl_FragCoord.xy), 0);
   // During blending with factors GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA (for text and markers)
@@ -421,16 +466,16 @@ ivec4 ObjectNearestHit (in int theBVHOffset, in int theVrtOffset, in int theTrgO
   return aTriIndex;
 }
 
-#define MATERIAL_AMBN(index) (11 * index + 0)
-#define MATERIAL_DIFF(index) (11 * index + 1)
-#define MATERIAL_SPEC(index) (11 * index + 2)
-#define MATERIAL_EMIS(index) (11 * index + 3)
-#define MATERIAL_REFL(index) (11 * index + 4)
-#define MATERIAL_REFR(index) (11 * index + 5)
-#define MATERIAL_TRAN(index) (11 * index + 6)
-#define MATERIAL_TRS1(index) (11 * index + 7)
-#define MATERIAL_TRS2(index) (11 * index + 8)
-#define MATERIAL_TRS3(index) (11 * index + 9)
+#define MATERIAL_AMBN(index) (18 * index + 0)
+#define MATERIAL_DIFF(index) (18 * index + 1)
+#define MATERIAL_SPEC(index) (18 * index + 2)
+#define MATERIAL_EMIS(index) (18 * index + 3)
+#define MATERIAL_REFL(index) (18 * index + 4)
+#define MATERIAL_REFR(index) (18 * index + 5)
+#define MATERIAL_TRAN(index) (18 * index + 6)
+#define MATERIAL_TRS1(index) (18 * index + 7)
+#define MATERIAL_TRS2(index) (18 * index + 8)
+#define MATERIAL_TRS3(index) (18 * index + 9)
 
 // =======================================================================
 // function : ObjectAnyHit
@@ -851,9 +896,20 @@ vec2 SmoothUV (in vec2 theUV, in ivec4 theTriangle)
 #endif
 
 // =======================================================================
+// function : FetchEnvironment
+// purpose  :
+// =======================================================================
+vec4 FetchEnvironment (in vec2 theTexCoord)
+{
+  return mix (vec4 (0.0f, 0.0f, 0.0f, 1.0f),
+    textureLod (uEnvironmentMapTexture, theTexCoord, 0.0f), float (uSphereMapEnabled));
+}
+
+// =======================================================================
 // function : Refract
 // purpose  : Computes refraction ray (also handles TIR)
 // =======================================================================
+#ifndef PATH_TRACING
 vec3 Refract (in vec3 theInput,
               in vec3 theNormal,
               in float theRefractIndex,
@@ -877,6 +933,7 @@ vec3 Refract (in vec3 theInput,
   return normalize (anIndex * theInput -
     (anIndex * aNdotI + (aNdotI < 0.0f ? aNdotT : -aNdotT)) * theNormal);
 }
+#endif
 
 #define MIN_SLOPE 0.0001f
 #define EPS_SCALE 8.0000f
@@ -892,6 +949,7 @@ vec3 Refract (in vec3 theInput,
 // function : Radiance
 // purpose  : Computes color along the given ray
 // =======================================================================
+#ifndef PATH_TRACING
 vec4 Radiance (in SRay theRay, in vec3 theInverse)
 {
   vec3 aResult = vec3 (0.0f);
@@ -909,19 +967,19 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
 
     if (aTriIndex.x == -1)
     {
-      vec4 aColor = vec4 (0.0f);
+      vec4 aColor = vec4 (0.0);
 
-      if (aWeight.w != 0.0f)
-      {
-        aColor = anOpenGlDepth != MAXFLOAT ?
-          ComputeOpenGlColor (theRay) : vec4 (0.0f, 0.0f, 0.0f, 1.0f);
-      }
-      else if (bool(uEnvironmentEnable))
+      if (bool(uSphereMapForBack) || aWeight.w == 0.0f /* reflection */)
       {
         float aTime = IntersectSphere (theRay, uSceneRadius);
 
-        aColor = textureLod (uEnvironmentMapTexture, Latlong (
-          theRay.Direct * aTime + theRay.Origin, uSceneRadius), 0.0f);
+        aColor = FetchEnvironment (Latlong (
+          theRay.Direct * aTime + theRay.Origin, uSceneRadius));
+      }
+      else
+      {
+        vec4 aGlColor = ComputeOpenGlColor();
+        aColor = vec4 (BackgroundColor().rgb * aGlColor.w + ComputeOpenGlColor().rgb, aGlColor.w);
       }
 
       return vec4 (aResult.xyz + aWeight.xyz * aColor.xyz, aWeight.w * aColor.w);
@@ -944,7 +1002,7 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
 
     if (anOpenGlDepth < aHit.Time + aPolygonOffset)
     {
-      vec4 aGlColor = ComputeOpenGlColor (theRay);
+      vec4 aGlColor = ComputeOpenGlColor();
 
       aResult += aWeight.xyz * aGlColor.xyz;
       aWeight *= aGlColor.w;
@@ -1018,7 +1076,7 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
       {
         float aVisibility = 1.0f;
 
-        if (bool(uShadowsEnable))
+        if (bool(uShadowsEnabled))
         {
           SRay aShadow = SRay (theRay.Origin, aLight.xyz);
 
@@ -1059,7 +1117,7 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
     }
     else
     {
-      aWeight *= bool(uReflectionsEnable) ?
+      aWeight *= bool(uReflectEnabled) ?
         texelFetch (uRaytraceMaterialTexture, MATERIAL_REFL (aTriIndex.w)) : vec4 (0.0f);
 
       vec3 aReflect = reflect (theRay.Direct, aNormal);
@@ -1096,3 +1154,4 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
                aResult.z,
                aWeight.w);
 }
+#endif
index 7610066..a15ddd2 100644 (file)
@@ -1,18 +1,51 @@
 out vec4 OutColor;
 
+// Seed for random number generator
+uniform int uFrameRndSeed;
+
+// Weight of current frame related to accumulated frames.
+uniform float uSampleWeight;
+
+//! Input accumulated image.
+uniform sampler2D uAccumTexture;
+
 // =======================================================================
 // function : main
 // purpose  :
 // =======================================================================
 void main (void)
 {
+#ifndef PATH_TRACING
   SRay aRay = GenerateRay (vPixel);
-  
+#else
+  ivec2 aWinSize = textureSize (uAccumTexture, 0);
+
+  SeedRand (uFrameRndSeed, aWinSize.x);
+
+  SRay aRay = GenerateRay (vPixel +
+    vec2 (RandFloat() + 1.f, RandFloat() + 1.f) / vec2 (aWinSize));
+#endif
+
   vec3 aInvDirect = 1.f / max (abs (aRay.Direct), SMALL);
-  
+
   aInvDirect = vec3 (aRay.Direct.x < 0.f ? -aInvDirect.x : aInvDirect.x,
                      aRay.Direct.y < 0.f ? -aInvDirect.y : aInvDirect.y,
                      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;
+  }
+
+  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 6207600..9b3f241 100644 (file)
@@ -9,14 +9,14 @@ out vec4 OutColor;
 
 #define LUM_DIFFERENCE 0.085f
 
-#define LUMA vec3 (0.2126f, 0.7152f, 0.0722f)
-
 // =======================================================================
 // function : main
 // purpose  :
 // =======================================================================
 void main (void)
 {
+#ifndef PATH_TRACING
+
   int aPixelX = int (gl_FragCoord.x);
   int aPixelY = int (gl_FragCoord.y);
 
@@ -75,4 +75,6 @@ void main (void)
   }
 
   OutColor = aColor;
+
+#endif
 }
\ No newline at end of file
index 12469bd..212646d 100644 (file)
@@ -86,6 +86,12 @@ is
        ---Level: Public
        ---Purpose: Calls SetDisplayPosition method.
 
+    SetSmoothAngle ( me       : mutable;
+                     theValue : Real from Standard )
+    ---Level: Public
+    ---Purpose: Modifies the smoothing angle (in radians)
+    is static;
+
         ---------------------------------------------------
         ---Category: display methods
         ---------------------------------------------------
index 3dae2b6..f792e91 100644 (file)
@@ -90,6 +90,15 @@ V3d_DirectionalLight::V3d_DirectionalLight(const Handle(V3d_Viewer)& VM,const St
 
 //-Methods, in order
 
+// =======================================================================
+// function : SetSmoothAngle
+// purpose  :
+// =======================================================================
+void V3d_DirectionalLight::SetSmoothAngle (const Standard_Real theValue)
+{
+  MyLight->SetSmoothAngle (theValue);
+}
+
 void V3d_DirectionalLight::SetDirection(const V3d_TypeOfOrientation Direction) {
 
   Graphic3d_Vector V = V3d::GetProjAxis(Direction) ;
index 2d8e8d4..40fb86a 100644 (file)
@@ -105,6 +105,20 @@ is
   ---Level: Public
   ---Purpose: Setup headlight flag.
 
+  SetIntensity ( me       : mutable;
+                 theValue : Real from Standard )
+  ---Level: Public
+  ---Purpose: Modifies the intensity of light source.
+  is static;
+
+  Intensity ( me ) returns Real from Standard is static;
+  ---Level: Public
+  ---Purpose: returns the intensity of light source
+
+  Smoothness ( me ) returns Real from Standard is static;
+  ---Level: Public
+  ---Purpose: returns the smoothness of light source
+
         IsDisplayed( me ) returns Boolean from Standard;
         ---Level: Public
         ---Purpose: Returns TRUE when a light representation is displayed
index 3763080..73f0dd6 100644 (file)
@@ -102,6 +102,32 @@ V3d_TypeOfLight V3d_Light::Type() const {
   return MyType;
 }
 
+// =======================================================================
+// function : SetIntensity
+// purpose  :
+// =======================================================================
+void V3d_Light::SetIntensity (const Standard_Real theValue)
+{
+  MyLight->SetIntensity (theValue);
+}
+
+// =======================================================================
+// function : Intensity
+// purpose  :
+// =======================================================================
+Standard_Real V3d_Light::Intensity() const
+{
+  return MyLight->Intensity();
+}
+
+// =======================================================================
+// function : Smoothness
+// purpose  :
+// =======================================================================
+Standard_Real V3d_Light::Smoothness() const
+{
+  return MyLight->Smoothness();
+}
 
 Standard_Boolean V3d_Light::Headlight() const {
   return MyLight->Headlight();
index be612b4..dd5fc01 100644 (file)
@@ -108,6 +108,12 @@ is
        --  Warning: raises BadValue from V3d
        --          if one of the attenuation coefficients is not between 0 et 1.
 
+    SetSmoothRadius ( me       : mutable;
+                      theValue : Real from Standard )
+    ---Level: Public
+    ---Purpose: Modifies the smoothing radius
+    is static;
+
        ---------------------------------------------------
         ---Category: Displaying methods 
         ---------------------------------------------------
index 0c58b94..43be7a4 100644 (file)
@@ -94,6 +94,15 @@ V3d_PositionalLight::V3d_PositionalLight(const Handle(V3d_Viewer)& VM, const Sta
 
 //-Methods, in order
 
+// =======================================================================
+// function : SetSmoothRadius
+// purpose  :
+// =======================================================================
+void V3d_PositionalLight::SetSmoothRadius (const Standard_Real theValue)
+{
+  MyLight->SetSmoothRadius (theValue);
+}
+
 void V3d_PositionalLight::SetPosition(const Standard_Real Xp, const Standard_Real Yp, const Standard_Real Zp) {
   MyLight->SetPosition (Graphic3d_Vertex (Xp,Yp,Zp));
 }
index a56c754..9ac6a24 100755 (executable)
@@ -12,3 +12,5 @@ ViewerTest_OpenGlCommands.cxx
 ViewerTest_ViewerCommands_1.mm
 ViewerTest.hxx
 ViewerTest.cxx
+ViewerTest_CmdParser.hxx
+ViewerTest_CmdParser.cxx
index a247df5..a1cc983 100644 (file)
@@ -25,6 +25,7 @@
 #include <Standard_Stream.hxx>
 
 #include <ViewerTest.hxx>
+#include <ViewerTest_CmdParser.hxx>
 
 #include <TopLoc_Location.hxx>
 #include <TopTools_HArray1OfShape.hxx>
@@ -4804,6 +4805,239 @@ static Standard_Integer vr(Draw_Interpretor& , Standard_Integer , const char** a
   return 0;
 }
 
+//===============================================================================================
+//function : VBsdf
+//purpose  :
+//===============================================================================================
+static int VBsdf (Draw_Interpretor& theDi,
+                  Standard_Integer  theArgsNb,
+                  const char**      theArgVec)
+{
+  Handle(V3d_View)   aView   = ViewerTest::CurrentView();
+  Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
+  if (aView.IsNull()
+   || aViewer.IsNull())
+  {
+    std::cerr << "No active viewer!\n";
+    return 1;
+  }
+
+  ViewerTest_CmdParser aCmd;
+
+  aCmd.AddDescription ("Adjusts parameters of material BSDF:");
+  aCmd.AddOption ("print|echo|p", "Print BSDF");
+
+  aCmd.AddOption ("kd", "Weight of the Lambertian BRDF");
+  aCmd.AddOption ("kr", "Weight of the reflection BRDF");
+  aCmd.AddOption ("kt", "Weight of the transmission BTDF");
+  aCmd.AddOption ("ks", "Weight of the glossy Blinn BRDF");
+  aCmd.AddOption ("le", "Self-emitted radiance");
+
+  aCmd.AddOption ("fresnel|f", "Fresnel coefficients; Allowed fresnel formats are: Constant x, Schlick x y z, Dielectric x, Conductor x y");
+
+  aCmd.AddOption ("roughness|r",    "Roughness of material (Blinn's exponent)");
+  aCmd.AddOption ("absorpCoeff|af", "Absorption coeff (only for transparent material)");
+  aCmd.AddOption ("absorpColor|ac", "Absorption color (only for transparent material)");
+
+  aCmd.AddOption ("normalize|n", "Normalize BSDF coefficients");
+
+  aCmd.Parse (theArgsNb, theArgVec);
+
+  if (aCmd.HasOption ("help"))
+  {
+    theDi.PrintHelp (theArgVec[0]);
+    return 0;
+  }
+
+  TCollection_AsciiString aName (aCmd.Arg ("", 0).c_str());
+
+  // find object
+  ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
+  if (!aMap.IsBound2 (aName) )
+  {
+    std::cerr << "Use 'vdisplay' before" << "\n";
+    return 1;
+  }
+
+  Handle(AIS_InteractiveObject) anIObj = Handle(AIS_InteractiveObject)::DownCast (aMap.Find2 (aName));
+  Graphic3d_MaterialAspect aMaterial = anIObj->Attributes()->ShadingAspect()->Material();
+  Graphic3d_BSDF aBSDF = aMaterial.BSDF();
+
+  if (aCmd.HasOption ("print"))
+  {
+    Graphic3d_Vec4 aFresnel = aBSDF.Fresnel.Serialize();
+
+    std::cout << "\n"
+      << "Kd:               " << aBSDF.Kd.r() << ", " << aBSDF.Kd.g() << ", " << aBSDF.Kd.b() << "\n"
+      << "Kr:               " << aBSDF.Kr.r() << ", " << aBSDF.Kr.g() << ", " << aBSDF.Kr.b() << "\n"
+      << "Kt:               " << aBSDF.Kt.r() << ", " << aBSDF.Kt.g() << ", " << aBSDF.Kt.b() << "\n"
+      << "Ks:               " << aBSDF.Ks.r() << ", " << aBSDF.Ks.g() << ", " << aBSDF.Ks.b() << "\n"
+      << "Le:               " << aBSDF.Le.r() << ", " << aBSDF.Le.g() << ", " << aBSDF.Le.b() << "\n"
+      << "Fresnel:          ";
+
+    if (aFresnel.x() >= 0.f)
+    {
+      std::cout
+        << "|Schlick| " << aFresnel.x() << ", " << aFresnel.y() << ", " << aFresnel.z() << "\n";
+    }
+    else if (aFresnel.x() >= -1.5f)
+    {
+      std::cout
+        << "|Constant| " << aFresnel.z() << "\n";
+    }
+    else if (aFresnel.x() >= -2.5f)
+    {
+      std::cout
+        << "|Conductor| " << aFresnel.y() << ", " << aFresnel.z() << "\n";
+    }
+    else
+    {
+      std::cout
+        << "|Dielectric| " << aFresnel.y() << "\n";
+    }
+
+
+    std::cout 
+      << "Roughness:        " << aBSDF.Roughness           << "\n"
+      << "Absorption coeff: " << aBSDF.AbsorptionCoeff     << "\n"
+      << "Absorption color: " << aBSDF.AbsorptionColor.r() << ", "
+                              << aBSDF.AbsorptionColor.g() << ", "
+                              << aBSDF.AbsorptionColor.b() << "\n";
+
+    return 0;
+  }
+
+  if (aCmd.HasOption ("roughness", 1, Standard_True))
+  {
+    aCmd.Arg ("roughness", 0);
+    aBSDF.Roughness = aCmd.ArgFloat ("roughness");
+  }
+
+  if (aCmd.HasOption ("absorpCoeff", 1, Standard_True))
+  {
+    aBSDF.AbsorptionCoeff = aCmd.ArgFloat ("absorpCoeff");
+  }
+
+  if (aCmd.HasOption ("absorpColor", 3, Standard_True))
+  {
+    aBSDF.AbsorptionColor = aCmd.ArgVec3f ("absorpColor");
+  }
+
+  if (aCmd.HasOption ("kd", 3))
+  {
+    aBSDF.Kd = aCmd.ArgVec3f ("kd");
+  }
+  else if (aCmd.HasOption ("kd", 1, Standard_True))
+  {
+    aBSDF.Kd = Graphic3d_Vec3 (aCmd.ArgFloat ("kd"));
+  }
+
+  if (aCmd.HasOption ("kr", 3))
+  {
+    aBSDF.Kr = aCmd.ArgVec3f ("kr");
+  }
+  else if (aCmd.HasOption ("kr", 1, Standard_True))
+  {
+    aBSDF.Kr = Graphic3d_Vec3 (aCmd.ArgFloat ("kr"));
+  }
+
+  if (aCmd.HasOption ("kt", 3))
+  {
+    aBSDF.Kt = aCmd.ArgVec3f ("kt");
+  }
+  else if (aCmd.HasOption ("kt", 1, Standard_True))
+  {
+    aBSDF.Kt = Graphic3d_Vec3 (aCmd.ArgFloat ("kt"));
+  }
+
+  if (aCmd.HasOption ("ks", 3))
+  {
+    aBSDF.Ks = aCmd.ArgVec3f ("ks");
+  }
+  else if (aCmd.HasOption ("ks", 1, Standard_True))
+  {
+    aBSDF.Ks = Graphic3d_Vec3 (aCmd.ArgFloat ("ks"));
+  }
+
+  if (aCmd.HasOption ("le", 3))
+  {
+    aBSDF.Le = aCmd.ArgVec3f ("le");
+  }
+  else if (aCmd.HasOption ("le", 1, Standard_True))
+  {
+    aBSDF.Le = Graphic3d_Vec3 (aCmd.ArgFloat ("le"));
+  }
+
+  const std::string aFresnelErrorMessage =
+    "Error! Wrong Fresnel type. Allowed types are: Constant x, Schlick x y z, Dielectric x, Conductor x y.\n";
+
+  if (aCmd.HasOption ("fresnel", 4)) // Schlick: type, x, y ,z
+  {
+    std::string aFresnelType = aCmd.Arg ("fresnel", 0);
+    std::transform (aFresnelType.begin(), aFresnelType.end(), aFresnelType.begin(), ::tolower);
+
+    if (aFresnelType == "schlick")
+    {
+      aBSDF.Fresnel = Graphic3d_Fresnel::CreateSchlick (
+        Graphic3d_Vec3 (static_cast<Standard_ShortReal> (Draw::Atof (aCmd.Arg ("fresnel", 1).c_str())),
+                        static_cast<Standard_ShortReal> (Draw::Atof (aCmd.Arg ("fresnel", 2).c_str())),
+                        static_cast<Standard_ShortReal> (Draw::Atof (aCmd.Arg ("fresnel", 3).c_str()))));
+    }
+    else
+    {
+      std::cout << aFresnelErrorMessage;
+    }
+  }
+  else if (aCmd.HasOption ("fresnel", 3)) // Conductor: type, x, y
+  {
+    std::string aFresnelType = aCmd.Arg ("fresnel", 0);
+    std::transform (aFresnelType.begin(), aFresnelType.end(), aFresnelType.begin(), ::tolower);
+
+    if (aFresnelType == "conductor")
+    {
+      aBSDF.Fresnel = Graphic3d_Fresnel::CreateConductor (
+        static_cast<Standard_ShortReal> (Draw::Atof (aCmd.Arg ("fresnel", 1).c_str())),
+        static_cast<Standard_ShortReal> (Draw::Atof (aCmd.Arg ("fresnel", 2).c_str())));
+    }
+    else
+    {
+      std::cout << aFresnelErrorMessage;
+    }
+  }
+  else if (aCmd.HasOption ("fresnel", 2)) // Dielectric, Constant: type, x
+  {
+    std::string aFresnelType = aCmd.Arg ("fresnel", 0);
+    std::transform (aFresnelType.begin(), aFresnelType.end(), aFresnelType.begin(), ::tolower);
+
+    if (aFresnelType == "dielectric")
+    {
+      aBSDF.Fresnel = Graphic3d_Fresnel::CreateDielectric (
+        static_cast<Standard_ShortReal> (Draw::Atof (aCmd.Arg ("fresnel", 1).c_str())));
+    }
+    else if (aFresnelType == "constant")
+    {
+      aBSDF.Fresnel = Graphic3d_Fresnel::CreateConstant (
+        static_cast<Standard_ShortReal> (Draw::Atof (aCmd.Arg ("fresnel", 1).c_str())));
+    }
+    else
+    {
+      std::cout << aFresnelErrorMessage;
+    }
+  }
+
+  if (aCmd.HasOption ("normalize"))
+  {
+    aBSDF.Normalize();
+  }
+
+  aMaterial.SetBSDF (aBSDF);
+  anIObj->SetMaterial (aMaterial);
+
+  aView->Redraw();
+
+  return 0;
+}
+
 //==============================================================================
 //function : VLoadSelection
 //purpose  : Adds given objects to map of AIS and loads selection primitives for them
@@ -5250,6 +5484,23 @@ void ViewerTest::Commands(Draw_Interpretor& theCommands)
     "\n\t\t:   [0|1] - turn off | on auto activation of selection",
     __FILE__, VAutoActivateSelection, group);
 
+  theCommands.Add("vbsdf", "vbsdf [name] [options]"
+    "\nAdjusts parameters of material BSDF:"
+    "\n    -help : Shows this message"
+    "\n    -print : Print BSDF"
+    "\n    -kd : Weight of the Lambertian BRDF"
+    "\n    -kr : Weight of the reflection BRDF"
+    "\n    -kt : Weight of the transmission BTDF"
+    "\n    -ks : Weight of the glossy Blinn BRDF"
+    "\n    -le : Self-emitted radiance"
+    "\n    -fresnel : Fresnel coefficients; Allowed fresnel formats are: Constant x,"
+    "\n               Schlick x y z, Dielectric x, Conductor x y"
+    "\n    -roughness : Roughness of material (Blinn's exponent)"
+    "\n    -absorpcoeff : Absorption coefficient (only for transparent material)"
+    "\n    -absorpcolor : Absorption color (only for transparent material)"
+    "\n    -normalize : Normalize BSDF coefficients",
+    __FILE__, VBsdf, group);
+
 }
 
 //=====================================================================
diff --git a/src/ViewerTest/ViewerTest_CmdParser.cxx b/src/ViewerTest/ViewerTest_CmdParser.cxx
new file mode 100644 (file)
index 0000000..001f2b6
--- /dev/null
@@ -0,0 +1,212 @@
+// Created on: 2015-03-15
+// Created by: Danila ULYANOV
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <ViewerTest_CmdParser.hxx>
+
+#include <Draw.hxx>
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+
+//===============================================================================================
+//function : ViewerTest_CmdParser
+//purpose  :
+//===============================================================================================
+ViewerTest_CmdParser::ViewerTest_CmdParser()
+{
+  ViewerTest_CmdOption aDefaultOption;
+  myArgumentStorage.push_back (aDefaultOption);
+  myArgumentLists[""] = 0;
+  myArgumentLists["help"] = 0;
+}
+
+//===============================================================================================
+//function : AddOption
+//purpose  :
+//===============================================================================================
+void ViewerTest_CmdParser::AddOption (const std::string& theOptionNames, const std::string& theOptionDescription)
+{
+  ViewerTest_CmdOption aNewOption;
+
+  // extract option names
+  std::vector<std::string> aNames;
+  std::stringstream aStream (theOptionNames);
+  std::string anItem;
+  while (std::getline (aStream, anItem, '|'))
+  {
+    std::transform (anItem.begin(), anItem.end(), anItem.begin(), ::tolower);
+    if (!anItem.empty())
+    {
+      aNames.push_back (anItem);
+    }
+  }
+
+  aNewOption.Name        = aNames.front();
+  aNewOption.Description = theOptionDescription;
+  aNewOption.IsSet       = Standard_False;
+
+  myArgumentStorage.push_back (aNewOption);
+
+  std::vector<std::string>::const_iterator anIt = aNames.begin();
+  for (; anIt != aNames.end(); ++anIt)
+  {
+    myArgumentLists[*anIt] = (Standard_Integer) myArgumentStorage.size() - 1;
+  }
+}
+
+//===============================================================================================
+//function : Help
+//purpose  :
+//===============================================================================================
+void ViewerTest_CmdParser::Help()
+{
+  std::cout << myDescription << std::endl;
+
+  std::vector<ViewerTest_CmdOption>::const_iterator anIt = myArgumentStorage.begin();
+  for (++anIt; anIt != myArgumentStorage.end(); ++anIt)
+  {
+    std::cout << "\n    -" << (*anIt).Name << " : " << (*anIt).Description;
+  }
+
+  std::cout << std::endl;
+}
+
+//===============================================================================================
+//function : Parse
+//purpose  :
+//===============================================================================================
+void ViewerTest_CmdParser::Parse (Standard_Integer theArgsNb, const char** theArgVec)
+{
+  Standard_Integer aCurrentOption = 0;
+
+  for (Standard_Integer anIter = 1; anIter < theArgsNb; ++anIter)
+  {
+    if (theArgVec[anIter][0] == '-')
+    {
+      std::string anOptionName (&theArgVec[anIter][1]);
+      std::transform (anOptionName.begin(), anOptionName.end(), anOptionName.begin(), ::tolower);
+
+      std::map<std::string, Standard_Integer>::iterator aMapIter = myArgumentLists.find (anOptionName);
+      if (aMapIter != myArgumentLists.end())
+      {
+        aCurrentOption = aMapIter->second;
+        myArgumentStorage[aCurrentOption].IsSet = true;
+        myArgumentStorage[aCurrentOption].Arguments.clear();
+      }
+      else
+      {
+        std::cerr << "Error: unknown argument '" << theArgVec[anIter] << "'\n";
+      }
+    }
+    else
+    {
+      myArgumentStorage[aCurrentOption].Arguments.push_back (theArgVec[anIter]);
+    }
+  }
+}
+
+//===============================================================================================
+//function : HasOption
+//purpose  :
+//===============================================================================================
+Standard_Boolean ViewerTest_CmdParser::HasOption (const std::string& theOptionName, Standard_Integer theMandatoryArgsNb /*= 0*/, Standard_Boolean isFatal /*= Standard_False*/)
+{
+  std::string aLowerName = theOptionName;
+  std::transform (aLowerName.begin(), aLowerName.end(), aLowerName.begin(), ::tolower);
+
+  Standard_Boolean aResult = Standard_False;
+  std::map<std::string, Standard_Integer>::iterator aMapIter = myArgumentLists.find (aLowerName);
+  if (aMapIter != myArgumentLists.end())
+  {
+    Standard_Integer anOption = aMapIter->second;
+    aResult = myArgumentStorage[anOption].Arguments.size() >= static_cast<size_t> (theMandatoryArgsNb);
+    if (isFatal && !aResult && myArgumentStorage[anOption].IsSet)
+    {
+      std::cerr << "Error: wrong syntax at argument '" << theOptionName << "'\n";
+    }
+
+    aResult &= myArgumentStorage[anOption].IsSet;
+  }
+
+  return aResult;
+}
+
+//===============================================================================================
+//function : Arg
+//purpose  :
+//===============================================================================================
+std::string ViewerTest_CmdParser::Arg (const std::string& theOptionName, Standard_Integer theArgumentIndex)
+{
+  std::string aLowerName = theOptionName;
+  std::transform (aLowerName.begin(), aLowerName.end(), aLowerName.begin(), ::tolower);
+
+  std::map<std::string, Standard_Integer>::iterator aMapIter = myArgumentLists.find (aLowerName);
+  if (aMapIter != myArgumentLists.end())
+  {
+    Standard_Integer anOption = aMapIter->second;
+    if (myArgumentStorage[anOption].Arguments.size() > static_cast<size_t> (theArgumentIndex))
+    {
+      return myArgumentStorage[anOption].Arguments[theArgumentIndex];
+    }
+    else
+    {
+      std::cerr << "Error: wrong syntax at argument '" << aLowerName << "'\n";
+    }
+  }
+
+  return "";
+}
+
+//===============================================================================================
+//function : ArgVec3f
+//purpose  :
+//===============================================================================================
+Graphic3d_Vec3 ViewerTest_CmdParser::ArgVec3f (const std::string& theOptionName)
+{
+  return Graphic3d_Vec3 (static_cast<Standard_ShortReal> (Draw::Atof (Arg (theOptionName, 0).c_str())),
+                         static_cast<Standard_ShortReal> (Draw::Atof (Arg (theOptionName, 1).c_str())),
+                         static_cast<Standard_ShortReal> (Draw::Atof (Arg (theOptionName, 2).c_str())));
+}
+
+//===============================================================================================
+//function : ArgVec3d
+//purpose  :
+//===============================================================================================
+Graphic3d_Vec3d ViewerTest_CmdParser::ArgVec3d (const std::string& theOptionName)
+{
+  return Graphic3d_Vec3d ( Draw::Atof (Arg (theOptionName, 0).c_str()),
+                           Draw::Atof (Arg (theOptionName, 1).c_str()),
+                           Draw::Atof (Arg (theOptionName, 2).c_str()));
+}
+
+//===============================================================================================
+//function : ArgDouble
+//purpose  :
+//===============================================================================================
+Standard_Real ViewerTest_CmdParser::ArgDouble (const std::string& theOptionName)
+{
+  return Draw::Atof (Arg (theOptionName, 0).c_str());
+}
+
+//===============================================================================================
+//function : ArgFloat
+//purpose  :
+//===============================================================================================
+Standard_ShortReal ViewerTest_CmdParser::ArgFloat (const std::string& theOptionName)
+{
+  return static_cast<Standard_ShortReal> (Draw::Atof (Arg (theOptionName, 0).c_str()));
+}
diff --git a/src/ViewerTest/ViewerTest_CmdParser.hxx b/src/ViewerTest/ViewerTest_CmdParser.hxx
new file mode 100644 (file)
index 0000000..2158a16
--- /dev/null
@@ -0,0 +1,95 @@
+// Created on: 2015-03-15
+// Created by: Danila ULYANOV
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _ViewerTest_CmdParser_HeaderFile
+#define _ViewerTest_CmdParser_HeaderFile
+
+#include <map>
+#include <vector>
+#include <string>
+#include <algorithm>
+
+#include <Standard.hxx>
+#include <Graphic3d_Vec.hxx>
+
+//! Command parser.
+class ViewerTest_CmdParser
+{
+public:
+
+  //! Initializes default option.
+  ViewerTest_CmdParser();
+
+  //! Sets description for command.
+  void AddDescription (const std::string& theDescription)
+  {
+    myDescription = theDescription;
+  }
+
+  //! Adds option to available option list. Several names may be provided if separated with '|'.
+  void AddOption (const std::string& theOptionNames, const std::string& theOptionDescription);
+
+  //! Prints help message based on provided command and options descriptions.
+  void Help();
+
+  //! Parses argument list; assignes local arguments to each option.
+  void Parse (Standard_Integer  theArgsNb,
+              const char**      theArgVec);
+
+  //! Checks if option was set with given minimal argument number.
+  //! Prints error message if isFatal flag was set.
+  Standard_Boolean HasOption (const std::string& theOptionName,
+                              Standard_Integer theMandatoryArgsNb = 0,
+                              Standard_Boolean isFatal = Standard_False);
+
+  //! Accesses local argument of option 'theOptionName' with index 'theArgumentIndex'.
+  std::string Arg (const std::string& theOptionName, Standard_Integer theArgumentIndex);
+
+  // Interprets arguments of option 'theOptionName' as float vector.
+  Graphic3d_Vec3 ArgVec3f (const std::string& theOptionName);
+
+  // Interprets arguments of option 'theOptionName' as double vector.
+  Graphic3d_Vec3d ArgVec3d (const std::string& theOptionName);
+
+  // Interprets arguments of option 'theOptionName' as double.
+  Standard_Real ArgDouble (const std::string& theOptionName);
+
+  // Interprets arguments of option 'theOptionName' as float.
+  Standard_ShortReal ArgFloat (const std::string& theOptionName);
+
+private:
+
+  //! Object representing option state.
+  struct ViewerTest_CmdOption
+  {
+    ViewerTest_CmdOption() : IsSet (Standard_False) {}
+
+    std::string Name;
+    std::string Description;
+    Standard_Boolean IsSet;
+    std::vector<std::string> Arguments;
+  };
+
+  //! Description of command.
+  std::string myDescription;
+
+  //! Map from all possible option names to option object indexes in myArgumentStorage.
+  std::map<std::string, Standard_Integer> myArgumentLists;
+
+  //! Container which stores option objects.
+  std::vector<ViewerTest_CmdOption> myArgumentStorage;
+};
+
+#endif // _ViewerTest_CmdParser_HeaderFile
index 8275d2a..22e5ce6 100644 (file)
@@ -7502,58 +7502,64 @@ static int VLight (Draw_Interpretor& theDi,
       {
         case V3d_AMBIENT:
         {
-          theDi << "  Type:      Ambient\n";
+          theDi << "  Type:       Ambient\n";
+          theDi << "  Intensity:  " << aLight->Intensity() << "\n";
           break;
         }
         case V3d_DIRECTIONAL:
         {
           Handle(V3d_DirectionalLight) aLightDir = Handle(V3d_DirectionalLight)::DownCast (aLight);
-          theDi << "  Type:      Directional\n";
-          theDi << "  Headlight: " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
+          theDi << "  Type:       Directional\n";
+          theDi << "  Intensity:  " << aLight->Intensity() << "\n";
+          theDi << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
+          theDi << "  Smoothness: " << aLight->Smoothness() << "\n";
           if (!aLightDir.IsNull())
           {
             aLightDir->Position  (anXYZ[0], anXYZ[1], anXYZ[2]);
-            theDi << "  Position:  " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
+            theDi << "  Position:   " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
             aLightDir->Direction (anXYZ[0], anXYZ[1], anXYZ[2]);
-            theDi << "  Direction: " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
+            theDi << "  Direction:  " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
           }
           break;
         }
         case V3d_POSITIONAL:
         {
           Handle(V3d_PositionalLight) aLightPos = Handle(V3d_PositionalLight)::DownCast (aLight);
-          theDi << "  Type:      Positional\n";
-          theDi << "  Headlight: " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
+          theDi << "  Type:       Positional\n";
+          theDi << "  Intensity:  " << aLight->Intensity() << "\n";
+          theDi << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
+          theDi << "  Smoothness: " << aLight->Smoothness() << "\n";
           if (!aLightPos.IsNull())
           {
             aLightPos->Position  (anXYZ[0], anXYZ[1], anXYZ[2]);
-            theDi << "  Position:  " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
+            theDi << "  Position:   " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
             aLightPos->Attenuation (anAtten[0], anAtten[1]);
-            theDi << "  Atten.:    " << anAtten[0] << " " << anAtten[1] << "\n";
+            theDi << "  Atten.:     " << anAtten[0] << " " << anAtten[1] << "\n";
           }
           break;
         }
         case V3d_SPOT:
         {
           Handle(V3d_SpotLight) aLightSpot = Handle(V3d_SpotLight)::DownCast (aLight);
-          theDi << "  Type:      Spot\n";
-          theDi << "  Headlight: " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
+          theDi << "  Type:       Spot\n";
+          theDi << "  Intensity:  " << aLight->Intensity() << "\n";
+          theDi << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
           if (!aLightSpot.IsNull())
           {
             aLightSpot->Position  (anXYZ[0], anXYZ[1], anXYZ[2]);
-            theDi << "  Position:  " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
+            theDi << "  Position:   " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
             aLightSpot->Direction (anXYZ[0], anXYZ[1], anXYZ[2]);
-            theDi << "  Direction: " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
+            theDi << "  Direction:  " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
             aLightSpot->Attenuation (anAtten[0], anAtten[1]);
-            theDi << "  Atten.:    " << anAtten[0] << " " << anAtten[1] << "\n";
-            theDi << "  Angle:     " << (aLightSpot->Angle() * 180.0 / M_PI) << "\n";
-            theDi << "  Exponent:  " << aLightSpot->Concentration() << "\n";
+            theDi << "  Atten.:     " << anAtten[0] << " " << anAtten[1] << "\n";
+            theDi << "  Angle:      " << (aLightSpot->Angle() * 180.0 / M_PI) << "\n";
+            theDi << "  Exponent:   " << aLightSpot->Concentration() << "\n";
           }
           break;
         }
         default:
         {
-          theDi << "  Type:      UNKNOWN\n";
+          theDi << "  Type:       UNKNOWN\n";
           break;
         }
       }
@@ -7785,6 +7791,56 @@ static int VLight (Draw_Interpretor& theDi,
         return 1;
       }
     }
+    else if (anArgCase.IsEqual ("SM")
+          || anArgCase.IsEqual ("SMOOTHNESS"))
+    {
+      if (++anArgIt >= theArgsNb)
+      {
+        std::cerr << "Wrong syntax at argument '" << anArg << "'!\n";
+        return 1;
+      }
+
+      Standard_Real aSmoothness = Atof (theArgVec[anArgIt]);
+
+      if (fabs (aSmoothness) < Precision::Confusion())
+      {
+        aLightCurr->SetIntensity (1.f);
+      }
+      else if (fabs (aLightCurr->Smoothness()) < Precision::Confusion())
+      {
+        aLightCurr->SetIntensity ((aSmoothness * aSmoothness) / 3.f);
+      }
+      else
+      {
+        Standard_ShortReal aSmoothnessRatio = static_cast<Standard_ShortReal> (aSmoothness / aLightCurr->Smoothness());
+        aLightCurr->SetIntensity (aLightCurr->Intensity() / (aSmoothnessRatio * aSmoothnessRatio));
+      }
+
+      if (!aLightPos.IsNull())
+      {
+        aLightPos->SetSmoothRadius (aSmoothness);
+      }
+      else if (!aLightDir.IsNull())
+      {
+        aLightDir->SetSmoothAngle (aSmoothness);
+      }
+    }
+    else if (anArgCase.IsEqual ("INT")
+          || anArgCase.IsEqual ("INTENSITY"))
+    {
+      if (++anArgIt >= theArgsNb)
+      {
+        std::cerr << "Wrong syntax at argument '" << anArg << "'!\n";
+        return 1;
+      }
+
+      Standard_Real aIntensity = Atof (theArgVec[anArgIt]);
+
+      if (!aLightCurr.IsNull())
+      {
+        aLightCurr->SetIntensity (aIntensity);
+      }
+    }
     else if (anArgCase.IsEqual ("ANG")
           || anArgCase.IsEqual ("ANGLE"))
     {
@@ -7975,11 +8031,12 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
       case Graphic3d_RM_RAYTRACING:    theDI << "raytrace ";      break;
     }
     theDI << "\n";
-    theDI << "fsaa:         " << (aParams.IsAntialiasingEnabled      ? "on" : "off") << "\n";
-    theDI << "shadows:      " << (aParams.IsShadowEnabled            ? "on" : "off") << "\n";
-    theDI << "reflections:  " << (aParams.IsReflectionEnabled        ? "on" : "off") << "\n";
-    theDI << "rayDepth:     " <<  aParams.RaytracingDepth                            << "\n";
-    theDI << "gleam:        " << (aParams.IsTransparentShadowEnabled ? "on" : "off") << "\n";
+    theDI << "fsaa:         " << (aParams.IsAntialiasingEnabled       ? "on" : "off") << "\n";
+    theDI << "shadows:      " << (aParams.IsShadowEnabled             ? "on" : "off") << "\n";
+    theDI << "reflections:  " << (aParams.IsReflectionEnabled         ? "on" : "off") << "\n";
+    theDI << "rayDepth:     " <<  aParams.RaytracingDepth                             << "\n";
+    theDI << "gleam:        " << (aParams.IsTransparentShadowEnabled  ? "on" : "off") << "\n";
+    theDI << "GI:           " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
     theDI << "shadingModel: ";
     switch (aView->ShadingModel())
     {
@@ -8066,7 +8123,9 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
       }
 
       const Standard_Integer aDepth = Draw::Atoi (theArgVec[anArgIter]);
-      if (aDepth < 1 || aDepth > 10)
+
+      // We allow RaytracingDepth be more than 10 in case of GI enabled
+      if (aDepth < 1 || (aDepth > 10 && !aParams.IsGlobalIlluminationEnabled))
       {
         std::cerr << "Error: invalid ray-tracing depth " << aDepth << ". Should be within range [1; 10]\n";
         return 1;
@@ -8142,6 +8201,42 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
       }
       aParams.IsTransparentShadowEnabled = toEnable;
     }
+    else if (aFlag == "-gi")
+    {
+      if (toPrint)
+      {
+        theDI << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << " ";
+        continue;
+      }
+
+      Standard_Boolean toEnable = Standard_True;
+      if (++anArgIter < theArgNb
+      && !parseOnOff (theArgVec[anArgIter], toEnable))
+      {
+        --anArgIter;
+      }
+      aParams.IsGlobalIlluminationEnabled = toEnable;
+      if (!toEnable)
+      {
+        aParams.RaytracingDepth = Min (aParams.RaytracingDepth, 10);
+      }
+    }
+    else if (aFlag == "-env")
+    {
+      if (toPrint)
+      {
+        theDI << (aParams.UseEnvironmentMapBackground ? "on" : "off") << " ";
+        continue;
+      }
+
+      Standard_Boolean toEnable = Standard_True;
+      if (++anArgIter < theArgNb
+        && !parseOnOff (theArgVec[anArgIter], toEnable))
+      {
+        --anArgIter;
+      }
+      aParams.UseEnvironmentMapBackground = toEnable;
+    }
     else if (aFlag == "-shademodel"
           || aFlag == "-shadingmodel"
           || aFlag == "-shading")
@@ -8200,8 +8295,55 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
       return 1;
     }
   }
+
+  return 0;
+}
+
+//=======================================================================
+//function : VProgressiveMode
+//purpose  :
+//=======================================================================
+#if defined(_WIN32)
+static Standard_Integer VProgressiveMode (Draw_Interpretor& /*theDI*/,
+                                          Standard_Integer  /*theNbArgs*/,
+                                          const char**      /*theArgs*/)
+{
+  Handle(V3d_View) aView = ViewerTest::CurrentView();
+  if (aView.IsNull())
+  {
+    std::cerr << "Error: no active viewer!\n";
+    return 1;
+  }
+
+  std::cout << "Press Enter or Escape key to exit progressive rendering mode" << std::endl;
+
+  for (;;)
+  {
+    aView->Redraw();
+
+    Standard_Boolean toExit = Standard_False;
+
+    MSG aMsg;
+    while (PeekMessage (&aMsg, NULL, NULL, NULL, PM_REMOVE))
+    {
+      if (aMsg.message == WM_KEYDOWN && (aMsg.wParam == 0x0d || aMsg.wParam == 0x1b))
+      {
+        toExit = Standard_True;
+      }
+
+      TranslateMessage (&aMsg);
+      DispatchMessage  (&aMsg);
+    }
+
+    if (toExit)
+    {
+      break;
+    }
+  }
+
   return 0;
 }
+#endif
 
 //=======================================================================
 //function : VFrustumCulling
@@ -8817,6 +8959,8 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "\n        {dir}ection X Y Z (for directional light or for spotlight)"
     "\n        color colorName"
     "\n        {head}light 0|1"
+    "\n        {sm}oothness value"
+    "\n        {int}ensity value"
     "\n        {constAtten}uation value"
     "\n        {linearAtten}uation value"
     "\n        angle angleDeg"
@@ -8827,7 +8971,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     __FILE__, VLight, group);
   theCommands.Add("vraytrace",
             "vraytrace [0|1]"
-    "\n\t\t: Turn on/off raytracing renderer."
+    "\n\t\t: Turns on/off ray-tracing renderer."
     "\n\t\t:   'vraytrace 0' alias for 'vrenderparams -raster'."
     "\n\t\t:   'vraytrace 1' alias for 'vrenderparams -rayTrace'.",
     __FILE__, VRenderParams, group);
@@ -8840,6 +8984,8 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "\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      '-env          on|off'  Enables/disables environment map background"
     "\n      '-shadingModel model'   Controls shading model from enumeration"
     "\n                              color, flat, gouraud, phong"
     "\n    Unlike vcaps, these parameters dramatically change visual properties."
@@ -8861,4 +9007,9 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "vxrotate",
     __FILE__,VXRotate,group);
 
+#if defined(_WIN32)
+  theCommands.Add("vprogressive",
+    "vprogressive",
+    __FILE__, VProgressiveMode, group);
+#endif
 }
index ca7f0ad..4ec6446 100644 (file)
@@ -67,30 +67,35 @@ is
        --          Light sources are created in a visualiser
        --          and are activated in one of its views.
 
-       Create ( Color          : Color from Quantity;
-                Direction      : Vector from Graphic3d; 
-                Headlight      : Boolean  from  Standard  =  Standard_False )
-               returns Light from Visual3d
-       ---Level: Public
-       ---Purpose: Creates a DIRECTIONAL light source.
-       --          Light sources are created in a visualiser
-       --          and are activated in one of its views.
-       --  Warning: Raises LightDefinitionError if <Direction> is null.
-       raises LightDefinitionError;
-
-       Create ( Color          : Color from Quantity;
-                Position       : Vertex from Graphic3d;
-                Fact1, Fact2   : Real from Standard )
-               returns Light from Visual3d
-       ---Level: Public
-       ---Purpose: Creates a POSITIONAL light source.
-       --          Light sources are created in a visualiser
-       --          and are activated in one of its views.
-       --  Warning: Raises LightDefinitionError 
-       --          if <Fact1> and <Fact2> are null.
-       --          if <Fact1> is a negative value or greater than 1.0.
-       --          if <Fact2> is a negative value or greater than 1.0.
-       raises LightDefinitionError;
+    Create ( theColor       : Color from Quantity;
+             theDirection   : Vector from Graphic3d;
+             theHeadlight   : Boolean from Standard = Standard_False;
+             theSmoothAngle : Real from Standard = 0.0;
+             theIntensity   : Real from Standard = 1.0 )
+    returns Light from Visual3d
+    ---Level: Public
+    ---Purpose: Creates a DIRECTIONAL light source.
+    --      Light sources are created in a visualiser
+    --      and are activated in one of its views.
+    --  Warning: Raises LightDefinitionError if <Direction> is null.
+    raises LightDefinitionError;
+
+    Create ( theColor        : Color from Quantity;
+             thePosition     : Vertex from Graphic3d;
+             theFact1        : Real from Standard;
+             theFact2        : Real from Standard;
+             theSmoothRadius : Real from Standard = 0.0;
+             theIntensity   : Real from Standard = 1.0 )
+    returns Light from Visual3d
+    ---Level: Public
+    ---Purpose: Creates a POSITIONAL light source.
+    --      Light sources are created in a visualiser
+    --      and are activated in one of its views.
+    --  Warning: Raises LightDefinitionError 
+    --      if <Fact1> and <Fact2> are null.
+    --      if <Fact1> is a negative value or greater than 1.0.
+    --      if <Fact2> is a negative value or greater than 1.0.
+    raises LightDefinitionError;
 
        Create ( Color          : Color from Quantity;
                 Position       : Vertex from Graphic3d;
@@ -196,6 +201,45 @@ is
        --          if the type of the light is not TOLS_POSITIONAL or TOLS_SPOT.
        raises LightDefinitionError is static;
 
+    SetSmoothAngle ( me       : mutable;
+                     theValue : Real from Standard )
+    ---Level: Public
+    ---Purpose: Modifies the smoothing angle (in radians) of
+    --          DIRECTIONAL light source.
+    --  Category: Methods to modify the class definition
+    --  Warning: Raises LightDefinitionError
+    --      if the type of the light is not TOLS_DIRECTIONAL
+    --      if <Value> is negative or greater than PI / 2.
+    raises LightDefinitionError is static;
+
+    SetSmoothRadius ( me       : mutable;
+                      theValue : Real from Standard )
+    ---Level: Public
+    ---Purpose: Modifies the smoothing radius of
+    --          POSITIONAL light source.
+    --  Category: Methods to modify the class definition
+    --  Warning: Raises LightDefinitionError
+    --      if the type of the light is not TOLS_POSITIONAL
+    --      if <Value> is negative.
+    raises LightDefinitionError is static;
+
+    SetIntensity ( me       : mutable;
+                   theValue : Real from Standard )
+    ---Level: Public
+    ---Purpose: Modifies the intensity of light source.
+    --  Category: Methods to modify the class definition
+    --  Warning: Raises LightDefinitionError
+    --      if <Value> is negative or equal to zero.
+    raises LightDefinitionError is static;
+
+    Intensity ( me ) returns Real from Standard is static;
+    ---Level: Public
+    ---Purpose: returns the intensity of light source
+
+    Smoothness ( me ) returns Real from Standard is static;
+    ---Level: Public
+    ---Purpose: returns the smoothness of light source
+
        ----------------------------
        -- Category: Inquire methods
        ----------------------------
index 68ee615..177dc27 100644 (file)
@@ -42,10 +42,12 @@ Visual3d_Light::Visual3d_Light (const Quantity_Color& theColor)
 // purpose  :
 // =======================================================================
 Visual3d_Light::Visual3d_Light (const Quantity_Color&   theColor,
-                                const Graphic3d_Vector& theDir,
-                                const Standard_Boolean  theIsHeadlight)
+                                const Graphic3d_Vector& theDirection,
+                                const Standard_Boolean  theIsHeadlight,
+                                const Standard_Real     theSmoothAngle,
+                                const Standard_Real     theIntensity)
 {
-  Visual3d_LightDefinitionError_Raise_if (theDir.LengthZero(),
+  Visual3d_LightDefinitionError_Raise_if (theDirection.LengthZero(),
                                           "Bad value for LightDirection");
   myCLight.Type        = Visual3d_TOLS_DIRECTIONAL;
   myCLight.IsHeadlight = theIsHeadlight;
@@ -54,11 +56,14 @@ Visual3d_Light::Visual3d_Light (const Quantity_Color&   theColor,
   myCLight.Color.b()   = Standard_ShortReal (theColor.Blue());
 
   Standard_Real X, Y, Z;
-  theDir.Coord (X, Y, Z);
+  theDirection.Coord (X, Y, Z);
   const Standard_Real aNorm = Sqrt (X * X + Y * Y + Z * Z);
   myCLight.Direction.x() = Standard_ShortReal (X / aNorm);
   myCLight.Direction.y() = Standard_ShortReal (Y / aNorm);
   myCLight.Direction.z() = Standard_ShortReal (Z / aNorm);
+
+  myCLight.Smoothness = static_cast<Standard_ShortReal> (theSmoothAngle);
+  myCLight.Intensity  = static_cast<Standard_ShortReal> (theIntensity);
 }
 
 // =======================================================================
@@ -66,9 +71,11 @@ Visual3d_Light::Visual3d_Light (const Quantity_Color&   theColor,
 // purpose  :
 // =======================================================================
 Visual3d_Light::Visual3d_Light (const Quantity_Color&   theColor,
-                                const Graphic3d_Vertex& thePos,
+                                const Graphic3d_Vertex& thePosition,
                                 const Standard_Real     theFact1,
-                                const Standard_Real     theFact2)
+                                const Standard_Real     theFact2,
+                                const Standard_Real     theSmoothRadius,
+                                const Standard_Real     theIntensity)
 {
   Visual3d_LightDefinitionError_Raise_if ((theFact1 == 0.0 && theFact2 == 0.0)
                                        || (theFact1  < 0.0 || theFact1 >  1.0)
@@ -79,11 +86,13 @@ Visual3d_Light::Visual3d_Light (const Quantity_Color&   theColor,
   myCLight.Color.r()    = Standard_ShortReal (theColor.Red());
   myCLight.Color.g()    = Standard_ShortReal (theColor.Green());
   myCLight.Color.b()    = Standard_ShortReal (theColor.Blue());
-  myCLight.Position.x() = Standard_ShortReal (thePos.X());
-  myCLight.Position.y() = Standard_ShortReal (thePos.Y());
-  myCLight.Position.z() = Standard_ShortReal (thePos.Z());
+  myCLight.Position.x() = Standard_ShortReal (thePosition.X());
+  myCLight.Position.y() = Standard_ShortReal (thePosition.Y());
+  myCLight.Position.z() = Standard_ShortReal (thePosition.Z());
   myCLight.ChangeConstAttenuation()  = Standard_ShortReal (theFact1);
   myCLight.ChangeLinearAttenuation() = Standard_ShortReal (theFact2);
+  myCLight.Smoothness = static_cast<Standard_ShortReal> (theSmoothRadius);
+  myCLight.Intensity  = static_cast<Standard_ShortReal> (theIntensity);
 }
 
 // =======================================================================
@@ -351,6 +360,66 @@ void Visual3d_Light::SetPosition (const Graphic3d_Vertex& thePos)
 }
 
 // =======================================================================
+// function : SetSmoothAngle
+// purpose  :
+// =======================================================================
+void Visual3d_Light::SetSmoothAngle (const Standard_Real theValue)
+{
+  Visual3d_LightDefinitionError_Raise_if (myCLight.Type != Visual3d_TOLS_DIRECTIONAL,
+    "Light Type != Visual3d_TOLS_DIRECTIONAL");
+
+  Visual3d_LightDefinitionError_Raise_if (theValue < 0.0 || theValue > M_PI / 2.0,
+    "Bad value for smoothing angle");
+
+  myCLight.Smoothness = static_cast<Standard_ShortReal> (theValue);
+}
+
+// =======================================================================
+// function : SetSmoothRadius
+// purpose  :
+// =======================================================================
+void Visual3d_Light::SetSmoothRadius (const Standard_Real theValue)
+{
+  Visual3d_LightDefinitionError_Raise_if (myCLight.Type != Visual3d_TOLS_POSITIONAL,
+    "Light Type != Visual3d_TOLS_POSITIONAL");
+
+  Visual3d_LightDefinitionError_Raise_if (theValue < 0.0,
+    "Bad value for smoothing radius");
+
+  myCLight.Smoothness = static_cast<Standard_ShortReal> (theValue);
+}
+
+// =======================================================================
+// function : SetIntensity
+// purpose  :
+// =======================================================================
+void Visual3d_Light::SetIntensity (const Standard_Real theValue)
+{
+  Visual3d_LightDefinitionError_Raise_if (theValue <= 0.0,
+    "Bad value for intensity");
+
+  myCLight.Intensity = static_cast<Standard_ShortReal> (theValue);
+}
+
+// =======================================================================
+// function : Intensity
+// purpose  :
+// =======================================================================
+Standard_Real Visual3d_Light::Intensity() const
+{
+  return static_cast<Standard_Real> (myCLight.Intensity);
+}
+
+// =======================================================================
+// function : Smoothness
+// purpose  :
+// =======================================================================
+Standard_Real Visual3d_Light::Smoothness() const
+{
+  return static_cast<Standard_Real> (myCLight.Smoothness);
+}
+
+// =======================================================================
 // function : IsValid
 // purpose  :
 // =======================================================================
diff --git a/tests/v3d/raytrace/bug25201 b/tests/v3d/raytrace/bug25201
new file mode 100644 (file)
index 0000000..0696239
--- /dev/null
@@ -0,0 +1,53 @@
+puts "========"
+puts "OCC25201: Visualization - Implementing soft shadows and ambient occlusion in OCCT ray-tracing core"
+puts "========"
+
+# custom shapes
+set aShape1 [locate_data_file occ/Top.brep]
+set aShape2 [locate_data_file occ/Bottom.brep]
+
+# setup 3D viewer content
+vinit name=View1 w=512 h=512
+vglinfo
+
+vvbo 0
+vsetdispmode 1
+vsetgradientbg 180 200 255 180 180 180 2
+vtextureenv on 4
+restore $aShape1 s1
+restore $aShape2 s2
+vdisplay s1 s2
+vsetmaterial s1 Gold
+vsetmaterial s2 Silver
+vsetlocation s1 0.0 0.1 0.0
+vlight change 0 pos -1 1 0.5
+vturnview 3.0 -1.2 -0.1
+vfit
+
+# activate path tracing
+vrenderparams -raytrace
+vrenderparams -gi
+vrenderparams -rayDepth 12
+
+set aModeNum 0
+
+vlight change 0 sm 0.1
+vlight change 0 int 100
+vbsdf s1 roughness 6400
+
+vfps 200
+vdump $imagedir/${casename}_${aModeNum}.png
+incr aModeNum
+
+vsetmaterial s1 glass
+vbsdf s1 absorpcoeff 1.0
+
+vfps 200
+vdump $imagedir/${casename}_${aModeNum}.png
+incr aModeNum
+
+vsetmaterial s2 plaster
+
+vfps 200
+vdump $imagedir/${casename}_${aModeNum}.png
+incr aModeNum
\ No newline at end of file