]> OCCT Git - occt.git/commitdiff
0032172: Visualization, TKOpenGl - implement simple shadow mapping for a spot light...
authormzernova <mzernova@opencascade.com>
Wed, 24 Aug 2022 12:04:10 +0000 (15:04 +0300)
committermzernova <mzernova@opencascade.com>
Wed, 31 Aug 2022 07:27:30 +0000 (10:27 +0300)
added test: opengl/data/shadows/spotlight

16 files changed:
src/Graphic3d/Graphic3d_CLight.cxx
src/Graphic3d/Graphic3d_ShaderManager.cxx
src/OpenGl/OpenGl_ShaderManager.hxx
src/OpenGl/OpenGl_ShadowMap.cxx
src/OpenGl/OpenGl_View.cxx
src/Shaders/DirectionalLightShadow.glsl [deleted file]
src/Shaders/FILES
src/Shaders/LightShadow.glsl [new file with mode: 0644]
src/Shaders/PBRSpotLight.glsl
src/Shaders/PhongSpotLight.glsl
src/Shaders/Shaders_DirectionalLightShadow_glsl.pxx [deleted file]
src/Shaders/Shaders_LightShadow_glsl.pxx [new file with mode: 0644]
src/Shaders/Shaders_PBRSpotLight_glsl.pxx
src/Shaders/Shaders_PhongSpotLight_glsl.pxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx
tests/opengl/data/shadows/spotlight [new file with mode: 0644]

index 4aa8a4bdfbb701dafd88d108fa9b780d21cd4b2b..8283af632d76fbf533e2e6e55be8eb491266e3c8 100644 (file)
@@ -149,7 +149,8 @@ void Graphic3d_CLight::SetEnabled (Standard_Boolean theIsOn)
 // =======================================================================
 void Graphic3d_CLight::SetCastShadows (Standard_Boolean theToCast)
 {
-  if (myType != Graphic3d_TypeOfLightSource_Directional)
+  if (myType != Graphic3d_TypeOfLightSource_Directional
+   && myType != Graphic3d_TypeOfLightSource_Spot)
   {
     throw Standard_NotImplemented ("Graphic3d_CLight::SetCastShadows() is not implemented for this light type");
   }
index 6c6edc6eef924fc4d9f3d1df465fcc906ab18f7b..8650a554dfcd70ed46e2d24dda5a1562a3ae9cf7 100644 (file)
@@ -18,7 +18,7 @@
 #include <Graphic3d_TextureSetBits.hxx>
 #include <Message.hxx>
 
-#include "../Shaders/Shaders_DirectionalLightShadow_glsl.pxx"
+#include "../Shaders/Shaders_LightShadow_glsl.pxx"
 #include "../Shaders/Shaders_PBRDistribution_glsl.pxx"
 #include "../Shaders/Shaders_PBRDirectionalLight_glsl.pxx"
 #include "../Shaders/Shaders_PBRGeometry_glsl.pxx"
@@ -1165,20 +1165,6 @@ TCollection_AsciiString Graphic3d_ShaderManager::stdComputeLighting (Standard_In
     if (theNbLights <= THE_NB_UNROLLED_LIGHTS_MAX)
     {
       Standard_Integer anIndex = 0;
-      if (theNbShadowMaps > 0)
-      {
-        for (Graphic3d_LightSet::Iterator aLightIter (theLights, Graphic3d_LightSet::IterationFilter_ExcludeDisabledAndAmbient);
-             aLightIter.More(); aLightIter.Next())
-        {
-          if (aLightIter.Value()->Type() == Graphic3d_TypeOfLightSource_Directional
-           && aLightIter.Value()->ToCastShadows())
-          {
-            aLightsLoop = aLightsLoop + EOL"    occDirectionalLight (" + anIndex + ", theNormal, theView, theIsFront,"
-                                        EOL"                         occDirectionalLightShadow (occShadowMapSamplers[" + anIndex + "], " + anIndex + ", theNormal));";
-            ++anIndex;
-          }
-        }
-      }
       for (Graphic3d_LightSet::Iterator aLightIter (theLights, Graphic3d_LightSet::IterationFilter_ExcludeDisabledAndAmbient);
            aLightIter.More(); aLightIter.Next())
       {
@@ -1193,9 +1179,14 @@ TCollection_AsciiString Graphic3d_ShaderManager::stdComputeLighting (Standard_In
             if (theNbShadowMaps > 0
              && aLightIter.Value()->ToCastShadows())
             {
-              break;
+              aLightsLoop = aLightsLoop +
+                EOL"    occDirectionalLight (" + anIndex + ", theNormal, theView, theIsFront,"
+                EOL"                         occLightShadow (occShadowMapSamplers[" + anIndex + "], " + anIndex + ", theNormal));";
+            }
+            else
+            {
+              aLightsLoop = aLightsLoop + EOL"    occDirectionalLight (" + anIndex + ", theNormal, theView, theIsFront, 1.0);";
             }
-            aLightsLoop = aLightsLoop + EOL"    occDirectionalLight (" + anIndex + ", theNormal, theView, theIsFront, 1.0);";
             ++anIndex;
             break;
           }
@@ -1207,7 +1198,17 @@ TCollection_AsciiString Graphic3d_ShaderManager::stdComputeLighting (Standard_In
           }
           case Graphic3d_TypeOfLightSource_Spot:
           {
-            aLightsLoop = aLightsLoop + EOL"    occSpotLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
+            if (theNbShadowMaps > 0
+             && aLightIter.Value()->ToCastShadows())
+            {
+              aLightsLoop = aLightsLoop +
+                EOL"    occSpotLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront,"
+                EOL"                  occLightShadow (occShadowMapSamplers[" + anIndex + "], " + anIndex + ", theNormal));";
+            }
+            else
+            {
+              aLightsLoop = aLightsLoop + EOL"    occSpotLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront, 1.0);";
+            }
             ++anIndex;
             break;
           }
@@ -1254,7 +1255,7 @@ TCollection_AsciiString Graphic3d_ShaderManager::stdComputeLighting (Standard_In
         aLightsLoop +=
           EOL"      if (aType == OccLightType_Spot)"
           EOL"      {"
-          EOL"        occSpotLight (anIndex, theNormal, theView, aPoint, theIsFront);"
+          EOL"        occSpotLight (anIndex, theNormal, theView, aPoint, theIsFront, 1.0);"
           EOL"      }";
       }
       aLightsLoop += EOL"    }";
@@ -1269,6 +1270,7 @@ TCollection_AsciiString Graphic3d_ShaderManager::stdComputeLighting (Standard_In
       aLightsFunc += Shaders_PBRIllumination_glsl;
     }
 
+    bool isShadowShaderAdded = false;
     if (theLights->NbEnabledLightsOfType (Graphic3d_TypeOfLightSource_Directional) == 1
      && theNbLights == 1
      && !theIsPBR
@@ -1280,9 +1282,10 @@ TCollection_AsciiString Graphic3d_ShaderManager::stdComputeLighting (Standard_In
     }
     else if (theLights->NbEnabledLightsOfType (Graphic3d_TypeOfLightSource_Directional) > 0)
     {
-      if (theNbShadowMaps > 0)
+      if (theNbShadowMaps > 0 && !isShadowShaderAdded)
       {
-        aLightsFunc += Shaders_DirectionalLightShadow_glsl;
+        aLightsFunc += Shaders_LightShadow_glsl;
+        isShadowShaderAdded = true;
       }
       aLightsFunc += theIsPBR ? Shaders_PBRDirectionalLight_glsl : Shaders_PhongDirectionalLight_glsl;
     }
@@ -1292,6 +1295,10 @@ TCollection_AsciiString Graphic3d_ShaderManager::stdComputeLighting (Standard_In
     }
     if (theLights->NbEnabledLightsOfType (Graphic3d_TypeOfLightSource_Spot) > 0)
     {
+      if (theNbShadowMaps > 0 && !isShadowShaderAdded)
+      {
+        aLightsFunc += Shaders_LightShadow_glsl;
+      }
       aLightsFunc += theIsPBR ? Shaders_PBRSpotLight_glsl : Shaders_PhongSpotLight_glsl;
     }
   }
index 00cbbb1e5fda70dd69398f90171a1f03eeb7f566..f8dc9da70b343e9f38da0edc0d32e1e0d0fda089 100644 (file)
@@ -268,7 +268,7 @@ public:
   {
     if (myLightSourceState.ShadowMaps().IsNull()
      || myLightSourceState.ToCastShadows() == theToCast)
-       {
+    {
       return myLightSourceState.ToCastShadows();
     }
 
index 2ca10fd6015235f3aafd3bb25e53eb5dcc3f0ac5..14854d91283a417ad4bfc73a099e38f75e47a194 100644 (file)
@@ -138,9 +138,41 @@ bool OpenGl_ShadowMap::UpdateCamera (const Graphic3d_CView& theView,
     }
     case Graphic3d_TypeOfLightSource_Spot:
     {
-      //myShadowCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
-      //myShadowCamera->SetEye (theCastShadowLight->Position());
-      return false; // not implemented
+      if (theOrigin != NULL)
+      {
+        Graphic3d_Mat4d aTrans;
+        aTrans.Translate (Graphic3d_Vec3d (theOrigin->X(), theOrigin->Y(), theOrigin->Z()));
+        Graphic3d_Mat4d anOrientMat = myShadowCamera->OrientationMatrix() * aTrans;
+        myLightMatrix = myShadowCamera->ProjectionMatrixF() * Graphic3d_Mat4 (anOrientMat);
+        return true;
+      }
+
+      Graphic3d_Vec4d aDir (myShadowLight->Direction().X(), myShadowLight->Direction().Y(), myShadowLight->Direction().Z(), 0.0);
+      if (myShadowLight->IsHeadlight())
+      {
+        Graphic3d_Mat4d anOrientInv;
+        theView.Camera()->OrientationMatrix().Inverted (anOrientInv);
+        aDir = anOrientInv * aDir;
+      }
+
+      myShadowCamera->SetZeroToOneDepth (theView.Camera()->IsZeroToOneDepth());
+      myShadowCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
+
+      const gp_Pnt& aLightPos = myShadowLight->Position();
+      Standard_Real aDistance (aMinMaxBox.Distance (Bnd_Box (aLightPos, aLightPos))
+                             + aMinMaxBox.CornerMin().Distance (aMinMaxBox.CornerMax()));
+      myShadowCamera->SetDistance (aDistance);
+      myShadowCamera->MoveEyeTo (aLightPos);
+      myShadowCamera->SetDirectionFromEye (myShadowLight->Direction());
+      myShadowCamera->SetUp (!myShadowCamera->Direction().IsParallel (gp::DY(), Precision::Angular())
+                            ? gp::DY()
+                            : gp::DX());
+      myShadowCamera->OrthogonalizeUp();
+      myShadowCamera->SetZRange (1.0, aDistance);
+
+      myLightMatrix = myShadowCamera->ProjectionMatrixF() * myShadowCamera->OrientationMatrixF();
+
+      return true;
     }
   }
   return false;
index 9eb16aeae755d94ab66b7efbf879c43ecafa5fc3..790779556779e7b528070c0260fd90a6d41729f5 100644 (file)
@@ -2334,9 +2334,12 @@ void OpenGl_View::renderShadowMap (const Handle(OpenGl_ShadowMap)& theShadowMap)
   aCtx->core11fwd->glClearDepth (1.0);
   aCtx->core11fwd->glClear (GL_DEPTH_BUFFER_BIT);
 
+  Graphic3d_Camera::Projection aProjection = theShadowMap->LightSource()->Type() == Graphic3d_TypeOfLightSource_Directional
+                                           ? Graphic3d_Camera::Projection_Orthographic
+                                           : Graphic3d_Camera::Projection_Perspective;
   myWorkspace->SetRenderFilter (myWorkspace->RenderFilter() | OpenGl_RenderFilter_SkipTrsfPersistence);
-  renderScene (Graphic3d_Camera::Projection_Orthographic, aShadowBuffer.get(), NULL, false);
-  myWorkspace->SetRenderFilter (myWorkspace->RenderFilter() & ~(Standard_Integer )OpenGl_RenderFilter_SkipTrsfPersistence);
+  renderScene (aProjection, aShadowBuffer.get(), NULL, false);
+  myWorkspace->SetRenderFilter (myWorkspace->RenderFilter() & ~(Standard_Integer)OpenGl_RenderFilter_SkipTrsfPersistence);
 
   aCtx->SetColorMask (true);
   myWorkspace->ResetAppliedAspect();
diff --git a/src/Shaders/DirectionalLightShadow.glsl b/src/Shaders/DirectionalLightShadow.glsl
deleted file mode 100644 (file)
index d0447fd..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#if (__VERSION__ >= 120)
-//! Coefficients for gathering close samples for antialiasing.
-//! Use only with decent OpenGL (array constants cannot be initialized with GLSL 1.1 / GLSL ES 1.1)
-const vec2 occPoissonDisk16[16] = vec2[](
- vec2(-0.94201624,-0.39906216), vec2( 0.94558609,-0.76890725), vec2(-0.09418410,-0.92938870), vec2( 0.34495938, 0.29387760),
- vec2(-0.91588581, 0.45771432), vec2(-0.81544232,-0.87912464), vec2(-0.38277543, 0.27676845), vec2( 0.97484398, 0.75648379),
- vec2( 0.44323325,-0.97511554), vec2( 0.53742981,-0.47373420), vec2(-0.26496911,-0.41893023), vec2( 0.79197514, 0.19090188),
- vec2(-0.24188840, 0.99706507), vec2(-0.81409955, 0.91437590), vec2( 0.19984126, 0.78641367), vec2( 0.14383161,-0.14100790)
-);
-#endif
-
-//! Function computes directional light shadow attenuation (1.0 means no shadow).
-float occDirectionalLightShadow (in sampler2D theShadow,
-                                 in int  theId,
-                                 in vec3 theNormal)
-{
-  vec4 aPosLightSpace = PosLightSpace[occLight_Index(theId)];
-  vec3 aLightDir = occLight_Position (theId);
-  vec3 aProjCoords = (aPosLightSpace.xyz / aPosLightSpace.w);
-#ifdef THE_ZERO_TO_ONE_DEPTH
-  aProjCoords.xy = aProjCoords.xy * 0.5 + vec2 (0.5);
-#else
-  aProjCoords = aProjCoords * 0.5 + vec3 (0.5);
-#endif
-  float aCurrentDepth = aProjCoords.z;
-  if (aProjCoords.x < 0.0 || aProjCoords.x > 1.0
-   || aProjCoords.y < 0.0 || aProjCoords.y > 1.0
-   || aCurrentDepth > 1.0)
-  {
-    return 1.0;
-  }
-
-  vec2 aTexelSize = vec2 (occShadowMapSizeBias.x);
-  float aBias = max (occShadowMapSizeBias.y * (1.0 - dot (theNormal, aLightDir)), occShadowMapSizeBias.y * 0.1);
-#if (__VERSION__ >= 120)
-  float aShadow = 0.0;
-  for (int aPosIter = 0; aPosIter < 16; ++aPosIter)
-  {
-    float aClosestDepth = occTexture2D (theShadow, aProjCoords.xy + occPoissonDisk16[aPosIter] * aTexelSize).r;
-    aShadow += (aCurrentDepth - aBias) > aClosestDepth ? 1.0 : 0.0;
-  }
-  return 1.0 - aShadow / 16.0;
-#else
-  float aClosestDepth = occTexture2D (theShadow, aProjCoords.xy).r;
-  float aShadow = (aCurrentDepth - aBias) > aClosestDepth ? 1.0 : 0.0;
-  return 1.0 - aShadow;
-#endif
-}
index 2a1d29017dddc2c7074877bdee5d69645e2eb290..f509a2387733155044fe3c1f34078221f7dbf73e 100644 (file)
@@ -1,6 +1,6 @@
 srcinc:::Declarations.glsl
 srcinc:::DeclarationsImpl.glsl
-srcinc:::DirectionalLightShadow.glsl
+srcinc:::LightShadow.glsl
 srcinc:::PBRCookTorrance.glsl
 srcinc:::PBRDirectionalLight.glsl
 srcinc:::PBRDistribution.glsl
@@ -27,7 +27,7 @@ srcinc:::TangentSpaceNormal.glsl
 srcinc:::SkydomBackground.fs
 Shaders_Declarations_glsl.pxx
 Shaders_DeclarationsImpl_glsl.pxx
-Shaders_DirectionalLightShadow_glsl.pxx
+Shaders_LightShadow_glsl.pxx
 Shaders_Display_fs.pxx
 Shaders_PBRCookTorrance_glsl.pxx
 Shaders_PBRDirectionalLight_glsl.pxx
diff --git a/src/Shaders/LightShadow.glsl b/src/Shaders/LightShadow.glsl
new file mode 100644 (file)
index 0000000..82dafea
--- /dev/null
@@ -0,0 +1,48 @@
+#if (__VERSION__ >= 120)
+//! Coefficients for gathering close samples for antialiasing.
+//! Use only with decent OpenGL (array constants cannot be initialized with GLSL 1.1 / GLSL ES 1.1)
+const vec2 occPoissonDisk16[16] = vec2[](
+ vec2(-0.94201624,-0.39906216), vec2( 0.94558609,-0.76890725), vec2(-0.09418410,-0.92938870), vec2( 0.34495938, 0.29387760),
+ vec2(-0.91588581, 0.45771432), vec2(-0.81544232,-0.87912464), vec2(-0.38277543, 0.27676845), vec2( 0.97484398, 0.75648379),
+ vec2( 0.44323325,-0.97511554), vec2( 0.53742981,-0.47373420), vec2(-0.26496911,-0.41893023), vec2( 0.79197514, 0.19090188),
+ vec2(-0.24188840, 0.99706507), vec2(-0.81409955, 0.91437590), vec2( 0.19984126, 0.78641367), vec2( 0.14383161,-0.14100790)
+);
+#endif
+
+//! Function computes directional and spot light shadow attenuation (1.0 means no shadow).
+float occLightShadow (in sampler2D theShadow,
+                      in int  theId,
+                      in vec3 theNormal)
+{
+  vec4 aPosLightSpace = PosLightSpace[occLight_Index(theId)];
+  vec3 aLightDir = occLight_Position (theId);
+  vec3 aProjCoords = (aPosLightSpace.xyz / aPosLightSpace.w);
+#ifdef THE_ZERO_TO_ONE_DEPTH
+  aProjCoords.xy = aProjCoords.xy * 0.5 + vec2 (0.5);
+#else
+  aProjCoords = aProjCoords * 0.5 + vec3 (0.5);
+#endif
+  float aCurrentDepth = aProjCoords.z;
+  if (aProjCoords.x < 0.0 || aProjCoords.x > 1.0
+   || aProjCoords.y < 0.0 || aProjCoords.y > 1.0
+   || aCurrentDepth > 1.0)
+  {
+    return 1.0;
+  }
+
+  vec2 aTexelSize = vec2 (occShadowMapSizeBias.x);
+  float aBias = max (occShadowMapSizeBias.y * (1.0 - dot (theNormal, aLightDir)), occShadowMapSizeBias.y * 0.1);
+#if (__VERSION__ >= 120)
+  float aShadow = 0.0;
+  for (int aPosIter = 0; aPosIter < 16; ++aPosIter)
+  {
+    float aClosestDepth = occTexture2D (theShadow, aProjCoords.xy + occPoissonDisk16[aPosIter] * aTexelSize).r;
+    aShadow += (aCurrentDepth - aBias) > aClosestDepth ? 1.0 : 0.0;
+  }
+  return 1.0 - aShadow / 16.0;
+#else
+  float aClosestDepth = occTexture2D (theShadow, aProjCoords.xy).r;
+  float aShadow = (aCurrentDepth - aBias) > aClosestDepth ? 1.0 : 0.0;
+  return 1.0 - aShadow;
+#endif
+}
index 4692f7be02f72d077853534f8937946594e29809..b1ad34281c2c45e46706bea9e26b8409d3bdbe77 100644 (file)
@@ -9,7 +9,8 @@ void occSpotLight (in int  theId,
                    in vec3 theNormal,
                    in vec3 theView,
                    in vec3 thePoint,
-                   in bool theIsFront)
+                   in bool theIsFront,
+                   in float theShadow)
 {
   vec3 aLight = occLight_Position (theId) - thePoint;
 
@@ -40,5 +41,5 @@ void occSpotLight (in int  theId,
   DirectLighting += occPBRIllumination (theView, aLight, theNormal,
                                         BaseColor, Metallic, Roughness, IOR,
                                         occLight_Specular(theId),
-                                        occLight_Intensity(theId) * anAtten);
+                                        occLight_Intensity(theId) * anAtten) * theShadow;
 }
index aab56c1bf8d5a0ed5415c71e64e7f160dd464fd8..611ceb5543dffa917460c459d631d33372c2b53c 100644 (file)
@@ -5,11 +5,13 @@
 //! @param theView    view direction
 //! @param thePoint   3D position (world space)
 //! @param theIsFront front/back face flag
+//! @param theShadow  the value from shadow map
 void occSpotLight (in int  theId,
                    in vec3 theNormal,
                    in vec3 theView,
                    in vec3 thePoint,
-                   in bool theIsFront)
+                   in bool theIsFront,
+                   in float theShadow)
 {
   vec3 aLight = occLight_Position (theId) - thePoint;
 
@@ -45,6 +47,6 @@ void occSpotLight (in int  theId,
     aSpecl = pow (aNdotH, occMaterial_Shininess (theIsFront));
   }
 
-  Diffuse  += occLight_Diffuse (theId) * aNdotL * anAtten;
-  Specular += occLight_Specular(theId) * aSpecl * anAtten;
+  Diffuse  += occLight_Diffuse (theId) * aNdotL * anAtten * theShadow;
+  Specular += occLight_Specular(theId) * aSpecl * anAtten * theShadow;
 }
diff --git a/src/Shaders/Shaders_DirectionalLightShadow_glsl.pxx b/src/Shaders/Shaders_DirectionalLightShadow_glsl.pxx
deleted file mode 100644 (file)
index d84223d..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-// This file has been automatically generated from resource file src/Shaders/DirectionalLightShadow.glsl
-
-static const char Shaders_DirectionalLightShadow_glsl[] =
-  "#if (__VERSION__ >= 120)\n"
-  "//! Coefficients for gathering close samples for antialiasing.\n"
-  "//! Use only with decent OpenGL (array constants cannot be initialized with GLSL 1.1 / GLSL ES 1.1)\n"
-  "const vec2 occPoissonDisk16[16] = vec2[](\n"
-  " vec2(-0.94201624,-0.39906216), vec2( 0.94558609,-0.76890725), vec2(-0.09418410,-0.92938870), vec2( 0.34495938, 0.29387760),\n"
-  " vec2(-0.91588581, 0.45771432), vec2(-0.81544232,-0.87912464), vec2(-0.38277543, 0.27676845), vec2( 0.97484398, 0.75648379),\n"
-  " vec2( 0.44323325,-0.97511554), vec2( 0.53742981,-0.47373420), vec2(-0.26496911,-0.41893023), vec2( 0.79197514, 0.19090188),\n"
-  " vec2(-0.24188840, 0.99706507), vec2(-0.81409955, 0.91437590), vec2( 0.19984126, 0.78641367), vec2( 0.14383161,-0.14100790)\n"
-  ");\n"
-  "#endif\n"
-  "\n"
-  "//! Function computes directional light shadow attenuation (1.0 means no shadow).\n"
-  "float occDirectionalLightShadow (in sampler2D theShadow,\n"
-  "                                 in int  theId,\n"
-  "                                 in vec3 theNormal)\n"
-  "{\n"
-  "  vec4 aPosLightSpace = PosLightSpace[occLight_Index(theId)];\n"
-  "  vec3 aLightDir = occLight_Position (theId);\n"
-  "  vec3 aProjCoords = (aPosLightSpace.xyz / aPosLightSpace.w);\n"
-  "#ifdef THE_ZERO_TO_ONE_DEPTH\n"
-  "  aProjCoords.xy = aProjCoords.xy * 0.5 + vec2 (0.5);\n"
-  "#else\n"
-  "  aProjCoords = aProjCoords * 0.5 + vec3 (0.5);\n"
-  "#endif\n"
-  "  float aCurrentDepth = aProjCoords.z;\n"
-  "  if (aProjCoords.x < 0.0 || aProjCoords.x > 1.0\n"
-  "   || aProjCoords.y < 0.0 || aProjCoords.y > 1.0\n"
-  "   || aCurrentDepth > 1.0)\n"
-  "  {\n"
-  "    return 1.0;\n"
-  "  }\n"
-  "\n"
-  "  vec2 aTexelSize = vec2 (occShadowMapSizeBias.x);\n"
-  "  float aBias = max (occShadowMapSizeBias.y * (1.0 - dot (theNormal, aLightDir)), occShadowMapSizeBias.y * 0.1);\n"
-  "#if (__VERSION__ >= 120)\n"
-  "  float aShadow = 0.0;\n"
-  "  for (int aPosIter = 0; aPosIter < 16; ++aPosIter)\n"
-  "  {\n"
-  "    float aClosestDepth = occTexture2D (theShadow, aProjCoords.xy + occPoissonDisk16[aPosIter] * aTexelSize).r;\n"
-  "    aShadow += (aCurrentDepth - aBias) > aClosestDepth ? 1.0 : 0.0;\n"
-  "  }\n"
-  "  return 1.0 - aShadow / 16.0;\n"
-  "#else\n"
-  "  float aClosestDepth = occTexture2D (theShadow, aProjCoords.xy).r;\n"
-  "  float aShadow = (aCurrentDepth - aBias) > aClosestDepth ? 1.0 : 0.0;\n"
-  "  return 1.0 - aShadow;\n"
-  "#endif\n"
-  "}\n";
diff --git a/src/Shaders/Shaders_LightShadow_glsl.pxx b/src/Shaders/Shaders_LightShadow_glsl.pxx
new file mode 100644 (file)
index 0000000..c35efe6
--- /dev/null
@@ -0,0 +1,51 @@
+// This file has been automatically generated from resource file src/Shaders/LightShadow.glsl
+
+static const char Shaders_LightShadow_glsl[] =
+  "#if (__VERSION__ >= 120)\n"
+  "//! Coefficients for gathering close samples for antialiasing.\n"
+  "//! Use only with decent OpenGL (array constants cannot be initialized with GLSL 1.1 / GLSL ES 1.1)\n"
+  "const vec2 occPoissonDisk16[16] = vec2[](\n"
+  " vec2(-0.94201624,-0.39906216), vec2( 0.94558609,-0.76890725), vec2(-0.09418410,-0.92938870), vec2( 0.34495938, 0.29387760),\n"
+  " vec2(-0.91588581, 0.45771432), vec2(-0.81544232,-0.87912464), vec2(-0.38277543, 0.27676845), vec2( 0.97484398, 0.75648379),\n"
+  " vec2( 0.44323325,-0.97511554), vec2( 0.53742981,-0.47373420), vec2(-0.26496911,-0.41893023), vec2( 0.79197514, 0.19090188),\n"
+  " vec2(-0.24188840, 0.99706507), vec2(-0.81409955, 0.91437590), vec2( 0.19984126, 0.78641367), vec2( 0.14383161,-0.14100790)\n"
+  ");\n"
+  "#endif\n"
+  "\n"
+  "//! Function computes directional and spot light shadow attenuation (1.0 means no shadow).\n"
+  "float occLightShadow (in sampler2D theShadow,\n"
+  "                      in int  theId,\n"
+  "                      in vec3 theNormal)\n"
+  "{\n"
+  "  vec4 aPosLightSpace = PosLightSpace[occLight_Index(theId)];\n"
+  "  vec3 aLightDir = occLight_Position (theId);\n"
+  "  vec3 aProjCoords = (aPosLightSpace.xyz / aPosLightSpace.w);\n"
+  "#ifdef THE_ZERO_TO_ONE_DEPTH\n"
+  "  aProjCoords.xy = aProjCoords.xy * 0.5 + vec2 (0.5);\n"
+  "#else\n"
+  "  aProjCoords = aProjCoords * 0.5 + vec3 (0.5);\n"
+  "#endif\n"
+  "  float aCurrentDepth = aProjCoords.z;\n"
+  "  if (aProjCoords.x < 0.0 || aProjCoords.x > 1.0\n"
+  "   || aProjCoords.y < 0.0 || aProjCoords.y > 1.0\n"
+  "   || aCurrentDepth > 1.0)\n"
+  "  {\n"
+  "    return 1.0;\n"
+  "  }\n"
+  "\n"
+  "  vec2 aTexelSize = vec2 (occShadowMapSizeBias.x);\n"
+  "  float aBias = max (occShadowMapSizeBias.y * (1.0 - dot (theNormal, aLightDir)), occShadowMapSizeBias.y * 0.1);\n"
+  "#if (__VERSION__ >= 120)\n"
+  "  float aShadow = 0.0;\n"
+  "  for (int aPosIter = 0; aPosIter < 16; ++aPosIter)\n"
+  "  {\n"
+  "    float aClosestDepth = occTexture2D (theShadow, aProjCoords.xy + occPoissonDisk16[aPosIter] * aTexelSize).r;\n"
+  "    aShadow += (aCurrentDepth - aBias) > aClosestDepth ? 1.0 : 0.0;\n"
+  "  }\n"
+  "  return 1.0 - aShadow / 16.0;\n"
+  "#else\n"
+  "  float aClosestDepth = occTexture2D (theShadow, aProjCoords.xy).r;\n"
+  "  float aShadow = (aCurrentDepth - aBias) > aClosestDepth ? 1.0 : 0.0;\n"
+  "  return 1.0 - aShadow;\n"
+  "#endif\n"
+  "}\n";
index 92734288a1bb979eed95e4d1eea819779fb258a5..00734d888bf1aca26cf7da959489b7da7e09eba8 100644 (file)
@@ -12,7 +12,8 @@ static const char Shaders_PBRSpotLight_glsl[] =
   "                   in vec3 theNormal,\n"
   "                   in vec3 theView,\n"
   "                   in vec3 thePoint,\n"
-  "                   in bool theIsFront)\n"
+  "                   in bool theIsFront,\n"
+  "                   in float theShadow)\n"
   "{\n"
   "  vec3 aLight = occLight_Position (theId) - thePoint;\n"
   "\n"
@@ -43,5 +44,5 @@ static const char Shaders_PBRSpotLight_glsl[] =
   "  DirectLighting += occPBRIllumination (theView, aLight, theNormal,\n"
   "                                        BaseColor, Metallic, Roughness, IOR,\n"
   "                                        occLight_Specular(theId),\n"
-  "                                        occLight_Intensity(theId) * anAtten);\n"
+  "                                        occLight_Intensity(theId) * anAtten) * theShadow;\n"
   "}\n";
index 0725975a902b24eae6be1d79bf588cff34dae869..e6c649337c5c0b30125d96a5cef6f1f1aa5c761a 100644 (file)
@@ -8,11 +8,13 @@ static const char Shaders_PhongSpotLight_glsl[] =
   "//! @param theView    view direction\n"
   "//! @param thePoint   3D position (world space)\n"
   "//! @param theIsFront front/back face flag\n"
+  "//! @param theShadow  the value from shadow map\n"
   "void occSpotLight (in int  theId,\n"
   "                   in vec3 theNormal,\n"
   "                   in vec3 theView,\n"
   "                   in vec3 thePoint,\n"
-  "                   in bool theIsFront)\n"
+  "                   in bool theIsFront,\n"
+  "                   in float theShadow)\n"
   "{\n"
   "  vec3 aLight = occLight_Position (theId) - thePoint;\n"
   "\n"
@@ -48,6 +50,6 @@ static const char Shaders_PhongSpotLight_glsl[] =
   "    aSpecl = pow (aNdotH, occMaterial_Shininess (theIsFront));\n"
   "  }\n"
   "\n"
-  "  Diffuse  += occLight_Diffuse (theId) * aNdotL * anAtten;\n"
-  "  Specular += occLight_Specular(theId) * aSpecl * anAtten;\n"
+  "  Diffuse  += occLight_Diffuse (theId) * aNdotL * anAtten * theShadow;\n"
+  "  Specular += occLight_Specular(theId) * aSpecl * anAtten * theShadow;\n"
   "}\n";
index b295489e47c6fbec47c6e570523478e365124fc4..c26d53e3405a9a8c0a20c7324808f53a8cb36f33 100644 (file)
@@ -9858,13 +9858,13 @@ static int VLight (Draw_Interpretor& theDi,
             << (aLight->IsEnabled() ? "ON" : "OFF") << "\n";
       switch (aLight->Type())
       {
-        case V3d_AMBIENT:
+        case Graphic3d_TypeOfLightSource_Ambient:
         {
           theDi << "  Type:       Ambient\n"
                 << "  Intensity:  " << aLight->Intensity() << "\n";
           break;
         }
-        case V3d_DIRECTIONAL:
+        case Graphic3d_TypeOfLightSource_Directional:
         {
           theDi << "  Type:       Directional\n"
                 << "  Intensity:  " << aLight->Intensity() << "\n"
@@ -9874,7 +9874,7 @@ static int VLight (Draw_Interpretor& theDi,
                 << "  Direction:  " << aLight->PackedDirection().x() << " " << aLight->PackedDirection().y() << " " << aLight->PackedDirection().z() << "\n";
           break;
         }
-        case V3d_POSITIONAL:
+        case Graphic3d_TypeOfLightSource_Positional:
         {
           theDi << "  Type:       Positional\n"
                 << "  Intensity:  " << aLight->Intensity() << "\n"
@@ -9886,7 +9886,7 @@ static int VLight (Draw_Interpretor& theDi,
                 << "  Range:      " << aLight->Range() << "\n";
           break;
         }
-        case V3d_SPOT:
+        case Graphic3d_TypeOfLightSource_Spot:
         {
           theDi << "  Type:       Spot\n"
                 << "  Intensity:  " << aLight->Intensity() << "\n"
@@ -14592,6 +14592,7 @@ Spot light parameters:
  -spotAngle   sets spotlight angle;
  -spotExp     sets spotlight exponenta;
  -headlight   sets headlight flag;
+ -castShadows enables/disables shadow casting;
  -constAtten  (obsolete) sets constant attenuation factor;
  -linearAtten (obsolete) sets linear   attenuation factor.
 
diff --git a/tests/opengl/data/shadows/spotlight b/tests/opengl/data/shadows/spotlight
new file mode 100644 (file)
index 0000000..7bed479
--- /dev/null
@@ -0,0 +1,39 @@
+puts "========"
+puts "0032172: Visualization, TKOpenGl - implement simple shadow mapping for a spot light source"
+puts "Test shadow map from a spot light source on a box geometry."
+puts "========"
+
+pload MODELING VISUALIZATION
+if { $::tcl_platform(os) == "Darwin" } { vcaps -core }
+box b 1 2 3
+box bb -5 -5 0 10 10 0 -preview
+vclear
+vinit View1
+vrenderparams -shadingModel phong
+vdisplay -dispMode 1 b bb
+vaspects b -material STONE -color blue
+vaspects bb -material STONE -color red
+vfit
+vlight -clear
+vlight lamp1 -add spot -castShadows 1 -direction 1 1 -1 -position -10 -10 10 
+vlight lamp2 -add spot -castShadows 1 -direction -1 -1 -1 -position 10 10 10 -intensity 1000
+vdump $::imagedir/${::casename}_two_spots.png
+
+vlight -remove lamp1
+
+vline lin1 10 10 10 -5 -5 -0.5
+vline lin2 10 10 10 -3.5 -5 -0.5
+vline lin3 10 10 10 -5 -2 -0.5
+
+if { ![string match "OpenGL ES 2.0*" [vglinfo VERSION]] && ![string match "OpenGL ES 3.0*" [vglinfo VERSION]] } {
+  vraytrace 1
+  vdump $::imagedir/${::casename}_raytrace.png
+}
+
+vraytrace 0
+vrenderparams -shadingModel phong
+vrenderparams -shadowMapBias 0.001
+vdump $::imagedir/${::casename}_phong.png
+
+vrenderparams -shadingModel pbr
+vdump $::imagedir/${::casename}_pbr.png