diff --git a/src/Graphic3d/Graphic3d_RenderTransparentMethod.hxx b/src/Graphic3d/Graphic3d_RenderTransparentMethod.hxx index 5066f09cfa..e18dfc11ec 100644 --- a/src/Graphic3d/Graphic3d_RenderTransparentMethod.hxx +++ b/src/Graphic3d/Graphic3d_RenderTransparentMethod.hxx @@ -19,8 +19,9 @@ //! Enumerates transparency rendering methods supported by rasterization mode. enum Graphic3d_RenderTransparentMethod { - Graphic3d_RTM_BLEND_UNORDERED, //!< Basic blend transparency with non-commuting blend operator without sorting - Graphic3d_RTM_BLEND_OIT //!< Weighted Blended Order-Independent Transparency with depth weight factor + Graphic3d_RTM_BLEND_UNORDERED, //!< Basic blend transparency with non-commuting blend operator without sorting + Graphic3d_RTM_BLEND_OIT, //!< Weighted Blended Order-Independent Transparency with depth weight factor + Graphic3d_RTM_DEPTH_PEELING_OIT //!< Depth Peeling with specified number of depth layers }; #endif // _Graphic3d_RenderTransparentMethod_HeaderFile diff --git a/src/Graphic3d/Graphic3d_RenderingParams.hxx b/src/Graphic3d/Graphic3d_RenderingParams.hxx index 7469c9e66e..48aebdef11 100644 --- a/src/Graphic3d/Graphic3d_RenderingParams.hxx +++ b/src/Graphic3d/Graphic3d_RenderingParams.hxx @@ -104,6 +104,7 @@ public: PbrEnvBakingProbability (0.99f), // OitDepthFactor (0.0f), + NbOitDepthPeelingLayers (4), NbMsaaSamples (0), RenderResolutionScale (1.0f), ShadowMapResolution (1024), @@ -197,7 +198,8 @@ public: Standard_ShortReal PbrEnvBakingProbability; //!< controls strength of samples reducing strategy during specular IBL map's generation //! (see 'SpecIBLMapSamplesFactor' function for detail explanation) [0.0, 1.0], 0.99 by default - Standard_ShortReal OitDepthFactor; //!< scalar factor [0-1] controlling influence of depth of a fragment to its final coverage + Standard_ShortReal OitDepthFactor; //!< scalar factor [0-1] controlling influence of depth of a fragment to its final coverage (Graphic3d_RTM_BLEND_OIT), 0.0 by default + Standard_Integer NbOitDepthPeelingLayers; //!< number of depth peeling (Graphic3d_RTM_DEPTH_PEELING_OIT) layers, 4 by default 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) diff --git a/src/Graphic3d/Graphic3d_ShaderProgram.cxx b/src/Graphic3d/Graphic3d_ShaderProgram.cxx index 28c8e7eac5..8fac2414a8 100755 --- a/src/Graphic3d/Graphic3d_ShaderProgram.cxx +++ b/src/Graphic3d/Graphic3d_ShaderProgram.cxx @@ -82,9 +82,9 @@ Graphic3d_ShaderProgram::Graphic3d_ShaderProgram() myNbClipPlanesMax (THE_MAX_CLIP_PLANES_DEFAULT), myNbFragOutputs (THE_NB_FRAG_OUTPUTS), myTextureSetBits (Graphic3d_TextureSetBits_NONE), + myOitOutput (Graphic3d_RTM_BLEND_UNORDERED), myHasDefSampler (true), myHasAlphaTest (false), - myHasWeightOitOutput (false), myIsPBR (false) { myID = TCollection_AsciiString ("Graphic3d_ShaderProgram_") diff --git a/src/Graphic3d/Graphic3d_ShaderProgram.hxx b/src/Graphic3d/Graphic3d_ShaderProgram.hxx index fb612f15d9..baf36dd283 100755 --- a/src/Graphic3d/Graphic3d_ShaderProgram.hxx +++ b/src/Graphic3d/Graphic3d_ShaderProgram.hxx @@ -16,6 +16,7 @@ #ifndef _Graphic3d_ShaderProgram_HeaderFile #define _Graphic3d_ShaderProgram_HeaderFile +#include #include #include #include @@ -151,12 +152,13 @@ public: //! Set if standard program header should define default texture sampler occSampler0. void SetDefaultSampler (Standard_Boolean theHasDefSampler) { myHasDefSampler = theHasDefSampler; } - //! Return true if Fragment Shader color should output the weighted OIT coverage; FALSE by default. - Standard_Boolean HasWeightOitOutput() const { return myHasWeightOitOutput; } + //! Return if Fragment Shader color should output to OIT buffers; OFF by default. + Graphic3d_RenderTransparentMethod OitOutput() const { return myOitOutput; } - //! Set if Fragment Shader color should output the weighted OIT coverage. - //! Note that weighted OIT also requires at least 2 Fragment Outputs (color + coverage). - void SetWeightOitOutput (Standard_Boolean theOutput) { myHasWeightOitOutput = theOutput; } + //! Set if Fragment Shader color should output to OIT buffers. + //! Note that weighted OIT also requires at least 2 Fragment Outputs (color + coverage), + //! and Depth Peeling requires at least 3 Fragment Outputs (depth + front color + back color), + void SetOitOutput (Graphic3d_RenderTransparentMethod theOutput) { myOitOutput = theOutput; } //! Return TRUE if standard program header should define functions and variables used in PBR pipeline. //! FALSE by default. @@ -223,9 +225,9 @@ private: 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 + Graphic3d_RenderTransparentMethod myOitOutput; //!< flag indicating that Fragment Shader includes OIT outputs Standard_Boolean myHasDefSampler; //!< flag indicating that program defines default texture sampler occSampler0 Standard_Boolean myHasAlphaTest; //!< flag indicating that Fragment Shader performs alpha test - Standard_Boolean myHasWeightOitOutput; //!< flag indicating that Fragment Shader includes weighted OIT coverage Standard_Boolean myIsPBR; //!< flag indicating that program defines functions and variables used in PBR pipeline }; diff --git a/src/Graphic3d/Graphic3d_TextureUnit.hxx b/src/Graphic3d/Graphic3d_TextureUnit.hxx index 34d4aa026d..6916c4ada8 100644 --- a/src/Graphic3d/Graphic3d_TextureUnit.hxx +++ b/src/Graphic3d/Graphic3d_TextureUnit.hxx @@ -67,6 +67,14 @@ enum Graphic3d_TextureUnit //! 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 occDepthPeelingDepth. + //! 1st texture unit for Depth Peeling lookups. + Graphic3d_TextureUnit_DepthPeelingDepth = -6, + + //! sampler2D occDepthPeelingFrontColor. + //! 2nd texture unit for Depth Peeling lookups. + Graphic3d_TextureUnit_DepthPeelingFrontColor = -5, + //! sampler2D occShadowMapSampler. //! Directional light source shadowmap texture. Graphic3d_TextureUnit_ShadowMap = -4, @@ -75,10 +83,12 @@ enum Graphic3d_TextureUnit //! Lookup table for approximated PBR environment lighting. //! Configured as index at the end of available texture units - 3. Graphic3d_TextureUnit_PbrEnvironmentLUT = -3, + //! sampler2D occDiffIBLMapSHCoeffs. //! Diffuse (irradiance) IBL map's spherical harmonics coefficients baked for PBR from environment cubemap image. //! Configured as index at the end of available texture units - 2. Graphic3d_TextureUnit_PbrIblDiffuseSH = -2, + //! samplerCube occSpecIBLMap. //! Specular IBL (Image-Based Lighting) environment map baked for PBR from environment cubemap image. //! Configured as index at the end of available texture units - 1. diff --git a/src/OpenGl/FILES b/src/OpenGl/FILES index 5c61112ef6..786abcf16d 100755 --- a/src/OpenGl/FILES +++ b/src/OpenGl/FILES @@ -75,6 +75,8 @@ OpenGl_ClippingIterator.hxx OpenGl_Context.cxx OpenGl_Context.hxx OpenGl_Context_1.mm +OpenGl_DepthPeeling.cxx +OpenGl_DepthPeeling.hxx OpenGl_ExtGS.hxx OpenGl_GLESExtensions.hxx OpenGl_GlFunctions.hxx diff --git a/src/OpenGl/OpenGl_Context.cxx b/src/OpenGl/OpenGl_Context.cxx index 05d1761729..097e12fefe 100644 --- a/src/OpenGl/OpenGl_Context.cxx +++ b/src/OpenGl/OpenGl_Context.cxx @@ -221,6 +221,8 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps) myPBRDiffIBLMapSHTexUnit (Graphic3d_TextureUnit_PbrIblDiffuseSH), myPBRSpecIBLMapTexUnit (Graphic3d_TextureUnit_PbrIblSpecular), myShadowMapTexUnit (Graphic3d_TextureUnit_ShadowMap), + myDepthPeelingDepthTexUnit (Graphic3d_TextureUnit_DepthPeelingDepth), + myDepthPeelingFrontColorTexUnit (Graphic3d_TextureUnit_DepthPeelingFrontColor), myFrameStats (new OpenGl_FrameStats()), myActiveMockTextures (0), myActiveHatchType (Aspect_HS_SOLID), @@ -3348,13 +3350,19 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile) || (IsGlGreaterEqual (2, 1) && CheckExtension ("GL_EXT_gpu_shader4")) #endif ); - if (myHasPBR) + + myDepthPeelingDepthTexUnit = static_cast(myMaxTexCombined + Graphic3d_TextureUnit_DepthPeelingDepth); // -6 + myDepthPeelingFrontColorTexUnit = static_cast(myMaxTexCombined + Graphic3d_TextureUnit_DepthPeelingFrontColor); // -5 + myShadowMapTexUnit = static_cast(myMaxTexCombined + Graphic3d_TextureUnit_ShadowMap); // -4 + myPBREnvLUTTexUnit = static_cast(myMaxTexCombined + Graphic3d_TextureUnit_PbrEnvironmentLUT); // -3 + myPBRDiffIBLMapSHTexUnit = static_cast(myMaxTexCombined + Graphic3d_TextureUnit_PbrIblDiffuseSH); // -2 + myPBRSpecIBLMapTexUnit = static_cast(myMaxTexCombined + Graphic3d_TextureUnit_PbrIblSpecular); // -1 + if (!myHasPBR) { - myPBREnvLUTTexUnit = static_cast(myMaxTexCombined + Graphic3d_TextureUnit_PbrEnvironmentLUT); - myPBRDiffIBLMapSHTexUnit = static_cast(myMaxTexCombined + Graphic3d_TextureUnit_PbrIblDiffuseSH); - myPBRSpecIBLMapTexUnit = static_cast(myMaxTexCombined + Graphic3d_TextureUnit_PbrIblSpecular); + myDepthPeelingDepthTexUnit = static_cast(myDepthPeelingDepthTexUnit + 3); + myDepthPeelingFrontColorTexUnit = static_cast(myDepthPeelingFrontColorTexUnit + 3); + myShadowMapTexUnit = static_cast(myShadowMapTexUnit + 3); } - myShadowMapTexUnit = static_cast(myMaxTexCombined + Graphic3d_TextureUnit_ShadowMap); } // ======================================================================= diff --git a/src/OpenGl/OpenGl_Context.hxx b/src/OpenGl/OpenGl_Context.hxx index 8e7d65780d..493a10e765 100644 --- a/src/OpenGl/OpenGl_Context.hxx +++ b/src/OpenGl/OpenGl_Context.hxx @@ -633,6 +633,12 @@ public: //! Returns texture unit where shadow map is expected to be bound, or 0 if unavailable. Graphic3d_TextureUnit ShadowMapTexUnit() const { return myShadowMapTexUnit; } + //! Returns texture unit for occDepthPeelingDepth within enabled Depth Peeling. + Graphic3d_TextureUnit DepthPeelingDepthTexUnit() const { return myDepthPeelingDepthTexUnit; } + + //! Returns texture unit for occDepthPeelingFrontColor within enabled Depth Peeling. + Graphic3d_TextureUnit DepthPeelingFrontColorTexUnit() const { return myDepthPeelingFrontColorTexUnit; } + //! Returns true if VBO is supported and permitted. inline bool ToUseVbo() const { @@ -1174,6 +1180,9 @@ private: // context info 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 + Graphic3d_TextureUnit myDepthPeelingDepthTexUnit; //!< sampler2D occDepthPeelingDepth, texture unit for Depth Peeling lookups + Graphic3d_TextureUnit myDepthPeelingFrontColorTexUnit; //!< sampler2D occDepthPeelingFrontColor, texture unit for Depth Peeling lookups + Handle(OpenGl_ShaderManager) myShaderManager; //! support object for managing shader programs private: //! @name fields tracking current state diff --git a/src/OpenGl/OpenGl_DepthPeeling.cxx b/src/OpenGl/OpenGl_DepthPeeling.cxx new file mode 100644 index 0000000000..af2e3adc6b --- /dev/null +++ b/src/OpenGl/OpenGl_DepthPeeling.cxx @@ -0,0 +1,107 @@ +// Created on: 2021-01-15 +// 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 +#include + +IMPLEMENT_STANDARD_RTTIEXT(OpenGl_DepthPeeling, OpenGl_NamedResource) + +//======================================================================= +// function : OpenGl_DepthPeeling +// purpose : +//======================================================================= +OpenGl_DepthPeeling::OpenGl_DepthPeeling() +: OpenGl_NamedResource ("depth_peeling") +{ + myDepthPeelFbosOit[0] = new OpenGl_FrameBuffer(); + myDepthPeelFbosOit[1] = new OpenGl_FrameBuffer(); + myFrontBackColorFbosOit[0] = new OpenGl_FrameBuffer(); + myFrontBackColorFbosOit[1] = new OpenGl_FrameBuffer(); + myBlendBackFboOit = new OpenGl_FrameBuffer(); +} + +// ======================================================================= +// function : ~OpenGl_DepthPeeling +// purpose : +// ======================================================================= +OpenGl_DepthPeeling::~OpenGl_DepthPeeling() +{ + Release (NULL); +} + +//======================================================================= +// function : Release +// purpose : +//======================================================================= +void OpenGl_DepthPeeling::Release (OpenGl_Context* theCtx) +{ + myDepthPeelFbosOit[0] ->Release (theCtx); + myDepthPeelFbosOit[1] ->Release (theCtx); + myFrontBackColorFbosOit[0]->Release (theCtx); + myFrontBackColorFbosOit[1]->Release (theCtx); + myBlendBackFboOit ->Release (theCtx); +} + +//======================================================================= +// function : EstimatedDataSize +// purpose : +//======================================================================= +Standard_Size OpenGl_DepthPeeling::EstimatedDataSize() const +{ + return myDepthPeelFbosOit[0]->EstimatedDataSize() + + myDepthPeelFbosOit[1]->EstimatedDataSize() + + myFrontBackColorFbosOit[0]->EstimatedDataSize() + + myFrontBackColorFbosOit[1]->EstimatedDataSize() + + myBlendBackFboOit->EstimatedDataSize(); +} + +//======================================================================= +// function : AttachDepthTexture +// purpose : +//======================================================================= +void OpenGl_DepthPeeling::AttachDepthTexture (const Handle(OpenGl_Context)& theCtx, + const Handle(OpenGl_Texture)& theDepthStencilTexture) +{ + if (!theDepthStencilTexture.IsNull() + && theDepthStencilTexture->IsValid()) + { + for (int aPairIter = 0; aPairIter < 2; ++aPairIter) + { + myDepthPeelFbosOit[aPairIter]->BindBuffer (theCtx); + theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + theDepthStencilTexture->GetTarget(), + theDepthStencilTexture->TextureId(), 0); + myDepthPeelFbosOit[aPairIter]->UnbindBuffer (theCtx); + } + } +} + +//======================================================================= +// function : DetachDepthTexture +// purpose : +//======================================================================= +void OpenGl_DepthPeeling::DetachDepthTexture (const Handle(OpenGl_Context)& theCtx) +{ + if (!myDepthPeelFbosOit[0]->DepthStencilTexture().IsNull()) + { + for (int aPairIter = 0; aPairIter < 2; ++aPairIter) + { + myDepthPeelFbosOit[aPairIter]->BindBuffer (theCtx); + theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + myDepthPeelFbosOit[aPairIter]->DepthStencilTexture()->GetTarget(), + 0, 0); + myDepthPeelFbosOit[aPairIter]->UnbindBuffer (theCtx); + } + } +} diff --git a/src/OpenGl/OpenGl_DepthPeeling.hxx b/src/OpenGl/OpenGl_DepthPeeling.hxx new file mode 100644 index 0000000000..b26a958c18 --- /dev/null +++ b/src/OpenGl/OpenGl_DepthPeeling.hxx @@ -0,0 +1,62 @@ +// Created on: 2021-01-15 +// 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_DepthPeeling_HeaderFile +#define _OpenGl_DepthPeeling_HeaderFile + +#include + +//! Class provides FBOs for dual depth peeling. +class OpenGl_DepthPeeling : public OpenGl_NamedResource +{ + DEFINE_STANDARD_RTTIEXT(OpenGl_DepthPeeling, OpenGl_NamedResource) +public: + + //! Constructor. + Standard_EXPORT OpenGl_DepthPeeling(); + + //! Destructor. + Standard_EXPORT virtual ~OpenGl_DepthPeeling(); + + //! Release OpenGL resources + Standard_EXPORT virtual void Release (OpenGl_Context* theGlCtx) 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; + + //! Attach a texture image + Standard_EXPORT void AttachDepthTexture (const Handle(OpenGl_Context)& theCtx, + const Handle(OpenGl_Texture)& theDepthStencilTexture); + + //! Detach a texture image + Standard_EXPORT void DetachDepthTexture (const Handle(OpenGl_Context)& theCtx); + + //! Returns additional buffers for ping-pong + const Handle(OpenGl_FrameBuffer)* DepthPeelFbosOit() const { return myDepthPeelFbosOit; } + + //! Returns additional buffers for ping-pong + const Handle(OpenGl_FrameBuffer)* FrontBackColorFbosOit() const { return myFrontBackColorFbosOit; } + + //! Returns additional FBO for depth peeling + const Handle(OpenGl_FrameBuffer)& BlendBackFboOit() const { return myBlendBackFboOit; } + +private: + + Handle(OpenGl_FrameBuffer) myDepthPeelFbosOit[2]; //!< depth + front color + back color + Handle(OpenGl_FrameBuffer) myFrontBackColorFbosOit[2]; //!< front color + back color + Handle(OpenGl_FrameBuffer) myBlendBackFboOit; + +}; + +#endif // _OpenGl_DepthPeeling_HeaderFile diff --git a/src/OpenGl/OpenGl_FrameBuffer.cxx b/src/OpenGl/OpenGl_FrameBuffer.cxx index a05e321660..0956287b83 100644 --- a/src/OpenGl/OpenGl_FrameBuffer.cxx +++ b/src/OpenGl/OpenGl_FrameBuffer.cxx @@ -74,7 +74,8 @@ OpenGl_FrameBuffer::OpenGl_FrameBuffer() myGlFBufferId (NO_FRAMEBUFFER), myGlColorRBufferId (NO_RENDERBUFFER), myGlDepthRBufferId (NO_RENDERBUFFER), - myIsOwnBuffer (false), + myIsOwnBuffer (false), + myIsOwnColor (false), myIsOwnDepth (false), myDepthStencilTexture (new OpenGl_Texture()) { @@ -91,6 +92,74 @@ OpenGl_FrameBuffer::~OpenGl_FrameBuffer() Release (NULL); } +// ======================================================================= +// function : InitWrapper +// purpose : +// ======================================================================= +Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlContext, + const NCollection_Sequence& theColorTextures, + const Handle(OpenGl_Texture)& theDepthTexture) +{ + Release (theGlContext.get()); + if (theGlContext->arbFBO == NULL) + { + return false; + } + + myColorFormats.Clear(); + myColorTextures.Clear(); + for (NCollection_Sequence::Iterator aColorIter (theColorTextures); aColorIter.More(); aColorIter.Next()) + { + myColorTextures.Append (aColorIter.Value()); + } + myDepthFormat = 0; + myDepthStencilTexture = theDepthTexture; + myNbSamples = theColorTextures.First()->NbSamples(); + + myIsOwnColor = false; + myIsOwnDepth = false; + myIsOwnBuffer = true; + + myVPSizeX = theColorTextures.First()->SizeX(); + myVPSizeY = theColorTextures.First()->SizeY(); + + theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId); + theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId); + for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx) + { + const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx); + if (aColorTexture->IsValid()) + { + theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx, + aColorTexture->GetTarget(), aColorTexture->TextureId(), 0); + } + } + if (!myDepthStencilTexture.IsNull() + && myDepthStencilTexture->IsValid()) + { + if (hasDepthStencilAttach (theGlContext)) + { + theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0); + } + else + { + theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0); + theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0); + } + } + if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + Release (theGlContext.get()); + return false; + } + + UnbindBuffer (theGlContext); + return true; +} + // ======================================================================= // function : Init // purpose : @@ -103,9 +172,10 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo const GLsizei theNbSamples) { OpenGl_ColorFormats aColorFormats; - - aColorFormats.Append (theColorFormat); - + if (theColorFormat != 0) + { + aColorFormats.Append (theColorFormat); + } return Init (theGlContext, theSizeX, theSizeY, aColorFormats, theDepthFormat, theNbSamples); } @@ -152,6 +222,7 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo } myDepthStencilTexture = theDepthStencilTexture; + myIsOwnColor = true; myIsOwnDepth = false; myIsOwnBuffer = true; @@ -168,8 +239,8 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo { const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx); const GLint aColorFormat = myColorFormats (aColorBufferIdx); - if (aColorFormat != 0 - && !aColorTexture->Init2DMultisample (theGlContext, theNbSamples, + if (aColorFormat == 0 + || !aColorTexture->Init2DMultisample (theGlContext, theNbSamples, aColorFormat, aSizeX, aSizeY)) { Release (theGlContext.get()); @@ -184,8 +255,8 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx); const GLint aColorFormat = myColorFormats (aColorBufferIdx); const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindSizedFormat (theGlContext, aColorFormat); - if (aFormat.IsValid() - && !aColorTexture->Init (theGlContext, aFormat, Graphic3d_Vec2i (aSizeX, aSizeY), Graphic3d_TOT_2D)) + if (!aFormat.IsValid() + || !aColorTexture->Init (theGlContext, aFormat, Graphic3d_Vec2i (aSizeX, aSizeY), Graphic3d_TOT_2D)) { Release (theGlContext.get()); return Standard_False; @@ -275,6 +346,7 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo return Standard_False; } + myIsOwnColor = true; myIsOwnBuffer = true; myIsOwnDepth = true; @@ -292,8 +364,8 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo { const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx); const GLint aColorFormat = myColorFormats (aColorBufferIdx); - if (aColorFormat != 0 - && !aColorTexture->Init2DMultisample (theGlContext, theNbSamples, aColorFormat, aSizeX, aSizeY)) + if (aColorFormat == 0 + || !aColorTexture->Init2DMultisample (theGlContext, theNbSamples, aColorFormat, aSizeX, aSizeY)) { Release (theGlContext.operator->()); return Standard_False; @@ -313,8 +385,8 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx); const GLint aColorFormat = myColorFormats (aColorBufferIdx); const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindSizedFormat (theGlContext, aColorFormat); - if (aFormat.IsValid() - && !aColorTexture->Init (theGlContext, aFormat, Graphic3d_Vec2i (aSizeX, aSizeY), Graphic3d_TOT_2D)) + if (!aFormat.IsValid() + || !aColorTexture->Init (theGlContext, aFormat, Graphic3d_Vec2i (aSizeX, aSizeY), Graphic3d_TOT_2D)) { Release (theGlContext.operator->()); return Standard_False; @@ -476,6 +548,7 @@ Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& t // clean up previous state Release (theGlCtx.operator->()); + myIsOwnColor = true; myIsOwnBuffer = true; myIsOwnDepth = true; @@ -573,6 +646,7 @@ Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aDepthType); myGlFBufferId = GLuint(anFbo); + myIsOwnColor = false; myIsOwnBuffer = false; myIsOwnDepth = false; if (aColorType == GL_RENDERBUFFER) @@ -648,9 +722,13 @@ void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx) myIsOwnBuffer = false; } - for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx) + if (myIsOwnColor) { - myColorTextures (aColorBufferIdx)->Release (theGlCtx); + for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx) + { + myColorTextures (aColorBufferIdx)->Release (theGlCtx); + } + myIsOwnColor = false; } if (myIsOwnDepth) diff --git a/src/OpenGl/OpenGl_FrameBuffer.hxx b/src/OpenGl/OpenGl_FrameBuffer.hxx index d043967779..bc204e1732 100644 --- a/src/OpenGl/OpenGl_FrameBuffer.hxx +++ b/src/OpenGl/OpenGl_FrameBuffer.hxx @@ -216,6 +216,11 @@ public: //! Retrieved OpenGL objects will not be destroyed on Release. Standard_EXPORT Standard_Boolean InitWrapper (const Handle(OpenGl_Context)& theGlCtx); + //! Wrap existing color textures. + Standard_EXPORT Standard_Boolean InitWrapper (const Handle(OpenGl_Context)& theGlContext, + const NCollection_Sequence& theColorTextures, + const Handle(OpenGl_Texture)& theDepthTexture = Handle(OpenGl_Texture)()); + //! Setup viewport to render into FBO Standard_EXPORT void SetupViewport (const Handle(OpenGl_Context)& theGlCtx); @@ -286,7 +291,8 @@ protected: GLuint myGlColorRBufferId; //!< color Render Buffer object (alternative to myColorTexture) GLuint myGlDepthRBufferId; //!< depth-stencil Render Buffer object (alternative to myDepthStencilTexture) bool myIsOwnBuffer; //!< flag indicating that FBO should be deallocated by this class - bool myIsOwnDepth; //!< flag indicating that FBO should be deallocated by this class + bool myIsOwnColor; //!< flag indicating that color textures should be deallocated by this class + bool myIsOwnDepth; //!< flag indicating that depth texture should be deallocated by this class OpenGl_TextureArray myColorTextures; //!< color texture objects Handle(OpenGl_Texture) myDepthStencilTexture; //!< depth-stencil texture object diff --git a/src/OpenGl/OpenGl_FrameStats.cxx b/src/OpenGl/OpenGl_FrameStats.cxx index d4bf258367..568c3c06b4 100644 --- a/src/OpenGl/OpenGl_FrameStats.cxx +++ b/src/OpenGl/OpenGl_FrameStats.cxx @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -149,6 +150,7 @@ void OpenGl_FrameStats::updateStatistics (const Handle(Graphic3d_CView)& theView aMemFbos += estimatedDataSize (aView->myMainSceneFbosOit[1]); aMemFbos += estimatedDataSize (aView->myImmediateSceneFbosOit[0]); aMemFbos += estimatedDataSize (aView->myImmediateSceneFbosOit[1]); + aMemFbos += estimatedDataSize (aView->myDepthPeelingFbos); // shadowmap FBOs aMemFbos += aView->myShadowMaps->EstimatedDataSize(); // dump FBO diff --git a/src/OpenGl/OpenGl_LayerList.cxx b/src/OpenGl/OpenGl_LayerList.cxx index 12e2754e1d..79b32cc789 100644 --- a/src/OpenGl/OpenGl_LayerList.cxx +++ b/src/OpenGl/OpenGl_LayerList.cxx @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -136,6 +137,11 @@ namespace OpenGl_LayerFilter myLayersToProcess; Standard_Boolean myToDrawImmediate; }; + + static const Standard_Integer THE_DRAW_BUFFERS0[] = { GL_COLOR_ATTACHMENT0 }; + static const Standard_Integer THE_DRAW_BUFFERS01[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT0 + 1 }; + static const Standard_Integer THE_DRAW_BUFFERS012[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT0 + 1, GL_COLOR_ATTACHMENT0 + 2 }; + static const float THE_DEPTH_CLEAR_VALUE = -1e15f; } struct OpenGl_GlobalLayerSettings @@ -860,17 +866,6 @@ void OpenGl_LayerList::renderTransparent (const Handle(OpenGl_Workspace)& theW OpenGl_FrameBuffer* theReadDrawFbo, OpenGl_FrameBuffer* theOitAccumFbo) const { - // Blended order-independent transparency algorithm require several preconditions - // to be enabled. It should be requested by user, at least two outputs from - // fragment shader should be supported by GPU, so is the given framebuffer - // should contain two additional color buffers to handle accumulated color channels, - // blended alpha channel and weight factors - these accumulation buffers are required - // to implement commuting blend operator (at least OpenGl 2.0 should be available). - const bool isEnabledOit = theOitAccumFbo != NULL - && theOitAccumFbo->NbColorBuffers() >= 2 - && theOitAccumFbo->ColorTexture (0)->IsValid() - && theOitAccumFbo->ColorTexture (1)->IsValid(); - // Check if current iterator has already reached the end of the stack. // This should happen if no additional layers has been added to // the processing stack after last transparency pass. @@ -879,105 +874,331 @@ void OpenGl_LayerList::renderTransparent (const Handle(OpenGl_Workspace)& theW return; } - const Handle(OpenGl_Context) aCtx = theWorkspace->GetGlContext(); + const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext(); const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager(); + const OpenGl_LayerStack::iterator aLayerFrom = theLayerIter; OpenGl_View* aView = theWorkspace->View(); - const float aDepthFactor = aView != NULL ? aView->RenderingParams().OitDepthFactor : 0.0f; + + Graphic3d_RenderTransparentMethod anOitMode = aView != NULL + ? aView->RenderingParams().TransparencyMethod + : Graphic3d_RTM_BLEND_UNORDERED; const Standard_Integer aPrevFilter = theWorkspace->RenderFilter() & ~(Standard_Integer )(OpenGl_RenderFilter_OpaqueOnly | OpenGl_RenderFilter_TransparentOnly); theWorkspace->SetRenderFilter (aPrevFilter | OpenGl_RenderFilter_TransparentOnly); - aCtx->core11fwd->glEnable (GL_BLEND); - if (isEnabledOit) + const Handle(OpenGl_FrameBuffer)* aGlDepthPeelFBOs = aView->DepthPeelingFbos()->DepthPeelFbosOit(); + const Handle(OpenGl_FrameBuffer)* aGlFrontBackColorFBOs = aView->DepthPeelingFbos()->FrontBackColorFbosOit(); + const Handle(OpenGl_FrameBuffer)& aGlBlendBackFBO = aView->DepthPeelingFbos()->BlendBackFboOit(); + + // Blended order-independent transparency algorithm require several preconditions to be enabled. + // It should be requested by user, at least two outputs from fragment shader should be supported by GPU, + // so is the given framebuffer should contain two additional color buffers to handle accumulated color channels, + // blended alpha channel and weight factors - these accumulation buffers are required + // to implement commuting blend operator (at least OpenGl 2.0 should be available). + if (anOitMode == Graphic3d_RTM_BLEND_OIT) { - aManager->SetOitState (true, aDepthFactor); - - theOitAccumFbo->BindBuffer (aCtx); - - static const Standard_Integer aDrawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT0 + 1 }; - aCtx->SetDrawBuffers (2, aDrawBuffers); - aCtx->SetColorMaskRGBA (NCollection_Vec4 (true)); // force writes into all components, including alpha - aCtx->core11fwd->glClearColor (0.0f, 0.0f, 0.0f, 1.0f); - aCtx->core11fwd->glClear (GL_COLOR_BUFFER_BIT); - aCtx->core15fwd->glBlendFuncSeparate (GL_ONE, GL_ONE, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); + if (theOitAccumFbo == NULL + || theOitAccumFbo->NbColorBuffers() < 2 + || !theOitAccumFbo->ColorTexture (0)->IsValid() + || !theOitAccumFbo->ColorTexture (1)->IsValid()) + { + anOitMode = Graphic3d_RTM_BLEND_UNORDERED; + } } - else + else if (anOitMode == Graphic3d_RTM_DEPTH_PEELING_OIT) { - aCtx->core11fwd->glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (!aGlBlendBackFBO->IsValid()) + { + anOitMode = Graphic3d_RTM_BLEND_UNORDERED; + } + } + const bool isMSAA = theReadDrawFbo && theReadDrawFbo->NbSamples() > 0; + int aDepthPeelingDrawId = -1; + + switch (anOitMode) + { + case Graphic3d_RTM_BLEND_UNORDERED: + { + aCtx->core11fwd->glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + } + case Graphic3d_RTM_BLEND_OIT: + { + const float aDepthFactor = aView->RenderingParams().OitDepthFactor; + aManager->SetWeighedOitState (aDepthFactor); + + theOitAccumFbo->BindBuffer (aCtx); + + aCtx->SetDrawBuffers (2, THE_DRAW_BUFFERS01); + aCtx->SetColorMaskRGBA (NCollection_Vec4 (true)); // force writes into all components, including alpha + aCtx->core11fwd->glClearColor (0.0f, 0.0f, 0.0f, 1.0f); + aCtx->core11fwd->glClear (GL_COLOR_BUFFER_BIT); + aCtx->core15fwd->glBlendFuncSeparate (GL_ONE, GL_ONE, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); + break; + } + case Graphic3d_RTM_DEPTH_PEELING_OIT: + { + static const float THE_MIN_DEPTH = 0.0f; + static const float THE_MAX_DEPTH = 1.0f; + + aView->DepthPeelingFbos()->AttachDepthTexture (aCtx, theReadDrawFbo->DepthStencilTexture()); + + // initialize min/max depth buffer + aGlBlendBackFBO->BindDrawBuffer (aCtx); + aCtx->SetDrawBuffers (1, THE_DRAW_BUFFERS0); + aCtx->core20fwd->glClearColor (0.0f, 0.0f, 0.0f, 0.0f); + aCtx->core20fwd->glClear (GL_COLOR_BUFFER_BIT); + + aGlDepthPeelFBOs[1]->BindDrawBuffer (aCtx); + aCtx->SetDrawBuffers (1, THE_DRAW_BUFFERS0); + aCtx->core20fwd->glClearColor(-THE_MIN_DEPTH, THE_MAX_DEPTH, 0.0f, 0.0f); + aCtx->core20fwd->glClear (GL_COLOR_BUFFER_BIT); + + aGlFrontBackColorFBOs[0]->BindDrawBuffer (aCtx); + aCtx->SetDrawBuffers (2, THE_DRAW_BUFFERS01); + aCtx->core20fwd->glClearColor (0.0f, 0.0f, 0.0f, 0.0f); + aCtx->core20fwd->glClear (GL_COLOR_BUFFER_BIT); + + aGlFrontBackColorFBOs[1]->BindDrawBuffer (aCtx); + aCtx->SetDrawBuffers (2, THE_DRAW_BUFFERS01); + aCtx->core20fwd->glClearColor (0.0f, 0.0f, 0.0f, 0.0f); + aCtx->core20fwd->glClear (GL_COLOR_BUFFER_BIT); + + // draw depth for first pass to peel + aGlDepthPeelFBOs[0]->BindBuffer (aCtx); + + aCtx->SetDrawBuffers (1, THE_DRAW_BUFFERS0); + aCtx->core20fwd->glClearColor (THE_DEPTH_CLEAR_VALUE, THE_DEPTH_CLEAR_VALUE, 0.0f, 0.0f); + aCtx->core20fwd->glClear (GL_COLOR_BUFFER_BIT); + aCtx->core20fwd->glBlendEquation (GL_MAX); + + aManager->SetOitState (Graphic3d_RTM_DEPTH_PEELING_OIT); + + aGlDepthPeelFBOs[1]->ColorTexture (0)->Bind (aCtx, aCtx->DepthPeelingDepthTexUnit()); + aGlDepthPeelFBOs[1]->ColorTexture (1)->Bind (aCtx, aCtx->DepthPeelingFrontColorTexUnit()); + break; + } } // During blended order-independent transparency pass the depth test // should be enabled to discard fragments covered by opaque geometry // and depth writing should be disabled, because transparent fragments - // overal each other with non unitary coverage factor. + // overall each other with non unitary coverage factor. OpenGl_GlobalLayerSettings aGlobalSettings = theGlobalSettings; aGlobalSettings.DepthMask = GL_FALSE; aCtx->core11fwd->glDepthMask (GL_FALSE); - for (; theLayerIter != myTransparentToProcess.Back(); ++theLayerIter) + for (theLayerIter = aLayerFrom; theLayerIter != myTransparentToProcess.Back(); ++theLayerIter) { renderLayer (theWorkspace, aGlobalSettings, *(*theLayerIter)); } - // Revert state of rendering. - if (isEnabledOit) + switch (anOitMode) { - aManager->SetOitState (false, aDepthFactor); - theOitAccumFbo->UnbindBuffer (aCtx); - if (theReadDrawFbo) + case Graphic3d_RTM_BLEND_UNORDERED: { - theReadDrawFbo->BindBuffer (aCtx); + break; } + case Graphic3d_RTM_BLEND_OIT: + { + // revert state of rendering + aManager->ResetOitState(); + theOitAccumFbo->UnbindBuffer (aCtx); + if (theReadDrawFbo) + { + theReadDrawFbo->BindBuffer (aCtx); + } - static const Standard_Integer aDrawBuffers[] = { GL_COLOR_ATTACHMENT0 }; - aCtx->SetDrawBuffers (1, aDrawBuffers); - aCtx->SetColorMask (true); // update writes into alpha component + aCtx->SetDrawBuffers (1, THE_DRAW_BUFFERS0); + aCtx->SetColorMask (true); // update writes into alpha component + break; + } + case Graphic3d_RTM_DEPTH_PEELING_OIT: + { + // Dual Depth Peeling Ping-Pong + const int aNbPasses = aView->RenderingParams().NbOitDepthPeelingLayers; + OpenGl_VertexBuffer* aQuadVerts = aView->initBlitQuad (false); + + aGlDepthPeelFBOs[1]->ColorTexture (1)->Unbind (aCtx, aCtx->DepthPeelingFrontColorTexUnit()); + aGlDepthPeelFBOs[1]->ColorTexture (0)->Unbind (aCtx, aCtx->DepthPeelingDepthTexUnit()); + + for (int aPass = 0; aPass < aNbPasses; ++aPass) + { + const int aReadId = aPass % 2; + aDepthPeelingDrawId = 1 - aReadId; + + aGlDepthPeelFBOs[aDepthPeelingDrawId]->BindDrawBuffer (aCtx); + aCtx->SetDrawBuffers (1, THE_DRAW_BUFFERS0); + aCtx->core20fwd->glClearColor (THE_DEPTH_CLEAR_VALUE, THE_DEPTH_CLEAR_VALUE, 0.0f, 0.0f); + aCtx->core20fwd->glClear (GL_COLOR_BUFFER_BIT); + + aGlFrontBackColorFBOs[aDepthPeelingDrawId]->BindDrawBuffer (aCtx); + aCtx->SetDrawBuffers (2, THE_DRAW_BUFFERS01); + aCtx->core20fwd->glClearColor (0.0f, 0.0f, 0.0f, 0.0f); + aCtx->core20fwd->glClear (GL_COLOR_BUFFER_BIT); + + ///aGlDepthPeelFBOs[aDepthPeelingDrawId]->BindDrawBuffer (aCtx); + aGlDepthPeelFBOs[aDepthPeelingDrawId]->BindBuffer (aCtx); + aCtx->SetDrawBuffers (3, THE_DRAW_BUFFERS012); + aCtx->core20fwd->glBlendEquation (GL_MAX); + + aGlDepthPeelFBOs[aReadId]->ColorTexture (0)->Bind (aCtx, aCtx->DepthPeelingDepthTexUnit()); + aGlDepthPeelFBOs[aReadId]->ColorTexture (1)->Bind (aCtx, aCtx->DepthPeelingFrontColorTexUnit()); + + // draw geometry + for (theLayerIter = aLayerFrom; theLayerIter != myTransparentToProcess.Back(); ++theLayerIter) + { + renderLayer (theWorkspace, aGlobalSettings, *(*theLayerIter)); + } + + aGlDepthPeelFBOs[aReadId]->ColorTexture (1)->Unbind (aCtx, aCtx->DepthPeelingFrontColorTexUnit()); + aGlDepthPeelFBOs[aReadId]->ColorTexture (0)->Unbind (aCtx, aCtx->DepthPeelingDepthTexUnit()); + + // blend back color + aGlBlendBackFBO->BindDrawBuffer (aCtx); + aCtx->SetDrawBuffers (1, THE_DRAW_BUFFERS0); + if (aQuadVerts->IsValid() + && aManager->BindOitDepthPeelingBlendProgram (isMSAA)) + { + aCtx->core20fwd->glBlendEquation (GL_FUNC_ADD); + aCtx->core20fwd->glBlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + aCtx->core20fwd->glDepthFunc (GL_ALWAYS); + + aQuadVerts->BindVertexAttrib (aCtx, Graphic3d_TOA_POS); + + const Handle(OpenGl_TextureSet) aTextureBack = aCtx->BindTextures (Handle(OpenGl_TextureSet)(), Handle(OpenGl_ShaderProgram)()); + aGlDepthPeelFBOs[aDepthPeelingDrawId]->ColorTexture (2)->Bind (aCtx, Graphic3d_TextureUnit_0); + + aCtx->core20fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); + + aQuadVerts->UnbindVertexAttrib (aCtx, Graphic3d_TOA_POS); + aGlDepthPeelFBOs[aDepthPeelingDrawId]->ColorTexture (2)->Unbind (aCtx, Graphic3d_TextureUnit_0); + aCtx->BindProgram (NULL); + + if (!aTextureBack.IsNull()) + { + aCtx->BindTextures (aTextureBack, Handle(OpenGl_ShaderProgram)()); + } + + aCtx->core11fwd->glDepthFunc (theGlobalSettings.DepthFunc); + } + else + { + aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, + "Initialization of OIT compositing pass has failed.\n" + " Depth Peeling order-independent transparency will not be available.\n"); + if (aView != NULL) + { + Standard_Boolean& aOITFlag = isMSAA ? aView->myToDisableOITMSAA : aView->myToDisableOIT; + aOITFlag = Standard_True; + } + } + } + + aManager->ResetOitState(); + aGlBlendBackFBO->UnbindBuffer (aCtx); + if (theReadDrawFbo) + { + theReadDrawFbo->BindBuffer (aCtx); + } + aCtx->SetDrawBuffers (1, THE_DRAW_BUFFERS0); + break; + } } theWorkspace->SetRenderFilter (aPrevFilter | OpenGl_RenderFilter_OpaqueOnly); - if (isEnabledOit) + switch (anOitMode) { - const Standard_Boolean isMSAA = theReadDrawFbo && theReadDrawFbo->NbSamples() > 0; - OpenGl_VertexBuffer* aVerts = theWorkspace->View()->initBlitQuad (Standard_False); - if (aVerts->IsValid() && aManager->BindOitCompositingProgram (isMSAA)) + case Graphic3d_RTM_BLEND_UNORDERED: { - aCtx->core11fwd->glDepthFunc (GL_ALWAYS); - aCtx->core11fwd->glDepthMask (GL_FALSE); - - // Bind full screen quad buffer and framebuffer resources. - aVerts->BindVertexAttrib (aCtx, Graphic3d_TOA_POS); - - const Handle(OpenGl_TextureSet) aTextureBack = aCtx->BindTextures (Handle(OpenGl_TextureSet)(), Handle(OpenGl_ShaderProgram)()); - - theOitAccumFbo->ColorTexture (0)->Bind (aCtx, Graphic3d_TextureUnit_0); - theOitAccumFbo->ColorTexture (1)->Bind (aCtx, Graphic3d_TextureUnit_1); - - // Draw full screen quad with special shader to compose the buffers. - aCtx->core11fwd->glBlendFunc (GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); - aCtx->core11fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); - - // Unbind OpenGL texture objects and shader program. - aVerts->UnbindVertexAttrib (aCtx, Graphic3d_TOA_POS); - theOitAccumFbo->ColorTexture (1)->Unbind (aCtx, Graphic3d_TextureUnit_1); - theOitAccumFbo->ColorTexture (0)->Unbind (aCtx, Graphic3d_TextureUnit_0); - aCtx->BindProgram (NULL); - - if (!aTextureBack.IsNull()) - { - aCtx->BindTextures (aTextureBack, Handle(OpenGl_ShaderProgram)()); - } + break; } - else + case Graphic3d_RTM_BLEND_OIT: { - aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, - "Initialization of OIT compositing pass has failed.\n" - " Blended order-independent transparency will not be available.\n"); - if (aView != NULL) + // draw full screen quad with special shader to compose the buffers + OpenGl_VertexBuffer* aVerts = aView->initBlitQuad (Standard_False); + if (aVerts->IsValid() + && aManager->BindOitCompositingProgram (isMSAA)) { - Standard_Boolean& aOITFlag = isMSAA ? aView->myToDisableOITMSAA : aView->myToDisableOIT; - aOITFlag = Standard_True; + aCtx->core11fwd->glDepthFunc (GL_ALWAYS); + aCtx->core11fwd->glDepthMask (GL_FALSE); + + aVerts->BindVertexAttrib (aCtx, Graphic3d_TOA_POS); + + const Handle(OpenGl_TextureSet) aTextureBack = aCtx->BindTextures (Handle(OpenGl_TextureSet)(), Handle(OpenGl_ShaderProgram)()); + theOitAccumFbo->ColorTexture (0)->Bind (aCtx, Graphic3d_TextureUnit_0); + theOitAccumFbo->ColorTexture (1)->Bind (aCtx, Graphic3d_TextureUnit_1); + + aCtx->core11fwd->glBlendFunc (GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); + aCtx->core11fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); + + aVerts->UnbindVertexAttrib (aCtx, Graphic3d_TOA_POS); + theOitAccumFbo->ColorTexture (1)->Unbind (aCtx, Graphic3d_TextureUnit_1); + theOitAccumFbo->ColorTexture (0)->Unbind (aCtx, Graphic3d_TextureUnit_0); + aCtx->BindProgram (NULL); + + if (!aTextureBack.IsNull()) + { + aCtx->BindTextures (aTextureBack, Handle(OpenGl_ShaderProgram)()); + } } + else + { + aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, + "Initialization of OIT compositing pass has failed.\n" + " Blended order-independent transparency will not be available.\n"); + if (aView != NULL) + { + Standard_Boolean& aOITFlag = isMSAA ? aView->myToDisableOITMSAA : aView->myToDisableOIT; + aOITFlag = Standard_True; + } + } + break; + } + case Graphic3d_RTM_DEPTH_PEELING_OIT: + { + // compose depth peeling results into destination FBO + OpenGl_VertexBuffer* aVerts = aView->initBlitQuad (Standard_False); + if (aVerts->IsValid() + && aManager->BindOitDepthPeelingFlushProgram (isMSAA)) + { + aCtx->core20fwd->glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + aCtx->core20fwd->glDepthFunc (GL_ALWAYS); + + aVerts->BindVertexAttrib (aCtx, Graphic3d_TOA_POS); + + const Handle(OpenGl_TextureSet) aTextureBack = aCtx->BindTextures (Handle(OpenGl_TextureSet)(), Handle(OpenGl_ShaderProgram)()); + aGlDepthPeelFBOs[aDepthPeelingDrawId]->ColorTexture (1)->Bind (aCtx, Graphic3d_TextureUnit_0); + aGlBlendBackFBO->ColorTexture (0)->Bind (aCtx, Graphic3d_TextureUnit_1); + + aCtx->core20fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); + + aVerts->UnbindVertexAttrib (aCtx, Graphic3d_TOA_POS); + aGlBlendBackFBO->ColorTexture (0)->Unbind (aCtx, Graphic3d_TextureUnit_1); + aGlDepthPeelFBOs[aDepthPeelingDrawId]->ColorTexture (1)->Unbind (aCtx, Graphic3d_TextureUnit_0); + aCtx->BindProgram (NULL); + + if (!aTextureBack.IsNull()) + { + aCtx->BindTextures (aTextureBack, Handle(OpenGl_ShaderProgram)()); + } + + aCtx->core11fwd->glDepthFunc (theGlobalSettings.DepthFunc); + } + else + { + aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, + "Initialization of OIT compositing pass has failed.\n" + " Depth Peeling order-independent transparency will not be available.\n"); + if (aView != NULL) + { + Standard_Boolean& aOITFlag = isMSAA ? aView->myToDisableOITMSAA : aView->myToDisableOIT; + aOITFlag = true; + } + } + aView->DepthPeelingFbos()->DetachDepthTexture (aCtx); + break; } } diff --git a/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx b/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx index 0c1eabe177..8b718bb5c7 100644 --- a/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx +++ b/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx @@ -38,8 +38,9 @@ enum OpenGl_ProgramOptions OpenGl_PO_MeshEdges = 0x0200, //!< draw mesh edges (wireframe) OpenGl_PO_AlphaTest = 0x0400, //!< discard fragment by alpha test (defined by cutoff value) OpenGl_PO_WriteOit = 0x0800, //!< write coverage buffer for Blended Order-Independent Transparency + OpenGl_PO_OitDepthPeeling = 0x1000, //!< handle Depth Peeling OIT // - OpenGl_PO_NB = 0x1000, //!< overall number of combinations + OpenGl_PO_NB = 0x2000, //!< overall number of combinations OpenGl_PO_IsPoint = OpenGl_PO_PointSimple|OpenGl_PO_PointSprite|OpenGl_PO_PointSpriteA, OpenGl_PO_HasTextures = OpenGl_PO_TextureRGB|OpenGl_PO_TextureEnv, OpenGl_PO_NeedsGeomShader = OpenGl_PO_MeshEdges, diff --git a/src/OpenGl/OpenGl_ShaderManager.cxx b/src/OpenGl/OpenGl_ShaderManager.cxx index 173156f026..b722f7bfe2 100644 --- a/src/OpenGl/OpenGl_ShaderManager.cxx +++ b/src/OpenGl/OpenGl_ShaderManager.cxx @@ -1216,14 +1216,11 @@ void OpenGl_ShaderManager::pushMaterialState (const Handle(OpenGl_ShaderProgram) // ======================================================================= void OpenGl_ShaderManager::pushOitState (const Handle(OpenGl_ShaderProgram)& theProgram) const { - const GLint aLocOutput = theProgram->GetStateLocation (OpenGl_OCCT_OIT_OUTPUT); - if (aLocOutput != OpenGl_ShaderProgram::INVALID_LOCATION) + if (const OpenGl_ShaderUniformLocation& aLocOutput = theProgram->GetStateLocation (OpenGl_OCCT_OIT_OUTPUT)) { - theProgram->SetUniform (myContext, aLocOutput, myOitState.ToEnableWrite()); + theProgram->SetUniform (myContext, aLocOutput, (GLint )myOitState.ActiveMode()); } - - const GLint aLocDepthFactor = theProgram->GetStateLocation (OpenGl_OCCT_OIT_DEPTH_FACTOR); - if (aLocDepthFactor != OpenGl_ShaderProgram::INVALID_LOCATION) + if (const OpenGl_ShaderUniformLocation& aLocDepthFactor = theProgram->GetStateLocation (OpenGl_OCCT_OIT_DEPTH_FACTOR)) { theProgram->SetUniform (myContext, aLocDepthFactor, myOitState.DepthFactor()); } @@ -1542,17 +1539,6 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramOitCompositing (const St EOL" float aWeight = occTexture2D (uWeightTexture, TexCoord).r;" EOL" occSetFragColor (vec4 (aAccum.rgb / max (aWeight, 0.00001), aAccum.a));" EOL"}"; - #if !defined(GL_ES_VERSION_2_0) - if (myContext->IsGlGreaterEqual (3, 2)) - { - aProgramSrc->SetHeader ("#version 150"); - } - #else - if (myContext->IsGlGreaterEqual (3, 0)) - { - aProgramSrc->SetHeader ("#version 300 es"); - } - #endif } else { @@ -1566,24 +1552,9 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramOitCompositing (const St EOL" float aWeight = texelFetch (uWeightTexture, aTexel, gl_SampleID).r;" EOL" occSetFragColor (vec4 (aAccum.rgb / max (aWeight, 0.00001), aAccum.a));" EOL"}"; - #if !defined(GL_ES_VERSION_2_0) - if (myContext->IsGlGreaterEqual (4, 0)) - { - aProgramSrc->SetHeader ("#version 400"); - } - #else - if (myContext->IsGlGreaterEqual (3, 2)) - { - aProgramSrc->SetHeader ("#version 320 es"); - } - else if (myContext->IsGlGreaterEqual (3, 0)) - { - aProgramSrc->SetHeader ("#version 300 es"); // with GL_OES_sample_variables extension - } - #endif } + defaultOitGlslVersion (aProgramSrc, "weight_oit", theMsaa); - aProgramSrc->SetId (theMsaa ? "occt_weight-oit-msaa" : "occt_weight-oit"); aProgramSrc->SetDefaultSampler (false); aProgramSrc->SetNbLightsMax (0); aProgramSrc->SetNbShadowMaps (0); @@ -1604,6 +1575,107 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramOitCompositing (const St return Standard_True; } +// ======================================================================= +// function : prepareStdProgramOitDepthPeelingBlend +// purpose : +// ======================================================================= +Standard_Boolean OpenGl_ShaderManager::prepareStdProgramOitDepthPeelingBlend (Standard_Boolean theMsaa) +{ + Handle(OpenGl_ShaderProgram)& aProgram = myOitDepthPeelingBlendProgram[theMsaa ? 1 : 0]; + Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram(); + TCollection_AsciiString aSrcVert, aSrcFrag; + + OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts; + aSrcVert = + EOL"void main()" + EOL"{" + EOL" gl_Position = vec4 (occVertex.x, occVertex.y, 0.0, 1.0);" + EOL"}"; + + aUniforms.Append (OpenGl_ShaderObject::ShaderVariable (theMsaa + ? "sampler2DMS uDepthPeelingBackColor" + : "sampler2D uDepthPeelingBackColor", Graphic3d_TOS_FRAGMENT)); + aSrcFrag = TCollection_AsciiString() + + EOL"void main()" + EOL"{" + EOL" #define THE_SAMPLE_ID " + (theMsaa ? "gl_SampleID" : "0") + + EOL" occFragColor = texelFetch (uDepthPeelingBackColor, ivec2 (gl_FragCoord.xy), THE_SAMPLE_ID);" + EOL" if (occFragColor.a == 0.0) { discard; }" + EOL"}"; + + defaultOitGlslVersion (aProgramSrc, "oit_peeling_blend", theMsaa); + aProgramSrc->SetDefaultSampler (false); + aProgramSrc->SetNbLightsMax (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)); + TCollection_AsciiString aKey; + if (!Create (aProgramSrc, aKey, aProgram)) + { + aProgram = new OpenGl_ShaderProgram(); // just mark as invalid + return false; + } + + myContext->BindProgram (aProgram); + aProgram->SetSampler (myContext, "uDepthPeelingBackColor", Graphic3d_TextureUnit_0); + myContext->BindProgram (Handle(OpenGl_ShaderProgram)()); + return true; +} + +// ======================================================================= +// function : prepareStdProgramOitDepthPeelingFlush +// purpose : +// ======================================================================= +Standard_Boolean OpenGl_ShaderManager::prepareStdProgramOitDepthPeelingFlush (Standard_Boolean theMsaa) +{ + Handle(OpenGl_ShaderProgram)& aProgram = myOitDepthPeelingFlushProgram[theMsaa ? 1 : 0]; + Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram(); + TCollection_AsciiString aSrcVert, aSrcFrag; + + OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts; + aSrcVert = + EOL"void main()" + EOL"{" + EOL" gl_Position = vec4 (occVertex.x, occVertex.y, 0.0, 1.0);" + EOL"}"; + + aUniforms.Append (OpenGl_ShaderObject::ShaderVariable (theMsaa + ? "sampler2DMS uDepthPeelingFrontColor" + : "sampler2D uDepthPeelingFrontColor", Graphic3d_TOS_FRAGMENT)); + aUniforms.Append (OpenGl_ShaderObject::ShaderVariable (theMsaa + ? "sampler2DMS uDepthPeelingBackColor" + : "sampler2D uDepthPeelingBackColor", Graphic3d_TOS_FRAGMENT)); + aSrcFrag = TCollection_AsciiString() + + EOL"void main()" + EOL"{" + EOL" #define THE_SAMPLE_ID " + (theMsaa ? "gl_SampleID" : "0") + + EOL" ivec2 aFragCoord = ivec2 (gl_FragCoord.xy);" + EOL" vec4 aFrontColor = texelFetch (uDepthPeelingFrontColor, aFragCoord, THE_SAMPLE_ID);" + EOL" vec4 aBackColor = texelFetch (uDepthPeelingBackColor, aFragCoord, THE_SAMPLE_ID);" + EOL" float anAlphaMult = 1.0 - aFrontColor.a;" + EOL" occFragColor = vec4 (aFrontColor.rgb + anAlphaMult * aBackColor.rgb, aFrontColor.a + aBackColor.a);" + EOL"}"; + + defaultOitGlslVersion (aProgramSrc, "oit_peeling_flush", theMsaa); + aProgramSrc->SetDefaultSampler (false); + aProgramSrc->SetNbLightsMax (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)); + TCollection_AsciiString aKey; + if (!Create (aProgramSrc, aKey, aProgram)) + { + aProgram = new OpenGl_ShaderProgram(); // just mark as invalid + return false; + } + + myContext->BindProgram (aProgram); + aProgram->SetSampler (myContext, "uDepthPeelingFrontColor", Graphic3d_TextureUnit_0); + aProgram->SetSampler (myContext, "uDepthPeelingBackColor", Graphic3d_TextureUnit_1); + myContext->BindProgram (Handle(OpenGl_ShaderProgram)()); + return true; +} + // ======================================================================= // function : pointSpriteAlphaSrc // purpose : @@ -1698,6 +1770,7 @@ int OpenGl_ShaderManager::defaultGlslVersion (const Handle(Graphic3d_ShaderProgr theProgram->SetHeader ("#version 300 es"); } if ((theBits & OpenGl_PO_WriteOit) != 0 + || (theBits & OpenGl_PO_OitDepthPeeling) != 0 || (theBits & OpenGl_PO_StippleLine) != 0) { if (myContext->IsGlGreaterEqual (3, 0)) @@ -1707,6 +1780,7 @@ int OpenGl_ShaderManager::defaultGlslVersion (const Handle(Graphic3d_ShaderProgr else { aBits = aBits & ~OpenGl_PO_WriteOit; + aBits = aBits & ~OpenGl_PO_OitDepthPeeling; if (!myContext->oesStdDerivatives) { aBits = aBits & ~OpenGl_PO_StippleLine; @@ -1734,6 +1808,49 @@ int OpenGl_ShaderManager::defaultGlslVersion (const Handle(Graphic3d_ShaderProgr return aBits; } +// ======================================================================= +// function : defaultOitGlslVersion +// purpose : +// ======================================================================= +void OpenGl_ShaderManager::defaultOitGlslVersion (const Handle(Graphic3d_ShaderProgram)& theProgram, + const TCollection_AsciiString& theName, + bool theMsaa) const +{ + if (theMsaa) + { + #if !defined(GL_ES_VERSION_2_0) + if (myContext->IsGlGreaterEqual (4, 0)) + { + theProgram->SetHeader ("#version 400"); + } + #else + if (myContext->IsGlGreaterEqual (3, 2)) + { + theProgram->SetHeader ("#version 320 es"); + } + else if (myContext->IsGlGreaterEqual (3, 0)) + { + theProgram->SetHeader ("#version 300 es"); // with GL_OES_sample_variables extension + } + #endif + } + else + { + #if !defined(GL_ES_VERSION_2_0) + if (myContext->IsGlGreaterEqual (3, 2)) + { + theProgram->SetHeader ("#version 150"); + } + #else + if (myContext->IsGlGreaterEqual (3, 0)) + { + theProgram->SetHeader ("#version 300 es"); + } + #endif + } + theProgram->SetId (TCollection_AsciiString ("occt_") + theName + (theMsaa ? "_msaa" : "")); +} + // ======================================================================= // function : prepareGeomMainSrc // purpose : @@ -1968,10 +2085,15 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_Sha : THE_FRAG_CLIP_PLANES_2; } } - if ((theBits & OpenGl_PO_WriteOit) != 0) + if ((theBits & OpenGl_PO_OitDepthPeeling) != 0) + { + aProgramSrc->SetNbFragmentOutputs (3); + aProgramSrc->SetOitOutput (Graphic3d_RTM_DEPTH_PEELING_OIT); + } + else if ((theBits & OpenGl_PO_WriteOit) != 0) { aProgramSrc->SetNbFragmentOutputs (2); - aProgramSrc->SetWeightOitOutput (true); + aProgramSrc->SetOitOutput (Graphic3d_RTM_BLEND_OIT); } if (theIsOutline) @@ -2041,6 +2163,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_Sha + aSrcGetAlpha + EOL"void main()" EOL"{" + EOL" if (occFragEarlyReturn()) { return; }" + aSrcFragExtraMain + aSrcFragMainGetColor + EOL"}"; @@ -2417,10 +2540,15 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S : THE_FRAG_CLIP_PLANES_2; } } - if ((theBits & OpenGl_PO_WriteOit) != 0) + if ((theBits & OpenGl_PO_OitDepthPeeling) != 0) + { + aProgramSrc->SetNbFragmentOutputs (3); + aProgramSrc->SetOitOutput (Graphic3d_RTM_DEPTH_PEELING_OIT); + } + else if ((theBits & OpenGl_PO_WriteOit) != 0) { aProgramSrc->SetNbFragmentOutputs (2); - aProgramSrc->SetWeightOitOutput (true); + aProgramSrc->SetOitOutput (Graphic3d_RTM_BLEND_OIT); } aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 FrontColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT)); @@ -2454,6 +2582,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S + aSrcFragGetColor + EOL"void main()" EOL"{" + EOL" if (occFragEarlyReturn()) { return; }" + aSrcFragExtraMain + EOL" occSetFragColor (getFinalColor());" + EOL"}"; @@ -2620,10 +2749,15 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha : THE_FRAG_CLIP_PLANES_2; } } - if ((theBits & OpenGl_PO_WriteOit) != 0) + if ((theBits & OpenGl_PO_OitDepthPeeling) != 0) + { + aProgramSrc->SetNbFragmentOutputs (3); + aProgramSrc->SetOitOutput (Graphic3d_RTM_DEPTH_PEELING_OIT); + } + else if ((theBits & OpenGl_PO_WriteOit) != 0) { aProgramSrc->SetNbFragmentOutputs (2); - aProgramSrc->SetWeightOitOutput (true); + aProgramSrc->SetOitOutput (Graphic3d_RTM_BLEND_OIT); } if (isFlatNormal) @@ -2722,6 +2856,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha + EOL EOL"void main()" EOL"{" + EOL" if (occFragEarlyReturn()) { return; }" + aSrcFragExtraMain + EOL" occSetFragColor (getFinalColor());" + EOL"}"; diff --git a/src/OpenGl/OpenGl_ShaderManager.hxx b/src/OpenGl/OpenGl_ShaderManager.hxx index 36558c9c77..7635518ff0 100644 --- a/src/OpenGl/OpenGl_ShaderManager.hxx +++ b/src/OpenGl/OpenGl_ShaderManager.hxx @@ -220,6 +220,32 @@ public: return !aProgram.IsNull() && myContext->BindProgram (aProgram); } + //! Bind program for Depth Peeling order-independent transparency back color blending. + Standard_Boolean BindOitDepthPeelingBlendProgram (bool theIsMSAAEnabled) + { + const Standard_Integer aProgramIdx = theIsMSAAEnabled ? 1 : 0; + if (myOitDepthPeelingBlendProgram[aProgramIdx].IsNull()) + { + prepareStdProgramOitDepthPeelingBlend (theIsMSAAEnabled); + } + + const Handle(OpenGl_ShaderProgram)& aProgram = myOitDepthPeelingBlendProgram [aProgramIdx]; + return !aProgram.IsNull() && myContext->BindProgram (aProgram); + } + + //! Bind program for Depth Peeling order-independent transparency flush. + Standard_Boolean BindOitDepthPeelingFlushProgram (bool theIsMSAAEnabled) + { + const Standard_Integer aProgramIdx = theIsMSAAEnabled ? 1 : 0; + if (myOitDepthPeelingFlushProgram[aProgramIdx].IsNull()) + { + prepareStdProgramOitDepthPeelingFlush (theIsMSAAEnabled); + } + + const Handle(OpenGl_ShaderProgram)& aProgram = myOitDepthPeelingFlushProgram [aProgramIdx]; + return !aProgram.IsNull() && myContext->BindProgram (aProgram); + } + //! Bind program for rendering stereoscopic image. Standard_Boolean BindStereoProgram (const Graphic3d_StereoMode theStereoMode) { @@ -448,12 +474,26 @@ public: //! Returns state of OIT uniforms. const OpenGl_OitState& OitState() const { return myOitState; } - //! Set the state of OIT rendering pass (only on state change). - //! @param theToEnableOitWrite [in] flag indicating whether the special output should be written for OIT algorithm. - //! @param theDepthFactor [in] the scalar factor of depth influence to the fragment's coverage. - void SetOitState (const bool theToEnableOitWrite, const float theDepthFactor) + //! Reset the state of OIT rendering pass (only on state change). + void ResetOitState() { - myOitState.Set (theToEnableOitWrite, theDepthFactor); + myOitState.Set (Graphic3d_RTM_BLEND_UNORDERED, 0.0f); + myOitState.Update(); + } + + //! Set the state of OIT rendering pass (only on state change). + //! @param theMode [in] flag indicating whether the special output should be written for OIT algorithm + void SetOitState (Graphic3d_RenderTransparentMethod theMode) + { + myOitState.Set (theMode, 0.0f); + myOitState.Update(); + } + + //! Set the state of weighed OIT rendering pass (only on state change). + //! @param theDepthFactor [in] the scalar factor of depth influence to the fragment's coverage + void SetWeighedOitState (float theDepthFactor) + { + myOitState.Set (Graphic3d_RTM_BLEND_OIT, theDepthFactor); myOitState.Update(); } @@ -636,10 +676,14 @@ protected: aBits |= OpenGl_PO_VertColor; } - if (myOitState.ToEnableWrite()) + if (myOitState.ActiveMode() == Graphic3d_RTM_BLEND_OIT) { aBits |= OpenGl_PO_WriteOit; } + else if (myOitState.ActiveMode() == Graphic3d_RTM_DEPTH_PEELING_OIT) + { + aBits |= OpenGl_PO_OitDepthPeeling; + } return aBits; } @@ -686,6 +730,12 @@ protected: //! Prepare standard GLSL programs for OIT compositing operation. Standard_EXPORT Standard_Boolean prepareStdProgramOitCompositing (const Standard_Boolean theMsaa); + //! Prepare standard GLSL programs for OIT Depth Peeling blend operation. + Standard_EXPORT Standard_Boolean prepareStdProgramOitDepthPeelingBlend (Standard_Boolean theMsaa); + + //! Prepare standard GLSL programs for OIT Depth Peeling flush operation. + Standard_EXPORT Standard_Boolean prepareStdProgramOitDepthPeelingFlush (Standard_Boolean theMsaa); + //! Prepare standard GLSL program without lighting. Standard_EXPORT Standard_Boolean prepareStdProgramUnlit (Handle(OpenGl_ShaderProgram)& theProgram, Standard_Integer theBits, @@ -753,6 +803,11 @@ protected: Standard_Integer theBits, bool theUsesDerivates = false) const; + //! Prepare GLSL version header for OIT composition programs. + Standard_EXPORT void defaultOitGlslVersion (const Handle(Graphic3d_ShaderProgram)& theProgram, + const TCollection_AsciiString& theName, + bool theMsaa) const; + //! Prepare GLSL source for geometry shader according to parameters. Standard_EXPORT TCollection_AsciiString prepareGeomMainSrc (OpenGl_ShaderObject::ShaderVariableList& theUnifoms, OpenGl_ShaderObject::ShaderVariableList& theStageInOuts, @@ -824,6 +879,8 @@ protected: myBlitPrograms[2]; //!< standard program for FBO blit emulation Handle(OpenGl_ShaderProgram) myBoundBoxProgram; //!< standard program for bounding box Handle(OpenGl_ShaderProgram) myOitCompositingProgram[2]; //!< standard program for OIT compositing (default and MSAA). + Handle(OpenGl_ShaderProgram) myOitDepthPeelingBlendProgram[2]; //!< standard program for OIT Depth Peeling blend (default and MSAA) + Handle(OpenGl_ShaderProgram) myOitDepthPeelingFlushProgram[2]; //!< standard program for OIT Depth Peeling flush (default and MSAA) OpenGl_MapOfShaderPrograms myMapOfLightPrograms; //!< map of lighting programs depending on lights configuration Handle(OpenGl_ShaderProgram) myPBREnvBakingProgram;//!< program for IBL maps generation used in PBR pipeline diff --git a/src/OpenGl/OpenGl_ShaderProgram.cxx b/src/OpenGl/OpenGl_ShaderProgram.cxx index c7ebf41cdb..040724fb45 100755 --- a/src/OpenGl/OpenGl_ShaderProgram.cxx +++ b/src/OpenGl/OpenGl_ShaderProgram.cxx @@ -176,8 +176,8 @@ OpenGl_ShaderProgram::OpenGl_ShaderProgram (const Handle(Graphic3d_ShaderProgram myNbClipPlanesMax (0), myNbFragOutputs (1), myTextureSetBits (Graphic3d_TextureSetBits_NONE), + myOitOutput (Graphic3d_RTM_BLEND_UNORDERED), myHasAlphaTest (false), - myHasWeightOitOutput (false), myHasTessShader (false) { memset (myCurrentState, 0, sizeof (myCurrentState)); @@ -206,7 +206,17 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)& myNbFragOutputs = !myProxy.IsNull() ? myProxy->NbFragmentOutputs() : 1; myTextureSetBits = Graphic3d_TextureSetBits_NONE; myHasAlphaTest = !myProxy.IsNull() && myProxy->HasAlphaTest(); - myHasWeightOitOutput = !myProxy.IsNull() ? myProxy->HasWeightOitOutput() && myNbFragOutputs >= 2 : 1; + myOitOutput = !myProxy.IsNull() ? myProxy->OitOutput() : Graphic3d_RTM_BLEND_UNORDERED; + if (myOitOutput == Graphic3d_RTM_BLEND_OIT + && myNbFragOutputs < 2) + { + myOitOutput = Graphic3d_RTM_BLEND_UNORDERED; + } + else if (myOitOutput == Graphic3d_RTM_DEPTH_PEELING_OIT + && myNbFragOutputs < 3) + { + myOitOutput = Graphic3d_RTM_BLEND_UNORDERED; + } // detect the minimum GLSL version required for defined Shader Objects #if defined(GL_ES_VERSION_2_0) @@ -334,9 +344,16 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)& if (theCtx->hasDrawBuffers) { anExtensions += "#define OCC_ENABLE_draw_buffers\n"; - if (myHasWeightOitOutput) + switch (myOitOutput) { - anExtensions += "#define OCC_WRITE_WEIGHT_OIT_COVERAGE\n"; + case Graphic3d_RTM_BLEND_UNORDERED: + break; + case Graphic3d_RTM_BLEND_OIT: + anExtensions += "#define OCC_WRITE_WEIGHT_OIT_COVERAGE\n"; + break; + case Graphic3d_RTM_DEPTH_PEELING_OIT: + anExtensions += "#define OCC_DEPTH_PEEL_OIT\n"; + break; } } else @@ -576,6 +593,15 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)& SetUniform (theCtx, aLocSampler, myNbShadowMaps, &aShadowSamplers.front()); } + if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occDepthPeelingDepth")) + { + SetUniform (theCtx, aLocSampler, GLint(theCtx->DepthPeelingDepthTexUnit())); + } + if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occDepthPeelingFrontColor")) + { + SetUniform (theCtx, aLocSampler, GLint(theCtx->DepthPeelingFrontColorTexUnit())); + } + const TCollection_AsciiString aSamplerNamePrefix ("occSampler"); const Standard_Integer aNbUnitsMax = Max (theCtx->MaxCombinedTextureUnits(), Graphic3d_TextureUnit_NB); for (GLint aUnitIter = 0; aUnitIter < aNbUnitsMax; ++aUnitIter) diff --git a/src/OpenGl/OpenGl_ShaderProgram.hxx b/src/OpenGl/OpenGl_ShaderProgram.hxx index f88eb8a00e..2d38afd70a 100755 --- a/src/OpenGl/OpenGl_ShaderProgram.hxx +++ b/src/OpenGl/OpenGl_ShaderProgram.hxx @@ -301,8 +301,8 @@ public: //! Return true if Fragment Shader should perform alpha test; FALSE by default. Standard_Boolean HasAlphaTest() const { return myHasAlphaTest; } - //! Return true if Fragment Shader color should output the weighted OIT coverage; FALSE by default. - Standard_Boolean HasWeightOitOutput() const { return myHasWeightOitOutput; } + //! Return if Fragment Shader color should output the OIT values; OFF by default. + Graphic3d_RenderTransparentMethod OitOutput() const { return myOitOutput; } //! Return texture units declared within the program, @sa Graphic3d_TextureSetBits. Standard_Integer TextureSetBits() const { return myTextureSetBits; } @@ -678,8 +678,8 @@ protected: 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 + Graphic3d_RenderTransparentMethod myOitOutput; //!< flag indicating that Fragment Shader includes OIT outputs Standard_Boolean myHasAlphaTest; //!< flag indicating that Fragment Shader should perform alpha-test - Standard_Boolean myHasWeightOitOutput; //!< flag indicating that Fragment Shader includes weighted OIT coverage Standard_Boolean myHasTessShader; //!< flag indicating that program defines tessellation stage protected: diff --git a/src/OpenGl/OpenGl_ShaderStates.hxx b/src/OpenGl/OpenGl_ShaderStates.hxx index d4fcc96970..b7cb484a7d 100755 --- a/src/OpenGl/OpenGl_ShaderStates.hxx +++ b/src/OpenGl/OpenGl_ShaderStates.hxx @@ -16,6 +16,7 @@ #ifndef _OpenGl_State_HeaderFile #define _OpenGl_State_HeaderFile +#include #include #include #include @@ -194,23 +195,23 @@ class OpenGl_OitState : public OpenGl_StateInterface public: //! Creates new uniform state. - OpenGl_OitState() : myToEnableWrite (false), myDepthFactor (0.5f) {} + OpenGl_OitState() : myOitMode (Graphic3d_RTM_BLEND_UNORDERED), myDepthFactor (0.5f) {} //! Sets the uniform values. //! @param theToEnableWrite [in] flag indicating whether color and coverage //! values for OIT processing should be written by shader program. //! @param theDepthFactor [in] scalar factor [0-1] defining influence of depth //! component of a fragment to its final coverage coefficient. - void Set (const bool theToEnableWrite, + void Set (Graphic3d_RenderTransparentMethod theMode, const float theDepthFactor) { - myToEnableWrite = theToEnableWrite; - myDepthFactor = static_cast (Max (0.f, Min (1.f, theDepthFactor))); + myOitMode = theMode; + myDepthFactor = static_cast (Max (0.f, Min (1.f, theDepthFactor))); } //! Returns flag indicating whether writing of output for OIT processing //! should be enabled/disabled. - bool ToEnableWrite() const { return myToEnableWrite; } + Graphic3d_RenderTransparentMethod ActiveMode() const { return myOitMode; } //! Returns factor defining influence of depth component of a fragment //! to its final coverage coefficient. @@ -218,8 +219,8 @@ public: private: - bool myToEnableWrite; //!< writing color and coverage. - float myDepthFactor; //!< factor of depth influence to coverage. + Graphic3d_RenderTransparentMethod myOitMode; //!< active OIT method for the main GLSL program + float myDepthFactor; //!< factor of depth influence to coverage }; #endif // _OpenGl_State_HeaderFile diff --git a/src/OpenGl/OpenGl_Texture.hxx b/src/OpenGl/OpenGl_Texture.hxx index 459c8abcd9..a4b2ca42e2 100644 --- a/src/OpenGl/OpenGl_Texture.hxx +++ b/src/OpenGl/OpenGl_Texture.hxx @@ -182,6 +182,9 @@ public: //! Return upper mipmap level index (0 means no mipmaps). Standard_Integer MaxMipmapLevel() const { return myMaxMipLevel; } + //! Return number of MSAA samples. + Standard_Integer NbSamples() const { return myNbSamples; } + //! Returns estimated GPU memory usage for holding data without considering overheads and allocation alignment rules. Standard_EXPORT virtual Standard_Size EstimatedDataSize() const Standard_OVERRIDE; diff --git a/src/OpenGl/OpenGl_TextureFormat.cxx b/src/OpenGl/OpenGl_TextureFormat.cxx index 19d4002818..afbfb07dcf 100644 --- a/src/OpenGl/OpenGl_TextureFormat.cxx +++ b/src/OpenGl/OpenGl_TextureFormat.cxx @@ -327,6 +327,14 @@ OpenGl_TextureFormat OpenGl_TextureFormat::FindSizedFormat (const Handle(OpenGl_ aFormat.SetDataType (GL_FLOAT); return aFormat; } + case GL_RG32F: + { + aFormat.SetNbComponents (1); + aFormat.SetInternalFormat (theSizedFormat); + aFormat.SetPixelFormat (GL_RG); + aFormat.SetDataType (GL_FLOAT); + return aFormat; + } case GL_RGBA16F: { aFormat.SetNbComponents (4); diff --git a/src/OpenGl/OpenGl_View.cxx b/src/OpenGl/OpenGl_View.cxx index 059c663620..4fcaa1fa3d 100644 --- a/src/OpenGl/OpenGl_View.cxx +++ b/src/OpenGl/OpenGl_View.cxx @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -150,6 +151,7 @@ OpenGl_View::OpenGl_View (const Handle(Graphic3d_StructureManager)& theMgr, myRaytraceFBO1[1] = new OpenGl_FrameBuffer(); myRaytraceFBO2[0] = new OpenGl_FrameBuffer(); myRaytraceFBO2[1] = new OpenGl_FrameBuffer(); + myDepthPeelingFbos = new OpenGl_DepthPeeling(); myShadowMaps = new OpenGl_ShadowMapArray(); } @@ -217,6 +219,7 @@ void OpenGl_View::releaseSrgbResources (const Handle(OpenGl_Context)& theCtx) myImmediateSceneFbosOit[0]->Release (theCtx.get()); myImmediateSceneFbosOit[1]->Release (theCtx.get()); myXrSceneFbo ->Release (theCtx.get()); + myDepthPeelingFbos ->Release (theCtx.get()); myOpenGlFBO ->Release (theCtx.get()); myOpenGlFBO2 ->Release (theCtx.get()); myFullScreenQuad .Release (theCtx.get()); @@ -1017,7 +1020,7 @@ bool OpenGl_View::prepareFrameBuffers (Graphic3d_Camera::Projection& theProj) aNbSamples = OpenGl_Context::GetPowerOfTwo (aNbSamples, aCtx->MaxMsaaSamples()); } - bool toUseOit = myRenderParams.TransparencyMethod == Graphic3d_RTM_BLEND_OIT + bool toUseOit = myRenderParams.TransparencyMethod != Graphic3d_RTM_BLEND_UNORDERED && checkOitCompatibility (aCtx, aNbSamples > 0); const bool toInitImmediateFbo = myTransientDrawToFront @@ -1063,6 +1066,7 @@ bool OpenGl_View::prepareFrameBuffers (Graphic3d_Camera::Projection& theProj) } } } + if (myMainSceneFbos[0]->IsValid() && (toInitImmediateFbo || myImmediateSceneFbos[0]->IsValid())) { const bool wasFailedImm0 = checkWasFailedFbo (myImmediateSceneFbos[0], myMainSceneFbos[0]); @@ -1218,7 +1222,44 @@ bool OpenGl_View::prepareFrameBuffers (Graphic3d_Camera::Projection& theProj) } // create color and coverage accumulation buffers required for OIT algorithm - if (toUseOit) + if (toUseOit + && myRenderParams.TransparencyMethod == Graphic3d_RTM_DEPTH_PEELING_OIT) + { + if (myDepthPeelingFbos->BlendBackFboOit()->GetSizeX() != aRendSizeX + || myDepthPeelingFbos->BlendBackFboOit()->GetSizeY() != aRendSizeY) + { + if (myDepthPeelingFbos->BlendBackFboOit()->Init (aCtx, aRendSizeX, aRendSizeY, GL_RGBA16F, 0)) + { + for (int aPairIter = 0; aPairIter < 2; ++aPairIter) + { + OpenGl_ColorFormats aColorFormats; + aColorFormats.Append (GL_RG32F); + aColorFormats.Append (GL_RGBA16F); + aColorFormats.Append (GL_RGBA16F); + myDepthPeelingFbos->DepthPeelFbosOit()[aPairIter]->Init (aCtx, aRendSizeX, aRendSizeY, aColorFormats, 0); + + NCollection_Sequence anAttachments; + anAttachments.Append (myDepthPeelingFbos->DepthPeelFbosOit()[aPairIter]->ColorTexture (1)); + anAttachments.Append (myDepthPeelingFbos->DepthPeelFbosOit()[aPairIter]->ColorTexture (2)); + myDepthPeelingFbos->FrontBackColorFbosOit()[aPairIter]->InitWrapper (aCtx, anAttachments); + } + } + else + { + toUseOit = false; + aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, + "Initialization of float texture framebuffer for use with\n" + " Depth-Peeling order-independent transparency rendering algorithm has failed."); + } + } + } + if (!toUseOit) + { + myDepthPeelingFbos->Release (aCtx.operator->()); + } + + if (toUseOit + && myRenderParams.TransparencyMethod == Graphic3d_RTM_BLEND_OIT) { Standard_Integer anFboIt = 0; for (; anFboIt < 2; ++anFboIt) @@ -1295,6 +1336,7 @@ bool OpenGl_View::prepareFrameBuffers (Graphic3d_Camera::Projection& theProj) } if (!toUseOit && myMainSceneFbosOit[0]->IsValid()) { + myDepthPeelingFbos->Release (aCtx.operator->()); myMainSceneFbosOit [0]->Release (aCtx.operator->()); myMainSceneFbosOit [1]->Release (aCtx.operator->()); myImmediateSceneFbosOit[0]->Release (aCtx.operator->()); diff --git a/src/OpenGl/OpenGl_View.hxx b/src/OpenGl/OpenGl_View.hxx index ea421e54aa..53811ac790 100644 --- a/src/OpenGl/OpenGl_View.hxx +++ b/src/OpenGl/OpenGl_View.hxx @@ -56,6 +56,7 @@ struct OpenGl_Matrix; class Graphic3d_StructureManager; +class OpenGl_DepthPeeling; class OpenGl_GraphicDriver; class OpenGl_PBREnvironment; class OpenGl_StateCounter; @@ -206,6 +207,9 @@ public: const Standard_Integer theWidth, const Standard_Integer theHeight) Standard_OVERRIDE; + //! Returns additional buffers for depth peeling OIT. + const Handle(OpenGl_DepthPeeling)& DepthPeelingFbos() const { return myDepthPeelingFbos; } + public: //! Returns gradient background fill colors. @@ -533,7 +537,8 @@ protected: //! @name Rendering properties Handle(OpenGl_FrameBuffer) myMainSceneFbosOit[2]; //!< Additional buffers for transparent draw of main layer. 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_FrameBuffer) myXrSceneFbo; //!< additional FBO (without MSAA) for submitting to XR + Handle(OpenGl_DepthPeeling) myDepthPeelingFbos; //!< additional buffers for depth peeling Handle(OpenGl_ShadowMapArray) myShadowMaps; //!< additional FBOs for shadow map rendering OpenGl_VertexBuffer myFullScreenQuad; //!< Vertices for full-screen quad rendering. OpenGl_VertexBuffer myFullScreenQuadFlip; diff --git a/src/Shaders/Declarations.glsl b/src/Shaders/Declarations.glsl index 644fe7b2a9..27418912ca 100644 --- a/src/Shaders/Declarations.glsl +++ b/src/Shaders/Declarations.glsl @@ -89,6 +89,13 @@ #define occFragColor occFragColor0 #define occFragCoverage occFragColor1 + #define occPeelDepth occFragColor0 + #define occPeelFrontColor occFragColor1 + #define occPeelBackColor occFragColor2 + + //! Define the main Fragment Shader early return procedure. + bool occFragEarlyReturn(); + //! Define the main Fragment Shader output - color value. void occSetFragColor (in vec4 theColor); #endif diff --git a/src/Shaders/DeclarationsImpl.glsl b/src/Shaders/DeclarationsImpl.glsl index dba698d0f3..791f298c92 100644 --- a/src/Shaders/DeclarationsImpl.glsl +++ b/src/Shaders/DeclarationsImpl.glsl @@ -1,7 +1,41 @@ //! @file DeclarationsImpl.glsl includes implementation of common functions and properties accessors #if defined(FRAGMENT_SHADER) -//! Output color (and coverage for accumulation by OIT algorithm). + +#if defined(OCC_DEPTH_PEEL_OIT) +uniform sampler2D occDepthPeelingDepth; +uniform sampler2D occDepthPeelingFrontColor; +int IsFrontPeelLayer = -1; +bool occFragEarlyReturn() +{ + #define THE_DEPTH_CLEAR_VALUE -1e15f + ivec2 aFragCoord = ivec2 (gl_FragCoord.xy); + vec2 aLastDepth = texelFetch (occDepthPeelingDepth, aFragCoord, 0).rg; + occPeelFrontColor = texelFetch (occDepthPeelingFrontColor, aFragCoord, 0); + occPeelDepth.rg = vec2 (THE_DEPTH_CLEAR_VALUE); // depth value always increases, so that MAX blend equation can be used + occPeelBackColor = vec4 (0.0); // back color is blend after each peeling pass + + float aNearDepth = -aLastDepth.x; + float aFarDepth = aLastDepth.y; + float aFragDepth = gl_FragCoord.z; // 0 - 1 + if (aFragDepth < aNearDepth || aFragDepth > aFarDepth) + { + return true; // skip peeled depth + } + else if (aFragDepth > aNearDepth && aFragDepth < aFarDepth) + { + // to be rendered at next peeling pass + occPeelDepth.rg = vec2 (-aFragDepth, aFragDepth); + return true; + } + + IsFrontPeelLayer = (gl_FragCoord.z == aNearDepth) ? 1 : 0; + return false; +} +#else +bool occFragEarlyReturn() { return false; } +#endif + void occSetFragColor (in vec4 theColor) { #if defined(OCC_ALPHA_TEST) @@ -11,6 +45,18 @@ void occSetFragColor (in vec4 theColor) float aWeight = theColor.a * clamp (1e+2 * pow (1.0 - gl_FragCoord.z * occOitDepthFactor, 3.0), 1e-2, 1e+2); occFragCoverage.r = theColor.a * aWeight; occFragColor = vec4 (theColor.rgb * theColor.a * aWeight, theColor.a); +#elif defined(OCC_DEPTH_PEEL_OIT) + if (IsFrontPeelLayer == 1) // front is blended directly + { + vec4 aLastColor = occPeelFrontColor; + float anAlphaMult = 1.0 - aLastColor.a; + occPeelFrontColor.rgb = aLastColor.rgb + theColor.rgb * theColor.a * anAlphaMult; + occPeelFrontColor.a = 1.0 - anAlphaMult * (1.0 - theColor.a); + } + else if (IsFrontPeelLayer == 0) // back is blended afterwards + { + occPeelBackColor = theColor; + } #else occFragColor = theColor; #endif diff --git a/src/Shaders/Shaders_DeclarationsImpl_glsl.pxx b/src/Shaders/Shaders_DeclarationsImpl_glsl.pxx index 51a35dc097..ebf3a1abc1 100644 --- a/src/Shaders/Shaders_DeclarationsImpl_glsl.pxx +++ b/src/Shaders/Shaders_DeclarationsImpl_glsl.pxx @@ -4,7 +4,41 @@ static const char Shaders_DeclarationsImpl_glsl[] = "\n" "//! @file DeclarationsImpl.glsl includes implementation of common functions and properties accessors\n" "#if defined(FRAGMENT_SHADER)\n" - "//! Output color (and coverage for accumulation by OIT algorithm).\n" + "\n" + "#if defined(OCC_DEPTH_PEEL_OIT)\n" + "uniform sampler2D occDepthPeelingDepth;\n" + "uniform sampler2D occDepthPeelingFrontColor;\n" + "int IsFrontPeelLayer = -1;\n" + "bool occFragEarlyReturn()\n" + "{\n" + " #define THE_DEPTH_CLEAR_VALUE -1e15f\n" + " ivec2 aFragCoord = ivec2 (gl_FragCoord.xy);\n" + " vec2 aLastDepth = texelFetch (occDepthPeelingDepth, aFragCoord, 0).rg;\n" + " occPeelFrontColor = texelFetch (occDepthPeelingFrontColor, aFragCoord, 0);\n" + " occPeelDepth.rg = vec2 (THE_DEPTH_CLEAR_VALUE); // depth value always increases, so that MAX blend equation can be used\n" + " occPeelBackColor = vec4 (0.0); // back color is blend after each peeling pass\n" + "\n" + " float aNearDepth = -aLastDepth.x;\n" + " float aFarDepth = aLastDepth.y;\n" + " float aFragDepth = gl_FragCoord.z; // 0 - 1\n" + " if (aFragDepth < aNearDepth || aFragDepth > aFarDepth)\n" + " {\n" + " return true; // skip peeled depth\n" + " }\n" + " else if (aFragDepth > aNearDepth && aFragDepth < aFarDepth)\n" + " {\n" + " // to be rendered at next peeling pass\n" + " occPeelDepth.rg = vec2 (-aFragDepth, aFragDepth);\n" + " return true;\n" + " }\n" + "\n" + " IsFrontPeelLayer = (gl_FragCoord.z == aNearDepth) ? 1 : 0;\n" + " return false;\n" + "}\n" + "#else\n" + "bool occFragEarlyReturn() { return false; }\n" + "#endif\n" + "\n" "void occSetFragColor (in vec4 theColor)\n" "{\n" "#if defined(OCC_ALPHA_TEST)\n" @@ -14,6 +48,18 @@ static const char Shaders_DeclarationsImpl_glsl[] = " float aWeight = theColor.a * clamp (1e+2 * pow (1.0 - gl_FragCoord.z * occOitDepthFactor, 3.0), 1e-2, 1e+2);\n" " occFragCoverage.r = theColor.a * aWeight;\n" " occFragColor = vec4 (theColor.rgb * theColor.a * aWeight, theColor.a);\n" + "#elif defined(OCC_DEPTH_PEEL_OIT)\n" + " if (IsFrontPeelLayer == 1) // front is blended directly\n" + " {\n" + " vec4 aLastColor = occPeelFrontColor;\n" + " float anAlphaMult = 1.0 - aLastColor.a;\n" + " occPeelFrontColor.rgb = aLastColor.rgb + theColor.rgb * theColor.a * anAlphaMult;\n" + " occPeelFrontColor.a = 1.0 - anAlphaMult * (1.0 - theColor.a);\n" + " }\n" + " else if (IsFrontPeelLayer == 0) // back is blended afterwards\n" + " {\n" + " occPeelBackColor = theColor;\n" + " }\n" "#else\n" " occFragColor = theColor;\n" "#endif\n" diff --git a/src/Shaders/Shaders_Declarations_glsl.pxx b/src/Shaders/Shaders_Declarations_glsl.pxx index b64b83d045..c33fdf60c0 100644 --- a/src/Shaders/Shaders_Declarations_glsl.pxx +++ b/src/Shaders/Shaders_Declarations_glsl.pxx @@ -92,6 +92,13 @@ static const char Shaders_Declarations_glsl[] = " #define occFragColor occFragColor0\n" " #define occFragCoverage occFragColor1\n" "\n" + " #define occPeelDepth occFragColor0\n" + " #define occPeelFrontColor occFragColor1\n" + " #define occPeelBackColor occFragColor2\n" + "\n" + " //! Define the main Fragment Shader early return procedure.\n" + " bool occFragEarlyReturn();\n" + "\n" " //! Define the main Fragment Shader output - color value.\n" " void occSetFragColor (in vec4 theColor);\n" "#endif\n" diff --git a/src/ViewerTest/ViewerTest_OpenGlCommands.cxx b/src/ViewerTest/ViewerTest_OpenGlCommands.cxx index 66c8dfbd24..2d51ec7b16 100644 --- a/src/ViewerTest/ViewerTest_OpenGlCommands.cxx +++ b/src/ViewerTest/ViewerTest_OpenGlCommands.cxx @@ -828,7 +828,7 @@ static Standard_Integer VShaderProg (Draw_Interpretor& theDI, && ViewerTest::CurrentView()->RenderingParams().TransparencyMethod == Graphic3d_RTM_BLEND_OIT) { aProgram->SetNbFragmentOutputs (2); - aProgram->SetWeightOitOutput (true); + aProgram->SetOitOutput (Graphic3d_RTM_BLEND_OIT); } ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName aGlobalPrsIter (GetMapOfAIS()); diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index 52a772266e..907a9afe5d 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -11556,6 +11556,8 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI, case Graphic3d_RTM_BLEND_UNORDERED: theDI << "Basic blended transparency with non-commuting operator "; break; case Graphic3d_RTM_BLEND_OIT: theDI << "Weighted Blended Order-Independent Transparency, depth weight factor: " << TCollection_AsciiString (aParams.OitDepthFactor); break; + case Graphic3d_RTM_DEPTH_PEELING_OIT: theDI << "Depth Peeling Order-Independent Transparency, Nb.Layers: " + << TCollection_AsciiString (aParams.NbOitDepthPeelingLayers); break; } theDI << "\n"; theDI << "msaa: " << aParams.NbMsaaSamples << "\n"; @@ -11801,6 +11803,10 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI, { theDI << "on, depth weight factor: " << TCollection_AsciiString (aParams.OitDepthFactor) << " "; } + else if (aParams.TransparencyMethod == Graphic3d_RTM_DEPTH_PEELING_OIT) + { + theDI << "on, depth peeling layers: " << TCollection_AsciiString (aParams.NbOitDepthPeelingLayers) << " "; + } else { theDI << "off" << " "; @@ -11815,7 +11821,41 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI, TCollection_AsciiString aParam = theArgVec[anArgIter]; aParam.LowerCase(); - if (aParam.IsRealValue (Standard_True)) + if (aParam == "peeling" + || aParam == "peel") + { + aParams.TransparencyMethod = Graphic3d_RTM_DEPTH_PEELING_OIT; + if (anArgIter + 1 < theArgNb + && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue()) + { + ++anArgIter; + const Standard_Integer aNbLayers = TCollection_AsciiString (theArgVec[anArgIter]).IntegerValue(); + if (aNbLayers < 2) + { + Message::SendFail() << "Syntax error: invalid layers number specified for Depth Peeling OIT " << aNbLayers; + return 1; + } + aParams.NbOitDepthPeelingLayers = TCollection_AsciiString (theArgVec[anArgIter]).IntegerValue(); + } + } + else if (aParam == "weighted" + || aParam == "weight") + { + aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT; + if (anArgIter + 1 < theArgNb + && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue()) + { + ++anArgIter; + const Standard_ShortReal aWeight = (Standard_ShortReal)TCollection_AsciiString (theArgVec[anArgIter]).RealValue(); + if (aWeight < 0.f || aWeight > 1.f) + { + Message::SendFail() << "Syntax error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]"; + return 1; + } + aParams.OitDepthFactor = aWeight; + } + } + else if (aParam.IsRealValue()) { const Standard_ShortReal aWeight = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]); if (aWeight < 0.f || aWeight > 1.f) diff --git a/tests/v3d/transparency/oit b/tests/v3d/transparency/oit new file mode 100644 index 0000000000..2d5e23ce59 --- /dev/null +++ b/tests/v3d/transparency/oit @@ -0,0 +1,55 @@ +puts "========" +puts "0031571: Visualization, TKOpenGl - provide depth peeling OIT option" +puts "========" + +pload MODELING VISUALIZATION +if { $::tcl_platform(os) == "Darwin" } { vcaps -core } +set hasVtk 1 +if { [catch { pload VIS }] } { set hasVtk 0 } + +# create objects +pcylinder c 0.5 1 +box b1 -1 -1 -0.5 1 1 1 +box b2 0 0 -0.5 1 1 1 +box b3 -1 0 -0.5 1 1 1 + +vclear +vinit View1 +vdisplay -dispMode 1 c b1 b2 b3 +vaspects c -color yellow -transparency 0.4 +vaspects b1 -color blue -transparency 0.8 +vaspects b2 -color green -transparency 0.0 +vaspects b3 -color red -transparency 0.5 +vfit +vaxo +vzoom 0.9 + +vraytrace 1 +vrenderparams -rayDepth 10 +vdump $imagedir/${casename}_raytrace.png + +vraytrace 0 +vrenderparams -oit off +vdump $imagedir/${casename}_nooit.png +vrenderparams -oit weight 0.0 +vdump $imagedir/${casename}_weight.png +vrenderparams -oit peeling 4 +vdump $imagedir/${casename}_peel.png + +# vtk viewer +if { $hasVtk == 1 } { + ivtkinit -msaa 0 -srgb 0 + ivtkdisplay c b1 b2 b3 + ivtkaxo + ivtksetdispmode 1 + ivtksetcolor c yellow + ivtksetcolor b1 blue + ivtksetcolor b2 green + ivtksetcolor b3 red + ivtksettransparency c 0.4 + ivtksettransparency b1 0.8 + ivtksettransparency b2 0.0 + ivtksettransparency b3 0.5 + ivtkrenderparams -depthPeeling 4 + ivtkdump $imagedir/${casename}_vtk.png +}