From 256f9ac0ad941db76bad206cd322ebcefe1c3c76 Mon Sep 17 00:00:00 2001 From: kgv Date: Wed, 8 Oct 2014 12:29:47 +0400 Subject: [PATCH] 0025303: Visualization, TKOpenGl - dynamically disable unused light sources in generated GLSL program --- src/OpenGl/FILES | 1 + src/OpenGl/OpenGl_SetOfShaderPrograms.hxx | 59 +++++++ src/OpenGl/OpenGl_ShaderManager.cxx | 179 +++++++++++++++------- src/OpenGl/OpenGl_ShaderManager.hxx | 60 +++----- src/OpenGl/OpenGl_View_2.cxx | 49 +++--- 5 files changed, 234 insertions(+), 114 deletions(-) create mode 100644 src/OpenGl/OpenGl_SetOfShaderPrograms.hxx diff --git a/src/OpenGl/FILES b/src/OpenGl/FILES index d8ab579bc2..c68daee966 100755 --- a/src/OpenGl/FILES +++ b/src/OpenGl/FILES @@ -136,6 +136,7 @@ OpenGl_ShaderObject.hxx OpenGl_ShaderObject.cxx OpenGl_ShaderProgram.hxx OpenGl_ShaderProgram.cxx +OpenGl_SetOfShaderPrograms.hxx OpenGl_ShaderManager.hxx OpenGl_ShaderManager.cxx OpenGl_ShaderStates.hxx diff --git a/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx b/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx new file mode 100644 index 0000000000..850be25ae5 --- /dev/null +++ b/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx @@ -0,0 +1,59 @@ +// Created on: 2014-10-08 +// Created by: Kirill Gavrilov +// Copyright (c) 2014 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _OpenGl_SetOfShaderPrograms_HeaderFile +#define _OpenGl_SetOfShaderPrograms_HeaderFile + +#include +#include + +//! Standard GLSL program combination bits. +enum OpenGl_ProgramOptions +{ + OpenGl_PO_ClipPlanes = 0x01, //!< handle clipping planes + OpenGl_PO_Point = 0x02, //!< point marker + OpenGl_PO_VertColor = 0x04, //!< per-vertex color + OpenGl_PO_TextureRGB = 0x08, //!< handle RGB texturing + OpenGl_PO_TextureA = 0x10, //!< handle Alpha texturing + OpenGl_PO_NB = 0x20 //!< overall number of combinations +}; + +//! Alias to programs array of predefined length +class OpenGl_SetOfShaderPrograms : public Standard_Transient +{ + +public: + + //! Empty constructor + OpenGl_SetOfShaderPrograms() {} + + //! Access program by index + Handle(OpenGl_ShaderProgram)& ChangeValue (const Standard_Integer theIndex) { return myPrograms[theIndex]; } + +protected: + + Handle(OpenGl_ShaderProgram) myPrograms[OpenGl_PO_NB]; //!< programs array + +public: + + DEFINE_STANDARD_RTTI (OpenGl_SetOfShaderPrograms) + +}; + +DEFINE_STANDARD_HANDLE(OpenGl_SetOfShaderPrograms, Standard_Transient) + +typedef NCollection_DataMap OpenGl_MapOfShaderPrograms; + +#endif // _OpenGl_SetOfShaderPrograms_HeaderFile diff --git a/src/OpenGl/OpenGl_ShaderManager.cxx b/src/OpenGl/OpenGl_ShaderManager.cxx index db9e56688a..c0ce0eba42 100755 --- a/src/OpenGl/OpenGl_ShaderManager.cxx +++ b/src/OpenGl/OpenGl_ShaderManager.cxx @@ -25,6 +25,9 @@ #include #include +IMPLEMENT_STANDARD_HANDLE (OpenGl_SetOfShaderPrograms, Standard_Transient) +IMPLEMENT_STANDARD_RTTIEXT(OpenGl_SetOfShaderPrograms, Standard_Transient) + IMPLEMENT_STANDARD_HANDLE (OpenGl_ShaderManager, Standard_Transient) IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShaderManager, Standard_Transient) @@ -49,45 +52,6 @@ const char THE_FUNC_lightDef[] = EOL"vec3 Diffuse;" //!< Diffuse contribution of light sources EOL"vec3 Specular;"; //!< Specular contribution of light sources -//! Computes illumination from light sources -const char THE_FUNC_computeLighting[] = - EOL"vec4 computeLighting (in vec3 theNormal," - EOL" in vec3 theView," - EOL" in vec4 thePoint," - EOL" in bool theIsFront)" - EOL"{" - // clear the light intensity accumulators - EOL" Ambient = occLightAmbient.rgb;" - EOL" Diffuse = vec3 (0.0);" - EOL" Specular = vec3 (0.0);" - EOL" vec3 aPoint = thePoint.xyz / thePoint.w;" - EOL" for (int anIndex = 0; anIndex < occLightSourcesCount; ++anIndex)" - EOL" {" - EOL" int aType = occLight_Type (anIndex);" - EOL" if (aType == OccLightType_Direct)" - EOL" {" - EOL" directionalLight (anIndex, theNormal, theView, theIsFront);" - EOL" }" - EOL" else if (aType == OccLightType_Point)" - EOL" {" - EOL" pointLight (anIndex, theNormal, theView, aPoint, theIsFront);" - EOL" }" - EOL" else if (aType == OccLightType_Spot)" - EOL" {" - EOL" spotLight (anIndex, theNormal, theView, aPoint, theIsFront);" - EOL" }" - EOL" }" - EOL - EOL" vec4 aMaterialAmbient = theIsFront ? occFrontMaterial_Ambient() : occBackMaterial_Ambient();" - EOL" vec4 aMaterialDiffuse = theIsFront ? occFrontMaterial_Diffuse() : occBackMaterial_Diffuse();" - EOL" vec4 aMaterialSpecular = theIsFront ? occFrontMaterial_Specular() : occBackMaterial_Specular();" - EOL" vec4 aMaterialEmission = theIsFront ? occFrontMaterial_Emission() : occBackMaterial_Emission();" - EOL" return vec4 (Ambient, 1.0) * aMaterialAmbient" - EOL" + vec4 (Diffuse, 1.0) * aMaterialDiffuse" - EOL" + vec4 (Specular, 1.0) * aMaterialSpecular" - EOL" + aMaterialEmission;" - EOL"}"; - //! Function computes contribution of isotropic point light source const char THE_FUNC_pointLight[] = EOL"void pointLight (in int theId," @@ -240,7 +204,7 @@ OpenGl_ShaderManager::OpenGl_ShaderManager (OpenGl_Context* theContext) myContext (theContext), myLastView (NULL) { - myLightPrograms = myGouraudPrograms; + // } // ======================================================================= @@ -345,6 +309,42 @@ Standard_Boolean OpenGl_ShaderManager::IsEmpty() const return myProgramList.IsEmpty(); } +// ======================================================================= +// function : switchLightPrograms +// purpose : +// ======================================================================= +void OpenGl_ShaderManager::switchLightPrograms() +{ + TCollection_AsciiString aKey (myShadingModel == Visual3d_TOM_FRAGMENT ? "p_" : "g_"); + const OpenGl_ListOfLight* aLights = myLightSourceState.LightSources(); + if (aLights != NULL) + { + for (OpenGl_ListOfLight::Iterator aLightIter (*aLights); aLightIter.More(); aLightIter.Next()) + { + switch (aLightIter.Value().Type) + { + case Visual3d_TOLS_AMBIENT: + break; // skip ambient + case Visual3d_TOLS_DIRECTIONAL: + aKey += "d"; + break; + case Visual3d_TOLS_POSITIONAL: + aKey += "p"; + break; + case Visual3d_TOLS_SPOT: + aKey += "s"; + break; + } + } + } + + if (!myMapOfLightPrograms.Find (aKey, myLightPrograms)) + { + myLightPrograms = new OpenGl_SetOfShaderPrograms(); + myMapOfLightPrograms.Bind (aKey, myLightPrograms); + } +} + // ======================================================================= // function : UpdateLightSourceStateTo // purpose : Updates state of OCCT light sources @@ -353,6 +353,17 @@ void OpenGl_ShaderManager::UpdateLightSourceStateTo (const OpenGl_ListOfLight* t { myLightSourceState.Set (theLights); myLightSourceState.Update(); + switchLightPrograms(); +} + +// ======================================================================= +// function : SetShadingModel +// purpose : +// ======================================================================= +void OpenGl_ShaderManager::SetShadingModel (const Visual3d_TypeOfModel theModel) +{ + myShadingModel = theModel; + switchLightPrograms(); } // ======================================================================= @@ -1115,6 +1126,78 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_Shad return Standard_True; } +// ======================================================================= +// function : stdComputeLighting +// purpose : +// ======================================================================= +TCollection_AsciiString OpenGl_ShaderManager::stdComputeLighting() +{ + bool aLightsMap[Visual3d_TOLS_SPOT + 1] = { false, false, false, false }; + TCollection_AsciiString aLightsFunc, aLightsLoop; + const OpenGl_ListOfLight* aLights = myLightSourceState.LightSources(); + if (aLights != NULL) + { + Standard_Integer anIndex = 0; + for (OpenGl_ListOfLight::Iterator aLightIter (*aLights); aLightIter.More(); aLightIter.Next(), ++anIndex) + { + switch (aLightIter.Value().Type) + { + case Visual3d_TOLS_AMBIENT: + --anIndex; + break; // skip ambient + case Visual3d_TOLS_DIRECTIONAL: + aLightsLoop = aLightsLoop + EOL" directionalLight (" + anIndex + ", theNormal, theView, theIsFront);"; + break; + case Visual3d_TOLS_POSITIONAL: + aLightsLoop = aLightsLoop + EOL" pointLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);"; + break; + case Visual3d_TOLS_SPOT: + aLightsLoop = aLightsLoop + EOL" spotLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);"; + break; + } + + bool& aTypeBit = aLightsMap[aLightIter.Value().Type]; + if (aTypeBit) + { + continue; + } + + aTypeBit = true; + switch (aLightIter.Value().Type) + { + case Visual3d_TOLS_AMBIENT: break; + case Visual3d_TOLS_DIRECTIONAL: aLightsFunc += THE_FUNC_directionalLight; break; + case Visual3d_TOLS_POSITIONAL: aLightsFunc += THE_FUNC_pointLight; break; + case Visual3d_TOLS_SPOT: aLightsFunc += THE_FUNC_spotLight; break; + } + } + } + + return TCollection_AsciiString() + + THE_FUNC_lightDef + + aLightsFunc + + EOL + EOL"vec4 computeLighting (in vec3 theNormal," + EOL" in vec3 theView," + EOL" in vec4 thePoint," + EOL" in bool theIsFront)" + EOL"{" + EOL" Ambient = occLightAmbient.rgb;" + EOL" Diffuse = vec3 (0.0);" + EOL" Specular = vec3 (0.0);" + EOL" vec3 aPoint = thePoint.xyz / thePoint.w;" + + aLightsLoop + + EOL" vec4 aMaterialAmbient = theIsFront ? occFrontMaterial_Ambient() : occBackMaterial_Ambient();" + EOL" vec4 aMaterialDiffuse = theIsFront ? occFrontMaterial_Diffuse() : occBackMaterial_Diffuse();" + EOL" vec4 aMaterialSpecular = theIsFront ? occFrontMaterial_Specular() : occBackMaterial_Specular();" + EOL" vec4 aMaterialEmission = theIsFront ? occFrontMaterial_Emission() : occBackMaterial_Emission();" + EOL" return vec4 (Ambient, 1.0) * aMaterialAmbient" + EOL" + vec4 (Diffuse, 1.0) * aMaterialDiffuse" + EOL" + vec4 (Specular, 1.0) * aMaterialSpecular" + EOL" + aMaterialEmission;" + EOL"}"; +} + // ======================================================================= // function : prepareStdProgramGouraud // purpose : @@ -1144,15 +1227,11 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S aSrcFragExtraMain += THE_FRAG_CLIP_PLANES; } + const TCollection_AsciiString aLights = stdComputeLighting(); aSrcVert = TCollection_AsciiString() + THE_FUNC_transformNormal + EOL - + THE_FUNC_lightDef - + THE_FUNC_pointLight - + THE_FUNC_spotLight - + THE_FUNC_directionalLight - + EOL - + THE_FUNC_computeLighting + + aLights + EOL EOL"varying vec4 FrontColor;" EOL"varying vec4 BackColor;" @@ -1230,18 +1309,14 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha + EOL" gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;" EOL"}"; + const TCollection_AsciiString aLights = stdComputeLighting(); aSrcFrag = TCollection_AsciiString() + EOL"varying vec4 PositionWorld;" EOL"varying vec4 Position;" EOL"varying vec3 Normal;" EOL"varying vec3 View;" + EOL - + THE_FUNC_lightDef - + THE_FUNC_pointLight - + THE_FUNC_spotLight - + THE_FUNC_directionalLight - + EOL - + THE_FUNC_computeLighting + + aLights + EOL EOL"void main()" EOL"{" diff --git a/src/OpenGl/OpenGl_ShaderManager.hxx b/src/OpenGl/OpenGl_ShaderManager.hxx index 94b3e104d5..6e637688f8 100755 --- a/src/OpenGl/OpenGl_ShaderManager.hxx +++ b/src/OpenGl/OpenGl_ShaderManager.hxx @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include @@ -39,17 +39,6 @@ typedef NCollection_Sequence OpenGl_ShaderProgramL //! Map to declare per-program states of OCCT materials. typedef NCollection_DataMap OpenGl_MaterialStates; -//! Standard GLSL program combination bits. -enum OpenGl_ProgramOptions -{ - OpenGl_PO_ClipPlanes = 0x01, //!< handle clipping planes - OpenGl_PO_Point = 0x02, //!< point marker - OpenGl_PO_VertColor = 0x04, //!< per-vertex color - OpenGl_PO_TextureRGB = 0x08, //!< handle RGB texturing - OpenGl_PO_TextureA = 0x10, //!< handle Alpha texturing - OpenGl_PO_NB = 0x20 //!< overall number of combinations -}; - //! This class is responsible for managing shader programs. class OpenGl_ShaderManager : public Standard_Transient { @@ -246,13 +235,7 @@ public: } //! Sets shading model. - void SetShadingModel(const Visual3d_TypeOfModel theModel) - { - myLightPrograms = theModel == Visual3d_TOM_FRAGMENT - ? myLightPrograms = myPhongPrograms - : myLightPrograms = myGouraudPrograms; - myShadingModel = theModel; - } + Standard_EXPORT void SetShadingModel(const Visual3d_TypeOfModel theModel); //! Sets last view manger used with. //! Helps to handle matrix states in multi-view configurations. @@ -296,7 +279,7 @@ protected: { if (theToLightOn) { - Handle(OpenGl_ShaderProgram)& aProgram = myLightPrograms[theBits]; + Handle(OpenGl_ShaderProgram)& aProgram = myLightPrograms->ChangeValue (theBits); if (aProgram.IsNull()) { prepareStdProgramLight (aProgram, theBits); @@ -304,7 +287,7 @@ protected: return aProgram; } - Handle(OpenGl_ShaderProgram)& aProgram = myFlatPrograms[theBits]; + Handle(OpenGl_ShaderProgram)& aProgram = myFlatPrograms.ChangeValue (theBits); if (aProgram.IsNull()) { prepareStdProgramFlat (aProgram, theBits); @@ -336,34 +319,39 @@ protected: Standard_EXPORT Standard_Boolean prepareStdProgramPhong (Handle(OpenGl_ShaderProgram)& theProgram, const Standard_Integer theBits); + //! Define computeLighting GLSL function depending on current lights configuration + Standard_EXPORT TCollection_AsciiString stdComputeLighting(); + //! Bind specified program to current context and apply state. Standard_EXPORT Standard_Boolean bindProgramWithState (const Handle(OpenGl_ShaderProgram)& theProgram, const OpenGl_Element* theAspect); + //! Set pointer myLightPrograms to active lighting programs set from myMapOfLightPrograms + Standard_EXPORT void switchLightPrograms(); + protected: - Visual3d_TypeOfModel myShadingModel; //!< lighting shading model - OpenGl_ShaderProgramList myProgramList; //!< The list of shader programs - Handle(OpenGl_ShaderProgram)* myLightPrograms; //!< pointer to active lighting programs matrix, depending on shading model and lights configuration - Handle(OpenGl_ShaderProgram) myGouraudPrograms[OpenGl_PO_NB]; //!< matrix with per-vertex lighting programs - Handle(OpenGl_ShaderProgram) myPhongPrograms [OpenGl_PO_NB]; //!< matrix with per-fragment lighting programs - Handle(OpenGl_ShaderProgram) myFlatPrograms [OpenGl_PO_NB]; //!< programs matrix without lighting - Handle(OpenGl_ShaderProgram) myFontProgram; //!< standard program for textured text + Visual3d_TypeOfModel myShadingModel; //!< lighting shading model + OpenGl_ShaderProgramList myProgramList; //!< The list of shader programs + Handle(OpenGl_SetOfShaderPrograms) myLightPrograms; //!< pointer to active lighting programs matrix + OpenGl_SetOfShaderPrograms myFlatPrograms; //!< programs matrix without lighting + Handle(OpenGl_ShaderProgram) myFontProgram; //!< standard program for textured text + OpenGl_MapOfShaderPrograms myMapOfLightPrograms; //!< map of lighting programs depending on shading model and lights configuration - OpenGl_Context* myContext; //!< OpenGL context + OpenGl_Context* myContext; //!< OpenGL context protected: - OpenGl_MaterialStates myMaterialStates; //!< Per-program state of OCCT material - OpenGl_ProjectionState myProjectionState; //!< State of OCCT projection transformation - OpenGl_ModelWorldState myModelWorldState; //!< State of OCCT model-world transformation - OpenGl_WorldViewState myWorldViewState; //!< State of OCCT world-view transformation - OpenGl_LightSourceState myClippingState; //!< State of OCCT clipping planes - OpenGl_LightSourceState myLightSourceState; //!< State of OCCT light sources + OpenGl_MaterialStates myMaterialStates; //!< Per-program state of OCCT material + OpenGl_ProjectionState myProjectionState; //!< State of OCCT projection transformation + OpenGl_ModelWorldState myModelWorldState; //!< State of OCCT model-world transformation + OpenGl_WorldViewState myWorldViewState; //!< State of OCCT world-view transformation + OpenGl_LightSourceState myClippingState; //!< State of OCCT clipping planes + OpenGl_LightSourceState myLightSourceState; //!< State of OCCT light sources private: - const OpenGl_View* myLastView; //!< Pointer to the last view shader manager used with + const OpenGl_View* myLastView; //!< Pointer to the last view shader manager used with public: diff --git a/src/OpenGl/OpenGl_View_2.cxx b/src/OpenGl/OpenGl_View_2.cxx index 507ddc7402..f346cb4877 100644 --- a/src/OpenGl/OpenGl_View_2.cxx +++ b/src/OpenGl/OpenGl_View_2.cxx @@ -404,37 +404,34 @@ void OpenGl_View::Render (const Handle(OpenGl_PrinterContext)& thePrintContext, // Set OCCT state uniform variables const Handle(OpenGl_ShaderManager) aManager = aContext->ShaderManager(); const Standard_Boolean isSameView = aManager->IsSameView (this); // force camera state update when needed - if (!aManager->IsEmpty()) + if (StateInfo (myCurrLightSourceState, aManager->LightSourceState().Index()) != myLastLightSourceState) { - if (StateInfo (myCurrLightSourceState, aManager->LightSourceState().Index()) != myLastLightSourceState) - { - aManager->UpdateLightSourceStateTo (&myLights); - myLastLightSourceState = StateInfo (myCurrLightSourceState, aManager->LightSourceState().Index()); - } + aManager->UpdateLightSourceStateTo (&myLights); + myLastLightSourceState = StateInfo (myCurrLightSourceState, aManager->LightSourceState().Index()); + } - if (myProjectionState != myCamera->ProjectionState() - || !isSameView) - { - myProjectionState = myCamera->ProjectionState(); - aManager->UpdateProjectionStateTo ((const Tmatrix3*)myCamera->ProjectionMatrixF().GetData()); - } + if (myProjectionState != myCamera->ProjectionState() + || !isSameView) + { + myProjectionState = myCamera->ProjectionState(); + aManager->UpdateProjectionStateTo ((const Tmatrix3*)myCamera->ProjectionMatrixF().GetData()); + } - if (myModelViewState != myCamera->ModelViewState() - || !isSameView) - { - myModelViewState = myCamera->ModelViewState(); - aManager->UpdateWorldViewStateTo ((const Tmatrix3*)myCamera->OrientationMatrixF().GetData()); - } + if (myModelViewState != myCamera->ModelViewState() + || !isSameView) + { + myModelViewState = myCamera->ModelViewState(); + aManager->UpdateWorldViewStateTo ((const Tmatrix3*)myCamera->OrientationMatrixF().GetData()); + } - if (aManager->ModelWorldState().Index() == 0) - { - Tmatrix3 aModelWorldState = { { 1.f, 0.f, 0.f, 0.f }, - { 0.f, 1.f, 0.f, 0.f }, - { 0.f, 0.f, 1.f, 0.f }, - { 0.f, 0.f, 0.f, 1.f } }; + if (aManager->ModelWorldState().Index() == 0) + { + Tmatrix3 aModelWorldState = { { 1.f, 0.f, 0.f, 0.f }, + { 0.f, 1.f, 0.f, 0.f }, + { 0.f, 0.f, 1.f, 0.f }, + { 0.f, 0.f, 0.f, 1.f } }; - aContext->ShaderManager()->UpdateModelWorldStateTo (&aModelWorldState); - } + aContext->ShaderManager()->UpdateModelWorldStateTo (&aModelWorldState); } if (isProjectionMatUpdateNeeded -- 2.39.5