Graphic3d_CLight::ToCastShadows() - added new property defining if light should cast shadows (ignored by Ray-Tracing).
OpenGl_ShaderManager::stdComputeLighting() now implements shadow mapping for directional lights.
OpenGl_ShaderManager::prepareGeomMainSrc() now handles copying of arrays.
OpenGl_Context::ShadowMapTexUnit() - added property defining an offset for shadow map texture units.
OpenGl_ShadowMap - added new class storing shadow map FBO with parameters.
OpenGl_View::prepareFrameBuffers() - added resizing of shadow map FBOs.
OpenGl_View::Redraw() - added section redrawing scene into shadow map FBOs via OpenGl_View::renderShadowMap() method.
vrenderparams - added new parameters -shadowMapResolution and -shadowMapBias.
#include <Graphic3d_CLight.hxx>
#include <Standard_Atomic.hxx>
+#include <Standard_NotImplemented.hxx>
#include <Standard_OutOfRange.hxx>
IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_CLight, Standard_Transient)
myType (theType),
myRevision (0),
myIsHeadlight(false),
- myIsEnabled (true)
+ myIsEnabled (true),
+ myToCastShadows (false)
{
switch (theType)
{
myIsEnabled = theIsOn;
}
+// =======================================================================
+// function : SetCastShadows
+// purpose :
+// =======================================================================
+void Graphic3d_CLight::SetCastShadows (Standard_Boolean theToCast)
+{
+ if (myType != Graphic3d_TOLS_DIRECTIONAL)
+ {
+ throw Standard_NotImplemented ("Graphic3d_CLight::SetCastShadows() is not implemented for this light type");
+ }
+ updateRevisionIf (myToCastShadows != theToCast);
+ myToCastShadows = theToCast;
+}
+
// =======================================================================
// function : SetHeadlight
// purpose :
//! instead it turns it OFF so that it just have no effect.
Standard_EXPORT void SetEnabled (Standard_Boolean theIsOn);
+ //! Return TRUE if shadow casting is enabled; FALSE by default.
+ //! Has no effect in Ray-Tracing rendering mode.
+ Standard_Boolean ToCastShadows() const { return myToCastShadows; }
+
+ //! Enable/disable shadow casting.
+ Standard_EXPORT void SetCastShadows (Standard_Boolean theToCast);
+
//! Returns true if the light is a headlight; FALSE by default.
//! Headlight flag means that light position/direction are defined not in a World coordinate system, but relative to the camera orientation.
Standard_Boolean IsHeadlight() const { return myIsHeadlight; }
Standard_Size myRevision; //!< modification counter
Standard_Boolean myIsHeadlight; //!< flag to mark head light
Standard_Boolean myIsEnabled; //!< enabled state
+ Standard_Boolean myToCastShadows;//!< casting shadows is requested
};
Graphic3d_LightSet::Graphic3d_LightSet()
: myAmbient (0.0f, 0.0f, 0.0f, 0.0f),
myNbEnabled (0),
+ myNbCastShadows (0),
myRevision (1),
myCacheRevision (0)
{
}
myCacheRevision = myRevision;
+ myNbCastShadows = 0;
myAmbient.SetValues (0.0f, 0.0f, 0.0f, 0.0f);
memset (myLightTypesEnabled, 0, sizeof(myLightTypesEnabled));
NCollection_LocalArray<char, 32> aKeyLong (myLights.Extent() + 1);
}
else
{
- aKeyLong[aLightLast++] = THE_LIGHT_KEY_LETTERS[aLight->Type()];
+ if (aLight->ToCastShadows())
+ {
+ ++myNbCastShadows;
+ aKeyLong[aLightLast++] = UpperCase (THE_LIGHT_KEY_LETTERS[aLight->Type()]);
+ }
+ else
+ {
+ aKeyLong[aLightLast++] = THE_LIGHT_KEY_LETTERS[aLight->Type()];
+ }
}
}
aKeyLong[aLightLast] = '\0';
IterationFilter_None = 0x0000, //!< no filter
IterationFilter_ExcludeAmbient = 0x0002, //!< exclude ambient light sources
IterationFilter_ExcludeDisabled = 0x0004, //!< exclude disabled light sources
+ IterationFilter_ExcludeNoShadow = 0x0008, //!< exclude light sources not casting shadow
IterationFilter_ExcludeDisabledAndAmbient = IterationFilter_ExcludeAmbient | IterationFilter_ExcludeDisabled,
+ IterationFilter_ActiveShadowCasters = IterationFilter_ExcludeDisabledAndAmbient | IterationFilter_ExcludeNoShadow,
};
//! Iterator through light sources.
{
continue;
}
+ else if ((myFilter & IterationFilter_ExcludeNoShadow) != 0
+ && !myIter.Key()->ToCastShadows())
+ {
+ continue;
+ }
break;
}
//! @sa UpdateRevision()
Standard_Integer NbEnabledLightsOfType (Graphic3d_TypeOfLightSource theType) const { return myLightTypesEnabled[theType]; }
+ //! Returns total amount of enabled lights castings shadows.
+ //! @sa UpdateRevision()
+ Standard_Integer NbCastShadows() const { return myNbCastShadows; }
+
//! Returns cumulative ambient color, which is computed as sum of all enabled ambient light sources.
//! Values are NOT clamped (can be greater than 1.0f) and alpha component is fixed to 1.0f.
//! @sa UpdateRevision()
Standard_Integer myLightTypes [Graphic3d_TypeOfLightSource_NB]; //!< counters per each light source type defined in the list
Standard_Integer myLightTypesEnabled[Graphic3d_TypeOfLightSource_NB]; //!< counters per each light source type enabled in the list
Standard_Integer myNbEnabled; //!< number of enabled light sources, excluding ambient
+ Standard_Integer myNbCastShadows; //!< number of enabled light sources casting shadows
Standard_Size myRevision; //!< current revision of light source set
Standard_Size myCacheRevision; //!< revision of cached state
};
OitDepthFactor (0.0f),
NbMsaaSamples (0),
RenderResolutionScale (1.0f),
+ ShadowMapResolution (1024),
+ ShadowMapBias (0.005f),
ToEnableDepthPrepass (Standard_False),
ToEnableAlphaToCoverage (Standard_True),
// ray tracing parameters
Standard_Integer NbMsaaSamples; //!< number of MSAA samples (should be within 0..GL_MAX_SAMPLES, power-of-two number), 0 by default
Standard_ShortReal RenderResolutionScale; //!< rendering resolution scale factor, 1 by default;
//! incompatible with MSAA (e.g. NbMsaaSamples should be set to 0)
+ Standard_Integer ShadowMapResolution; //!< shadow texture map resolution, 1024 by default
+ Standard_ShortReal ShadowMapBias; //!< shadowmap bias, 0.005 by default;
Standard_Boolean ToEnableDepthPrepass; //!< enables/disables depth pre-pass, False by default
Standard_Boolean ToEnableAlphaToCoverage; //!< enables/disables alpha to coverage, True by default
// =======================================================================
Graphic3d_ShaderProgram::Graphic3d_ShaderProgram()
: myNbLightsMax (THE_MAX_LIGHTS_DEFAULT),
+ myNbShadowMaps (0),
myNbClipPlanesMax (THE_MAX_CLIP_PLANES_DEFAULT),
myNbFragOutputs (THE_NB_FRAG_OUTPUTS),
myTextureSetBits (Graphic3d_TextureSetBits_NONE),
//! Specify the length of array of light sources (THE_MAX_LIGHTS).
void SetNbLightsMax (Standard_Integer theNbLights) { myNbLightsMax = theNbLights; }
+ //! Return the length of array of shadow maps (THE_NB_SHADOWMAPS); 0 by default.
+ Standard_Integer NbShadowMaps() const { return myNbShadowMaps; }
+
+ //! Specify the length of array of shadow maps (THE_NB_SHADOWMAPS).
+ void SetNbShadowMaps (Standard_Integer theNbMaps) { myNbShadowMaps = theNbMaps; }
+
//! Return the length of array of clipping planes (THE_MAX_CLIP_PLANES),
//! to be used for initialization occClipPlaneEquations.
//! Default value is THE_MAX_CLIP_PLANES_DEFAULT.
Graphic3d_ShaderAttributeList myAttributes; //!< the list of custom vertex attributes
TCollection_AsciiString myHeader; //!< GLSL header with version code and used extensions
Standard_Integer myNbLightsMax; //!< length of array of light sources (THE_MAX_LIGHTS)
+ Standard_Integer myNbShadowMaps; //!< length of array of shadow maps (THE_NB_SHADOWMAPS)
Standard_Integer myNbClipPlanesMax; //!< length of array of clipping planes (THE_MAX_CLIP_PLANES)
Standard_Integer myNbFragOutputs; //!< length of array of Fragment Shader outputs (THE_NB_FRAG_OUTPUTS)
Standard_Integer myTextureSetBits;//!< texture units declared within the program, @sa Graphic3d_TextureSetBits
//! Note that it can be overridden to Graphic3d_TextureUnit_0 for FFP fallback on hardware without multi-texturing.
Graphic3d_TextureUnit_PointSprite = Graphic3d_TextureUnit_1,
+ //! sampler2D occShadowMapSampler.
+ //! Directional light source shadowmap texture.
+ Graphic3d_TextureUnit_ShadowMap = -4,
+
//! sampler2D occEnvLUT.
//! Lookup table for approximated PBR environment lighting.
//! Configured as index at the end of available texture units - 3.
OpenGl_ShaderProgram.hxx
OpenGl_ShaderStates.cxx
OpenGl_ShaderStates.hxx
+OpenGl_ShadowMap.cxx
+OpenGl_ShadowMap.hxx
OpenGl_StencilTest.cxx
OpenGl_StencilTest.hxx
OpenGl_TileSampler.hxx
myPBREnvLUTTexUnit (Graphic3d_TextureUnit_PbrEnvironmentLUT),
myPBRDiffIBLMapSHTexUnit (Graphic3d_TextureUnit_PbrIblDiffuseSH),
myPBRSpecIBLMapTexUnit (Graphic3d_TextureUnit_PbrIblSpecular),
+ myShadowMapTexUnit (Graphic3d_TextureUnit_ShadowMap),
myFrameStats (new OpenGl_FrameStats()),
myActiveMockTextures (0),
myActiveHatchType (Aspect_HS_SOLID),
myPBRDiffIBLMapSHTexUnit = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined + Graphic3d_TextureUnit_PbrIblDiffuseSH);
myPBRSpecIBLMapTexUnit = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined + Graphic3d_TextureUnit_PbrIblSpecular);
}
+ myShadowMapTexUnit = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined + Graphic3d_TextureUnit_ShadowMap);
}
// =======================================================================
//! Returns texture unit where Specular IBL map is expected to be bound, or 0 if PBR is unavailable.
Graphic3d_TextureUnit PBRSpecIBLMapTexUnit() const { return myPBRSpecIBLMapTexUnit; }
+ //! Returns texture unit where shadow map is expected to be bound, or 0 if unavailable.
+ Graphic3d_TextureUnit ShadowMapTexUnit() const { return myShadowMapTexUnit; }
+
//! Returns true if VBO is supported and permitted.
inline bool ToUseVbo() const
{
Graphic3d_TextureUnit myPBRDiffIBLMapSHTexUnit; //!< sampler2D occDiffIBLMapSHCoeffs, texture unit where diffuse (irradiance) IBL map's spherical harmonics coefficients is expected to be binded
//! (0 if PBR is not supported)
Graphic3d_TextureUnit myPBRSpecIBLMapTexUnit; //!< samplerCube occSpecIBLMap, texture unit where specular IBL map is expected to be binded (0 if PBR is not supported)
+ Graphic3d_TextureUnit myShadowMapTexUnit; //!< sampler2D occShadowMapSampler
Handle(OpenGl_ShaderManager) myShaderManager; //! support object for managing shader programs
Standard_EXPORT virtual void UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx);
//! Returns the color texture for the given color buffer index.
- inline const Handle(OpenGl_Texture)& ColorTexture (const GLint theColorBufferIndex = 0) const
+ const Handle(OpenGl_Texture)& ColorTexture (const GLint theColorBufferIndex = 0) const
{
return myColorTextures (theColorBufferIndex);
}
//! Returns the depth-stencil texture.
- inline const Handle(OpenGl_Texture)& DepthStencilTexture() const
+ const Handle(OpenGl_Texture)& DepthStencilTexture() const
{
return myDepthStencilTexture;
}
#include <OpenGl_GlCore20.hxx>
#include <OpenGl_View.hxx>
+#include <OpenGl_ShadowMap.hxx>
#include <OpenGl_Workspace.hxx>
IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameStats, Graphic3d_FrameStats)
aMemFbos += estimatedDataSize (aView->myMainSceneFbosOit[1]);
aMemFbos += estimatedDataSize (aView->myImmediateSceneFbosOit[0]);
aMemFbos += estimatedDataSize (aView->myImmediateSceneFbosOit[1]);
+ // shadowmap FBOs
+ aMemFbos += aView->myShadowMaps->EstimatedDataSize();
// dump FBO
aMemFbos += estimatedDataSize (aView->myFBO);
// RayTracing FBO
const Standard_Boolean hasLocalCS = !aLayerSettings.OriginTransformation().IsNull();
const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager();
- Handle(Graphic3d_LightSet) aLightsBack = aManager->LightSourceState().LightSources();
+ Handle(Graphic3d_LightSet) aLightsBack = aManager->LightSourceState().LightSources();
+ Handle(OpenGl_ShadowMapArray) aShadowMaps = aManager->LightSourceState().ShadowMaps();
const bool hasOwnLights = aCtx->ColorMask() && !aLayerSettings.Lights().IsNull() && aLayerSettings.Lights() != aLightsBack;
if (hasOwnLights)
{
aLayerSettings.Lights()->UpdateRevision();
- aManager->UpdateLightSourceStateTo (aLayerSettings.Lights(), theWorkspace->View()->SpecIBLMapLevels());
+ aManager->UpdateLightSourceStateTo (aLayerSettings.Lights(), theWorkspace->View()->SpecIBLMapLevels(), Handle(OpenGl_ShadowMapArray)());
}
const Handle(Graphic3d_Camera)& aWorldCamera = theWorkspace->View()->Camera();
if (hasOwnLights)
{
- aManager->UpdateLightSourceStateTo (aLightsBack, theWorkspace->View()->SpecIBLMapLevels());
+ aManager->UpdateLightSourceStateTo (aLightsBack, theWorkspace->View()->SpecIBLMapLevels(), aShadowMaps);
}
if (hasLocalCS)
{
aCtx->core11fwd->glGetIntegerv (GL_DEPTH_FUNC, &aPrevSettings.DepthFunc);
aCtx->core11fwd->glGetBooleanv (GL_DEPTH_WRITEMASK, &aPrevSettings.DepthMask);
OpenGl_GlobalLayerSettings aDefaultSettings = aPrevSettings;
+ const bool isShadowMapPass = theReadDrawFbo != NULL
+ && !theReadDrawFbo->HasColor();
// Two render filters are used to support transparency draw. Opaque filter accepts
// only non-transparent OpenGl elements of a layer and counts number of skipped
OpenGl_LayerStack::iterator aStackIter (myTransparentToProcess.Origin());
Standard_Integer aClearDepthLayerPrev = -1, aClearDepthLayer = -1;
const bool toPerformDepthPrepass = theWorkspace->View()->RenderingParams().ToEnableDepthPrepass
- && aPrevSettings.DepthMask == GL_TRUE;
- const Handle(Graphic3d_LightSet) aLightsBack = aCtx->ShaderManager()->LightSourceState().LightSources();
+ && aPrevSettings.DepthMask == GL_TRUE
+ && !isShadowMapPass;
+ const Handle(Graphic3d_LightSet) aLightsBack = aCtx->ShaderManager()->LightSourceState().LightSources();
+ const Handle(OpenGl_ShadowMapArray) aShadowMaps = aCtx->ShaderManager()->LightSourceState().ShadowMaps();
for (OpenGl_FilteredIndexedLayerIterator aLayerIterStart (myLayers, theToDrawImmediate, theLayersToProcess); aLayerIterStart.More();)
{
bool hasSkippedDepthLayers = false;
if (aPassIter == 0)
{
aCtx->SetColorMask (false);
- aCtx->ShaderManager()->UpdateLightSourceStateTo (Handle(Graphic3d_LightSet)(), theWorkspace->View()->SpecIBLMapLevels());
+ aCtx->ShaderManager()->UpdateLightSourceStateTo (Handle(Graphic3d_LightSet)(), theWorkspace->View()->SpecIBLMapLevels(), Handle(OpenGl_ShadowMapArray)());
aDefaultSettings.DepthFunc = aPrevSettings.DepthFunc;
aDefaultSettings.DepthMask = GL_TRUE;
}
continue;
}
aCtx->SetColorMask (true);
- aCtx->ShaderManager()->UpdateLightSourceStateTo (aLightsBack, theWorkspace->View()->SpecIBLMapLevels());
+ aCtx->ShaderManager()->UpdateLightSourceStateTo (aLightsBack, theWorkspace->View()->SpecIBLMapLevels(), aShadowMaps);
aDefaultSettings = aPrevSettings;
}
else if (aPassIter == 2)
{
- aCtx->SetColorMask (true);
- aCtx->ShaderManager()->UpdateLightSourceStateTo (aLightsBack, theWorkspace->View()->SpecIBLMapLevels());
+ if (isShadowMapPass)
+ {
+ aCtx->SetColorMask (false);
+ aCtx->ShaderManager()->UpdateLightSourceStateTo (Handle(Graphic3d_LightSet)(), theWorkspace->View()->SpecIBLMapLevels(), Handle(OpenGl_ShadowMapArray)());
+ }
+ else
+ {
+ aCtx->SetColorMask (true);
+ aCtx->ShaderManager()->UpdateLightSourceStateTo (aLightsBack, theWorkspace->View()->SpecIBLMapLevels(), aShadowMaps);
+ }
if (toPerformDepthPrepass)
{
aDefaultSettings.DepthFunc = GL_EQUAL;
}
}
+ aCtx->ShaderManager()->UpdateLightSourceStateTo (aLightsBack, theWorkspace->View()->SpecIBLMapLevels(), aShadowMaps);
aCtx->core11fwd->glDepthMask (aPrevSettings.DepthMask);
aCtx->core11fwd->glDepthFunc (aPrevSettings.DepthFunc);
#include <OpenGl_Context.hxx>
#include <Graphic3d_CubeMapPacked.hxx>
#include <OpenGl_ShaderManager.hxx>
+#include <OpenGl_ShadowMap.hxx>
#include <OpenGl_ShaderProgram.hxx>
#include <OpenGl_VertexBufferCompat.hxx>
#include <OpenGl_PointSprite.hxx>
#include <OpenGl_Workspace.hxx>
#include <TCollection_ExtendedString.hxx>
+#include "../Shaders/Shaders_DirectionalLightShadow_glsl.pxx"
#include "../Shaders/Shaders_PBRDistribution_glsl.pxx"
#include "../Shaders/Shaders_PBRGeometry_glsl.pxx"
#include "../Shaders/Shaders_PBRFresnel_glsl.pxx"
EOL"void directionalLight (in int theId,"
EOL" in vec3 theNormal,"
EOL" in vec3 theView,"
- EOL" in bool theIsFront)"
+ EOL" in bool theIsFront,"
+ EOL" in float theShadow)"
EOL"{"
EOL" vec3 aLight = vec3 (occWorldViewMatrix * vec4 (occLight_Position (theId), 0.0));"
EOL
EOL" aSpecl = pow (aNdotH, theIsFront ? occFrontMaterial_Shininess() : occBackMaterial_Shininess());"
EOL" }"
EOL
- EOL" Diffuse += occLight_Diffuse (theId) * aNdotL;"
- EOL" Specular += occLight_Specular (theId) * aSpecl;"
+ EOL" Diffuse += occLight_Diffuse (theId) * aNdotL * theShadow;"
+ EOL" Specular += occLight_Specular (theId) * aSpecl * theShadow;"
EOL"}";
//! Function computes contribution of directional light source
EOL"void directionalLight (in int theId,"
EOL" in vec3 theNormal,"
EOL" in vec3 theView,"
- EOL" in bool theIsFront)"
+ EOL" in bool theIsFront,"
+ EOL" in float theShadow)"
EOL"{"
EOL" vec3 aLight = occLight_Position (theId);"
EOL
EOL" DirectLighting += occPBRIllumination (theView, aLight, theNormal,"
EOL" BaseColor, Metallic, Roughness, IOR,"
EOL" occLight_Specular (theId),"
- EOL" occLight_Intensity(theId));"
+ EOL" occLight_Intensity(theId)) * theShadow;"
EOL"}";
//! The same as THE_FUNC_directionalLight but for the light with zero index
const char THE_FUNC_directionalLightFirst[] =
EOL"void directionalLightFirst (in vec3 theNormal,"
EOL" in vec3 theView,"
- EOL" in bool theIsFront)"
+ EOL" in bool theIsFront,"
+ EOL" in float theShadow)"
EOL"{"
EOL" vec3 aLight = vec3 (occWorldViewMatrix * vec4 (occLight_Position (0), 0.0));"
EOL
EOL" aSpecl = pow (aNdotH, theIsFront ? occFrontMaterial_Shininess() : occBackMaterial_Shininess());"
EOL" }"
EOL
- EOL" Diffuse += occLight_Diffuse(0) * aNdotL;"
- EOL" Specular += occLight_Specular(0) * aSpecl;"
+ EOL" Diffuse += occLight_Diffuse(0) * aNdotL * theShadow;"
+ EOL" Specular += occLight_Specular(0) * aSpecl * theShadow;"
EOL"}";
//! Returns the real cubemap fetching direction considering sides orientation, memory layout and vertical flip.
#endif
//! Generate map key for light sources configuration.
- static TCollection_AsciiString genLightKey (const Handle(Graphic3d_LightSet)& theLights)
+ static TCollection_AsciiString genLightKey (const Handle(Graphic3d_LightSet)& theLights,
+ const bool theHasShadowMap)
{
if (theLights->NbEnabled() <= THE_NB_UNROLLED_LIGHTS_MAX)
{
- return TCollection_AsciiString ("l_") + theLights->KeyEnabledLong();
+ return theHasShadowMap
+ ? TCollection_AsciiString ("ls_") + theLights->KeyEnabledLong()
+ : TCollection_AsciiString ("l_") + theLights->KeyEnabledLong();
}
const Standard_Integer aMaxLimit = roundUpMaxLightSources (theLights->NbEnabled());
return;
}
- const TCollection_AsciiString aKey = genLightKey (aLights);
+ const TCollection_AsciiString aKey = genLightKey (aLights, myLightSourceState.HasShadowMaps());
if (!myMapOfLightPrograms.Find (aKey, myLightPrograms))
{
myLightPrograms = new OpenGl_SetOfShaderPrograms();
// purpose : Updates state of OCCT light sources
// =======================================================================
void OpenGl_ShaderManager::UpdateLightSourceStateTo (const Handle(Graphic3d_LightSet)& theLights,
- Standard_Integer theSpecIBLMapLevels)
+ Standard_Integer theSpecIBLMapLevels,
+ const Handle(OpenGl_ShadowMapArray)& theShadowMaps)
{
myLightSourceState.Set (theLights);
myLightSourceState.SetSpecIBLMapLevels (theSpecIBLMapLevels);
+ myLightSourceState.SetShadowMaps (theShadowMaps);
myLightSourceState.Update();
switchLightPrograms();
}
{
theProgram->SetUniform (myContext, aLocation, myLightSourceState.SpecIBLMapLevels());
}
+
+ // update shadow map variables
+ if (const OpenGl_ShaderUniformLocation aShadowMatLoc = theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SHADOWMAP_MATRICES))
+ {
+ if (myShadowMatArray.Size() < theProgram->NbShadowMaps())
+ {
+ myShadowMatArray.Resize (0, theProgram->NbShadowMaps() - 1, false);
+ }
+
+ Graphic3d_Vec2 aSizeBias;
+ if (myLightSourceState.HasShadowMaps())
+ {
+ aSizeBias.SetValues (1.0f / (float )myLightSourceState.ShadowMaps()->First()->Texture()->SizeX(),
+ myLightSourceState.ShadowMaps()->First()->ShadowMapBias());
+ const Standard_Integer aNbShadows = Min (theProgram->NbShadowMaps(), myLightSourceState.ShadowMaps()->Size());
+ for (Standard_Integer aShadowIter = 0; aShadowIter < aNbShadows; ++aShadowIter)
+ {
+ const Handle(OpenGl_ShadowMap)& aShadow = myLightSourceState.ShadowMaps()->Value (aShadowIter);
+ myShadowMatArray[aShadowIter] = aShadow->LightSourceMatrix();
+ }
+ }
+
+ theProgram->SetUniform (myContext, aShadowMatLoc, theProgram->NbShadowMaps(), &myShadowMatArray.First());
+ theProgram->SetUniform (myContext, theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SHADOWMAP_SIZE_BIAS), aSizeBias);
+ }
}
// =======================================================================
defaultGlslVersion (aProgramSrc, "font", 0);
aProgramSrc->SetDefaultSampler (false);
aProgramSrc->SetNbLightsMax (0);
+ aProgramSrc->SetNbShadowMaps (0);
aProgramSrc->SetNbClipPlanesMax (0);
aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX, aUniforms, aStageInOuts));
aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
aProgramSrc->SetId (anId);
aProgramSrc->SetDefaultSampler (false);
aProgramSrc->SetNbLightsMax (0);
+ aProgramSrc->SetNbShadowMaps (0);
aProgramSrc->SetNbClipPlanesMax (0);
aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX, aUniforms, aStageInOuts));
aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
aProgramSrc->SetId (theMsaa ? "occt_weight-oit-msaa" : "occt_weight-oit");
aProgramSrc->SetDefaultSampler (false);
aProgramSrc->SetNbLightsMax (0);
+ aProgramSrc->SetNbShadowMaps (0);
aProgramSrc->SetNbClipPlanesMax (0);
aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX, aUniforms, aStageInOuts));
aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
if (aVarListIter.Value().Stages == (Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT))
{
const TCollection_AsciiString aVarName = aVarListIter.Value().Name.Token (" ", 2);
- aSrcMainGeom += TCollection_AsciiString()
- + EOL" geomOut." + aVarName + " = geomIn[" + aVertIndex + "]." + aVarName + ";";
+ if (aVarName.Value (aVarName.Length()) == ']')
+ {
+ // copy the whole array
+ const TCollection_AsciiString aVarName2 = aVarName.Token ("[", 1);
+ aSrcMainGeom += TCollection_AsciiString()
+ + EOL" geomOut." + aVarName2 + " = geomIn[" + aVertIndex + "]." + aVarName2 + ";";
+ }
+ else
+ {
+ aSrcMainGeom += TCollection_AsciiString()
+ + EOL" geomOut." + aVarName + " = geomIn[" + aVertIndex + "]." + aVarName + ";";
+ }
}
}
defaultGlslVersion (aProgramSrc, theIsOutline ? "outline" : "unlit", theBits);
aProgramSrc->SetDefaultSampler (false);
aProgramSrc->SetNbLightsMax (0);
+ aProgramSrc->SetNbShadowMaps (0);
aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
aProgramSrc->SetAlphaTest ((theBits & OpenGl_PO_AlphaTest) != 0);
const Standard_Integer aNbGeomInputVerts = !aSrcGeom.IsEmpty() ? 3 : 0;
TCollection_AsciiString OpenGl_ShaderManager::stdComputeLighting (Standard_Integer& theNbLights,
Standard_Boolean theHasVertColor,
Standard_Boolean theIsPBR,
- Standard_Boolean theHasEmissive)
+ Standard_Boolean theHasEmissive,
+ Standard_Boolean theHasShadowMap)
{
TCollection_AsciiString aLightsFunc, aLightsLoop;
theNbLights = 0;
const Handle(Graphic3d_LightSet)& aLights = myLightSourceState.LightSources();
if (!aLights.IsNull())
{
+ const bool hasShadowMap = theHasShadowMap && myLightSourceState.HasShadowMaps();
theNbLights = aLights->NbEnabled();
if (theNbLights <= THE_NB_UNROLLED_LIGHTS_MAX)
{
Standard_Integer anIndex = 0;
+ if (hasShadowMap)
+ {
+ for (Graphic3d_LightSet::Iterator aLightIter (aLights, Graphic3d_LightSet::IterationFilter_ExcludeDisabledAndAmbient);
+ aLightIter.More(); aLightIter.Next())
+ {
+ if (aLightIter.Value()->Type() == Graphic3d_TOLS_DIRECTIONAL
+ && aLightIter.Value()->ToCastShadows())
+ {
+ aLightsLoop = aLightsLoop + EOL" directionalLight (" + anIndex + ", theNormal, theView, theIsFront,"
+ EOL" occDirectionalLightShadow (" + anIndex + ", theNormal));";
+ ++anIndex;
+ }
+ }
+ }
for (Graphic3d_LightSet::Iterator aLightIter (aLights, Graphic3d_LightSet::IterationFilter_ExcludeDisabledAndAmbient);
- aLightIter.More(); aLightIter.Next(), ++anIndex)
+ aLightIter.More(); aLightIter.Next())
{
switch (aLightIter.Value()->Type())
{
case Graphic3d_TOLS_AMBIENT:
- --anIndex;
+ {
break; // skip ambient
+ }
case Graphic3d_TOLS_DIRECTIONAL:
- aLightsLoop = aLightsLoop + EOL" directionalLight (" + anIndex + ", theNormal, theView, theIsFront);";
+ {
+ if (hasShadowMap
+ && aLightIter.Value()->ToCastShadows())
+ {
+ break;
+ }
+ aLightsLoop = aLightsLoop + EOL" directionalLight (" + anIndex + ", theNormal, theView, theIsFront, 1.0);";
+ ++anIndex;
break;
+ }
case Graphic3d_TOLS_POSITIONAL:
+ {
aLightsLoop = aLightsLoop + EOL" pointLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
+ ++anIndex;
break;
+ }
case Graphic3d_TOLS_SPOT:
+ {
aLightsLoop = aLightsLoop + EOL" spotLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
+ ++anIndex;
break;
+ }
}
}
}
aLightsLoop +=
EOL" if (aType == OccLightType_Direct)"
EOL" {"
- EOL" directionalLight (anIndex, theNormal, theView, theIsFront);"
+ EOL" directionalLight (anIndex, theNormal, theView, theIsFront, 1.0);"
EOL" }";
}
if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_POSITIONAL) > 0)
if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_DIRECTIONAL) == 1
&& theNbLights == 1
- && !theIsPBR)
+ && !theIsPBR
+ && !hasShadowMap)
{
// use the version with hard-coded first index
- aLightsLoop = EOL" directionalLightFirst(theNormal, theView, theIsFront);";
+ aLightsLoop = EOL" directionalLightFirst(theNormal, theView, theIsFront, 1.0);";
aLightsFunc += THE_FUNC_directionalLightFirst;
}
else if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_DIRECTIONAL) > 0)
{
+ if (hasShadowMap)
+ {
+ aLightsFunc += Shaders_DirectionalLightShadow_glsl;
+ }
aLightsFunc += theIsPBR ? THE_FUNC_PBR_directionalLight : THE_FUNC_directionalLight;
}
if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_POSITIONAL) > 0)
aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 BackColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
Standard_Integer aNbLights = 0;
- const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, !aSrcVertColor.IsEmpty(), false, true);
+ const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, !aSrcVertColor.IsEmpty(), false, true, false);
aSrcVert = TCollection_AsciiString()
+ THE_FUNC_transformNormal_view
+ EOL
EOL" vec4 aPosition = occWorldViewMatrix * aPositionWorld;"
EOL" vec3 aNormal = transformNormal (occNormal);"
EOL" vec3 aView = vec3 (0.0, 0.0, 1.0);"
- EOL" FrontColor = computeLighting (normalize (aNormal), normalize (aView), aPosition, true);"
- EOL" BackColor = computeLighting (normalize (aNormal), normalize (aView), aPosition, false);"
+ EOL" FrontColor = computeLighting (aNormal, aView, aPosition, true);"
+ EOL" BackColor = computeLighting (aNormal, aView, aPosition, false);"
+ aSrcVertExtraMain
+ THE_VERT_gl_Position
+ EOL"}";
+ EOL" occSetFragColor (getFinalColor());"
+ EOL"}";
- const TCollection_AsciiString aProgId = TCollection_AsciiString ("gouraud-") + genLightKey (myLightSourceState.LightSources()) + "-";
+ const TCollection_AsciiString aProgId = TCollection_AsciiString ("gouraud-") + genLightKey (myLightSourceState.LightSources(), false) + "-";
defaultGlslVersion (aProgramSrc, aProgId, theBits);
aProgramSrc->SetDefaultSampler (false);
aProgramSrc->SetNbLightsMax (aNbLights);
+ aProgramSrc->SetNbShadowMaps (0);
aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
aProgramSrc->SetAlphaTest ((theBits & OpenGl_PO_AlphaTest) != 0);
const Standard_Integer aNbGeomInputVerts = !aSrcGeom.IsEmpty() ? 3 : 0;
aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 PositionWorld", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 Position", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec3 View", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
+ if (myLightSourceState.HasShadowMaps())
+ {
+ aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("mat4 occShadowMapMatrices[THE_NB_SHADOWMAPS]", Graphic3d_TOS_VERTEX));
+ aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occShadowMapSamplers[THE_NB_SHADOWMAPS]", Graphic3d_TOS_FRAGMENT));
+ aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("vec2 occShadowMapSizeBias", Graphic3d_TOS_FRAGMENT));
+
+ aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 PosLightSpace[THE_NB_SHADOWMAPS]", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
+ aSrcVertExtraMain +=
+ EOL" for (int aShadowIter = 0; aShadowIter < THE_NB_SHADOWMAPS; ++aShadowIter)"
+ EOL" {"
+ EOL" PosLightSpace[aShadowIter] = occShadowMapMatrices[aShadowIter] * PositionWorld;"
+ EOL" }";
+ }
aSrcVert = TCollection_AsciiString()
+ aSrcVertExtraFunc
: EOL"#define getFinalColor getColor";
Standard_Integer aNbLights = 0;
+ Standard_Integer aNbShadowMaps = myLightSourceState.HasShadowMaps()
+ ? myLightSourceState.LightSources()->NbCastShadows()
+ : 0;
const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, !aSrcFragGetVertColor.IsEmpty(), theIsPBR,
(theBits & OpenGl_PO_TextureRGB) == 0
- || (theBits & OpenGl_PO_IsPoint) != 0);
+ || (theBits & OpenGl_PO_IsPoint) != 0,
+ myLightSourceState.HasShadowMaps());
aSrcFrag += TCollection_AsciiString()
+ EOL
+ aSrcFragGetVertColor
+ EOL" occSetFragColor (getFinalColor());"
+ EOL"}";
- const TCollection_AsciiString aProgId = TCollection_AsciiString (theIsFlatNormal ? "flat-" : "phong-") + (theIsPBR ? "pbr-" : "") + genLightKey (myLightSourceState.LightSources()) + "-";
+ const TCollection_AsciiString aProgId = TCollection_AsciiString (theIsFlatNormal ? "flat-" : "phong-") + (theIsPBR ? "pbr-" : "")
+ + genLightKey (myLightSourceState.LightSources(), aNbShadowMaps > 0) + "-";
defaultGlslVersion (aProgramSrc, aProgId, theBits, isFlatNormal);
aProgramSrc->SetDefaultSampler (false);
aProgramSrc->SetNbLightsMax (aNbLights);
+ aProgramSrc->SetNbShadowMaps (aNbShadowMaps);
aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
aProgramSrc->SetAlphaTest ((theBits & OpenGl_PO_AlphaTest) != 0);
defaultGlslVersion (aProgramSrc, aName, 0);
aProgramSrc->SetDefaultSampler (false);
aProgramSrc->SetNbLightsMax (0);
+ aProgramSrc->SetNbShadowMaps (0);
aProgramSrc->SetNbClipPlanesMax (0);
aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX, aUniforms, aStageInOuts));
aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
defaultGlslVersion (aProgramSrc, "bndbox", 0);
aProgramSrc->SetDefaultSampler (false);
aProgramSrc->SetNbLightsMax (0);
+ aProgramSrc->SetNbShadowMaps (0);
aProgramSrc->SetNbClipPlanesMax (0);
aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX, aUniforms, aStageInOuts));
aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
defaultGlslVersion (aProgramSrc, "pbr_env_baking", 0);
aProgramSrc->SetDefaultSampler (false);
aProgramSrc->SetNbLightsMax (0);
+ aProgramSrc->SetNbShadowMaps (0);
aProgramSrc->SetNbClipPlanesMax (0);
aProgramSrc->SetPBR (true);
aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX, aUniforms, aStageInOuts));
defaultGlslVersion (myBgCubeMapProgram, "background_cubemap", 0);
myBgCubeMapProgram->SetDefaultSampler (false);
myBgCubeMapProgram->SetNbLightsMax (0);
+ myBgCubeMapProgram->SetNbShadowMaps (0);
myBgCubeMapProgram->SetNbClipPlanesMax (0);
myBgCubeMapProgram->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX, aUniforms, aStageInOuts));
myBgCubeMapProgram->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
//! Updates state of OCCT light sources.
Standard_EXPORT void UpdateLightSourceStateTo (const Handle(Graphic3d_LightSet)& theLights,
- Standard_Integer theSpecIBLMapLevels = 0);
+ Standard_Integer theSpecIBLMapLevels,
+ const Handle(OpenGl_ShadowMapArray)& theShadowMaps);
+
+ //! Updates state of OCCT light sources to dynamically enable/disable shadowmap.
+ //! @param theToCast [in] flag to enable/disable shadowmap
+ //! @return previous flag state
+ bool SetCastShadows (const bool theToCast)
+ {
+ if (myLightSourceState.ShadowMaps().IsNull()
+ || myLightSourceState.ToCastShadows() == theToCast)
+ {
+ return myLightSourceState.ToCastShadows();
+ }
+
+ myLightSourceState.SetCastShadows (theToCast);
+ switchLightPrograms();
+ return !theToCast;
+ }
//! Invalidate state of OCCT light sources.
Standard_EXPORT void UpdateLightSourceState();
//! @param theHasVertColor [in] flag to use getVertColor() instead of Ambient and Diffuse components of active material
//! @param theIsPBR [in] flag to activate PBR pipeline
//! @param theHasEmissive [in] flag to include emissive
+ //! @param theHasShadowMap [in] flag to include shadow map
Standard_EXPORT TCollection_AsciiString stdComputeLighting (Standard_Integer& theNbLights,
Standard_Boolean theHasVertColor,
Standard_Boolean theIsPBR,
- Standard_Boolean theHasEmissive = true);
+ Standard_Boolean theHasEmissive,
+ Standard_Boolean theHasShadowMap);
//! Bind specified program to current context and apply state.
Standard_EXPORT Standard_Boolean bindProgramWithState (const Handle(OpenGl_ShaderProgram)& theProgram,
mutable NCollection_Array1<Standard_Integer> myLightTypeArray;
mutable NCollection_Array1<OpenGl_ShaderLightParameters> myLightParamsArray;
+ mutable NCollection_Array1<Graphic3d_Mat4> myShadowMatArray;
mutable NCollection_Array1<OpenGl_Vec4> myClipPlaneArray;
mutable NCollection_Array1<OpenGl_Vec4d> myClipPlaneArrayFfp;
mutable NCollection_Array1<Standard_Integer> myClipChainArray;
"occLightSourcesTypes", // OpenGl_OCC_LIGHT_SOURCE_TYPES
"occLightSources", // OpenGl_OCC_LIGHT_SOURCE_PARAMS
"occLightAmbient", // OpenGl_OCC_LIGHT_AMBIENT
+ "occShadowMapSizeBias", // OpenGl_OCC_LIGHT_SHADOWMAP_SIZE_BIAS
+ "occShadowMapSamplers", // OpenGl_OCC_LIGHT_SHADOWMAP_SAMPLERS,
+ "occShadowMapMatrices", // OpenGl_OCC_LIGHT_SHADOWMAP_MATRICES,
"occTextureEnable", // OpenGl_OCCT_TEXTURE_ENABLE
"occDistinguishingMode", // OpenGl_OCCT_DISTINGUISH_MODE
myProxy (theProxy),
myShareCount(1),
myNbLightsMax (0),
+ myNbShadowMaps (0),
myNbClipPlanesMax (0),
myNbFragOutputs (1),
myTextureSetBits (Graphic3d_TextureSetBits_NONE),
TCollection_AsciiString aHeaderConstants;
myNbLightsMax = !myProxy.IsNull() ? myProxy->NbLightsMax() : 0;
+ myNbShadowMaps = !myProxy.IsNull() ? myProxy->NbShadowMaps() : 0;
myNbClipPlanesMax = !myProxy.IsNull() ? myProxy->NbClipPlanesMax() : 0;
aHeaderConstants += TCollection_AsciiString("#define THE_MAX_LIGHTS ") + myNbLightsMax + "\n";
aHeaderConstants += TCollection_AsciiString("#define THE_MAX_CLIP_PLANES ") + myNbClipPlanesMax + "\n";
aHeaderConstants += TCollection_AsciiString("#define THE_NB_FRAG_OUTPUTS ") + myNbFragOutputs + "\n";
+ if (myNbShadowMaps > 0)
+ {
+ aHeaderConstants += TCollection_AsciiString("#define THE_NB_SHADOWMAPS ") + myNbShadowMaps + "\n";
+ }
if (!myProxy.IsNull()
&& myProxy->HasDefaultSampler())
{
{
SetUniform (theCtx, aLocSampler, GLint(theCtx->PBREnvLUTTexUnit()));
}
+ if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occShadowMapSamplers"))
+ {
+ std::vector<GLint> aShadowSamplers (myNbShadowMaps);
+ const GLint aSamplFrom = GLint(theCtx->ShadowMapTexUnit()) - myNbShadowMaps + 1;
+ for (Standard_Integer aSamplerIter = 0; aSamplerIter < myNbShadowMaps; ++aSamplerIter)
+ {
+ aShadowSamplers[aSamplerIter] = aSamplFrom + aSamplerIter;
+ }
+ SetUniform (theCtx, aLocSampler, myNbShadowMaps, &aShadowSamplers.front());
+ }
const TCollection_AsciiString aSamplerNamePrefix ("occSampler");
const Standard_Integer aNbUnitsMax = Max (theCtx->MaxCombinedTextureUnits(), Graphic3d_TextureUnit_NB);
return SetUniform (theCtx, theLocation, OpenGl_Mat4::Map (*theValue.mat), theTranspose);
}
+// =======================================================================
+// function : SetUniform
+// purpose :
+// =======================================================================
+Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
+ GLint theLocation,
+ GLuint theCount,
+ const OpenGl_Mat4* theData)
+{
+ if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
+ {
+ return Standard_False;
+ }
+
+ theCtx->core20fwd->glUniformMatrix4fv (theLocation, theCount, GL_FALSE, theData->GetData());
+ return Standard_True;
+}
+
// =======================================================================
// function : SetUniform
// purpose : Specifies the value of the float uniform array
OpenGl_OCC_LIGHT_SOURCE_TYPES,
OpenGl_OCC_LIGHT_SOURCE_PARAMS,
OpenGl_OCC_LIGHT_AMBIENT,
+ OpenGl_OCC_LIGHT_SHADOWMAP_SIZE_BIAS,// occShadowMapSizeBias
+ OpenGl_OCC_LIGHT_SHADOWMAP_SAMPLERS, // occShadowMapSamplers
+ OpenGl_OCC_LIGHT_SHADOWMAP_MATRICES, // occShadowMapMatrices
// Material state
OpenGl_OCCT_TEXTURE_ENABLE,
//! to be used for initialization occLightSources (OpenGl_OCC_LIGHT_SOURCE_PARAMS).
Standard_Integer NbLightsMax() const { return myNbLightsMax; }
+ //! Return the length of array of shadow maps (THE_NB_SHADOWMAPS); 0 by default.
+ Standard_Integer NbShadowMaps() const { return myNbShadowMaps; }
+
//! Return the length of array of clipping planes (THE_MAX_CLIP_PLANES),
//! to be used for initialization occClipPlaneEquations (OpenGl_OCC_CLIP_PLANE_EQUATIONS) and occClipPlaneChains (OpenGl_OCC_CLIP_PLANE_CHAINS).
Standard_Integer NbClipPlanesMax() const { return myNbClipPlanesMax; }
const OpenGl_Mat4& theValue,
GLboolean theTranspose = GL_FALSE);
+ //! Specifies the value of the array of float uniform 4x4 matrices.
+ //! Wrapper over glUniformMatrix4fv().
+ Standard_EXPORT Standard_Boolean SetUniform (const Handle(OpenGl_Context)& theCtx,
+ GLint theLocation,
+ GLuint theCount,
+ const OpenGl_Mat4* theData);
+
//! Specifies the value of the float uniform 4x4 matrix.
Standard_EXPORT Standard_Boolean SetUniform (const Handle(OpenGl_Context)& theCtx,
const GLchar* theName,
Handle(Graphic3d_ShaderProgram) myProxy; //!< Proxy shader program (from application layer)
Standard_Integer myShareCount; //!< program users count, initialized with 1 (already shared by one user)
Standard_Integer myNbLightsMax; //!< length of array of light sources (THE_MAX_LIGHTS)
+ Standard_Integer myNbShadowMaps; //!< length of array of shadow maps (THE_NB_SHADOWMAPS)
Standard_Integer myNbClipPlanesMax; //!< length of array of clipping planes (THE_MAX_CLIP_PLANES)
Standard_Integer myNbFragOutputs; //!< length of array of Fragment Shader outputs (THE_NB_FRAG_OUTPUTS)
Standard_Integer myTextureSetBits;//!< texture units declared within the program, @sa Graphic3d_TextureSetBits
#include <OpenGl_Element.hxx>
#include <OpenGl_Vec.hxx>
+class OpenGl_ShadowMapArray;
+
//! Defines interface for OpenGL state.
class OpenGl_StateInterface
{
public:
//! Creates uninitialized state of light sources.
- OpenGl_LightSourceState() : mySpecIBLMapLevels (0) {}
+ OpenGl_LightSourceState() : mySpecIBLMapLevels (0), myToCastShadows (Standard_True) {}
//! Sets new light sources.
void Set (const Handle(Graphic3d_LightSet)& theLightSources) { myLightSources = theLightSources; }
//! Sets number of mipmap levels used in specular IBL map.
void SetSpecIBLMapLevels(Standard_Integer theSpecIBLMapLevels) { mySpecIBLMapLevels = theSpecIBLMapLevels; }
+ //! Returns TRUE if shadowmap is set.
+ bool HasShadowMaps() const { return myToCastShadows && !myShadowMaps.IsNull(); }
+
+ //! Returns shadowmap.
+ const Handle(OpenGl_ShadowMapArray)& ShadowMaps() const { return myShadowMaps; }
+
+ //! Sets shadowmap.
+ void SetShadowMaps (const Handle(OpenGl_ShadowMapArray)& theMap) { myShadowMaps = theMap; }
+
+ //! Returns TRUE if shadowmap should be enabled when available; TRUE by default.
+ bool ToCastShadows() const { return myToCastShadows; }
+
+ //! Set if shadowmap should be enabled when available.
+ void SetCastShadows (bool theToCast) { myToCastShadows = theToCast; }
+
private:
Handle(Graphic3d_LightSet) myLightSources; //!< List of OCCT light sources
Standard_Integer mySpecIBLMapLevels; //!< Number of mipmap levels used in specular IBL map (0 by default or in case of using non-PBR shading model)
+ Handle(OpenGl_ShadowMapArray) myShadowMaps; //!< active shadowmap
+ Standard_Boolean myToCastShadows; //!< enable/disable shadowmap
};
--- /dev/null
+// Copyright (c) 2021 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 <OpenGl_ShadowMap.hxx>
+
+#include <OpenGl_ArbFBO.hxx>
+#include <OpenGl_FrameBuffer.hxx>
+#include <OpenGl_ShaderManager.hxx>
+#include <Graphic3d_Camera.hxx>
+#include <Graphic3d_CView.hxx>
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShadowMap, OpenGl_NamedResource)
+
+// =======================================================================
+// function : OpenGl_ShadowMap
+// purpose :
+// =======================================================================
+OpenGl_ShadowMap::OpenGl_ShadowMap()
+: OpenGl_NamedResource ("shadow_map"),
+ myShadowMapFbo (new OpenGl_FrameBuffer()),
+ myShadowCamera (new Graphic3d_Camera()),
+ myShadowMapBias (0.0f)
+{
+ //
+}
+
+// =======================================================================
+// function : Release
+// purpose :
+// =======================================================================
+void OpenGl_ShadowMap::Release (OpenGl_Context* theCtx)
+{
+ myShadowMapFbo->Release (theCtx);
+}
+
+// =======================================================================
+// function : ~OpenGl_ShadowMap
+// purpose :
+// =======================================================================
+OpenGl_ShadowMap::~OpenGl_ShadowMap()
+{
+ Release (NULL);
+}
+
+// =======================================================================
+// function : EstimatedDataSize
+// purpose :
+// =======================================================================
+Standard_Size OpenGl_ShadowMap::EstimatedDataSize() const
+{
+ return myShadowMapFbo->EstimatedDataSize();
+}
+
+// =======================================================================
+// function : IsValid
+// purpose :
+// =======================================================================
+bool OpenGl_ShadowMap::IsValid() const
+{
+ return myShadowMapFbo->IsValid();
+}
+
+// =======================================================================
+// function : Texture
+// purpose :
+// =======================================================================
+const Handle(OpenGl_Texture)& OpenGl_ShadowMap::Texture() const
+{
+ return myShadowMapFbo->DepthStencilTexture();
+}
+
+// =======================================================================
+// function : UpdateCamera
+// purpose :
+// =======================================================================
+bool OpenGl_ShadowMap::UpdateCamera (const Graphic3d_CView& theView)
+{
+ const Bnd_Box aMinMaxBox = theView.MinMaxValues (false); // applicative min max boundaries
+ const Bnd_Box aGraphicBox = theView.MinMaxValues (true); // real graphical boundaries (not accounting infinite flag).
+
+ switch (myShadowLight->Type())
+ {
+ case Graphic3d_TOLS_AMBIENT:
+ {
+ return false; // not applicable
+ }
+ case Graphic3d_TOLS_DIRECTIONAL:
+ {
+ 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->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
+ myShadowCamera->SetDirection (gp_Dir (aDir.x(), aDir.y(), aDir.z()));
+ myShadowCamera->SetUp (!myShadowCamera->Direction().IsParallel (gp::DY(), Precision::Angular())
+ ? gp::DY()
+ : gp::DX());
+ myShadowCamera->OrthogonalizeUp();
+
+ // Fitting entire scene to the light might produce a shadow map of too low resolution.
+ // More reliable approach would be putting a center to a current eye position and limiting maximum range,
+ // so that shadow range will be limited to some reasonable distance from current eye.
+ if (myShadowCamera->FitMinMax (aMinMaxBox, 10.0 * Precision::Confusion(), false))
+ {
+ myShadowCamera->SetScale (Max (myShadowCamera->ViewDimensions().X() * 1.1, myShadowCamera->ViewDimensions().Y() * 1.1)); // add margin
+ }
+ myShadowCamera->ZFitAll (1.0, aMinMaxBox, aGraphicBox);
+ myLightMatrix = myShadowCamera->ProjectionMatrixF() * myShadowCamera->OrientationMatrixF();
+ return true;
+ }
+ case Graphic3d_TOLS_POSITIONAL:
+ {
+ // render into cubemap shadowmap texture
+ return false; // not implemented
+ }
+ case Graphic3d_TOLS_SPOT:
+ {
+ //myShadowCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
+ //myShadowCamera->SetEye (theCastShadowLight->Position());
+ return false; // not implemented
+ }
+ }
+ return false;
+}
+
+// =======================================================================
+// function : Release
+// purpose :
+// =======================================================================
+void OpenGl_ShadowMapArray::Release (OpenGl_Context* theCtx)
+{
+ for (Standard_Integer anIter = Lower(); anIter <= Upper(); ++anIter)
+ {
+ if (const Handle(OpenGl_ShadowMap)& aShadow = ChangeValue (anIter))
+ {
+ aShadow->Release (theCtx);
+ }
+ }
+}
+
+// =======================================================================
+// function : EstimatedDataSize
+// purpose :
+// =======================================================================
+Standard_Size OpenGl_ShadowMapArray::EstimatedDataSize() const
+{
+ Standard_Size aSize = 0;
+ for (Standard_Integer anIter = Lower(); anIter <= Upper(); ++anIter)
+ {
+ if (const Handle(OpenGl_ShadowMap)& aShadow = Value (anIter))
+ {
+ aSize += aShadow->EstimatedDataSize();
+ }
+ }
+ return aSize;
+}
--- /dev/null
+// Copyright (c) 2021 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 _OpenGl_ShadowMap_HeaderFile
+#define _OpenGl_ShadowMap_HeaderFile
+
+#include <Graphic3d_Mat4.hxx>
+#include <NCollection_Array1.hxx>
+#include <NCollection_Shared.hxx>
+#include <OpenGl_NamedResource.hxx>
+
+class Graphic3d_Camera;
+class Graphic3d_CLight;
+class Graphic3d_CView;
+class OpenGl_FrameBuffer;
+class OpenGl_Texture;
+
+//! This class contains shadow mapping resources.
+class OpenGl_ShadowMap : public OpenGl_NamedResource
+{
+ DEFINE_STANDARD_RTTIEXT(OpenGl_ShadowMap, OpenGl_NamedResource)
+public:
+
+ //! Empty constructor.
+ OpenGl_ShadowMap();
+
+ //! Releases all OpenGL resources.
+ Standard_EXPORT virtual void Release (OpenGl_Context* theCtx) Standard_OVERRIDE;
+
+ //! Returns estimated GPU memory usage for holding data without considering overheads and allocation alignment rules.
+ Standard_EXPORT virtual Standard_Size EstimatedDataSize() const Standard_OVERRIDE;
+
+ //! Destructor.
+ Standard_EXPORT virtual ~OpenGl_ShadowMap();
+
+ //! Return TRUE if defined.
+ Standard_EXPORT bool IsValid() const;
+
+ //! Return framebuffer.
+ const Handle(OpenGl_FrameBuffer)& FrameBuffer() const { return myShadowMapFbo; }
+
+ //! Return depth texture.
+ Standard_EXPORT const Handle(OpenGl_Texture)& Texture() const;
+
+ //! Return light source casting the shadow or NULL if undefined.
+ const Handle(Graphic3d_CLight)& LightSource() const { return myShadowLight; }
+
+ //! Set light source casting the shadow.
+ void SetLightSource (const Handle(Graphic3d_CLight)& theLight) { myShadowLight = theLight; }
+
+ //! Return rendering camera.
+ const Handle(Graphic3d_Camera)& Camera() const { return myShadowCamera; }
+
+ //! Return light source mapping matrix.
+ const Graphic3d_Mat4& LightSourceMatrix() const { return myLightMatrix; }
+
+ //! Set light source mapping matrix.
+ void SetLightSourceMatrix (const Graphic3d_Mat4& theMat) { myLightMatrix = theMat; }
+
+ //! Returns shadowmap bias.
+ Standard_ShortReal ShadowMapBias() const { return myShadowMapBias; }
+
+ //! Sets shadowmap bias.
+ void SetShadowMapBias (Standard_ShortReal theBias) { myShadowMapBias = theBias; }
+
+ //! Compute camera.
+ Standard_EXPORT bool UpdateCamera (const Graphic3d_CView& theView);
+
+private:
+
+ Handle(OpenGl_FrameBuffer) myShadowMapFbo; //!< frame buffer for rendering shadow map
+ Handle(Graphic3d_CLight) myShadowLight; //!< light source to render shadow map
+ Handle(Graphic3d_Camera) myShadowCamera; //!< rendering camera
+ Graphic3d_Mat4 myLightMatrix; //!< light source matrix
+ Standard_ShortReal myShadowMapBias; //!< shadowmap bias
+
+};
+
+//! Array of shadow maps.
+class OpenGl_ShadowMapArray : public Standard_Transient, public NCollection_Array1<Handle(OpenGl_ShadowMap)>
+{
+public:
+ //! Empty constructor.
+ OpenGl_ShadowMapArray() {}
+
+ //! Releases all OpenGL resources.
+ Standard_EXPORT void Release (OpenGl_Context* theCtx);
+
+ //! Return TRUE if defined.
+ bool IsValid() const
+ {
+ return !IsEmpty()
+ && First()->IsValid();
+ }
+
+ //! Returns estimated GPU memory usage for holding data without considering overheads and allocation alignment rules.
+ Standard_EXPORT Standard_Size EstimatedDataSize() const;
+
+public:
+ DEFINE_STANDARD_ALLOC
+ DEFINE_NCOLLECTION_ALLOC
+
+};
+
+#endif // _OpenGl_ShadowMap_HeaderFile
}
#endif
+ bool anOldCastShadows = false;
if (!myTrsfPers.IsNull())
{
+ // temporarily disable shadows on non-3d objects
+ anOldCastShadows = aCtx->ShaderManager()->SetCastShadows (false);
+
aCtx->WorldViewState.Push();
OpenGl_Mat4& aWorldView = aCtx->WorldViewState.ChangeCurrent();
myTrsfPers->Apply (aCtx->Camera(),
if (!myTrsfPers.IsNull())
{
aCtx->WorldViewState.Pop();
+ aCtx->ShaderManager()->SetCastShadows (anOldCastShadows);
}
// Restore named status
#include <OpenGl_GraduatedTrihedron.hxx>
#include <OpenGl_GraphicDriver.hxx>
#include <OpenGl_ShaderManager.hxx>
+#include <OpenGl_ShadowMap.hxx>
#include <OpenGl_Texture.hxx>
#include <OpenGl_Window.hxx>
#include <OpenGl_Workspace.hxx>
myRaytraceFBO1[1] = new OpenGl_FrameBuffer();
myRaytraceFBO2[0] = new OpenGl_FrameBuffer();
myRaytraceFBO2[1] = new OpenGl_FrameBuffer();
+ myShadowMaps = new OpenGl_ShadowMapArray();
}
// =======================================================================
myOpenGlFBO2 ->Release (theCtx.get());
myFullScreenQuad .Release (theCtx.get());
myFullScreenQuadFlip .Release (theCtx.get());
+ myShadowMaps->Release (theCtx.get());
// Technically we should also re-initialize all sRGB/RGB8 color textures.
// But for now consider this sRGB disabling/enabling to be done at application start-up
myImmediateSceneFbosOit[1]->ChangeViewport (0, 0);
}
+ // allocate shadow maps
+ const Handle(Graphic3d_LightSet)& aLights = myShadingModel == Graphic3d_TOSM_UNLIT ? myNoShadingLight : myLights;
+ if (!aLights.IsNull())
+ {
+ aLights->UpdateRevision();
+ }
+ bool toUseShadowMap = myRenderParams.IsShadowEnabled
+ && myRenderParams.ShadowMapResolution > 0
+ && !myLights.IsNull()
+ && myLights->NbCastShadows() > 0
+ && myRenderParams.Method != Graphic3d_RM_RAYTRACING;
+ if (toUseShadowMap)
+ {
+ if (myShadowMaps->Size() != myLights->NbCastShadows())
+ {
+ myShadowMaps->Release (aCtx.get());
+ myShadowMaps->Resize (0, myLights->NbCastShadows() - 1, true);
+ }
+
+ const GLint aSamplFrom = GLint(aCtx->ShadowMapTexUnit()) - myLights->NbCastShadows() + 1;
+ for (Standard_Integer aShadowIter = 0; aShadowIter < myShadowMaps->Size(); ++aShadowIter)
+ {
+ Handle(OpenGl_ShadowMap)& aShadow = myShadowMaps->ChangeValue (aShadowIter);
+ if (aShadow.IsNull())
+ {
+ aShadow = new OpenGl_ShadowMap();
+ }
+ aShadow->SetShadowMapBias (myRenderParams.ShadowMapBias);
+ aShadow->Texture()->Sampler()->Parameters()->SetTextureUnit ((Graphic3d_TextureUnit )(aSamplFrom + aShadowIter));
+
+ const Handle(OpenGl_FrameBuffer)& aShadowFbo = aShadow->FrameBuffer();
+ if (aShadowFbo->GetVPSizeX() != myRenderParams.ShadowMapResolution
+ && toUseShadowMap)
+ {
+ OpenGl_ColorFormats aDummy;
+ if (!aShadowFbo->Init (aCtx, myRenderParams.ShadowMapResolution, myRenderParams.ShadowMapResolution, aDummy, myFboDepthFormat, 0))
+ {
+ toUseShadowMap = false;
+ }
+ }
+ }
+ }
+ if (!toUseShadowMap && myShadowMaps->IsValid())
+ {
+ myShadowMaps->Release (aCtx.get());
+ }
+
return true;
}
return;
}
+ // draw shadow maps
+ if (myShadowMaps->IsValid())
+ {
+ Standard_Integer aShadowIndex = myShadowMaps->Lower();
+ for (Graphic3d_LightSet::Iterator aLightIter (myLights, Graphic3d_LightSet::IterationFilter_ActiveShadowCasters);
+ aLightIter.More(); aLightIter.Next())
+ {
+ const Handle(Graphic3d_CLight)& aLight = aLightIter.Value();
+ if (aLight->ToCastShadows())
+ {
+ const Handle(OpenGl_ShadowMap)& aShadowMap = myShadowMaps->ChangeValue (aShadowIndex);
+ aShadowMap->SetLightSource (aLight);
+ renderShadowMap (aShadowMap);
+ ++aShadowIndex;
+ }
+ }
+ for (; aShadowIndex <= myShadowMaps->Upper(); ++aShadowIndex)
+ {
+ myShadowMaps->ChangeValue (aShadowIndex)->SetLightSource (Handle(Graphic3d_CLight)());
+ }
+ }
+
OpenGl_FrameBuffer* aFrameBuffer = myFBO.get();
bool toSwap = aCtx->IsRender()
&& !aCtx->caps->buffersNoSwap
}
// =======================================================================
-// function : redrawMonoImmediate
+// function : redrawImmediate
// purpose :
// =======================================================================
bool OpenGl_View::redrawImmediate (const Graphic3d_Camera::Projection theProjection,
return !toCopyBackToFront;
}
+//=======================================================================
+//function : renderShadowMap
+//purpose :
+//=======================================================================
+void OpenGl_View::renderShadowMap (const Handle(OpenGl_ShadowMap)& theShadowMap)
+{
+ const Handle(OpenGl_Context)& aCtx = myWorkspace->GetGlContext();
+ if (!theShadowMap->UpdateCamera (*this))
+ {
+ return;
+ }
+
+ myBVHSelector.SetViewVolume (theShadowMap->Camera());
+ myBVHSelector.SetViewportSize (myWindow->Width(), myWindow->Height(), myRenderParams.ResolutionRatio());
+ myBVHSelector.CacheClipPtsProjections();
+
+ myLocalOrigin.SetCoord (0.0, 0.0, 0.0);
+ aCtx->SetCamera (theShadowMap->Camera());
+ aCtx->ProjectionState.SetCurrent (theShadowMap->Camera()->ProjectionMatrixF());
+ aCtx->ApplyProjectionMatrix();
+
+ aCtx->ShaderManager()->UpdateMaterialState();
+ aCtx->ShaderManager()->UpdateModelWorldStateTo (OpenGl_Mat4());
+ aCtx->ShaderManager()->SetShadingModel (Graphic3d_TOSM_UNLIT);
+
+ const Handle(OpenGl_FrameBuffer)& aShadowBuffer = theShadowMap->FrameBuffer();
+ aShadowBuffer->BindBuffer (aCtx);
+ aShadowBuffer->SetupViewport (aCtx);
+
+ aCtx->SetColorMask (false);
+ aCtx->SetAllowSampleAlphaToCoverage (false);
+ aCtx->SetSampleAlphaToCoverage (false);
+
+ myWorkspace->UseZBuffer() = true;
+ myWorkspace->UseDepthWrite() = true;
+ aCtx->core11fwd->glDepthFunc (GL_LEQUAL);
+ aCtx->core11fwd->glDepthMask (GL_TRUE);
+ aCtx->core11fwd->glEnable (GL_DEPTH_TEST);
+ aCtx->core11fwd->glClearDepth (1.0);
+ aCtx->core11fwd->glClear (GL_DEPTH_BUFFER_BIT);
+
+ renderScene (Graphic3d_Camera::Projection_Orthographic, aShadowBuffer.get(), NULL, false);
+
+ aCtx->SetColorMask (true);
+ myWorkspace->ResetAppliedAspect();
+ aCtx->BindProgram (Handle(OpenGl_ShaderProgram)());
+
+//Image_AlienPixMap anImage; anImage.InitZero (Image_Format_Gray, aShadowBuffer->GetVPSizeX(), aShadowBuffer->GetVPSizeY());
+//OpenGl_FrameBuffer::BufferDump (aCtx, aShadowBuffer, anImage, Graphic3d_BT_Depth);
+//anImage.Save (TCollection_AsciiString ("shadow") + theShadowMap->Texture()->Sampler()->Parameters()->TextureUnit() + ".png");
+
+ bindDefaultFbo();
+}
+
//=======================================================================
//function : Render
//purpose :
|| aLightsRevision != myLightsRevision)
{
myLightsRevision = aLightsRevision;
- aManager->UpdateLightSourceStateTo (aLights, SpecIBLMapLevels());
+ aManager->UpdateLightSourceStateTo (aLights, SpecIBLMapLevels(), myShadowMaps->IsValid() ? myShadowMaps : Handle(OpenGl_ShadowMapArray)());
myLastLightSourceState = StateInfo (myCurrLightSourceState, aManager->LightSourceState().Index());
}
myWorkspace->SetEnvironmentTexture (myTextureEnv);
+ const bool hasShadowMap = aContext->ShaderManager()->LightSourceState().HasShadowMaps();
+ if (hasShadowMap)
+ {
+ for (Standard_Integer aShadowIter = myShadowMaps->Lower(); aShadowIter <= myShadowMaps->Upper(); ++aShadowIter)
+ {
+ const Handle(OpenGl_ShadowMap)& aShadow = myShadowMaps->Value (aShadowIter);
+ aShadow->Texture()->Bind (aContext);
+ }
+ }
+
renderScene (theProjection, theOutputFBO, theOitAccumFbo, theToDrawImmediate);
+ if (hasShadowMap)
+ {
+ for (Standard_Integer aShadowIter = myShadowMaps->Lower(); aShadowIter <= myShadowMaps->Upper(); ++aShadowIter)
+ {
+ const Handle(OpenGl_ShadowMap)& aShadow = myShadowMaps->Value (aShadowIter);
+ aShadow->Texture()->Unbind (aContext);
+ }
+ if (aContext->core15fwd != NULL)
+ {
+ aContext->core15fwd->glActiveTexture (GL_TEXTURE0);
+ }
+ }
+
myWorkspace->SetEnvironmentTexture (Handle(OpenGl_TextureSet)());
// ===============================
class OpenGl_GraphicDriver;
class OpenGl_PBREnvironment;
class OpenGl_StateCounter;
+class OpenGl_ShadowMap;
+class OpenGl_ShadowMapArray;
class OpenGl_TriangleSet;
class OpenGl_Workspace;
class OpenGl_View;
+
DEFINE_STANDARD_HANDLE(OpenGl_View,Graphic3d_CView)
//! Implementation of OpenGl view.
protected: //! @name Rendering of GL graphics (with prepared drawing buffer).
+ //! Renders the graphical contents of the view into the preprepared shadowmap framebuffer.
+ //! @param theShadowMap [in] the framebuffer for rendering shadowmap.
+ Standard_EXPORT virtual void renderShadowMap (const Handle(OpenGl_ShadowMap)& theShadowMap);
+
//! Renders the graphical contents of the view into the preprepared window or framebuffer.
//! @param theProjection [in] the projection that should be used for rendering.
//! @param theReadDrawFbo [in] the framebuffer for rendering graphics.
Handle(OpenGl_FrameBuffer) myImmediateSceneFbos[2]; //!< Additional buffers for immediate layer in stereo mode.
Handle(OpenGl_FrameBuffer) myImmediateSceneFbosOit[2]; //!< Additional buffers for transparency draw of immediate layer.
Handle(OpenGl_FrameBuffer) myXrSceneFbo; //!< additional FBO (without MSAA) for submitting to XR
+ Handle(OpenGl_ShadowMapArray) myShadowMaps; //!< additional FBOs for shadow map rendering
OpenGl_VertexBuffer myFullScreenQuad; //!< Vertices for full-screen quad rendering.
OpenGl_VertexBuffer myFullScreenQuadFlip;
Standard_Boolean myToFlipOutput; //!< Flag to draw result image upside-down
--- /dev/null
+//! Coefficients for gathering close samples.
+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)
+);
+
+//! Function computes directional light shadow attenuation (1.0 means no shadow).
+float occDirectionalLightShadow (in int theId,
+ in vec3 theNormal)
+{
+ vec4 aPosLightSpace = PosLightSpace[theId];
+ vec3 aLightDir = vec3 (occWorldViewMatrix * vec4 (occLight_Position (theId), 0.0));
+ vec3 aProjCoords = (aPosLightSpace.xyz / aPosLightSpace.w) * 0.5 + vec3 (0.5);
+ float aCurrentDepth = aProjCoords.z;
+ if (abs(aProjCoords.x) > 1.0 || abs(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);
+ float aShadow = 0.0;
+ for (int aPosIter = 0; aPosIter < 16; ++aPosIter)
+ {
+ float aClosestDepth = occTexture2D (occShadowMapSamplers[theId], aProjCoords.xy + occPoissonDisk16[aPosIter] * aTexelSize).r;
+ aShadow += (aCurrentDepth - aBias) > aClosestDepth ? 1.0 : 0.0;
+ }
+ return 1.0 - aShadow / 16.0;
+}
srcinc:::Declarations.glsl
srcinc:::DeclarationsImpl.glsl
+srcinc:::DirectionalLightShadow.glsl
srcinc:::PBRCookTorrance.glsl
srcinc:::PBRDistribution.glsl
srcinc:::PBREnvBaking.fs
srcinc:::TangentSpaceNormal.glsl
Shaders_Declarations_glsl.pxx
Shaders_DeclarationsImpl_glsl.pxx
+Shaders_DirectionalLightShadow_glsl.pxx
Shaders_Display_fs.pxx
Shaders_PBRCookTorrance_glsl.pxx
Shaders_PBRDistribution_glsl.pxx
--- /dev/null
+// This file has been automatically generated from resource file src/Shaders/DirectionalLightShadow.glsl
+
+static const char Shaders_DirectionalLightShadow_glsl[] =
+ "//! Coefficients for gathering close samples.\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"
+ "\n"
+ "//! Function computes directional light shadow attenuation (1.0 means no shadow).\n"
+ "float occDirectionalLightShadow (in int theId,\n"
+ " in vec3 theNormal)\n"
+ "{\n"
+ " vec4 aPosLightSpace = PosLightSpace[theId];\n"
+ " vec3 aLightDir = vec3 (occWorldViewMatrix * vec4 (occLight_Position (theId), 0.0));\n"
+ " vec3 aProjCoords = (aPosLightSpace.xyz / aPosLightSpace.w) * 0.5 + vec3 (0.5);\n"
+ " float aCurrentDepth = aProjCoords.z;\n"
+ " if (abs(aProjCoords.x) > 1.0 || abs(aProjCoords.y) > 1.0 || aCurrentDepth > 1.0) { return 1.0; }\n"
+ " vec2 aTexelSize = vec2 (occShadowMapSizeBias.x);\n"
+ " float aBias = max (occShadowMapSizeBias.y * (1.0 - dot (theNormal, aLightDir)), occShadowMapSizeBias.y * 0.1);\n"
+ " float aShadow = 0.0;\n"
+ " for (int aPosIter = 0; aPosIter < 16; ++aPosIter)\n"
+ " {\n"
+ " float aClosestDepth = occTexture2D (occShadowMapSamplers[theId], aProjCoords.xy + occPoissonDisk16[aPosIter] * aTexelSize).r;\n"
+ " aShadow += (aCurrentDepth - aBias) > aClosestDepth ? 1.0 : 0.0;\n"
+ " }\n"
+ " return 1.0 - aShadow / 16.0;\n"
+ "}\n";
theDi << " Type: Directional\n";
theDi << " Intensity: " << aLight->Intensity() << "\n";
theDi << " Headlight: " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
+ theDi << " CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n";
theDi << " Smoothness: " << aLight->Smoothness() << "\n";
aLight->Direction (anXYZ[0], anXYZ[1], anXYZ[2]);
theDi << " Direction: " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
theDi << " Type: Positional\n";
theDi << " Intensity: " << aLight->Intensity() << "\n";
theDi << " Headlight: " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
+ theDi << " CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n";
theDi << " Smoothness: " << aLight->Smoothness() << "\n";
aLight->Position (anXYZ[0], anXYZ[1], anXYZ[2]);
theDi << " Position: " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
theDi << " Type: Spot\n";
theDi << " Intensity: " << aLight->Intensity() << "\n";
theDi << " Headlight: " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
+ theDi << " CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n";
aLight->Position (anXYZ[0], anXYZ[1], anXYZ[2]);
theDi << " Position: " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
aLight->Direction (anXYZ[0], anXYZ[1], anXYZ[2]);
}
aLightCurr->SetHeadlight (isHeadLight);
}
+ else if (anArgCase.IsEqual ("-CASTSHADOW")
+ || anArgCase.IsEqual ("-CASTSHADOWS")
+ || anArgCase.IsEqual ("-SHADOWS"))
+ {
+ if (aLightCurr.IsNull()
+ || aLightCurr->Type() == Graphic3d_TOLS_AMBIENT)
+ {
+ Message::SendFail() << "Syntax error at argument '" << anArg << "'";
+ return 1;
+ }
+
+ bool toCastShadows = true;
+ if (anArgIt + 1 < theArgsNb
+ && Draw::ParseOnOff (theArgVec[anArgIt + 1], toCastShadows))
+ {
+ ++anArgIt;
+ }
+ aLightCurr->SetCastShadows (toCastShadows);
+ }
else
{
Message::SendFail() << "Warning: unknown argument '" << anArg << "'";
theDI << "rayDepth: " << aParams.RaytracingDepth << "\n";
theDI << "fsaa: " << (aParams.IsAntialiasingEnabled ? "on" : "off") << "\n";
theDI << "shadows: " << (aParams.IsShadowEnabled ? "on" : "off") << "\n";
+ theDI << "shadowMapRes: " << aParams.ShadowMapResolution << "\n";
+ theDI << "shadowMapBias: " << aParams.ShadowMapBias << "\n";
theDI << "reflections: " << (aParams.IsReflectionEnabled ? "on" : "off") << "\n";
theDI << "gleam: " << (aParams.IsTransparentShadowEnabled ? "on" : "off") << "\n";
theDI << "GI: " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
}
aParams.IsShadowEnabled = toEnable;
}
+ else if (aFlag == "-shadowmapresolution"
+ || aFlag == "-shadowmap")
+ {
+ if (toPrint)
+ {
+ theDI << aParams.ShadowMapResolution << " ";
+ continue;
+ }
+ else if (++anArgIter >= theArgNb)
+ {
+ Message::SendFail() << "Syntax error at argument '" << anArg << "'";
+ return 1;
+ }
+
+ aParams.ShadowMapResolution = Draw::Atoi (theArgVec[anArgIter]);
+ }
+ else if (aFlag == "-shadowmapbias")
+ {
+ if (toPrint)
+ {
+ theDI << aParams.ShadowMapBias << " ";
+ continue;
+ }
+ else if (++anArgIter >= theArgNb)
+ {
+ Message::SendFail() << "Syntax error at argument '" << anArg << "'";
+ return 1;
+ }
+
+ aParams.ShadowMapBias = (float )Draw::Atof (theArgVec[anArgIter]);
+ }
else if (aFlag == "-refl"
|| aFlag == "-reflections")
{
"\n -{dir}ection X Y Z (for directional light or for spotlight)"
"\n -color colorName"
"\n -{head}light 0|1"
+ "\n -castShadows 0|1"
"\n -{sm}oothness value"
"\n -{int}ensity value"
"\n -{constAtten}uation value"
"\n\t\t: vrenderparams [-raster] [-shadingModel {unlit|facet|gouraud|phong|pbr|pbr_facet}=gouraud]"
"\n\t\t: [-msaa 0..8=0] [-rendScale scale=1] [-resolution value=72]"
"\n\t\t: [-oit {off|0.0-1.0}=off]"
+ "\n\t\t: [-shadows {on|off}=on] [-shadowMapResolution value=1024] [-shadowMapBias value=0.005]"
"\n\t\t: [-depthPrePass {on|off}=off] [-alphaToCoverage {on|off}=on]"
"\n\t\t: [-frustumCulling {on|off|noupdate}=on] [-lineFeather width=1.0]"
"\n\t\t: [-sync {default|views}] [-reset]"
"\n\t\t: -oit Enables/disables order-independent transparency (OIT) rendering;"
"\n\t\t: weight OIT fixes transparency artifacts at the cost of blurry result,"
"\n\t\t: it is managed by depth weight factor (0.0 value also enables weight OIT)."
+ "\n\t\t: -shadows Enables/disables shadows rendering."
+ "\n\t\t: -shadowMapResolution Shadow texture map resolution."
+ "\n\t\t: -shadowMapBias Shadow map bias."
"\n\t\t: -depthPrePass Enables/disables depth pre-pass."
"\n\t\t: -frustumCulling Enables/disables objects frustum clipping or"
"\n\t\t: sets state to check structures culled previously."
"\n\t\t: -perfChart Show frame timers chart limited by specified number of frames."
"\n\t\t: -perfChartMax Maximum time in seconds with the chart."
"\n\t\t: Ray-Tracing options:"
- "\n\t\t: vrenderparams [-rayTrace] [-rayDepth {0..10}=3] [-shadows {on|off}=on] [-reflections {on|off}=off]"
+ "\n\t\t: vrenderparams [-rayTrace] [-rayDepth {0..10}=3] [-reflections {on|off}=off]"
"\n\t\t: [-fsaa {on|off}=off] [-gleam {on|off}=off] [-env {on|off}=off]"
"\n\t\t: [-gi {on|off}=off] [-brng {on|off}=off]"
"\n\t\t: [-iss {on|off}=off] [-tileSize {1..4096}=32] [-nbTiles {64..1024}=256]"
"\n\t\t: [-exposure value=0.0] [-whitePoint value=1.0] [-toneMapping {disabled|filmic}=disabled]"
"\n\t\t: -rayTrace Enables GPU ray-tracing."
"\n\t\t: -rayDepth Defines maximum ray-tracing depth."
- "\n\t\t: -shadows Enables/disables shadows rendering."
"\n\t\t: -reflections Enables/disables specular reflections."
"\n\t\t: -fsaa Enables/disables adaptive anti-aliasing."
"\n\t\t: -gleam Enables/disables transparency shadow effects."
023 viewcube
024 colors
025 quadric
+026 shadows
--- /dev/null
+puts "========"
+puts "0032039: Visualization, TKOpenGl - implement simple shadow mapping for a direct light source"
+puts "Test shadow map from single directional light source on a buggy."
+puts "========"
+
+pload MODELING VISUALIZATION XDE OCAF
+if { $::tcl_platform(os) == "Darwin" } { vcaps -core }
+catch {Close D}
+ReadGltf D [locate_data_file bug30691_Buggy.glb]
+vclear
+vinit View1
+vzbufftrihedron
+XDisplay -dispMode 1 D
+vfit
+vzoom 0.75
+box bb -500000 -500000 -10875 1000000 1000000 0 -preview
+vdisplay -dispMode 1 bb
+vaspects bb -material STONE
+vlight -change 0 -head 0 -dir -1 -1 -1 -castShadows 1
+
+vraytrace 1
+vdump $::imagedir/${::casename}_raytrace.png
+
+vraytrace 0
+vrenderparams -shadingModel phong
+vrenderparams -shadowMapResolution 2048
+vdump $::imagedir/${::casename}_phong.png
+
+vrenderparams -shadingModel pbr
+vdump $::imagedir/${::casename}_pbr.png
--- /dev/null
+puts "========"
+puts "0032039: Visualization, TKOpenGl - implement simple shadow mapping for a direct light source"
+puts "Test shadow map from a single directional 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
+vgldebug 1
+vcaps -core
+vcaps -vsync 0
+vclear
+vinit View1
+vrenderparams -shadingModel PHONG
+vdisplay -dispMode 1 b bb
+vaspects bb -material STONE
+vfit
+vlight -change 0 -castShadows 1 -direction 1 1 -1 -head 0
+
+vraytrace 1
+vdump $::imagedir/${::casename}_raytrace.png
+
+vraytrace 0
+vrenderparams -shadingModel phong
+vrenderparams -shadowMapBias 0.01
+vdump $::imagedir/${::casename}_phong.png
+
+vrenderparams -shadingModel pbr
+vdump $::imagedir/${::casename}_pbr.png
--- /dev/null
+puts "========"
+puts "0032039: Visualization, TKOpenGl - implement simple shadow mapping for a direct light source"
+puts "Test shadow map from two directional light sources 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
+vgldebug 1
+vcaps -core
+vcaps -vsync 0
+vclear
+vinit View1
+vrenderparams -shadingModel PHONG
+vdisplay -dispMode 1 b bb
+vaspects bb -material STONE
+vfit
+
+vlight -clear
+vlight -add AMBIENT
+vlight -add DIRECTIONAL -direction 0.2 0.2 -1 -head 0 -castShadows 1 -color RED
+vlight -add DIRECTIONAL -direction -0.2 -0.2 -1 -head 0 -castShadows 1 -color GREEN
+
+vraytrace 1
+vdump $::imagedir/${::casename}_raytrace.png
+
+vraytrace 0
+vrenderparams -shadingModel phong
+vrenderparams -shadowMapBias 0.01
+vdump $::imagedir/${::casename}_phong.png
+
+vrenderparams -shadingModel pbr
+vdump $::imagedir/${::casename}_pbr.png
--- /dev/null
+puts "========"
+puts "0032039: Visualization, TKOpenGl - implement simple shadow mapping for a direct light source"
+puts "Test shadow map from a single directional light source with headlight flag."
+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
+vgldebug 1
+vcaps -core
+vcaps -vsync 0
+vclear
+vinit View1
+vcamera -persp
+vrenderparams -shadingModel PHONG
+vdisplay -dispMode 1 b bb
+vaspects bb -material STONE
+vfit
+vlight -change 0 -castShadows 1 -direction -0.2 0.2 -1 -head 1
+
+vraytrace 1
+vdump $::imagedir/${::casename}_raytrace.png
+
+vraytrace 0
+vrenderparams -shadingModel phong
+vrenderparams -shadowMapBias 0.01
+vdump $::imagedir/${::casename}_phong.png
+
+vrenderparams -shadingModel pbr
+vdump $::imagedir/${::casename}_pbr.png