From: apl Date: Thu, 13 Apr 2017 10:25:13 +0000 (+0300) Subject: 0027925: Visualization - implement order-independent transparency algorithm within... X-Git-Tag: V_01_2017_06_30~11 X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=2390f514ab4c801d51e5de76251dedf88690c000;p=occt-copy.git 0027925: Visualization - implement order-independent transparency algorithm within rasterization rendering The weighted, blended order-independent transparency algorithm has been added rasterization pipeline. It requires shaders, multiple render targets extension and floating point texture format. Patch does not modify API and does not require porting - it adds new rendering options (vrenderparams): - OIT-enabling flag and, - Scalar factor [0-1] controlling influence of a fragment's depth to its visibility. The feature supports MSAA, OpenGL ES 2.0 and ANGLE. The usage rules for default transparency algorithm become simpler - rendering priority of transparent graphical structures is managed automatically, therefore no need to change it application side. --- diff --git a/src/AIS/AIS_Shape.cxx b/src/AIS/AIS_Shape.cxx index 484a33c968..9796f04f91 100644 --- a/src/AIS/AIS_Shape.cxx +++ b/src/AIS/AIS_Shape.cxx @@ -981,7 +981,6 @@ void AIS_Shape::SetTransparency (const Standard_Real theValue) } const Handle(Prs3d_Presentation)& aPrs = aPrsModed.Presentation()->Presentation(); - aPrs->SetDisplayPriority (10); // force highest priority for translucent objects for (Graphic3d_SequenceOfGroup::Iterator aGroupIt (aPrs->Groups()); aGroupIt.More(); aGroupIt.Next()) { const Handle(Graphic3d_Group)& aGroup = aGroupIt.Value(); @@ -1037,7 +1036,6 @@ void AIS_Shape::UnsetTransparency() aGroup->SetGroupPrimitivesAspect (anAreaAsp); } } - aPrs->ResetDisplayPriority(); } myRecomputeEveryPrs = Standard_False; // no mode to recalculate :only viewer update diff --git a/src/AIS/AIS_Triangulation.cxx b/src/AIS/AIS_Triangulation.cxx index f4df8e4c27..3374b05f61 100644 --- a/src/AIS/AIS_Triangulation.cxx +++ b/src/AIS/AIS_Triangulation.cxx @@ -105,11 +105,6 @@ void AIS_Triangulation::updatePresentation() const Handle(Prs3d_Presentation)& aPrs = aPrsModed.Presentation()->Presentation(); - if (IsTransparent()) - { - aPrs->SetDisplayPriority (10); // force highest priority for translucent objects - } - for (Graphic3d_SequenceOfGroup::Iterator aGroupIt (aPrs->Groups()); aGroupIt.More(); aGroupIt.Next()) { const Handle(Graphic3d_Group)& aGroup = aGroupIt.Value(); @@ -118,11 +113,6 @@ void AIS_Triangulation::updatePresentation() aGroup->SetGroupPrimitivesAspect (anAreaAsp); } } - - if (!IsTransparent()) - { - aPrs->ResetDisplayPriority(); - } } myRecomputeEveryPrs = Standard_False; // no mode to recalculate - only viewer update diff --git a/src/Graphic3d/Graphic3d_RenderingParams.hxx b/src/Graphic3d/Graphic3d_RenderingParams.hxx index b264d44361..bda650918b 100644 --- a/src/Graphic3d/Graphic3d_RenderingParams.hxx +++ b/src/Graphic3d/Graphic3d_RenderingParams.hxx @@ -48,6 +48,8 @@ public: Graphic3d_RenderingParams() : Method (Graphic3d_RM_RASTERIZATION), NbMsaaSamples (0), + IsOitEnabled (Standard_True), + OitDepthWeight (0.0f), // ray tracing parameters IsGlobalIlluminationEnabled (Standard_False), RaytracingDepth (THE_DEFAULT_DEPTH), @@ -90,6 +92,8 @@ public: Graphic3d_RenderingMode Method; //!< specifies rendering mode, Graphic3d_RM_RASTERIZATION by default Standard_Integer NbMsaaSamples; //!< number of MSAA samples (should be within 0..GL_MAX_SAMPLES, power-of-two number), 0 by default + Standard_Boolean IsOitEnabled; //!< enables/disables order-independent transparency for rasterization, True by default + Standard_ShortReal OitDepthWeight; //!< scalar factor [0-1] controlling influence of depth of a fragment to its final coverage Standard_Boolean IsGlobalIlluminationEnabled; //!< enables/disables global illumination effects (path tracing) Standard_Integer SamplesPerPixel; //!< number of samples per pixel (SPP) diff --git a/src/OpenGl/FILES b/src/OpenGl/FILES index b9dbf9e68e..3aec70537b 100755 --- a/src/OpenGl/FILES +++ b/src/OpenGl/FILES @@ -104,6 +104,7 @@ OpenGl_IndexBuffer.cxx OpenGl_IndexBuffer.hxx OpenGl_Layer.cxx OpenGl_Layer.hxx +OpenGl_OitUniformState.hxx OpenGl_RenderFilter.cxx OpenGl_RenderFilter.hxx OpenGl_Sampler.cxx diff --git a/src/OpenGl/OpenGl_CappingAlgo.cxx b/src/OpenGl/OpenGl_CappingAlgo.cxx index f0bfb6695a..3ba9545632 100755 --- a/src/OpenGl/OpenGl_CappingAlgo.cxx +++ b/src/OpenGl/OpenGl_CappingAlgo.cxx @@ -27,14 +27,6 @@ IMPLEMENT_STANDARD_RTTIEXT(OpenGl_CappingAlgoFilter,OpenGl_RenderFilter) namespace { -#if !defined(GL_ES_VERSION_2_0) - static const GLint THE_FILLPRIM_FROM = GL_TRIANGLES; - static const GLint THE_FILLPRIM_TO = GL_POLYGON; -#else - static const GLint THE_FILLPRIM_FROM = GL_TRIANGLES; - static const GLint THE_FILLPRIM_TO = GL_TRIANGLE_FAN; -#endif - //! Render infinite capping plane. //! @param theWorkspace [in] the GL workspace, context state. //! @param thePlane [in] the graphical plane, for which the capping surface is rendered. @@ -88,8 +80,14 @@ namespace theWorkspace->ApplyAspectFace(); // evaluate number of pair faces - glDisable (GL_DEPTH_TEST); - glDepthMask (GL_FALSE); + if (theWorkspace->UseZBuffer()) + { + glDisable (GL_DEPTH_TEST); + } + if (theWorkspace->UseDepthWrite()) + { + glDepthMask (GL_FALSE); + } glStencilFunc (GL_ALWAYS, 1, 0x01); glStencilOp (GL_KEEP, GL_INVERT, GL_INVERT); @@ -119,10 +117,16 @@ namespace // render capping plane using the generated stencil mask glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glDepthMask (GL_TRUE); + if (theWorkspace->UseDepthWrite()) + { + glDepthMask (GL_TRUE); + } glStencilFunc (GL_EQUAL, 1, 0x01); glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); - glEnable (GL_DEPTH_TEST); + if (theWorkspace->UseZBuffer()) + { + glEnable (GL_DEPTH_TEST); + } renderPlane (theWorkspace, thePlane, aRenderPlane->ToUseObjectProperties() ? aGroupIter.Value()->AspectFace() @@ -160,7 +164,9 @@ void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)& theWorks // replace primitive groups rendering filter Handle(OpenGl_RenderFilter) aRenderFilter = theWorkspace->GetRenderFilter(); - theWorkspace->SetRenderFilter (theWorkspace->DefaultCappingAlgoFilter()); + Handle(OpenGl_CappingAlgoFilter) aCappingFilter = theWorkspace->DefaultCappingAlgoFilter(); + aCappingFilter->SetPreviousFilter (aRenderFilter); + theWorkspace->SetRenderFilter (aCappingFilter); // prepare for rendering the clip planes glEnable (GL_STENCIL_TEST); @@ -214,10 +220,16 @@ void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)& theWorks // function : CanRender // purpose : // ======================================================================= -Standard_Boolean OpenGl_CappingAlgoFilter::CanRender (const OpenGl_Element* theElement) +Standard_Boolean OpenGl_CappingAlgoFilter::ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace, + const OpenGl_Element* theGlElement) { - const OpenGl_PrimitiveArray* aPArray = dynamic_cast (theElement); + if (!myFilter.IsNull() && !myFilter->ShouldRender (theWorkspace, theGlElement)) + { + return Standard_False; + } + + const OpenGl_PrimitiveArray* aPArray = dynamic_cast (theGlElement); return aPArray != NULL - && aPArray->DrawMode() >= THE_FILLPRIM_FROM - && aPArray->DrawMode() <= THE_FILLPRIM_TO; + && aPArray->DrawMode() >= OpenGl_PrimitiveArray::THE_FILLPRIM_FROM + && aPArray->DrawMode() <= OpenGl_PrimitiveArray::THE_FILLPRIM_TO; } diff --git a/src/OpenGl/OpenGl_CappingAlgo.hxx b/src/OpenGl/OpenGl_CappingAlgo.hxx index 7fc7881448..23d9ae33b0 100755 --- a/src/OpenGl/OpenGl_CappingAlgo.hxx +++ b/src/OpenGl/OpenGl_CappingAlgo.hxx @@ -49,14 +49,23 @@ public: //! Default constructor. OpenGl_CappingAlgoFilter() {} + //! Sets the current active filter in workspace. + //! @param thePrevFilter [in] the previously active filter that should have additive effect. + void SetPreviousFilter (const Handle(OpenGl_RenderFilter)& thePrevFitler) { myFilter = thePrevFitler; } + //! Checks whether the element can be rendered or not. //! @param theElement [in] the element to check. //! @return True if element can be rendered. - virtual Standard_Boolean CanRender (const OpenGl_Element* theElement) Standard_OVERRIDE; + virtual Standard_Boolean ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace, + const OpenGl_Element* theGlElement) Standard_OVERRIDE; + +private: + + Handle(OpenGl_RenderFilter) myFilter; //!< Previous active filter that should be combined. public: - DEFINE_STANDARD_RTTIEXT(OpenGl_CappingAlgoFilter,OpenGl_RenderFilter) + DEFINE_STANDARD_RTTIEXT(OpenGl_CappingAlgoFilter, OpenGl_RenderFilter) }; #endif diff --git a/src/OpenGl/OpenGl_Context.cxx b/src/OpenGl/OpenGl_Context.cxx index 43ae9fa763..37fc98e3d7 100644 --- a/src/OpenGl/OpenGl_Context.cxx +++ b/src/OpenGl/OpenGl_Context.cxx @@ -127,6 +127,8 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps) arbNPTW (Standard_False), arbTexRG (Standard_False), arbTexFloat (Standard_False), + arbTexHalfFloat (Standard_False), + arbSampleShading (Standard_False), arbTexBindless (NULL), arbTBO (NULL), arbTboRGB32 (Standard_False), @@ -152,11 +154,13 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps) myMaxTexDim (1024), myMaxClipPlanes (6), myMaxMsaaSamples(0), + myMaxDrawBuffers (1), myGlVerMajor (0), myGlVerMinor (0), myIsInitialized (Standard_False), myIsStereoBuffers (Standard_False), myIsGlNormalizeEnabled (Standard_False), + myHasHalfFloatTextures (Standard_False), myHasRayTracing (Standard_False), myHasRayTracingTextures (Standard_False), myHasRayTracingAdaptiveSampling (Standard_False), @@ -171,7 +175,7 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps) #endif myToCullBackFaces (false), myReadBuffer (0), - myDrawBuffer (0), + myDrawBuffers (1), myDefaultVao (0), myIsGlDebugCtx (Standard_False), myResolutionRatio (1.0f) @@ -371,18 +375,60 @@ void OpenGl_Context::SetReadBuffer (const Standard_Integer theReadBuffer) void OpenGl_Context::SetDrawBuffer (const Standard_Integer theDrawBuffer) { #if !defined(GL_ES_VERSION_2_0) - myDrawBuffer = !myIsStereoBuffers ? stereoToMonoBuffer (theDrawBuffer) : theDrawBuffer; - if (myDrawBuffer < GL_COLOR_ATTACHMENT0 + const Standard_Integer aDrawBuffer = !myIsStereoBuffers ? stereoToMonoBuffer (theDrawBuffer) : theDrawBuffer; + if (aDrawBuffer < GL_COLOR_ATTACHMENT0 && arbFBO != NULL) { arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER); } - ::glDrawBuffer (myDrawBuffer); + ::glDrawBuffer (aDrawBuffer); + + myDrawBuffers.Clear(); + + if (aDrawBuffer != GL_NONE) + { + myDrawBuffers.SetValue (0, aDrawBuffer); + } #else (void )theDrawBuffer; #endif } +// ======================================================================= +// function : SetDrawBuffers +// purpose : +// ======================================================================= +void OpenGl_Context::SetDrawBuffers (const Standard_Integer theNb, const Standard_Integer* theDrawBuffers) +{ + Standard_ASSERT_RETURN (Functions()->glDrawBuffers != NULL, "Multiple render targets feature is not supported by the context", Standard_ASSERT_DO_NOTHING()); + + myDrawBuffers.Clear(); + + Standard_Boolean useDefaultFbo = Standard_False; + for (Standard_Integer anI = 0; anI < theNb; ++anI) + { +#if !defined(GL_ES_VERSION_2_0) + const Standard_Integer aDrawBuffer = !myIsStereoBuffers ? stereoToMonoBuffer (theDrawBuffers[anI]) : theDrawBuffers[anI]; +#else + const Standard_Integer aDrawBuffer = theDrawBuffers[anI]; +#endif + if (aDrawBuffer < GL_COLOR_ATTACHMENT0 && aDrawBuffer != GL_NONE) + { + useDefaultFbo = Standard_True; + } + else if (aDrawBuffer != GL_NONE) + { + myDrawBuffers.SetValue (anI, aDrawBuffer); + } + } + if (arbFBO != NULL && useDefaultFbo) + { + arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER); + } + + Functions()->glDrawBuffers (theNb, (const GLenum*)theDrawBuffers); +} + // ======================================================================= // function : SetCullBackFaces // purpose : @@ -419,9 +465,35 @@ void OpenGl_Context::FetchState() ::glGetIntegerv (GL_RENDER_MODE, &myRenderMode); } - // cache buffers state + // cache read buffers state ::glGetIntegerv (GL_READ_BUFFER, &myReadBuffer); - ::glGetIntegerv (GL_DRAW_BUFFER, &myDrawBuffer); + + // cache draw buffers state + myDrawBuffers.Clear(); + + Standard_Integer aDrawBuffer; + + if (myMaxDrawBuffers == 1) + { + ::glGetIntegerv (GL_DRAW_BUFFER, &aDrawBuffer); + + if (aDrawBuffer != GL_NONE) + { + myDrawBuffers.SetValue (0, aDrawBuffer); + } + } + else + { + for (Standard_Integer anI = 0; anI < myMaxDrawBuffers; ++anI) + { + ::glGetIntegerv (GL_DRAW_BUFFER0 + anI, &aDrawBuffer); + + if (aDrawBuffer != GL_NONE) + { + myDrawBuffers.SetValue (anI, aDrawBuffer); + } + } + } #endif } @@ -1096,6 +1168,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile) myGlVerMajor = 0; myGlVerMinor = 0; myMaxMsaaSamples = 0; + myMaxDrawBuffers = 1; ReadGlVersion (myGlVerMajor, myGlVerMinor); myVendor = (const char* )::glGetString (GL_VENDOR); if (!caps->ffpEnable @@ -1188,6 +1261,8 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile) arbNPTW = Standard_True; arbTexRG = IsGlGreaterEqual (3, 0) || CheckExtension ("GL_EXT_texture_rg"); + arbSampleShading = IsGlGreaterEqual (3, 2) + || CheckExtension ("GL_OES_sample_variables"); extBgra = CheckExtension ("GL_EXT_texture_format_BGRA8888"); extAnis = CheckExtension ("GL_EXT_texture_filter_anisotropic"); extPDS = CheckExtension ("GL_OES_packed_depth_stencil"); @@ -1227,8 +1302,10 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile) hasHighp = Standard_True; } - arbTexFloat = IsGlGreaterEqual (3, 0) - && FindProc ("glTexImage3D", myFuncs->glTexImage3D); + arbTexFloat = IsGlGreaterEqual (3, 0) + && FindProc ("glTexImage3D", myFuncs->glTexImage3D); + arbTexHalfFloat = IsGlGreaterEqual (3, 0) + || CheckExtension ("GL_OES_texture_half_float"); const Standard_Boolean hasTexBuffer32 = IsGlGreaterEqual (3, 2) && FindProc ("glTexBuffer", myFuncs->glTexBuffer); const Standard_Boolean hasExtTexBuffer = CheckExtension ("GL_EXT_texture_buffer") && FindProc ("glTexBufferEXT", myFuncs->glTexBuffer); @@ -1268,19 +1345,30 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile) } } + const Standard_Boolean hasDrawBuffersExt = (IsGlGreaterEqual (3, 0) || CheckExtension ("GL_EXT_draw_buffers")) + && FindProc ("glDrawBuffersEXT", myFuncs->glDrawBuffers); + // get number of maximum supported draw buffers + if (hasDrawBuffersExt) + { + glGetIntegerv (GL_MAX_DRAW_BUFFERS, &myMaxDrawBuffers); + } #else myTexClamp = IsGlGreaterEqual (1, 2) ? GL_CLAMP_TO_EDGE : GL_CLAMP; - hasTexRGBA8 = Standard_True; - arbNPTW = CheckExtension ("GL_ARB_texture_non_power_of_two"); - arbTexFloat = IsGlGreaterEqual (3, 0) - || CheckExtension ("GL_ARB_texture_float"); - extBgra = CheckExtension ("GL_EXT_bgra"); - extAnis = CheckExtension ("GL_EXT_texture_filter_anisotropic"); - extPDS = CheckExtension ("GL_EXT_packed_depth_stencil"); - atiMem = CheckExtension ("GL_ATI_meminfo"); - nvxMem = CheckExtension ("GL_NVX_gpu_memory_info"); + hasTexRGBA8 = Standard_True; + arbNPTW = CheckExtension ("GL_ARB_texture_non_power_of_two"); + arbTexFloat = IsGlGreaterEqual (3, 0) + || CheckExtension ("GL_ARB_texture_float"); + arbTexHalfFloat = IsGlGreaterEqual (3, 0) + || CheckExtension ("GL_ARB_half_float_pixel"); + arbSampleShading = IsGlGreaterEqual (4, 0) + || CheckExtension("GL_ARB_sample_shading"); + extBgra = CheckExtension ("GL_EXT_bgra"); + extAnis = CheckExtension ("GL_EXT_texture_filter_anisotropic"); + extPDS = CheckExtension ("GL_EXT_packed_depth_stencil"); + atiMem = CheckExtension ("GL_ATI_meminfo"); + nvxMem = CheckExtension ("GL_NVX_gpu_memory_info"); GLint aStereo = GL_FALSE; glGetIntegerv (GL_STEREO, &aStereo); @@ -1288,6 +1376,12 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile) // get number of maximum clipping planes glGetIntegerv (GL_MAX_CLIP_PLANES, &myMaxClipPlanes); + + // get number of maximum supported draw buffers + if (IsGlGreaterEqual (2, 0)) + { + glGetIntegerv (GL_MAX_DRAW_BUFFERS, &myMaxDrawBuffers); + } #endif glGetIntegerv (GL_MAX_TEXTURE_SIZE, &myMaxTexDim); @@ -2848,7 +2942,6 @@ Handle(OpenGl_FrameBuffer) OpenGl_Context::SetDefaultFrameBuffer (const Handle(O // ======================================================================= void OpenGl_Context::SetShadingMaterial (const OpenGl_AspectFace* theAspect, const Handle(Graphic3d_PresentationAttributes)& theHighlight, - const Standard_Boolean theUseDepthWrite, Standard_Integer& theRenderingPassFlags) { const Handle(Graphic3d_AspectFillArea3d)& anAspect = (!theHighlight.IsNull() && !theHighlight->BasicFillAreaAspect().IsNull()) @@ -2902,26 +2995,12 @@ void OpenGl_Context::SetShadingMaterial (const OpenGl_AspectFace* theAspect, theRenderingPassFlags |= OPENGL_NS_2NDPASSNEED; } - GLboolean aDepthMask = GL_TRUE; if (aTranspFront != 0.0f || aTranspBack != 0.0f) { // render transparent myMatFront.Diffuse.a() = 1.0f - aTranspFront; myMatBack .Diffuse.a() = 1.0f - aTranspBack; - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable (GL_BLEND); - aDepthMask = GL_FALSE; - } - else - { - // render opaque - glBlendFunc (GL_ONE, GL_ZERO); - glDisable (GL_BLEND); - } - if (theUseDepthWrite) - { - glDepthMask (aDepthMask); } } diff --git a/src/OpenGl/OpenGl_Context.hxx b/src/OpenGl/OpenGl_Context.hxx index e5bddc0380..555abc2f33 100644 --- a/src/OpenGl/OpenGl_Context.hxx +++ b/src/OpenGl/OpenGl_Context.hxx @@ -24,9 +24,11 @@ #include #include #include -#include +#include #include #include +#include +#include #include #include #include @@ -43,6 +45,8 @@ #include +#include + //! Forward declarations #if defined(__APPLE__) #import @@ -456,12 +460,18 @@ public: //! @return value for GL_MAX_SAMPLES Standard_Integer MaxMsaaSamples() const { return myMaxMsaaSamples; } + //! @return value for GL_MAX_DRAW_BUFFERS + Standard_Integer MaxDrawBuffers() const { return myMaxDrawBuffers; } + //! Get maximum number of clip planes supported by OpenGl. //! This value is implementation dependent. At least 6 //! planes should be supported by OpenGl (see specs). //! @return value for GL_MAX_CLIP_PLANES Standard_Integer MaxClipPlanes() const { return myMaxClipPlanes; } + //! @return TRUE if half-float textures are supported by OpenGl. + Standard_Boolean HasHalfFloatTextures() const { return myHasHalfFloatTextures; } + //! @return TRUE if ray tracing mode is supported Standard_Boolean HasRayTracing() const { return myHasRayTracing; } @@ -583,12 +593,18 @@ public: //! @name methods to alter or retrieve current state //! Switch read buffer, wrapper for ::glReadBuffer(). Standard_EXPORT void SetReadBuffer (const Standard_Integer theReadBuffer); - //! Return active draw buffer. - Standard_Integer DrawBuffer() { return myDrawBuffer; } + //! Return active draw buffer attached to a render target referred by layout location. + Standard_Integer DrawBuffer (const Standard_Integer theLayoutIdx = 0) + { + return myDrawBuffers.IsBound (theLayoutIdx) ? myDrawBuffers.Value (theLayoutIdx) : GL_NONE; + } //! Switch draw buffer, wrapper for ::glDrawBuffer(). Standard_EXPORT void SetDrawBuffer (const Standard_Integer theDrawBuffer); + //! Switch draw buffer, wrapper for ::glDrawBuffers (GLsizei, const GLenum*). + Standard_EXPORT void SetDrawBuffers (const Standard_Integer theNb, const Standard_Integer* theDrawBuffers); + //! Switch read/draw buffers. void SetReadDrawBuffer (const Standard_Integer theBuffer) { @@ -628,7 +644,6 @@ public: //! @name methods to alter or retrieve current state //! Setup current shading material. Standard_EXPORT void SetShadingMaterial (const OpenGl_AspectFace* theAspect, const Handle(Graphic3d_PresentationAttributes)& theHighlight, - const Standard_Boolean theUseDepthWrite, Standard_Integer& theRenderingPassFlags); //! Setup current color. @@ -723,26 +738,28 @@ public: //! @name core profiles public: //! @name extensions - Standard_Boolean hasHighp; //!< highp in GLSL ES fragment shader is supported - Standard_Boolean hasUintIndex; //!< GLuint for index buffer is supported (always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_element_index_uint) - Standard_Boolean hasTexRGBA8; //!< always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_rgb8_rgba8 - Standard_Boolean arbNPTW; //!< GL_ARB_texture_non_power_of_two - Standard_Boolean arbTexRG; //!< GL_ARB_texture_rg - Standard_Boolean arbTexFloat; //!< GL_ARB_texture_float (on desktop OpenGL - since 3.0 or as extension GL_ARB_texture_float; on OpenGL ES - since 3.0) - OpenGl_ArbTexBindless* arbTexBindless; //!< GL_ARB_bindless_texture - OpenGl_ArbTBO* arbTBO; //!< GL_ARB_texture_buffer_object - Standard_Boolean arbTboRGB32; //!< GL_ARB_texture_buffer_object_rgb32 (3-component TBO), in core since 4.0 - OpenGl_ArbIns* arbIns; //!< GL_ARB_draw_instanced - OpenGl_ArbDbg* arbDbg; //!< GL_ARB_debug_output - OpenGl_ArbFBO* arbFBO; //!< GL_ARB_framebuffer_object - OpenGl_ArbFBOBlit* arbFBOBlit; //!< glBlitFramebuffer function, moved out from OpenGl_ArbFBO structure for compatibility with OpenGL ES 2.0 - Standard_Boolean extFragDepth; //!< GL_EXT_frag_depth on OpenGL ES 2.0 (gl_FragDepthEXT built-in variable, before OpenGL ES 3.0) - OpenGl_ExtGS* extGS; //!< GL_EXT_geometry_shader4 - Standard_Boolean extBgra; //!< GL_EXT_bgra or GL_EXT_texture_format_BGRA8888 on OpenGL ES - Standard_Boolean extAnis; //!< GL_EXT_texture_filter_anisotropic - Standard_Boolean extPDS; //!< GL_EXT_packed_depth_stencil - Standard_Boolean atiMem; //!< GL_ATI_meminfo - Standard_Boolean nvxMem; //!< GL_NVX_gpu_memory_info + Standard_Boolean hasHighp; //!< highp in GLSL ES fragment shader is supported + Standard_Boolean hasUintIndex; //!< GLuint for index buffer is supported (always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_element_index_uint) + Standard_Boolean hasTexRGBA8; //!< always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_rgb8_rgba8 + Standard_Boolean arbNPTW; //!< GL_ARB_texture_non_power_of_two + Standard_Boolean arbTexRG; //!< GL_ARB_texture_rg + Standard_Boolean arbTexFloat; //!< GL_ARB_texture_float (on desktop OpenGL - since 3.0 or as extension GL_ARB_texture_float; on OpenGL ES - since 3.0) + Standard_Boolean arbTexHalfFloat; //!< GL_ARB_half_float_pixel (on desktop OpenGL - since 3.0 or as extension GL_ARB_half_float_pixel; on OpenGL ES - since 3.0 or as extension GL_OES_texture_half_float) + Standard_Boolean arbSampleShading;//!< GL_ARB_sample_shading + OpenGl_ArbTexBindless* arbTexBindless; //!< GL_ARB_bindless_texture + OpenGl_ArbTBO* arbTBO; //!< GL_ARB_texture_buffer_object + Standard_Boolean arbTboRGB32; //!< GL_ARB_texture_buffer_object_rgb32 (3-component TBO), in core since 4.0 + OpenGl_ArbIns* arbIns; //!< GL_ARB_draw_instanced + OpenGl_ArbDbg* arbDbg; //!< GL_ARB_debug_output + OpenGl_ArbFBO* arbFBO; //!< GL_ARB_framebuffer_object + OpenGl_ArbFBOBlit* arbFBOBlit; //!< glBlitFramebuffer function, moved out from OpenGl_ArbFBO structure for compatibility with OpenGL ES 2.0 + Standard_Boolean extFragDepth; //!< GL_EXT_frag_depth on OpenGL ES 2.0 (gl_FragDepthEXT built-in variable, before OpenGL ES 3.0) + OpenGl_ExtGS* extGS; //!< GL_EXT_geometry_shader4 + Standard_Boolean extBgra; //!< GL_EXT_bgra or GL_EXT_texture_format_BGRA8888 on OpenGL ES + Standard_Boolean extAnis; //!< GL_EXT_texture_filter_anisotropic + Standard_Boolean extPDS; //!< GL_EXT_packed_depth_stencil + Standard_Boolean atiMem; //!< GL_ATI_meminfo + Standard_Boolean nvxMem; //!< GL_NVX_gpu_memory_info public: //! @name public properties tracking current state @@ -777,6 +794,7 @@ private: // context info typedef NCollection_Shared< NCollection_DataMap > OpenGl_DelayReleaseMap; typedef NCollection_Shared< NCollection_DataMap > OpenGl_ResourcesMap; typedef NCollection_Shared< NCollection_List > OpenGl_ResourcesStack; + typedef NCollection_SparseArray OpenGl_DrawBuffers; Handle(OpenGl_ResourcesMap) mySharedResources; //!< shared resources with unique identification key Handle(OpenGl_DelayReleaseMap) myDelayed; //!< shared resources for delayed release @@ -792,6 +810,7 @@ private: // context info Standard_Integer myMaxTexDim; //!< value for GL_MAX_TEXTURE_SIZE Standard_Integer myMaxClipPlanes; //!< value for GL_MAX_CLIP_PLANES Standard_Integer myMaxMsaaSamples; //!< value for GL_MAX_SAMPLES + Standard_Integer myMaxDrawBuffers; //!< value for GL_MAX_DRAW_BUFFERS Standard_Integer myGlVerMajor; //!< cached GL version major number Standard_Integer myGlVerMinor; //!< cached GL version minor number Standard_Boolean myIsInitialized; //!< flag indicates initialization state @@ -799,6 +818,7 @@ private: // context info Standard_Boolean myIsGlNormalizeEnabled; //!< GL_NORMALIZE flag //!< Used to tell OpenGl that normals should be normalized + Standard_Boolean myHasHalfFloatTextures; //! indicates whether half-float textures are supported Standard_Boolean myHasRayTracing; //! indicates whether ray tracing mode is supported Standard_Boolean myHasRayTracingTextures; //! indicates whether textures in ray tracing mode are supported Standard_Boolean myHasRayTracingAdaptiveSampling; //! indicates whether adaptive screen sampling in ray tracing mode is supported @@ -817,7 +837,7 @@ private: //! @name fields tracking current state Standard_Integer myPolygonMode; //!< currently used polygon rasterization mode (glPolygonMode) bool myToCullBackFaces; //!< back face culling mode enabled state (glIsEnabled (GL_CULL_FACE)) Standard_Integer myReadBuffer; //!< current read buffer - Standard_Integer myDrawBuffer; //!< current draw buffer + OpenGl_DrawBuffers myDrawBuffers; //!< current draw buffers unsigned int myDefaultVao; //!< default Vertex Array Object Standard_Boolean myIsGlDebugCtx; //!< debug context initialization state TCollection_AsciiString myVendor; //!< Graphics Driver's vendor diff --git a/src/OpenGl/OpenGl_Element.hxx b/src/OpenGl/OpenGl_Element.hxx index b3354212b6..bbfb52a248 100644 --- a/src/OpenGl/OpenGl_Element.hxx +++ b/src/OpenGl/OpenGl_Element.hxx @@ -68,7 +68,7 @@ public: RenderFiltered (const Handle(OpenGl_Workspace)& theWorkspace, const Handle(OpenGl_RenderFilter)& theFilter) const { - if (!theFilter.IsNull() && !theFilter->CanRender (this)) + if (!theFilter.IsNull() && !theFilter->ShouldRender (theWorkspace, this)) { return Standard_False; } diff --git a/src/OpenGl/OpenGl_FrameBuffer.cxx b/src/OpenGl/OpenGl_FrameBuffer.cxx index 6f686a48d4..c9abe4ff53 100644 --- a/src/OpenGl/OpenGl_FrameBuffer.cxx +++ b/src/OpenGl/OpenGl_FrameBuffer.cxx @@ -18,6 +18,8 @@ #include #include +#include + IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer,OpenGl_Resource) namespace @@ -64,6 +66,68 @@ namespace return false; } + //! Determine data type from texture sized format. + static bool getColorDataFormat (GLint theTextFormat, + GLenum& thePixelFormat, + GLenum& theDataType) + { + switch (theTextFormat) + { + case GL_RGBA32F: + { + thePixelFormat = GL_RGBA; + theDataType = GL_FLOAT; + return true; + } + case GL_R32F: + { + thePixelFormat = GL_RED; + theDataType = GL_FLOAT; + return true; + } + case GL_RGBA16F: + { + thePixelFormat = GL_RGBA; + theDataType = GL_HALF_FLOAT; + return true; + } + case GL_R16F: + { + thePixelFormat = GL_RED; + theDataType = GL_HALF_FLOAT; + return true; + } + case GL_RGBA8: + { + thePixelFormat = GL_RGBA; + theDataType = GL_UNSIGNED_INT; + return true; + } + case GL_RGBA: + { + thePixelFormat = GL_RGBA; + theDataType = GL_UNSIGNED_BYTE; + return true; + } + } + return false; + } + + //! Checks whether two format arrays are equal or not. + static bool operator== (const OpenGl_ColorFormats& theFmt1, + const OpenGl_ColorFormats& theFmt2) + { + if (theFmt1.Length() != theFmt2.Length()) + return false; + OpenGl_ColorFormats::Iterator anIt1 (theFmt1); + OpenGl_ColorFormats::Iterator anIt2 (theFmt1); + for (; anIt1.More(); anIt1.Next(), anIt2.Next()) + { + if (anIt1.Value() != anIt2.Value()) + return false; + } + return true; + } } // ======================================================================= @@ -74,16 +138,16 @@ OpenGl_FrameBuffer::OpenGl_FrameBuffer() : myVPSizeX (0), myVPSizeY (0), myNbSamples (0), - myColorFormat (GL_RGBA8), myDepthFormat (GL_DEPTH24_STENCIL8), myGlFBufferId (NO_FRAMEBUFFER), myGlColorRBufferId (NO_RENDERBUFFER), myGlDepthRBufferId (NO_RENDERBUFFER), myIsOwnBuffer (false), - myColorTexture (new OpenGl_Texture()), + myIsOwnDepth (false), myDepthStencilTexture (new OpenGl_Texture()) { - // + myColorFormats.Append (GL_RGBA8); + myColorTextures.Append (new OpenGl_Texture()); } // ======================================================================= @@ -100,15 +164,49 @@ OpenGl_FrameBuffer::~OpenGl_FrameBuffer() // purpose : // ======================================================================= Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext, - const GLsizei theSizeX, - const GLsizei theSizeY, - const GLint theColorFormat, - const GLint theDepthFormat, - const GLsizei theNbSamples) + const GLsizei theSizeX, + const GLsizei theSizeY, + const GLint theColorFormat, + const GLint theDepthFormat, + const GLsizei theNbSamples) { - myColorFormat = theColorFormat; - myDepthFormat = theDepthFormat; - myNbSamples = theNbSamples; + OpenGl_ColorFormats aColorFormats; + + aColorFormats.Append (theColorFormat); + + return Init (theGlContext, theSizeX, theSizeY, aColorFormats, theDepthFormat, theNbSamples); +} + +// ======================================================================= +// function : Init +// purpose : +// ======================================================================= +Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext, + const GLsizei theSizeX, + const GLsizei theSizeY, + const OpenGl_ColorFormats& theColorFormats, + const Handle(OpenGl_Texture)& theDepthStencilTexture, + const GLsizei theNbSamples) +{ + myColorFormats = theColorFormats; + + OpenGl_TextureArray aTextures (myColorTextures); + if (!myColorTextures.IsEmpty()) + { + OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); + for (; aTextureIt.More(); aTextureIt.Next()) + { + aTextureIt.Value()->Release (theGlContext.operator->()); + } + myColorTextures.Clear(); + } + for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength) + { + myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture()); + } + + myDepthFormat = theDepthStencilTexture->GetFormat(); + myNbSamples = theNbSamples; if (theGlContext->arbFBO == NULL) { return Standard_False; @@ -116,12 +214,14 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo // clean up previous state Release (theGlContext.operator->()); - if (myColorFormat == 0 + if (std::count (myColorFormats.begin(), myColorFormats.end(), 0) == myColorFormats.Length() && myDepthFormat == 0) { return Standard_False; } + myDepthStencilTexture = theDepthStencilTexture; + myIsOwnDepth = false; myIsOwnBuffer = true; // setup viewport sizes as is @@ -133,11 +233,147 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo // Create the textures (will be used as color buffer and depth-stencil buffer) if (theNbSamples != 0) { - if (myColorFormat != 0 - && !myColorTexture ->Init2DMultisample (theGlContext, theNbSamples, myColorFormat, aSizeX, aSizeY)) + for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx) { - Release (theGlContext.operator->()); - return Standard_False; + const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx); + const GLint aColorFormat = myColorFormats (aColorBufferIdx); + if (aColorFormat != 0 + && !aColorTexture->Init2DMultisample (theGlContext, theNbSamples, + aColorFormat, aSizeX, aSizeY)) + { + Release (theGlContext.operator->()); + return Standard_False; + } + } + } + else + { + GLenum aPixelFormat = 0; + GLenum aDataType = 0; + for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx) + { + const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx); + const GLint aColorFormat = myColorFormats (aColorBufferIdx); + if (aColorFormat != 0 + && getColorDataFormat (aColorFormat, aPixelFormat, aDataType) + && !aColorTexture->Init (theGlContext, aColorFormat, + aPixelFormat, aDataType, + aSizeX, aSizeY, Graphic3d_TOT_2D)) + { + Release (theGlContext.operator->()); + return Standard_False; + } + } + } + + // Build FBO and setup it as texture + 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->IsValid()) + { + #ifdef GL_DEPTH_STENCIL_ATTACHMENT + 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); + #endif + } + else if (myGlDepthRBufferId != NO_RENDERBUFFER) + { + theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, myGlDepthRBufferId); + } + if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + Release (theGlContext.operator->()); + return Standard_False; + } + + UnbindBuffer (theGlContext); + return Standard_True; +} + +// ======================================================================= +// function : Init +// purpose : +// ======================================================================= +Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext, + const GLsizei theSizeX, + const GLsizei theSizeY, + const OpenGl_ColorFormats& theColorFormats, + const GLint theDepthFormat, + const GLsizei theNbSamples) +{ + myColorFormats = theColorFormats; + + OpenGl_TextureArray aTextures (myColorTextures); + if (!myColorTextures.IsEmpty()) + { + OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); + for (; aTextureIt.More(); aTextureIt.Next()) + { + aTextureIt.Value()->Release (theGlContext.operator->()); + } + myColorTextures.Clear(); + } + for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength) + { + myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture()); + } + + myDepthFormat = theDepthFormat; + myNbSamples = theNbSamples; + if (theGlContext->arbFBO == NULL) + { + return Standard_False; + } + + // clean up previous state + Release (theGlContext.operator->()); + if (std::count (myColorFormats.begin(), myColorFormats.end(), 0) == myColorFormats.Length() + && myDepthFormat == 0) + { + return Standard_False; + } + + myIsOwnBuffer = true; + myIsOwnDepth = true; + + // setup viewport sizes as is + myVPSizeX = theSizeX; + myVPSizeY = theSizeY; + const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2; + const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2; + + // Create the textures (will be used as color buffer and depth-stencil buffer) + if (theNbSamples != 0) + { + for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx) + { + const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx); + const GLint aColorFormat = myColorFormats (aColorBufferIdx); + if (aColorFormat != 0 + && !aColorTexture->Init2DMultisample (theGlContext, theNbSamples, + aColorFormat, aSizeX, aSizeY)) + { + Release (theGlContext.operator->()); + return Standard_False; + } } if (myDepthFormat != 0 && !myDepthStencilTexture->Init2DMultisample (theGlContext, theNbSamples, myDepthFormat, aSizeX, aSizeY)) @@ -148,19 +384,25 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo } else { - if (myColorFormat != 0 - && !myColorTexture->Init (theGlContext, myColorFormat, - GL_RGBA, GL_UNSIGNED_BYTE, - aSizeX, aSizeY, Graphic3d_TOT_2D)) + GLenum aPixelFormat = 0; + GLenum aDataType = 0; + for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx) { - Release (theGlContext.operator->()); - return Standard_False; + const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx); + const GLint aColorFormat = myColorFormats (aColorBufferIdx); + if (aColorFormat != 0 + && getColorDataFormat (aColorFormat, aPixelFormat, aDataType) + && !aColorTexture->Init (theGlContext, aColorFormat, + aPixelFormat, aDataType, + aSizeX, aSizeY, Graphic3d_TOT_2D)) + { + Release (theGlContext.operator->()); + return Standard_False; + } } // extensions (GL_OES_packed_depth_stencil, GL_OES_depth_texture) + GL version might be used to determine supported formats // instead of just trying to create such texture - GLenum aPixelFormat = 0; - GLenum aDataType = 0; if (myDepthFormat != 0 && getDepthDataFormat (myDepthFormat, aPixelFormat, aDataType) && !myDepthStencilTexture->Init (theGlContext, myDepthFormat, @@ -185,11 +427,18 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo // Build FBO and setup it as texture theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId); theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId); - if (myColorTexture->IsValid()) + + for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx) { - theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - myColorTexture->GetTarget(), myColorTexture->TextureId(), 0); + 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->IsValid()) { #ifdef GL_DEPTH_STENCIL_ATTACHMENT @@ -218,7 +467,7 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo } // ======================================================================= -// function : Init +// function : InitLazy // purpose : // ======================================================================= Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext, @@ -228,16 +477,44 @@ Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& the const GLint theDepthFormat, const GLsizei theNbSamples) { - if (myVPSizeX == theViewportSizeX - && myVPSizeY == theViewportSizeY - && myColorFormat == theColorFormat - && myDepthFormat == theDepthFormat - && myNbSamples == theNbSamples) + OpenGl_ColorFormats aColorFormats; + + aColorFormats.Append (theColorFormat); + + return InitLazy (theGlContext, theViewportSizeX, theViewportSizeY, aColorFormats, theDepthFormat, theNbSamples); +} + +// ======================================================================= +// function : InitLazy +// purpose : +// ======================================================================= +Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext, + const GLsizei theViewportSizeX, + const GLsizei theViewportSizeY, + const OpenGl_ColorFormats& theColorFormats, + const GLint theDepthFormat, + const GLsizei theNbSamples) +{ + if (myVPSizeX == theViewportSizeX + && myVPSizeY == theViewportSizeY + && myColorFormats == theColorFormats + && myDepthFormat == theDepthFormat + && myNbSamples == theNbSamples) { return IsValid(); } - return Init (theGlContext, theViewportSizeX, theViewportSizeY, theColorFormat, theDepthFormat, theNbSamples); + return Init (theGlContext, theViewportSizeX, theViewportSizeY, theColorFormats, theDepthFormat, theNbSamples); +} + +// ======================================================================= +// function : InitLazy +// purpose : +// ======================================================================= +Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlCtx, + const OpenGl_FrameBuffer& theFbo) +{ + return InitLazy (theGlCtx, theFbo.myVPSizeX, theFbo.myVPSizeY, theFbo.myColorFormats, theFbo.myDepthFormat, theFbo.myNbSamples); } // ======================================================================= @@ -251,9 +528,22 @@ Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& t const GLint theDepthFormat, const GLuint theColorRBufferFromWindow) { - myColorFormat = theColorFormat; - myDepthFormat = theDepthFormat; - myNbSamples = 0; + myColorFormats.Clear(); + myColorFormats.Append (theColorFormat); + if (!myColorTextures.IsEmpty()) + { + Handle(OpenGl_Texture) aTexutre = myColorTextures.First(); + OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); + for (; aTextureIt.More(); aTextureIt.Next()) + { + aTextureIt.Value()->Release (theGlCtx.operator->()); + } + myColorTextures.Clear(); + myColorTextures.Append (aTexutre); + } + + myDepthFormat = theDepthFormat; + myNbSamples = 0; if (theGlCtx->arbFBO == NULL) { return Standard_False; @@ -263,6 +553,7 @@ Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& t Release (theGlCtx.operator->()); myIsOwnBuffer = true; + myIsOwnDepth = true; // setup viewport sizes as is myVPSizeX = theSizeX; @@ -275,11 +566,11 @@ Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& t { myGlColorRBufferId = theColorRBufferFromWindow; } - else if (myColorFormat != 0) + else if (theColorFormat != 0) { theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId); theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId); - theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myColorFormat, aSizeX, aSizeY); + theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, theColorFormat, aSizeX, aSizeY); } if (myDepthFormat != 0) @@ -344,17 +635,19 @@ Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& GLint aColorId = 0; GLint aDepthType = 0; GLint aDepthId = 0; + theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aColorType); theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aDepthType); myGlFBufferId = GLuint(anFbo); myIsOwnBuffer = false; + myIsOwnDepth = false; if (aColorType == GL_RENDERBUFFER) { theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId); myGlColorRBufferId = aColorId; } - else if (aColorType != GL_NONE) + else if (aColorType != 0) { TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), color attachment of unsupported type has been skipped!"; theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, @@ -369,7 +662,7 @@ Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aDepthId); myGlDepthRBufferId = aDepthId; } - else if (aDepthType != GL_NONE) + else if (aDepthType != 0) { TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), depth attachment of unsupported type has been skipped!"; theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, @@ -422,8 +715,17 @@ void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx) myIsOwnBuffer = false; } - myColorTexture->Release (theGlCtx); - myDepthStencilTexture->Release (theGlCtx); + for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < NbColorBuffers(); ++aColorBufferIdx) + { + myColorTextures (aColorBufferIdx)->Release (theGlCtx); + } + + if (myIsOwnDepth) + { + myDepthStencilTexture->Release (theGlCtx); + + myIsOwnDepth = false; + } myVPSizeX = 0; myVPSizeY = 0; diff --git a/src/OpenGl/OpenGl_FrameBuffer.hxx b/src/OpenGl/OpenGl_FrameBuffer.hxx index 6baf4ff8b8..6f5c170883 100644 --- a/src/OpenGl/OpenGl_FrameBuffer.hxx +++ b/src/OpenGl/OpenGl_FrameBuffer.hxx @@ -19,14 +19,18 @@ #include #include +#include + class OpenGl_FrameBuffer; DEFINE_STANDARD_HANDLE(OpenGl_FrameBuffer, OpenGl_Resource) +//! Short declaration of useful collection types. +typedef NCollection_Vector OpenGl_ColorFormats; + //! Class implements FrameBuffer Object (FBO) resource //! intended for off-screen rendering. class OpenGl_FrameBuffer : public OpenGl_Resource { - public: //! Helpful constants @@ -35,7 +39,7 @@ public: public: - //! Empty constructor + //! Constructor. Standard_EXPORT OpenGl_FrameBuffer(); //! Destructor @@ -50,10 +54,16 @@ public: return myNbSamples; } + //! Number of color buffers. + GLsizei NbColorBuffers() const + { + return myColorTextures.Length(); + } + //! Return true if FBO has been created with color attachment. - bool HasColor() const + bool HasColor (const GLint theColorBufferIdx = 0) const { - return myColorFormat != 0; + return myColorFormats (theColorBufferIdx) != 0; } //! Return true if FBO has been created with depth attachment. @@ -65,13 +75,13 @@ public: //! Textures width. GLsizei GetSizeX() const { - return myColorTexture->SizeX(); + return myColorTextures (0)->SizeX(); } //! Textures height. GLsizei GetSizeY() const { - return myColorTexture->SizeY(); + return myColorTextures (0)->SizeY(); } //! Viewport width. @@ -92,13 +102,20 @@ public: return isValidFrameBuffer(); } + Standard_EXPORT Standard_Boolean Init (const Handle(OpenGl_Context)& theGlCtx, + const GLsizei theSizeX, + const GLsizei theSizeY, + const OpenGl_ColorFormats& theColorFormats, + const Handle(OpenGl_Texture)& theDepthStencilTexture, + const GLsizei theNbSamples = 0); + //! Initialize FBO for rendering into textures. - //! @param theGlCtx currently bound OpenGL context - //! @param theSizeX texture width - //! @param theSizeY texture height - //! @param theColorFormat color texture sized format (0 means no color attachment), e.g. GL_RGBA8 - //! @param theDepthFormat depth-stencil texture sized format (0 means no depth attachment), e.g. GL_DEPTH24_STENCIL8 - //! @param theNbSamples MSAA number of samples (0 means normal texture) + //! @param theGlCtx currently bound OpenGL context + //! @param theSizeX texture width + //! @param theSizeY texture height + //! @param theColorFormat color texture sized format (0 means no color attachment), e.g. GL_RGBA8 + //! @param theDepthFormat depth-stencil texture sized format (0 means no depth attachment), e.g. GL_DEPTH24_STENCIL8 + //! @param theNbSamples MSAA number of samples (0 means normal texture) //! @return true on success Standard_EXPORT Standard_Boolean Init (const Handle(OpenGl_Context)& theGlCtx, const GLsizei theSizeX, @@ -107,6 +124,21 @@ public: const GLint theDepthFormat, const GLsizei theNbSamples = 0); + //! Initialize FBO for rendering into textures. + //! @param theGlCtx currently bound OpenGL context + //! @param theSizeX texture width + //! @param theSizeY texture height + //! @param theColorFormats color texture sized format (0 means no color attachment), e.g. GL_RGBA8 + //! @param theDepthFormat depth-stencil texture sized format (0 means no depth attachment), e.g. GL_DEPTH24_STENCIL8 + //! @param theNbSamples MSAA number of samples (0 means normal texture) + //! @return true on success + Standard_EXPORT Standard_Boolean Init (const Handle(OpenGl_Context)& theGlCtx, + const GLsizei theSizeX, + const GLsizei theSizeY, + const OpenGl_ColorFormats& theColorFormats, + const GLint theDepthFormat, + const GLsizei theNbSamples = 0); + //! (Re-)initialize FBO with specified dimensions. Standard_EXPORT Standard_Boolean InitLazy (const Handle(OpenGl_Context)& theGlCtx, const GLsizei theViewportSizeX, @@ -115,20 +147,25 @@ public: const GLint theDepthFormat, const GLsizei theNbSamples = 0); + //! (Re-)initialize FBO with specified dimensions. + Standard_EXPORT Standard_Boolean InitLazy (const Handle(OpenGl_Context)& theGlCtx, + const GLsizei theViewportSizeX, + const GLsizei theViewportSizeY, + const OpenGl_ColorFormats& theColorFormats, + const GLint theDepthFormat, + const GLsizei theNbSamples = 0); + //! (Re-)initialize FBO with properties taken from another FBO. - Standard_Boolean InitLazy (const Handle(OpenGl_Context)& theGlCtx, - const OpenGl_FrameBuffer& theFbo) - { - return InitLazy (theGlCtx, theFbo.myVPSizeX, theFbo.myVPSizeY, theFbo.myColorFormat, theFbo.myDepthFormat, theFbo.myNbSamples); - } + Standard_EXPORT Standard_Boolean InitLazy (const Handle(OpenGl_Context)& theGlCtx, + const OpenGl_FrameBuffer& theFbo); //! (Re-)initialize FBO with specified dimensions. //! The Render Buffer Objects will be used for Color, Depth and Stencil attachments (as opposite to textures). - //! @param theGlCtx currently bound OpenGL context - //! @param theSizeX render buffer width - //! @param theSizeY render buffer height - //! @param theColorFormat color render buffer sized format, e.g. GL_RGBA8 - //! @param theDepthFormat depth-stencil render buffer sized format, e.g. GL_DEPTH24_STENCIL8 + //! @param theGlCtx currently bound OpenGL context + //! @param theSizeX render buffer width + //! @param theSizeY render buffer height + //! @param theColorFormat color render buffer sized format, e.g. GL_RGBA8 + //! @param theDepthFormat depth-stencil render buffer sized format, e.g. GL_DEPTH24_STENCIL8 //! @param theColorRBufferFromWindow when specified - should be ID of already initialized RB object, which will be released within this class Standard_EXPORT Standard_Boolean InitWithRB (const Handle(OpenGl_Context)& theGlCtx, const GLsizei theSizeX, @@ -161,9 +198,9 @@ public: Standard_EXPORT virtual void UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx); //! Returns the color texture. - inline const Handle(OpenGl_Texture)& ColorTexture() const + inline const Handle(OpenGl_Texture)& ColorTexture (const GLint theColorBufferIdx = 0) const { - return myColorTexture; + return myColorTextures (theColorBufferIdx); } //! Returns the depth-stencil texture. @@ -193,16 +230,19 @@ protected: protected: + typedef NCollection_Vector OpenGl_TextureArray; + GLsizei myVPSizeX; //!< viewport width (should be <= texture width) GLsizei myVPSizeY; //!< viewport height (should be <= texture height) GLsizei myNbSamples; //!< number of MSAA samples - GLint myColorFormat; //!< sized format for color texture, GL_RGBA8 by default + OpenGl_ColorFormats myColorFormats; //!< sized format for color texture, GL_RGBA8 by default GLint myDepthFormat; //!< sized format for depth-stencil texture, GL_DEPTH24_STENCIL8 by default GLuint myGlFBufferId; //!< FBO object ID 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 - Handle(OpenGl_Texture) myColorTexture; //!< color texture object + bool myIsOwnDepth; //!< flag indicating that FBO should be deallocated by this class + OpenGl_TextureArray myColorTextures; //!< color texture objects Handle(OpenGl_Texture) myDepthStencilTexture; //!< depth-stencil texture object public: diff --git a/src/OpenGl/OpenGl_GlFunctions.hxx b/src/OpenGl/OpenGl_GlFunctions.hxx index 37af4709af..05e0b27463 100644 --- a/src/OpenGl/OpenGl_GlFunctions.hxx +++ b/src/OpenGl/OpenGl_GlFunctions.hxx @@ -186,6 +186,45 @@ #define GL_DEBUG_SEVERITY_HIGH 0x9146 #define GL_DEBUG_SEVERITY_MEDIUM 0x9147 #define GL_DEBUG_SEVERITY_LOW 0x9148 + + // GL_EXT_draw_buffers + #define GL_MAX_COLOR_ATTACHMENTS 0x8CDF + #define GL_MAX_DRAW_BUFFERS 0x8824 + #define GL_DRAW_BUFFER0 0x8825 + #define GL_DRAW_BUFFER1 0x8826 + #define GL_DRAW_BUFFER2 0x8827 + #define GL_DRAW_BUFFER3 0x8828 + #define GL_DRAW_BUFFER4 0x8829 + #define GL_DRAW_BUFFER5 0x882A + #define GL_DRAW_BUFFER6 0x882B + #define GL_DRAW_BUFFER7 0x882C + #define GL_DRAW_BUFFER8 0x882D + #define GL_DRAW_BUFFER9 0x882E + #define GL_DRAW_BUFFER10 0x882F + #define GL_DRAW_BUFFER11 0x8830 + #define GL_DRAW_BUFFER12 0x8831 + #define GL_DRAW_BUFFER13 0x8832 + #define GL_DRAW_BUFFER14 0x8833 + #define GL_DRAW_BUFFER15 0x8834 + #define GL_COLOR_ATTACHMENT0 0x8CE0 + #define GL_COLOR_ATTACHMENT1 0x8CE1 + #define GL_COLOR_ATTACHMENT2 0x8CE2 + #define GL_COLOR_ATTACHMENT3 0x8CE3 + #define GL_COLOR_ATTACHMENT4 0x8CE4 + #define GL_COLOR_ATTACHMENT5 0x8CE5 + #define GL_COLOR_ATTACHMENT6 0x8CE6 + #define GL_COLOR_ATTACHMENT7 0x8CE7 + #define GL_COLOR_ATTACHMENT8 0x8CE8 + #define GL_COLOR_ATTACHMENT9 0x8CE9 + #define GL_COLOR_ATTACHMENT10 0x8CEA + #define GL_COLOR_ATTACHMENT11 0x8CEB + #define GL_COLOR_ATTACHMENT12 0x8CEC + #define GL_COLOR_ATTACHMENT13 0x8CED + #define GL_COLOR_ATTACHMENT14 0x8CEE + #define GL_COLOR_ATTACHMENT15 0x8CEF + + // OES_texture_half_float + #define GL_HALF_FLOAT 0x8D61 #endif #if !defined(HAVE_EGL) && (defined(__ANDROID__) || defined(__QNX__) || defined(HAVE_GLES2) || defined(OCCT_UWP)) @@ -752,6 +791,9 @@ public: //! @name OpenGL ES 3.0 typedef void (*glTexImage3D_t)(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* data); glTexImage3D_t glTexImage3D; + typedef void (*glDrawBuffers_t)(GLsizei n, const GLenum* bufs); + glDrawBuffers_t glDrawBuffers; + public: //! @name OpenGL ES 3.1 typedef void (*glTexStorage2DMultisample_t)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); diff --git a/src/OpenGl/OpenGl_Layer.cxx b/src/OpenGl/OpenGl_Layer.cxx index c9bb46beeb..0e0554d4f5 100644 --- a/src/OpenGl/OpenGl_Layer.cxx +++ b/src/OpenGl/OpenGl_Layer.cxx @@ -687,7 +687,9 @@ void OpenGl_Layer::Render (const Handle(OpenGl_Workspace)& theWorkspace, theWorkspace->SetPolygonOffset (myLayerSettings.PolygonOffset()); // handle depth write - theWorkspace->UseDepthWrite() = myLayerSettings.ToEnableDepthWrite(); + theWorkspace->UseDepthWrite() = myLayerSettings.ToEnableDepthWrite() + && theDefaultSettings.DepthMask == GL_TRUE; + glDepthMask (theWorkspace->UseDepthWrite() ? GL_TRUE : GL_FALSE); const Standard_Boolean hasLocalCS = !myLayerSettings.OriginTransformation().IsNull(); diff --git a/src/OpenGl/OpenGl_Layer.hxx b/src/OpenGl/OpenGl_Layer.hxx index 57edf25f96..6a215e20ba 100644 --- a/src/OpenGl/OpenGl_Layer.hxx +++ b/src/OpenGl/OpenGl_Layer.hxx @@ -27,7 +27,6 @@ #include #include - struct OpenGl_GlobalLayerSettings { GLint DepthFunc; diff --git a/src/OpenGl/OpenGl_LayerList.cxx b/src/OpenGl/OpenGl_LayerList.cxx index 5f6c61973c..d239cc1f9b 100644 --- a/src/OpenGl/OpenGl_LayerList.cxx +++ b/src/OpenGl/OpenGl_LayerList.cxx @@ -13,10 +13,14 @@ // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. -#include +#include +#include #include +#include #include +#include +#include #include #include @@ -31,7 +35,9 @@ OpenGl_LayerList::OpenGl_LayerList (const Standard_Integer theNbPriorities) myNbPriorities (theNbPriorities), myNbStructures (0), myImmediateNbStructures (0), - myModifStateOfRaytraceable (0) + myModifStateOfRaytraceable (0), + myRenderOpaqueFilter (new OpenGl_OpaqueFilter()), + myRenderTranspFilter (new OpenGl_TransparentFilter()) { // insert default priority layers myLayers.Append (OpenGl_Layer (myNbPriorities)); @@ -50,6 +56,8 @@ OpenGl_LayerList::OpenGl_LayerList (const Standard_Integer theNbPriorities) myLayerIds.Bind (Graphic3d_ZLayerId_TopOSD, myLayers.Upper()); myDefaultLayerIndex = myLayerIds.Find (Graphic3d_ZLayerId_Default); + + myTransparentToProcess.Allocate (myLayers.Length()); } //======================================================================= @@ -76,6 +84,8 @@ void OpenGl_LayerList::AddLayer (const Graphic3d_ZLayerId theLayerId) // add the new layer myLayers.Append (OpenGl_Layer (myNbPriorities)); myLayerIds.Bind (theLayerId, myLayers.Length()); + + myTransparentToProcess.Allocate (myLayers.Length()); } //======================================================================= @@ -128,6 +138,8 @@ void OpenGl_LayerList::RemoveLayer (const Graphic3d_ZLayerId theLayerId) } myDefaultLayerIndex = myLayerIds.Find (Graphic3d_ZLayerId_Default); + + myTransparentToProcess.Allocate (myLayers.Length()); } //======================================================================= @@ -378,17 +390,39 @@ void OpenGl_LayerList::SetLayerSettings (const Graphic3d_ZLayerId theLaye //======================================================================= void OpenGl_LayerList::Render (const Handle(OpenGl_Workspace)& theWorkspace, const Standard_Boolean theToDrawImmediate, - const OpenGl_LayerFilter theLayersToProcess) const + const OpenGl_LayerFilter theLayersToProcess, + OpenGl_FrameBuffer* theReadDrawFbo, + OpenGl_FrameBuffer* theOitAccumFbo) const { + // Remember global settings for glDepth function and write mask. OpenGl_GlobalLayerSettings aDefaultSettings; const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext(); aCtx->core11fwd->glGetIntegerv (GL_DEPTH_FUNC, &aDefaultSettings.DepthFunc); aCtx->core11fwd->glGetBooleanv (GL_DEPTH_WRITEMASK, &aDefaultSettings.DepthMask); + // Two render filters are used to support transparency draw. Opaque filter accepts + // only non-transparent OpenGl elements of a layer and counts number of skipped + // transparent ones. If the counter has positive value the layer is added into + // transparency post-processing stack. At the end of drawing or once the depth + // buffer is to be cleared the layers in the stack should be drawn using + // blending and depth mask settings and another transparency filter which accepts + // only transparent OpenGl elements of a layer. The stack + // was preallocated before going into this method and has enough space to keep + // maximum number of references to layers, therefore it will not increase memory + // fragmentation during regular rendering. + const Handle(OpenGl_RenderFilter) aPrevFilter = theWorkspace->GetRenderFilter(); + myRenderOpaqueFilter->SetPreviousFilter (aPrevFilter); + myRenderTranspFilter->SetPreviousFilter (aPrevFilter); + theWorkspace->SetRenderFilter (myRenderOpaqueFilter); + + myTransparentToProcess.Clear(); + + OpenGl_LayerStack ::iterator aStackIter (myTransparentToProcess.Origin()); + OpenGl_SequenceOfLayers::iterator anIts (myLayers.begin()); Standard_Integer aSeqId = myLayers.Lower(); - bool toClearDepth = false; - for (OpenGl_SequenceOfLayers::Iterator anIts (myLayers); anIts.More(); anIts.Next(), ++aSeqId) + bool toClearDepth = false; + for (; anIts != myLayers.end(); ++anIts, ++aSeqId) { if (theLayersToProcess == OpenGl_LF_Bottom) { @@ -403,28 +437,54 @@ void OpenGl_LayerList::Render (const Handle(OpenGl_Workspace)& theWorkspace, if (aSeqId != myDefaultLayerIndex) continue; } - const OpenGl_Layer& aLayer = anIts.Value(); + const OpenGl_Layer& aLayer = (*anIts); if (aLayer.IsImmediate() != theToDrawImmediate) { continue; } else if (aLayer.NbStructures() < 1) { - // make sure to clear depth of previous layers even if layer has no structures + // Make sure to clear depth of previous layers even if layer has no structures. toClearDepth = toClearDepth || aLayer.LayerSettings().ToClearDepth(); continue; } - // depth buffers + // At this point the depth buffer may be set to clear by + // previous configuration of layers or configuration of the + // current layer. Additional rendering pass to handle transparent + // elements of recently drawn layers require use of current depth + // buffer so we put remaining layers for processing as one bunch before + // erasing the depth buffer. if (toClearDepth || aLayer.LayerSettings().ToClearDepth()) { + if (!myTransparentToProcess.IsEmpty()) + { + renderTransparent (theWorkspace, aStackIter, aDefaultSettings, theReadDrawFbo, theOitAccumFbo); + } + toClearDepth = false; glDepthMask (GL_TRUE); glClear (GL_DEPTH_BUFFER_BIT); } + // Render opaque OpenGl elements of a layer and count the number of skipped. + // If a layer has skipped (e.g. transparent) elements it should be added into + // the transparency post-processing stack. + myRenderOpaqueFilter->SetSkippedCounter (0); + aLayer.Render (theWorkspace, aDefaultSettings); + + if (myRenderOpaqueFilter->NbSkipped() > 0) + { + myTransparentToProcess.Push (&aLayer); + } + } + + // Before finishing process the remaining collected layers with transparency. + if (!myTransparentToProcess.IsEmpty()) + { + renderTransparent (theWorkspace, aStackIter, aDefaultSettings, theReadDrawFbo, theOitAccumFbo); } if (toClearDepth) @@ -435,4 +495,232 @@ void OpenGl_LayerList::Render (const Handle(OpenGl_Workspace)& theWorkspace, aCtx->core11fwd->glDepthMask (aDefaultSettings.DepthMask); aCtx->core11fwd->glDepthFunc (aDefaultSettings.DepthFunc); + + theWorkspace->SetRenderFilter (aPrevFilter); +} + +//======================================================================= +//function : renderTransparent +//purpose : Render transparent objects using blending operator. +//======================================================================= +void OpenGl_LayerList::renderTransparent (const Handle(OpenGl_Workspace)& theWorkspace, + OpenGl_LayerStack::iterator& theLayerIter, + const OpenGl_GlobalLayerSettings& theGlobalSettings, + 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. + if (theLayerIter == myTransparentToProcess.Back()) + { + return; + } + + const Handle(OpenGl_Context) aCtx = theWorkspace->GetGlContext(); + const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager(); + const OpenGl_View* aView = theWorkspace->View(); + const float aOitDepthWeight = aView ? aView->RenderingParams().OitDepthWeight : 0.0f; + + theWorkspace->SetRenderFilter (myRenderTranspFilter); + + aCtx->core11fwd->glEnable (GL_BLEND); + + if (isEnabledOit) + { + aManager->SetOitState (true, aOitDepthWeight); + + theOitAccumFbo->BindBuffer (aCtx); + + static const Standard_Integer aDrawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; + aCtx->SetDrawBuffers (2, aDrawBuffers); + aCtx->core11fwd->glClearColor (0.f, 0.f, 0.f, 1.f); + aCtx->core11fwd->glClear (GL_COLOR_BUFFER_BIT); + aCtx->core15fwd->glBlendFuncSeparate (GL_ONE, GL_ONE, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); + } + else + { + aCtx->core11fwd->glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + // 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. + OpenGl_GlobalLayerSettings aGlobalSettings = theGlobalSettings; + aGlobalSettings.DepthMask = GL_FALSE; + aCtx->core11fwd->glDepthMask (GL_FALSE); + + for (; theLayerIter != myTransparentToProcess.Back(); ++theLayerIter) + { + (*theLayerIter)->Render (theWorkspace, aGlobalSettings); + } + + // Revert state of rendering. + if (isEnabledOit) + { + aManager->SetOitState (false, aOitDepthWeight); + + theOitAccumFbo->UnbindBuffer (aCtx); + + if (theReadDrawFbo) + { + theReadDrawFbo->BindBuffer (aCtx); + } + + static const Standard_Integer aDrawBuffers[] = { GL_COLOR_ATTACHMENT0 }; + + aCtx->SetDrawBuffers (1, aDrawBuffers); + } + + theWorkspace->SetRenderFilter (myRenderOpaqueFilter); + + if (isEnabledOit) + { + const Standard_Boolean isMSAA = theReadDrawFbo && theReadDrawFbo->NbSamples() > 0; + + OpenGl_VertexBuffer* aVerts = theWorkspace->View()->initBlitQuad (Standard_False); + + if (aVerts->IsValid() && aManager->BindOitCompositingProgram (isMSAA)) + { + 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_Texture) aTextureBack = theWorkspace->DisableTexture(); + + theOitAccumFbo->ColorTexture (0)->Bind (aCtx, GL_TEXTURE0 + 0); + theOitAccumFbo->ColorTexture (1)->Bind (aCtx, GL_TEXTURE0 + 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 (0)->Unbind (aCtx, GL_TEXTURE0 + 0); + theOitAccumFbo->ColorTexture (1)->Unbind (aCtx, GL_TEXTURE0 + 1); + aCtx->BindProgram (NULL); + + if (!aTextureBack.IsNull()) + { + theWorkspace->EnableTexture (aTextureBack); + } + } + else + { + TCollection_ExtendedString aMsg = TCollection_ExtendedString() + + "Initialization of OIT compositing pass has failed.\n" + + " Blended order-independent transparency will not be available.\n"; + aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, + GL_DEBUG_TYPE_ERROR, + 0, + GL_DEBUG_SEVERITY_HIGH, + aMsg); + OpenGl_View* aView = theWorkspace->View(); + if (aView) + { + Standard_Boolean& aOITFlag = isMSAA ? aView->myToDisableOITMSAA : aView->myToDisableOIT; + aOITFlag = Standard_True; + } + } + } + + aCtx->core11fwd->glDisable (GL_BLEND); + aCtx->core11fwd->glBlendFunc (GL_ONE, GL_ZERO); + aCtx->core11fwd->glDepthMask (theGlobalSettings.DepthMask); + aCtx->core11fwd->glDepthFunc (theGlobalSettings.DepthFunc); +} + +//======================================================================= +//class : OpenGl_OpaqueFilter +//function : ShouldRender +//purpose : Checks whether the element should be rendered or skipped. +//======================================================================= +Standard_Boolean OpenGl_LayerList::OpenGl_OpaqueFilter::ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace, + const OpenGl_Element* theGlElement) +{ + if (!myFilter.IsNull() && !myFilter->ShouldRender (theWorkspace, theGlElement)) + { + return Standard_False; + } + + const OpenGl_PrimitiveArray* aPArray = dynamic_cast (theGlElement); + if (aPArray != NULL + && aPArray->DrawMode() >= OpenGl_PrimitiveArray::THE_FILLPRIM_FROM + && aPArray->DrawMode() <= OpenGl_PrimitiveArray::THE_FILLPRIM_TO) + { + const OpenGl_AspectFace* anAspect = theWorkspace->ApplyAspectFace(); + if (anAspect) + { + const bool toDistinguish = anAspect->Aspect()->Distinguish(); + const Graphic3d_MaterialAspect& aMatFrontSrc = anAspect->Aspect()->FrontMaterial(); + const Graphic3d_MaterialAspect& aMatBackSrc = toDistinguish + ? anAspect->Aspect()->BackMaterial() + : aMatFrontSrc; + + const Standard_Size aSkippedCounter = mySkippedCounter; + if (((float)aMatFrontSrc.Transparency() > ShortRealEpsilon()) + || ((float)aMatBackSrc .Transparency() > ShortRealEpsilon())) + { + mySkippedCounter++; + } + + return mySkippedCounter == aSkippedCounter; + } + } + + return Standard_True; +} + +//======================================================================= +//class : OpenGl_TransparentFilter +//function : ShouldRender +//purpose : Checks whether the element should be rendered or skipped. +//======================================================================= +Standard_Boolean OpenGl_LayerList::OpenGl_TransparentFilter::ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace, + const OpenGl_Element* theGlElement) +{ + if (!myFilter.IsNull() && !myFilter->ShouldRender (theWorkspace, theGlElement)) + { + return Standard_False; + } + + const OpenGl_PrimitiveArray* aPArray = dynamic_cast (theGlElement); + if (aPArray != NULL + && aPArray->DrawMode() >= OpenGl_PrimitiveArray::THE_FILLPRIM_FROM + && aPArray->DrawMode() <= OpenGl_PrimitiveArray::THE_FILLPRIM_TO) + { + const OpenGl_AspectFace* anAspect = theWorkspace->ApplyAspectFace(); + if (anAspect) + { + const bool toDistinguish = anAspect->Aspect()->Distinguish(); + const Graphic3d_MaterialAspect& aMatFrontSrc = anAspect->Aspect()->FrontMaterial(); + const Graphic3d_MaterialAspect& aMatBackSrc = toDistinguish + ? anAspect->Aspect()->BackMaterial() + : aMatFrontSrc; + + return ((float)aMatFrontSrc.Transparency() > ShortRealEpsilon()) + || ((float)aMatBackSrc .Transparency() > ShortRealEpsilon()); + } + } + else + { + return dynamic_cast (theGlElement) != NULL; + } + + return Standard_False; } diff --git a/src/OpenGl/OpenGl_LayerList.hxx b/src/OpenGl/OpenGl_LayerList.hxx index cd45cc3fd0..7b1c2f1086 100644 --- a/src/OpenGl/OpenGl_LayerList.hxx +++ b/src/OpenGl/OpenGl_LayerList.hxx @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include @@ -89,7 +91,9 @@ public: //! Render this element void Render (const Handle(OpenGl_Workspace)& theWorkspace, const Standard_Boolean theToDrawImmediate, - const OpenGl_LayerFilter theLayersToProcess) const; + const OpenGl_LayerFilter theLayersToProcess, + OpenGl_FrameBuffer* theReadDrawFbo, + OpenGl_FrameBuffer* theOitAccumFbo) const; //! Returns the set of OpenGL Z-layers. const OpenGl_SequenceOfLayers& Layers() const { return myLayers; } @@ -104,6 +108,132 @@ public: //! Returns structure modification state (for ray-tracing). Standard_Size ModificationStateOfRaytracable() const { return myModifStateOfRaytraceable; } +protected: + + //! Filter of TKOpenGl elements for processing only shading geometry and + //! for collecting number of skipped elements to an external counter. + class OpenGl_OpaqueFilter : public OpenGl_RenderFilter + { + public: + + //! Constructor. + //! @param thePrevFilter [in] the previously active filter that should have additive effect. + OpenGl_OpaqueFilter() : mySkippedCounter (0) {} + + //! Sets the current active filter in workspace. + //! @param thePrevFilter [in] the previously active filter that should have additive effect. + void SetPreviousFilter (const Handle(OpenGl_RenderFilter)& thePrevFitler) { myFilter = thePrevFitler; } + + //! Sets the value of the skipped elements counter. + void SetSkippedCounter (const Standard_Size theCounter) { mySkippedCounter = theCounter; } + + //! Returns number of skipped elements. + Standard_Size NbSkipped() const { return mySkippedCounter; } + + //! Checks whether the element should be rendered or skipped. + //! @param theWorkspace [in] the currently used workspace for rendering. + //! @param theGlElement [in] the TKOpenGl rendering queue element that should be checked before streaming to GPU. + Standard_EXPORT virtual Standard_Boolean ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace, + const OpenGl_Element* theGlElement) Standard_OVERRIDE; + + DEFINE_STANDARD_RTTI_INLINE (OpenGl_OpaqueFilter, OpenGl_RenderFilter) + + private: + + Standard_Size mySkippedCounter; //!< Counter of skipped elements. + Handle(OpenGl_RenderFilter) myFilter; //!< Previous active filter that should be combined. + }; + + //! Filter of TKOpenGl elements for keeping only shading geometry with transparency. + class OpenGl_TransparentFilter : public OpenGl_RenderFilter + { + public: + + //! Constructor. + OpenGl_TransparentFilter() {} + + //! Sets the current active filter in workspace. + //! @param thePrevFilter [in] the previously active filter that should have additive effect. + void SetPreviousFilter (const Handle(OpenGl_RenderFilter)& thePrevFitler) { myFilter = thePrevFitler; } + + //! Checks whether the element should be rendered or skipped. + //! @param theWorkspace [in] the currently used workspace for rendering. + //! @param theGlElement [in] the TKOpenGl rendering queue element that should be checked before streaming to GPU. + Standard_EXPORT virtual Standard_Boolean ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace, + const OpenGl_Element* theGlElement) Standard_OVERRIDE; + + DEFINE_STANDARD_RTTI_INLINE (OpenGl_TransparentFilter, OpenGl_RenderFilter) + + private: + + Handle(OpenGl_RenderFilter) myFilter; //!< Previous active filter that should be combined. + }; + + //! Stack of references to existing layers of predefined maximum size. + class OpenGl_LayerStack + { + public: + typedef NCollection_Array1::iterator iterator; + + //! Reallocate internal buffer of the stack. + void Allocate (const Standard_Integer theSize) + { + if (theSize > 0) + { + myStackSpace = new NCollection_Array1 (1, theSize); + myStackSpace->Init (NULL); + myBackPtr = myStackSpace->begin(); + } + else + { + myStackSpace.Nullify(); + myBackPtr = iterator(); + } + } + + //! Clear stack. + void Clear() + { + if (myStackSpace) + { + myStackSpace->Init (NULL); + myBackPtr = myStackSpace->begin(); + } + } + + //! Push a new layer reference to the stack. + void Push (const OpenGl_Layer* theLayer) { (*myBackPtr++) = theLayer; } + + //! Returns iterator to the origin of the stack. + iterator Origin() const { return myStackSpace.IsNull() ? iterator() : myStackSpace->begin(); } + + //! Returns iterator to the back of the stack (after last item added). + iterator Back() const { return myBackPtr; } + + //! Returns true if nothing has been pushed into the stack. + Standard_Boolean IsEmpty() const { return Back() == Origin(); } + + private: + + NCollection_Handle > myStackSpace; + iterator myBackPtr; + }; + + //! Render transparent objects using blending operator. + //! Additional accumulation framebuffer is used for blended order-independent + //! transparency algorithm. It should support floating-point color components + //! and share depth with main reading/drawing framebuffer. + //! @param theWorkspace [in] the currently used workspace for rendering. + //! @param theLayerIter [in/out] the current iterator of transparent layers to process. + //! @param theGlobalSettings [in] the set of global settings used for rendering. + //! @param theReadDrawFbo [in] the framebuffer for reading depth and writing final color. + //! @param theOitAccumFbo [in] the framebuffer for accumulating color and coverage for OIT process. + void renderTransparent (const Handle(OpenGl_Workspace)& theWorkspace, + OpenGl_LayerStack::iterator& theLayerIter, + const OpenGl_GlobalLayerSettings& theGlobalSettings, + OpenGl_FrameBuffer* theReadDrawFbo, + OpenGl_FrameBuffer* theOitAccumFbo) const; + protected: // number of structures temporary put to default layer @@ -117,6 +247,12 @@ protected: mutable Standard_Size myModifStateOfRaytraceable; + //! Collection of references to layers with transparency gathered during rendering pass. + mutable OpenGl_LayerStack myTransparentToProcess; + + Handle(OpenGl_OpaqueFilter) myRenderOpaqueFilter; //!< rendering filter for opaque drawing pass (blended OIT). + Handle(OpenGl_TransparentFilter) myRenderTranspFilter; //!< rendering filter for transparency drawing pass (blended OIT). + public: DEFINE_STANDARD_ALLOC diff --git a/src/OpenGl/OpenGl_OitUniformState.hxx b/src/OpenGl/OpenGl_OitUniformState.hxx new file mode 100644 index 0000000000..9e1cff8669 --- /dev/null +++ b/src/OpenGl/OpenGl_OitUniformState.hxx @@ -0,0 +1,55 @@ +// Created on: 2017-01-26 +// Created by: Anton POLETAEV +// Copyright (c) 2017 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_OitUniformState_HeaderFile +#define _OpenGl_OitUniformState_HeaderFile + +#include + +//! Defines generic state of order-independent transparency rendering properties. +class OpenGl_OitUniformState : public OpenGl_StateInterface +{ +public: + + //! Creates new uniform state. + OpenGl_OitUniformState() : myToEnableWrite (false), myDepthWeight (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 theDepthWeight [in] scalar factor [0-1] defining influence of depth + //! component of a fragment to its final coverage coefficient. + void Set (const bool theToEnableWrite, + const float theDepthWeight) + { + myToEnableWrite = theToEnableWrite; + myDepthWeight = Max (0.f, Min (1.f, theDepthWeight)); + } + + //! Returns flag indicating whether writing of output for OIT processing + //! should be enabled/disabled. + bool ToEnableWrite() const { return myToEnableWrite; } + + //! Returns factor defining influence of depth component of a fragment + //! to its final coverage coefficient. + float DepthWeight() const { return myDepthWeight; } + +private: + + bool myToEnableWrite; //!< writing color and coverage. + float myDepthWeight; //!< factor of depth influence to coverage. +}; + +#endif // _OpenGl_OitUniformState_HeaderFile diff --git a/src/OpenGl/OpenGl_PrimitiveArray.hxx b/src/OpenGl/OpenGl_PrimitiveArray.hxx index 167dfe2298..fccdcb07de 100644 --- a/src/OpenGl/OpenGl_PrimitiveArray.hxx +++ b/src/OpenGl/OpenGl_PrimitiveArray.hxx @@ -40,6 +40,14 @@ public: DRAW_MODE_NONE = -1 }; +#if !defined(GL_ES_VERSION_2_0) + static const GLint THE_FILLPRIM_FROM = GL_TRIANGLES; + static const GLint THE_FILLPRIM_TO = GL_POLYGON; +#else + static const GLint THE_FILLPRIM_FROM = GL_TRIANGLES; + static const GLint THE_FILLPRIM_TO = GL_TRIANGLE_FAN; +#endif + //! Empty constructor Standard_EXPORT OpenGl_PrimitiveArray (const OpenGl_GraphicDriver* theDriver); diff --git a/src/OpenGl/OpenGl_RenderFilter.hxx b/src/OpenGl/OpenGl_RenderFilter.hxx index a82a1cc445..ac1a156227 100755 --- a/src/OpenGl/OpenGl_RenderFilter.hxx +++ b/src/OpenGl/OpenGl_RenderFilter.hxx @@ -23,6 +23,7 @@ class OpenGl_RenderFilter; DEFINE_STANDARD_HANDLE (OpenGl_RenderFilter, Standard_Transient) class OpenGl_Element; +class OpenGl_Workspace; //! Base class for defining element rendering filters. //! This class can be used in pair with advance rendering passes, and for @@ -32,13 +33,14 @@ class OpenGl_RenderFilter : public Standard_Transient public: //! Checks whether the element can be rendered or not. + //! @param theWorkspace [in] the current workspace. //! @param theElement [in] the element to check. //! @return True if element can be rendered. - virtual Standard_Boolean CanRender (const OpenGl_Element* theElement) = 0; + virtual Standard_Boolean ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace, const OpenGl_Element* theElement) = 0; public: - DEFINE_STANDARD_RTTIEXT(OpenGl_RenderFilter,Standard_Transient) + DEFINE_STANDARD_RTTIEXT(OpenGl_RenderFilter, Standard_Transient) }; #endif diff --git a/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx b/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx index c4977b6a68..6bfd58a08a 100644 --- a/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx +++ b/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx @@ -31,7 +31,8 @@ enum OpenGl_ProgramOptions OpenGl_PO_ClipPlanes1 = 0x040, //!< handle 1 clipping plane OpenGl_PO_ClipPlanes2 = 0x080, //!< handle 2 clipping planes OpenGl_PO_ClipPlanesN = 0x100, //!< handle N clipping planes - OpenGl_PO_NB = 0x200 //!< overall number of combinations + OpenGl_PO_WriteOit = 0x200, //!< write color/coverage buffer for blended order independet transparency + OpenGl_PO_NB = 0x400 //!< overall number of combinations }; //! Alias to programs array of predefined length diff --git a/src/OpenGl/OpenGl_ShaderManager.cxx b/src/OpenGl/OpenGl_ShaderManager.cxx index 991824cc76..7feee964d1 100644 --- a/src/OpenGl/OpenGl_ShaderManager.cxx +++ b/src/OpenGl/OpenGl_ShaderManager.cxx @@ -331,6 +331,12 @@ const char THE_FRAG_CLIP_PLANES_2[] = } #endif +//! Output color and coverage for accumulation by OIT algorithm. +const char THE_FRAG_write_oit_buffers[] = + EOL" float aWeight = occFragColor.a * clamp (1e+2 * pow (1.0 - gl_FragCoord.z * occOitDepthWeight, 3.0), 1e-2, 1e+2);" + EOL" occFragCoverage.r = occFragColor.a * aWeight;" + EOL" occFragColor = vec4 (occFragColor.rgb * occFragColor.a * aWeight, occFragColor.a);"; + } // ======================================================================= @@ -1069,6 +1075,37 @@ void OpenGl_ShaderManager::PushMaterialState (const Handle(OpenGl_ShaderProgram) } } +// ======================================================================= +// function : PushOitUniformState +// purpose : Pushes state of OIT uniforms to the specified program +// ======================================================================= +void OpenGl_ShaderManager::PushOitUniformState (const Handle(OpenGl_ShaderProgram)& theProgram) const +{ + if (!theProgram->IsValid()) + { + return; + } + + if (myOitUniformState.Index() == theProgram->ActiveState (OpenGL_OIT_UNIFORM_STATE)) + { + return; + } + + const GLint aLocEnableWrite = theProgram->GetStateLocation (OpenGl_OCCT_OIT_ENABLE_WRITE); + if (aLocEnableWrite != OpenGl_ShaderProgram::INVALID_LOCATION) + { + theProgram->SetUniform (myContext, aLocEnableWrite, + myOitUniformState.ToEnableWrite()); + } + + const GLint aLocDepthWeight = theProgram->GetStateLocation (OpenGl_OCCT_OIT_DEPTH_WEIGHT); + if (aLocDepthWeight != OpenGl_ShaderProgram::INVALID_LOCATION) + { + theProgram->SetUniform (myContext, aLocDepthWeight, + myOitUniformState.DepthWeight()); + } +} + // ======================================================================= // function : PushState // purpose : Pushes state of OCCT graphics parameters to the program @@ -1082,6 +1119,7 @@ void OpenGl_ShaderManager::PushState (const Handle(OpenGl_ShaderProgram)& thePro PushProjectionState (aProgram); PushLightSourceState (aProgram); PushMaterialState (aProgram); + PushOitUniformState (aProgram); } // ======================================================================= @@ -1208,6 +1246,82 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFboBlit() return Standard_True; } +// ======================================================================= +// function : prepareStdProgramOitCompositing +// purpose : +// ======================================================================= +Standard_Boolean OpenGl_ShaderManager::prepareStdProgramOitCompositing (const Standard_Boolean theMsaa) +{ + Handle(OpenGl_ShaderProgram)& aProgram = myOitCompositingProgram [theMsaa ? 1 : 0]; + Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram(); + TCollection_AsciiString aSrcVert, aSrcFrag; + + aSrcVert = + EOL"THE_SHADER_OUT vec2 TexCoord;" + EOL"void main()" + EOL"{" + EOL" TexCoord = occVertex.zw;" + EOL" gl_Position = vec4(occVertex.x, occVertex.y, 0.0, 1.0);" + EOL"}"; + + if (!theMsaa) + { + aSrcFrag = + EOL"uniform sampler2D uAccumTexture;" + EOL"uniform sampler2D uWeightTexture;" + EOL + EOL"THE_SHADER_IN vec2 TexCoord;" + EOL + EOL"void main()" + EOL"{" + EOL" vec4 aAccum = occTexture2D (uAccumTexture, TexCoord);" + EOL" float aWeight = occTexture2D (uWeightTexture, TexCoord).r;" + EOL" occFragColor = vec4 (aAccum.rgb / max (aWeight, 0.00001), aAccum.a);" + EOL"}"; + + if (myContext->IsGlGreaterEqual (3, 2)) + { + aProgramSrc->SetHeader ("#version 150"); + } + } + else + { + aSrcFrag = + EOL"uniform sampler2DMS uAccumTexture;" + EOL"uniform sampler2DMS uWeightTexture;" + EOL + EOL"THE_SHADER_IN vec2 TexCoord;" + EOL + EOL"void main()" + EOL"{" + EOL" ivec2 aTexel = ivec2 (textureSize (uAccumTexture) * TexCoord);" + EOL" vec4 aAccum = texelFetch (uAccumTexture, aTexel, gl_SampleID);" + EOL" float aWeight = texelFetch (uWeightTexture, aTexel, gl_SampleID).r;" + EOL" occFragColor = vec4 (aAccum.rgb / max (aWeight, 0.00001), aAccum.a);" + EOL"}"; + + if (myContext->IsGlGreaterEqual (4, 0)) + { + aProgramSrc->SetHeader ("#version 400"); + } + } + + aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX, aSrcVert)); + aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag)); + TCollection_AsciiString aKey; + if (!Create (aProgramSrc, aKey, aProgram)) + { + aProgram = new OpenGl_ShaderProgram(); // just mark as invalid + return Standard_False; + } + + myContext->BindProgram (aProgram); + aProgram->SetSampler (myContext, "uAccumTexture", 0); + aProgram->SetSampler (myContext, "uWeightTexture", 1); + myContext->BindProgram (NULL); + return Standard_True; +} + // ======================================================================= // function : pointSpriteAlphaSrc // purpose : @@ -1249,7 +1363,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_Shad const Standard_Integer theBits) { Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram(); - TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain, aSrcVertExtraFunc, aSrcGetAlpha, aSrcFrag, aSrcFragExtraOut, aSrcFragExtraMain; + TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain, aSrcVertExtraFunc, aSrcGetAlpha, aSrcFrag; + TCollection_AsciiString aSrcFragExtraOut, aSrcFragExtraMain, aSrcFragWriteOit; TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return occColor; }"; TCollection_AsciiString aSrcFragMainGetColor = EOL" occFragColor = getColor();"; if ((theBits & OpenGl_PO_Point) != 0) @@ -1351,6 +1466,10 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_Shad aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N; } } + if ((theBits & OpenGl_PO_WriteOit) != 0) + { + aSrcFragWriteOit += THE_FRAG_write_oit_buffers; + } TCollection_AsciiString aSrcVertEndMain; if ((theBits & OpenGl_PO_StippleLine) != 0) @@ -1421,6 +1540,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_Shad EOL"{" + aSrcFragExtraMain + aSrcFragMainGetColor + + aSrcFragWriteOit + EOL"}"; #if !defined(GL_ES_VERSION_2_0) @@ -1572,7 +1692,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S const Standard_Integer theBits) { Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram(); - TCollection_AsciiString aSrcVert, aSrcVertColor, aSrcVertExtraOut, aSrcVertExtraMain, aSrcFrag, aSrcFragExtraOut, aSrcFragExtraMain; + TCollection_AsciiString aSrcVert, aSrcVertColor, aSrcVertExtraOut, aSrcVertExtraMain, aSrcFrag, aSrcFragExtraOut; + TCollection_AsciiString aSrcFragExtraMain, aSrcFragWriteOit; TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return gl_FrontFacing ? FrontColor : BackColor; }"; if ((theBits & OpenGl_PO_Point) != 0) { @@ -1640,6 +1761,10 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N; } } + if ((theBits & OpenGl_PO_WriteOit) != 0) + { + aSrcFragWriteOit += THE_FRAG_write_oit_buffers; + } const TCollection_AsciiString aLights = stdComputeLighting ((theBits & OpenGl_PO_VertColor) != 0); aSrcVert = TCollection_AsciiString() @@ -1673,7 +1798,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S EOL"{" + aSrcFragExtraMain + EOL" occFragColor = getColor();" - EOL"}"; + + aSrcFragWriteOit + + EOL"}"; #if !defined(GL_ES_VERSION_2_0) if (myContext->core32 != NULL) @@ -1702,7 +1828,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha #define thePhongCompLight "computeLighting (normalize (Normal), normalize (View), Position, gl_FrontFacing)" Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram(); - TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain, aSrcFrag, aSrcFragExtraOut, aSrcFragGetVertColor, aSrcFragExtraMain; + TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain, aSrcFrag, aSrcFragExtraOut; + TCollection_AsciiString aSrcFragGetVertColor, aSrcFragExtraMain, aSrcFragWriteOit; TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return " thePhongCompLight "; }"; if ((theBits & OpenGl_PO_Point) != 0) { @@ -1763,6 +1890,10 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N; } } + if ((theBits & OpenGl_PO_WriteOit) != 0) + { + aSrcFragWriteOit += THE_FRAG_write_oit_buffers; + } aSrcVert = TCollection_AsciiString() + THE_FUNC_transformNormal @@ -1799,7 +1930,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha EOL"{" + aSrcFragExtraMain + EOL" occFragColor = getColor();" - EOL"}"; + + aSrcFragWriteOit + + EOL"}"; #if !defined(GL_ES_VERSION_2_0) if (myContext->core32 != NULL) diff --git a/src/OpenGl/OpenGl_ShaderManager.hxx b/src/OpenGl/OpenGl_ShaderManager.hxx index ce503a634c..0b9c982121 100644 --- a/src/OpenGl/OpenGl_ShaderManager.hxx +++ b/src/OpenGl/OpenGl_ShaderManager.hxx @@ -23,12 +23,13 @@ #include #include -#include -#include #include #include -#include #include +#include +#include +#include +#include #include #include @@ -168,6 +169,19 @@ public: && myContext->BindProgram (myBlitProgram); } + //! Bind program for blended order-independent transparency buffers compositing. + Standard_Boolean BindOitCompositingProgram (const Standard_Boolean theIsMSAAEnabled) + { + const Standard_Integer aProgramIdx = theIsMSAAEnabled ? 1 : 0; + if (myOitCompositingProgram[aProgramIdx].IsNull()) + { + prepareStdProgramOitCompositing (theIsMSAAEnabled); + } + + const Handle(OpenGl_ShaderProgram)& aProgram = myOitCompositingProgram [aProgramIdx]; + return !aProgram.IsNull() && myContext->BindProgram (aProgram); + } + //! Bind program for rendering stereoscopic image. Standard_Boolean BindStereoProgram (const Graphic3d_StereoMode theStereoMode) { @@ -267,6 +281,20 @@ public: //! Pushes current state of material to specified program. void PushMaterialState (const Handle(OpenGl_ShaderProgram)& theProgram) const; +public: + + //! Set the state of OIT rendering pass. + //! @param theToEnableOitWrite [in] flag indicating whether the special output should be written for OIT algorithm. + //! @param theDepthWeight [in] the scalar factor of depth influence to the fragment's coverage. + void SetOitState (const bool theToEnableOitWrite, const float theDepthWeight) + { + myOitUniformState.Set (theToEnableOitWrite, theDepthWeight); + myOitUniformState.Update(); + } + + //! Pushes state of OIT uniforms to the specified program. + Standard_EXPORT void PushOitUniformState (const Handle(OpenGl_ShaderProgram)& theProgram) const; + public: //! Pushes current state of OCCT graphics parameters to specified program. @@ -339,6 +367,12 @@ protected: { aBits |= OpenGl_PO_VertColor; } + + if (myOitUniformState.ToEnableWrite()) + { + aBits |= OpenGl_PO_WriteOit; + } + return aBits; } @@ -378,6 +412,9 @@ protected: //! Prepare standard GLSL program for FBO blit operation. Standard_EXPORT Standard_Boolean prepareStdProgramFboBlit(); + //! Prepare standard GLSL programs for Oit compositing operation. + Standard_EXPORT Standard_Boolean prepareStdProgramOitCompositing (const Standard_Boolean theMsaa); + //! Prepare standard GLSL program without lighting. Standard_EXPORT Standard_Boolean prepareStdProgramFlat (Handle(OpenGl_ShaderProgram)& theProgram, const Standard_Integer theBits); @@ -452,13 +489,14 @@ protected: Handle(OpenGl_ShaderProgramFFP) myFfpProgram; - Graphic3d_TypeOfShadingModel 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 - Handle(OpenGl_ShaderProgram) myBlitProgram; //!< standard program for FBO blit emulation - OpenGl_MapOfShaderPrograms myMapOfLightPrograms; //!< map of lighting programs depending on shading model and lights configuration + Graphic3d_TypeOfShadingModel 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 + Handle(OpenGl_ShaderProgram) myBlitProgram; //!< standard program for FBO blit emulation + Handle(OpenGl_ShaderProgram) myOitCompositingProgram[2]; //!< standard program for OIT compositing (default and msaa). + OpenGl_MapOfShaderPrograms myMapOfLightPrograms; //!< map of lighting programs depending on shading model and lights configuration Handle(OpenGl_ShaderProgram) myStereoPrograms[Graphic3d_StereoMode_NB]; //!< standard stereo programs @@ -472,6 +510,7 @@ protected: OpenGl_ClippingState myClippingState; //!< State of OCCT clipping planes OpenGl_LightSourceState myLightSourceState; //!< State of OCCT light sources OpenGl_MaterialState myMaterialState; //!< State of Front and Back materials + OpenGl_OitUniformState myOitUniformState; //!< State of OIT uniforms gp_XYZ myLocalOrigin; //!< local camera transformation Standard_Boolean myHasLocalOrigin; //!< flag indicating that local camera transformation has been set diff --git a/src/OpenGl/OpenGl_ShaderProgram.cxx b/src/OpenGl/OpenGl_ShaderProgram.cxx index d792b16afa..4f1aefb11f 100755 --- a/src/OpenGl/OpenGl_ShaderProgram.cxx +++ b/src/OpenGl/OpenGl_ShaderProgram.cxx @@ -70,11 +70,27 @@ Standard_CString OpenGl_ShaderProgram::PredefinedKeywords[] = "occBackMaterial", // OpenGl_OCCT_BACK_MATERIAL "occColor", // OpenGl_OCCT_COLOR + "occOitEnableWrite", // OpenGl_OCCT_OIT_ENABLE_WRITE + "occOitDepthWeight", // OpenGl_OCCT_OIT_DEPTH_WEIGHT + "occTexTrsf2d", // OpenGl_OCCT_TEXTURE_TRSF2D "occPointSize" // OpenGl_OCCT_POINT_SIZE - }; +namespace +{ + #define EOL "\n" + const char THE_enable_draw_buffers[] = + EOL"#ifdef GL_ES" + EOL" #if (__VERSION__ < 300)" + EOL" #extension GL_EXT_draw_buffers : enable" + EOL" #endif" + EOL"#else" + EOL" #extension GL_ARB_draw_buffers : enable" + EOL"#endif" + EOL"#define OCC_enable_draw_buffers 1"; +} + // ======================================================================= // function : OpenGl_VariableSetterSelector // purpose : Creates new variable setter selector @@ -204,11 +220,16 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)& } TCollection_AsciiString aSource = aDeclarations + anIter.Value()->Source(); + TCollection_AsciiString aExtensions; + if (theCtx->MaxDrawBuffers() > 1) { + aExtensions += THE_enable_draw_buffers; + } + switch (anIter.Value()->Type()) { case Graphic3d_TOS_VERTEX: { - aSource = aHeader + TCollection_AsciiString ("#define VERTEX_SHADER\n") + aSource; + aSource = aHeader + TCollection_AsciiString ("#define VERTEX_SHADER\n") + aExtensions + aSource; break; } case Graphic3d_TOS_FRAGMENT: @@ -219,9 +240,9 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)& "precision highp int;\n" : "precision mediump float;\n" "precision mediump int;\n"); - aSource = aHeader + aPrefix + aSource; + aSource = aHeader + aPrefix + aExtensions + aSource; #else - aSource = aHeader + aSource; + aSource = aHeader + aExtensions + aSource; #endif break; } diff --git a/src/OpenGl/OpenGl_ShaderProgram.hxx b/src/OpenGl/OpenGl_ShaderProgram.hxx index f38506fa74..0d3c39c8d7 100755 --- a/src/OpenGl/OpenGl_ShaderProgram.hxx +++ b/src/OpenGl/OpenGl_ShaderProgram.hxx @@ -65,6 +65,11 @@ enum OpenGl_StateVariable OpenGl_OCCT_BACK_MATERIAL, OpenGl_OCCT_COLOR, + // Order-independent transparency rendering state + OpenGl_OCCT_OIT_ENABLE_WRITE, //!< Enable bit for writing color (occFragColor) and coverage (occFragCoverage) buffers of OIT processing + OpenGl_OCCT_OIT_DEPTH_WEIGHT, //!< Influence of the depth component to the coverage of the accumulated fragment + + // Context-dependent state OpenGl_OCCT_TEXTURE_TRSF2D, OpenGl_OCCT_POINT_SIZE, @@ -124,6 +129,7 @@ enum OpenGl_UniformStateType OpenGl_PROJECTION_STATE, OpenGl_MATERIAL_STATE, OpenGl_SURF_DETAIL_STATE, + OpenGL_OIT_UNIFORM_STATE, OpenGl_UniformStateType_NB }; diff --git a/src/OpenGl/OpenGl_Texture.cxx b/src/OpenGl/OpenGl_Texture.cxx index f0ec3e4969..0020bd2a6a 100644 --- a/src/OpenGl/OpenGl_Texture.cxx +++ b/src/OpenGl/OpenGl_Texture.cxx @@ -900,6 +900,20 @@ bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx, Unbind (theCtx); return false; } + else if (theDataType == GL_HALF_FLOAT && !theCtx->arbTexHalfFloat) + { + TCollection_ExtendedString aMsg ("Error: half-precision floating-point textures are not supported by hardware."); + + theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, + GL_DEBUG_TYPE_ERROR, + 0, + GL_DEBUG_SEVERITY_HIGH, + aMsg); + + Release (theCtx.operator->()); + Unbind (theCtx); + return false; + } const GLint anIntFormat = theTextFormat; diff --git a/src/OpenGl/OpenGl_View.cxx b/src/OpenGl/OpenGl_View.cxx index c60c68452c..32b165aef2 100644 --- a/src/OpenGl/OpenGl_View.cxx +++ b/src/OpenGl/OpenGl_View.cxx @@ -61,11 +61,17 @@ OpenGl_View::OpenGl_View (const Handle(Graphic3d_StructureManager)& theMgr, myToShowGradTrihedron (false), myStateCounter (theCounter), myLastLightSourceState (0, 0), +#if !defined(GL_ES_VERSION_2_0) myFboColorFormat (GL_RGBA8), +#else + myFboColorFormat (GL_RGBA), +#endif myFboDepthFormat (GL_DEPTH24_STENCIL8), myToFlipOutput (Standard_False), myFrameCounter (0), myHasFboBlit (Standard_True), + myToDisableOIT (Standard_False), + myToDisableOITMSAA (Standard_False), myToDisableMSAA (Standard_False), myTransientDrawToFront (Standard_True), myBackBufferRestored (Standard_False), @@ -90,17 +96,21 @@ OpenGl_View::OpenGl_View (const Handle(Graphic3d_StructureManager)& theMgr, aLight.Color.b() = 1.; myNoShadingLight.Append (aLight); - myCurrLightSourceState = myStateCounter->Increment(); - myMainSceneFbos[0] = new OpenGl_FrameBuffer(); - myMainSceneFbos[1] = new OpenGl_FrameBuffer(); - myImmediateSceneFbos[0] = new OpenGl_FrameBuffer(); - myImmediateSceneFbos[1] = new OpenGl_FrameBuffer(); - myOpenGlFBO = new OpenGl_FrameBuffer(); - myOpenGlFBO2 = new OpenGl_FrameBuffer(); - myRaytraceFBO1[0] = new OpenGl_FrameBuffer(); - myRaytraceFBO1[1] = new OpenGl_FrameBuffer(); - myRaytraceFBO2[0] = new OpenGl_FrameBuffer(); - myRaytraceFBO2[1] = new OpenGl_FrameBuffer(); + myCurrLightSourceState = myStateCounter->Increment(); + myMainSceneFbos[0] = new OpenGl_FrameBuffer(); + myMainSceneFbos[1] = new OpenGl_FrameBuffer(); + myMainSceneFbosOit[0] = new OpenGl_FrameBuffer(); + myMainSceneFbosOit[1] = new OpenGl_FrameBuffer(); + myImmediateSceneFbos[0] = new OpenGl_FrameBuffer(); + myImmediateSceneFbos[1] = new OpenGl_FrameBuffer(); + myImmediateSceneFbosOit[0] = new OpenGl_FrameBuffer(); + myImmediateSceneFbosOit[1] = new OpenGl_FrameBuffer(); + myOpenGlFBO = new OpenGl_FrameBuffer(); + myOpenGlFBO2 = new OpenGl_FrameBuffer(); + myRaytraceFBO1[0] = new OpenGl_FrameBuffer(); + myRaytraceFBO1[1] = new OpenGl_FrameBuffer(); + myRaytraceFBO2[0] = new OpenGl_FrameBuffer(); + myRaytraceFBO2[1] = new OpenGl_FrameBuffer(); } // ======================================================================= @@ -142,14 +152,18 @@ void OpenGl_View::ReleaseGlResources (const Handle(OpenGl_Context)& theCtx) myBgTextureArray->Release (theCtx.operator->()); } - myMainSceneFbos[0] ->Release (theCtx.operator->()); - myMainSceneFbos[1] ->Release (theCtx.operator->()); - myImmediateSceneFbos[0]->Release (theCtx.operator->()); - myImmediateSceneFbos[1]->Release (theCtx.operator->()); - myOpenGlFBO ->Release (theCtx.operator->()); - myOpenGlFBO2 ->Release (theCtx.operator->()); - myFullScreenQuad .Release (theCtx.operator->()); - myFullScreenQuadFlip .Release (theCtx.operator->()); + myMainSceneFbos[0] ->Release (theCtx.operator->()); + myMainSceneFbos[1] ->Release (theCtx.operator->()); + myMainSceneFbosOit[0] ->Release (theCtx.operator->()); + myMainSceneFbosOit[1] ->Release (theCtx.operator->()); + myImmediateSceneFbos[0] ->Release (theCtx.operator->()); + myImmediateSceneFbos[1] ->Release (theCtx.operator->()); + myImmediateSceneFbosOit[0]->Release (theCtx.operator->()); + myImmediateSceneFbosOit[1]->Release (theCtx.operator->()); + myOpenGlFBO ->Release (theCtx.operator->()); + myOpenGlFBO2 ->Release (theCtx.operator->()); + myFullScreenQuad .Release (theCtx.operator->()); + myFullScreenQuadFlip .Release (theCtx.operator->()); releaseRaytraceResources (theCtx); } diff --git a/src/OpenGl/OpenGl_View.hxx b/src/OpenGl/OpenGl_View.hxx index 3a1bfaa77b..d4b4d94bca 100644 --- a/src/OpenGl/OpenGl_View.hxx +++ b/src/OpenGl/OpenGl_View.hxx @@ -367,7 +367,8 @@ protected: //! @name low-level redrawing sub-routines //! Redraws view for the given monographic camera projection, or left/right eye. Standard_EXPORT virtual void redraw (const Graphic3d_Camera::Projection theProjection, - OpenGl_FrameBuffer* theReadDrawFbo); + OpenGl_FrameBuffer* theReadDrawFbo, + OpenGl_FrameBuffer* theOitAccumFbo); //! Redraws view for the given monographic camera projection, or left/right eye. //! @@ -384,6 +385,7 @@ protected: //! @name low-level redrawing sub-routines Standard_EXPORT virtual bool redrawImmediate (const Graphic3d_Camera::Projection theProjection, OpenGl_FrameBuffer* theReadFbo, OpenGl_FrameBuffer* theDrawFbo, + OpenGl_FrameBuffer* theOitAccumFbo, const Standard_Boolean theIsPartialUpdate = Standard_False); //! Blit image from/to specified buffers. @@ -399,17 +401,21 @@ protected: //! @name Rendering of GL graphics (with prepared drawing buffer). //! Renders the graphical contents of the view into the preprepared window or framebuffer. //! @param theProjection [in] the projection that should be used for rendering. //! @param theReadDrawFbo [in] the framebuffer for rendering graphics. + //! @param theOitAccumFbo [in] the framebuffer for accumulating color and coverage for OIT process. //! @param theToDrawImmediate [in] the flag indicates whether the rendering performs in immediate mode. Standard_EXPORT virtual void render (Graphic3d_Camera::Projection theProjection, OpenGl_FrameBuffer* theReadDrawFbo, + OpenGl_FrameBuffer* theOitAccumFbo, const Standard_Boolean theToDrawImmediate); //! Renders the graphical scene. //! @param theProjection [in] the projection that is used for rendering. //! @param theReadDrawFbo [in] the framebuffer for rendering graphics. + //! @param theOitAccumFbo [in] the framebuffer for accumulating color and coverage for OIT process. //! @param theToDrawImmediate [in] the flag indicates whether the rendering performs in immediate mode. Standard_EXPORT virtual void renderScene (Graphic3d_Camera::Projection theProjection, OpenGl_FrameBuffer* theReadDrawFbo, + OpenGl_FrameBuffer* theOitAccumFbo, const Standard_Boolean theToDrawImmediate); //! Draw background (gradient / image) @@ -418,9 +424,11 @@ protected: //! @name Rendering of GL graphics (with prepared drawing buffer). //! Render set of structures presented in the view. //! @param theProjection [in] the projection that is used for rendering. //! @param theReadDrawFbo [in] the framebuffer for rendering graphics. + //! @param theOitAccumFbo [in] the framebuffer for accumulating color and coverage for OIT process. //! @param theToDrawImmediate [in] the flag indicates whether the rendering performs in immediate mode. Standard_EXPORT virtual void renderStructs (Graphic3d_Camera::Projection theProjection, OpenGl_FrameBuffer* theReadDrawFbo, + OpenGl_FrameBuffer* theOitAccumFbo, const Standard_Boolean theToDrawImmediate); //! Renders trihedron. @@ -460,6 +468,15 @@ private: //! Blend together views pair into stereo image. void drawStereoPair (OpenGl_FrameBuffer* theDrawFbo); + //! Check and update OIT compatibility with current OpenGL context's state. + bool checkOitCompatibility (const Handle(OpenGl_Context)& theGlContext, + const Standard_Boolean theMSAA); + + //! Chooses compatible internal color format for OIT frame buffer. + bool chooseOitColorConfiguration (const Handle(OpenGl_Context)& theGlContext, + const Standard_Integer theConfigIndex, + OpenGl_ColorFormats& theFormats); + protected: OpenGl_GraphicDriver* myDriver; @@ -513,13 +530,18 @@ protected: //! @name Rendering properties //! of the view (without presentation of immediate layers). GLint myFboColorFormat; //!< sized format for color attachments GLint myFboDepthFormat; //!< sized format for depth-stencil attachments + OpenGl_ColorFormats myFboOitColorConfig; //!< selected color format configuration for OIT color attachments Handle(OpenGl_FrameBuffer) myMainSceneFbos[2]; - Handle(OpenGl_FrameBuffer) myImmediateSceneFbos[2]; //!< Additional buffers for immediate layer in stereo mode. + 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. OpenGl_VertexBuffer myFullScreenQuad; //!< Vertices for full-screen quad rendering. OpenGl_VertexBuffer myFullScreenQuadFlip; Standard_Boolean myToFlipOutput; //!< Flag to draw result image upside-down unsigned int myFrameCounter; //!< redraw counter, for debugging Standard_Boolean myHasFboBlit; //!< disable FBOs on failure + Standard_Boolean myToDisableOIT; //!< disable OIT on failure + Standard_Boolean myToDisableOITMSAA; //!< disable OIT with MSAA on failure Standard_Boolean myToDisableMSAA; //!< disable MSAA after failure Standard_Boolean myTransientDrawToFront; //!< optimization flag for immediate mode (to render directly to the front buffer) Standard_Boolean myBackBufferRestored; @@ -1051,6 +1073,7 @@ public: friend class OpenGl_GraphicDriver; friend class OpenGl_Workspace; + friend class OpenGl_LayerList; }; #endif // _OpenGl_View_Header diff --git a/src/OpenGl/OpenGl_View_Redraw.cxx b/src/OpenGl/OpenGl_View_Redraw.cxx index 7835b4f3a1..d15d44994d 100644 --- a/src/OpenGl/OpenGl_View_Redraw.cxx +++ b/src/OpenGl/OpenGl_View_Redraw.cxx @@ -163,6 +163,12 @@ void OpenGl_View::Redraw() aNbSamples = OpenGl_Context::GetPowerOfTwo (aNbSamples, aCtx->MaxMsaaSamples()); } + bool toUseOit = myRenderParams.IsOitEnabled + && checkOitCompatibility (aCtx, aNbSamples > 0); + + bool toInitImmediateFbo = myTransientDrawToFront + && (!aCtx->caps->useSystemBuffer || (toUseOit && HasImmediateStructures())); + if ( aFrameBuffer == NULL && !aCtx->DefaultFrameBuffer().IsNull() && aCtx->DefaultFrameBuffer()->IsValid()) @@ -173,7 +179,8 @@ void OpenGl_View::Redraw() if (myHasFboBlit && (myTransientDrawToFront || aProjectType == Graphic3d_Camera::Projection_Stereo - || aNbSamples != 0)) + || aNbSamples != 0 + || toUseOit)) { if (myMainSceneFbos[0]->GetVPSizeX() != aSizeX || myMainSceneFbos[0]->GetVPSizeY() != aSizeY @@ -193,12 +200,10 @@ void OpenGl_View::Redraw() { myMainSceneFbos[0]->Init (aCtx, aSizeX, aSizeY, myFboColorFormat, myFboDepthFormat, aNbSamples); } - if (myTransientDrawToFront - && !aCtx->caps->useSystemBuffer - && myMainSceneFbos[0]->IsValid()) - { - myImmediateSceneFbos[0]->InitLazy (aCtx, *myMainSceneFbos[0]); - } + } + if (myMainSceneFbos[0]->IsValid() && (toInitImmediateFbo || myImmediateSceneFbos[0]->IsValid())) + { + myImmediateSceneFbos[0]->InitLazy (aCtx, *myMainSceneFbos[0]); } } else @@ -238,6 +243,93 @@ void OpenGl_View::Redraw() } } + // create color and coverage accumulation buffers required for OIT algorithm + if (toUseOit) + { + Standard_Integer anFboIt = 0; + for (; anFboIt < 2; ++anFboIt) + { + if (myMainSceneFbos[anFboIt]->IsValid() + && (myMainSceneFbosOit[anFboIt]->GetVPSizeX() != aSizeX + || myMainSceneFbosOit[anFboIt]->GetVPSizeY() != aSizeY + || myMainSceneFbosOit[anFboIt]->NbSamples() != aNbSamples)) + { + Standard_Integer aColorConfig = 0; + for (;;) // seemly responding to driver limitation (GL_FRAMEBUFFER_UNSUPPORTED) + { + if (myFboOitColorConfig.IsEmpty()) + { + if (!chooseOitColorConfiguration (aCtx, aColorConfig++, myFboOitColorConfig)) + { + break; + } + } + if (myMainSceneFbosOit[anFboIt]->Init (aCtx, aSizeX, aSizeY, myFboOitColorConfig, myMainSceneFbos[anFboIt]->DepthStencilTexture(), aNbSamples)) + { + break; + } + myFboOitColorConfig.Clear(); + } + if (!myMainSceneFbosOit[anFboIt]->IsValid()) + { + break; + } + } + else if (!myMainSceneFbosOit[anFboIt]->IsValid()) + { + myMainSceneFbosOit[anFboIt]->Release (aCtx.operator->()); + myMainSceneFbosOit[anFboIt]->ChangeViewport (0, 0); + } + + if (myImmediateSceneFbos[anFboIt]->IsValid() + && (myImmediateSceneFbosOit[anFboIt]->GetVPSizeX() != aSizeX + || myImmediateSceneFbosOit[anFboIt]->GetVPSizeY() != aSizeY + || myImmediateSceneFbosOit[anFboIt]->NbSamples() != aNbSamples)) + { + if (!myImmediateSceneFbosOit[anFboIt]->Init (aCtx, aSizeX, aSizeY, myFboOitColorConfig, myImmediateSceneFbos[anFboIt]->DepthStencilTexture(), aNbSamples)) + { + break; + } + } + else if (!myImmediateSceneFbosOit[anFboIt]->IsValid()) + { + myImmediateSceneFbosOit[anFboIt]->Release (aCtx.operator->()); + myImmediateSceneFbosOit[anFboIt]->ChangeViewport (0, 0); + } + } + if (!anFboIt) // only the first OIT framebuffer is mandatory + { + TCollection_ExtendedString aMsg = + "Initialization of float texture framebuffer for use with\n" + " blended order-independent transparency rendering algorithm has failed.\n" + " Blended order-independent transparency will not be available.\n"; + + aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, + GL_DEBUG_TYPE_ERROR, + 0, + GL_DEBUG_SEVERITY_HIGH, + aMsg); + + if (aNbSamples > 0) + myToDisableOITMSAA = Standard_True; + else + myToDisableOIT = Standard_True; + + toUseOit = false; + } + } + if (!toUseOit && myMainSceneFbosOit[0]->IsValid()) + { + myMainSceneFbosOit [0]->Release (aCtx.operator->()); + myMainSceneFbosOit [1]->Release (aCtx.operator->()); + myImmediateSceneFbosOit[0]->Release (aCtx.operator->()); + myImmediateSceneFbosOit[1]->Release (aCtx.operator->()); + myMainSceneFbosOit [0]->ChangeViewport (0, 0); + myMainSceneFbosOit [1]->ChangeViewport (0, 0); + myImmediateSceneFbosOit[0]->ChangeViewport (0, 0); + myImmediateSceneFbosOit[1]->ChangeViewport (0, 0); + } + if (aProjectType == Graphic3d_Camera::Projection_Stereo) { OpenGl_FrameBuffer* aMainFbos[2] = @@ -245,34 +337,51 @@ void OpenGl_View::Redraw() myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL, myMainSceneFbos[1]->IsValid() ? myMainSceneFbos[1].operator->() : NULL }; + OpenGl_FrameBuffer* aMainFbosOit[2] = + { + myMainSceneFbosOit[0]->IsValid() ? myMainSceneFbosOit[0].operator->() : NULL, + myMainSceneFbosOit[1]->IsValid() ? myMainSceneFbosOit[1].operator->() : + myMainSceneFbosOit[0]->IsValid() ? myMainSceneFbosOit[0].operator->() : NULL + }; + OpenGl_FrameBuffer* anImmFbos[2] = { myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL, myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL }; + OpenGl_FrameBuffer* anImmFbosOit[2] = + { + myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL, + myImmediateSceneFbosOit[1]->IsValid() ? myImmediateSceneFbosOit[1].operator->() : + myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL + }; if (!myTransientDrawToFront) { - anImmFbos[0] = aMainFbos[0]; - anImmFbos[1] = aMainFbos[1]; + anImmFbos [0] = aMainFbos [0]; + anImmFbos [1] = aMainFbos [1]; + anImmFbosOit[0] = aMainFbosOit[0]; + anImmFbosOit[1] = aMainFbosOit[1]; } else if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip || aStereoMode == Graphic3d_StereoMode_QuadBuffer) { - anImmFbos[0] = NULL; - anImmFbos[1] = NULL; + anImmFbos [0] = NULL; + anImmFbos [1] = NULL; + anImmFbosOit[0] = NULL; + anImmFbosOit[1] = NULL; } #if !defined(GL_ES_VERSION_2_0) aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK); #endif - redraw (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0]); + redraw (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0], aMainFbosOit[0]); myBackBufferRestored = Standard_True; myIsImmediateDrawn = Standard_False; #if !defined(GL_ES_VERSION_2_0) aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK); #endif - if (!redrawImmediate (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0], anImmFbos[0])) + if (!redrawImmediate (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0], anImmFbos[0], anImmFbosOit[0])) { toSwap = false; } @@ -284,10 +393,10 @@ void OpenGl_View::Redraw() #if !defined(GL_ES_VERSION_2_0) aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_RIGHT : GL_BACK); #endif - redraw (Graphic3d_Camera::Projection_MonoRightEye, aMainFbos[1]); + redraw (Graphic3d_Camera::Projection_MonoRightEye, aMainFbos[1], aMainFbosOit[1]); myBackBufferRestored = Standard_True; myIsImmediateDrawn = Standard_False; - if (!redrawImmediate (Graphic3d_Camera::Projection_MonoRightEye, aMainFbos[1], anImmFbos[1])) + if (!redrawImmediate (Graphic3d_Camera::Projection_MonoRightEye, aMainFbos[1], anImmFbos[1], anImmFbosOit[1])) { toSwap = false; } @@ -299,15 +408,19 @@ void OpenGl_View::Redraw() } else { - OpenGl_FrameBuffer* aMainFbo = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : aFrameBuffer; - OpenGl_FrameBuffer* anImmFbo = aFrameBuffer; - if (!aCtx->caps->useSystemBuffer && myImmediateSceneFbos[0]->IsValid()) + OpenGl_FrameBuffer* aMainFbo = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : aFrameBuffer; + OpenGl_FrameBuffer* aMainFboOit = myMainSceneFbosOit[0]->IsValid() ? myMainSceneFbosOit[0].operator->() : NULL; + OpenGl_FrameBuffer* anImmFbo = aFrameBuffer; + OpenGl_FrameBuffer* anImmFboOit = NULL; + if (!myTransientDrawToFront) { - anImmFbo = myImmediateSceneFbos[0].operator->(); + anImmFbo = aMainFbo; + anImmFboOit = aMainFboOit; } - if (!myTransientDrawToFront) + else if (myImmediateSceneFbos[0]->IsValid()) { - anImmFbo = aMainFbo; + anImmFbo = myImmediateSceneFbos[0].operator->(); + anImmFboOit = myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL; } #if !defined(GL_ES_VERSION_2_0) @@ -316,10 +429,10 @@ void OpenGl_View::Redraw() aCtx->SetReadDrawBuffer (GL_BACK); } #endif - redraw (aProjectType, aMainFbo); + redraw (aProjectType, aMainFbo, aMainFboOit); myBackBufferRestored = Standard_True; myIsImmediateDrawn = Standard_False; - if (!redrawImmediate (aProjectType, aMainFbo, anImmFbo)) + if (!redrawImmediate (aProjectType, aMainFbo, anImmFbo, anImmFboOit)) { toSwap = false; } @@ -422,11 +535,19 @@ void OpenGl_View::RedrawImmediate() myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL, myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL }; + OpenGl_FrameBuffer* anImmFbosOit[2] = + { + myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL, + myImmediateSceneFbosOit[1]->IsValid() ? myImmediateSceneFbosOit[1].operator->() : + myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL + }; if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip || aStereoMode == Graphic3d_StereoMode_QuadBuffer) { - anImmFbos[0] = NULL; - anImmFbos[1] = NULL; + anImmFbos[0] = NULL; + anImmFbos[1] = NULL; + anImmFbosOit[0] = NULL; + anImmFbosOit[1] = NULL; } if (aCtx->arbFBO != NULL) @@ -442,6 +563,7 @@ void OpenGl_View::RedrawImmediate() toSwap = redrawImmediate (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0], anImmFbos[0], + anImmFbosOit[0], Standard_True) || toSwap; if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip && toSwap @@ -463,6 +585,7 @@ void OpenGl_View::RedrawImmediate() toSwap = redrawImmediate (Graphic3d_Camera::Projection_MonoRightEye, aMainFbos[1], anImmFbos[1], + anImmFbosOit[1], Standard_True) || toSwap; if (anImmFbos[0] != NULL) { @@ -473,9 +596,11 @@ void OpenGl_View::RedrawImmediate() { OpenGl_FrameBuffer* aMainFbo = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL; OpenGl_FrameBuffer* anImmFbo = aFrameBuffer; - if (!aCtx->caps->useSystemBuffer && myImmediateSceneFbos[0]->IsValid()) + OpenGl_FrameBuffer* anImmFboOit = NULL; + if (myImmediateSceneFbos[0]->IsValid()) { - anImmFbo = myImmediateSceneFbos[0].operator->(); + anImmFbo = myImmediateSceneFbos[0].operator->(); + anImmFboOit = myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL; } #if !defined(GL_ES_VERSION_2_0) if (aMainFbo == NULL) @@ -486,6 +611,7 @@ void OpenGl_View::RedrawImmediate() toSwap = redrawImmediate (aProjectType, aMainFbo, anImmFbo, + anImmFboOit, Standard_True) || toSwap; if (anImmFbo != NULL && anImmFbo != aFrameBuffer) @@ -517,7 +643,9 @@ void OpenGl_View::RedrawImmediate() // function : redraw // purpose : // ======================================================================= -void OpenGl_View::redraw (const Graphic3d_Camera::Projection theProjection, OpenGl_FrameBuffer* theReadDrawFbo) +void OpenGl_View::redraw (const Graphic3d_Camera::Projection theProjection, + OpenGl_FrameBuffer* theReadDrawFbo, + OpenGl_FrameBuffer* theOitAccumFbo) { Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext(); if (theReadDrawFbo != NULL) @@ -552,7 +680,7 @@ void OpenGl_View::redraw (const Graphic3d_Camera::Projection theProjection, Open glClear (toClear); - render (theProjection, theReadDrawFbo, Standard_False); + render (theProjection, theReadDrawFbo, theOitAccumFbo, Standard_False); } // ======================================================================= @@ -562,6 +690,7 @@ void OpenGl_View::redraw (const Graphic3d_Camera::Projection theProjection, Open bool OpenGl_View::redrawImmediate (const Graphic3d_Camera::Projection theProjection, OpenGl_FrameBuffer* theReadFbo, OpenGl_FrameBuffer* theDrawFbo, + OpenGl_FrameBuffer* theOitAccumFbo, const Standard_Boolean theIsPartialUpdate) { Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext(); @@ -617,7 +746,7 @@ bool OpenGl_View::redrawImmediate (const Graphic3d_Camera::Projection theProject glClearDepthf (1.0f); #endif - render (theProjection, theDrawFbo, Standard_True); + render (theProjection, theDrawFbo, theOitAccumFbo, Standard_True); return !toCopyBackToFront; } @@ -628,6 +757,7 @@ bool OpenGl_View::redrawImmediate (const Graphic3d_Camera::Projection theProject //======================================================================= void OpenGl_View::render (Graphic3d_Camera::Projection theProjection, OpenGl_FrameBuffer* theOutputFBO, + OpenGl_FrameBuffer* theOitAccumFbo, const Standard_Boolean theToDrawImmediate) { // ================================== @@ -752,7 +882,7 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection, myWorkspace->SetEnvironmentTexture (myTextureEnv); - renderScene (theProjection, theOutputFBO, theToDrawImmediate); + renderScene (theProjection, theOutputFBO, theOitAccumFbo, theToDrawImmediate); myWorkspace->SetEnvironmentTexture (Handle(OpenGl_Texture)()); @@ -812,6 +942,7 @@ void OpenGl_View::InvalidateBVHData (const Graphic3d_ZLayerId theLayerId) //======================================================================= void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection, OpenGl_FrameBuffer* theReadDrawFbo, + OpenGl_FrameBuffer* theOitAccumFbo, const Standard_Boolean theToDrawImmediate) { if ( myZLayers.NbStructures() <= 0 ) @@ -848,7 +979,7 @@ void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection, if (aCtx->arbFBOBlit != NULL) { // Render bottom OSD layer - myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_Bottom); + myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_Bottom, theReadDrawFbo, theOitAccumFbo); myWorkspace->SetRenderFilter (myRaytraceFilter); { @@ -862,7 +993,7 @@ void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection, } // Render non-polygonal elements in default layer - myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_Default); + myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_Default, theReadDrawFbo, theOitAccumFbo); } myWorkspace->SetRenderFilter (myRaytraceFilter->PrevRenderFilter()); } @@ -884,7 +1015,7 @@ void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection, raytrace (aSizeX, aSizeY, theProjection, theReadDrawFbo, aCtx); // Render upper (top and topmost) OpenGL layers - myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_Upper); + myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_Upper, theReadDrawFbo, theOitAccumFbo); } } @@ -892,7 +1023,7 @@ void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection, // mode or in case of ray-tracing failure if (toRenderGL) { - myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_All); + myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_All, theReadDrawFbo, theOitAccumFbo); // Set flag that scene was redrawn by standard pipeline myWasRedrawnGL = Standard_True; @@ -926,6 +1057,7 @@ void OpenGl_View::Invalidate() //======================================================================= void OpenGl_View::renderScene (Graphic3d_Camera::Projection theProjection, OpenGl_FrameBuffer* theReadDrawFbo, + OpenGl_FrameBuffer* theOitAccumFbo, const Standard_Boolean theToDrawImmediate) { const Handle(OpenGl_Context)& aContext = myWorkspace->GetGlContext(); @@ -942,7 +1074,7 @@ void OpenGl_View::renderScene (Graphic3d_Camera::Projection theProjection, myWorkspace->NamedStatus &= ~(OPENGL_NS_2NDPASSNEED | OPENGL_NS_2NDPASSDO); // First pass - renderStructs (theProjection, theReadDrawFbo, theToDrawImmediate); + renderStructs (theProjection, theReadDrawFbo, theOitAccumFbo, theToDrawImmediate); myWorkspace->DisableTexture(); // Second pass @@ -972,7 +1104,7 @@ void OpenGl_View::renderScene (Graphic3d_Camera::Projection theProjection, glEnable (GL_DEPTH_TEST); // Render the view - renderStructs (theProjection, theReadDrawFbo, theToDrawImmediate); + renderStructs (theProjection, theReadDrawFbo, theOitAccumFbo, theToDrawImmediate); myWorkspace->DisableTexture(); // Restore properties back @@ -1477,3 +1609,74 @@ void OpenGl_View::copyBackToFront() #endif myIsImmediateDrawn = Standard_False; } + +// ======================================================================= +// function : checkOitCompatibility +// purpose : +// ======================================================================= +Standard_Boolean OpenGl_View::checkOitCompatibility (const Handle(OpenGl_Context)& theGlContext, + const Standard_Boolean theMSAA) +{ + // determine if OIT is supported by current OpenGl context + Standard_Boolean& aToDisableOIT = theMSAA ? myToDisableMSAA : myToDisableOIT; + + if (!aToDisableOIT && theMSAA) + { + if (!theGlContext->arbSampleShading) + { + TCollection_ExtendedString aMsg = TCollection_ExtendedString() + + "Current version of GLSL does not support built-in sample variables.\n" + + " Blended order-independent transparency will not be available.\n"; + theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, + GL_DEBUG_TYPE_ERROR, + 0, + GL_DEBUG_SEVERITY_HIGH, + aMsg); + + aToDisableOIT = Standard_True; + } + } + else if (!aToDisableOIT) + { + if (theGlContext->MaxDrawBuffers() < 2) + { + TCollection_ExtendedString aMsg = TCollection_ExtendedString() + + "OpenGL context does not support multiple rendering targets.\n" + + " Blended order-independent transparency will not be available.\n"; + theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, + GL_DEBUG_TYPE_ERROR, + 0, + GL_DEBUG_SEVERITY_HIGH, + aMsg); + aToDisableOIT = Standard_True; + } + } + + return !aToDisableOIT; +} + +// ======================================================================= +// function : chooseOitColorConfiguration +// purpose : +// ======================================================================= +bool OpenGl_View::chooseOitColorConfiguration (const Handle(OpenGl_Context)& theGlContext, + const Standard_Integer theConfigIndex, + OpenGl_ColorFormats& theFormats) +{ + theFormats.Clear(); + + switch (theConfigIndex) + { + case 0: // choose best applicable color format combination + theFormats.Append (theGlContext->arbTexHalfFloat ? GL_RGBA16F : GL_RGBA32F); + theFormats.Append (theGlContext->arbTexHalfFloat ? GL_R16F : GL_R32F); + return true; + + case 1: // choose non-optimal applicable color format combination + theFormats.Append (theGlContext->arbTexHalfFloat ? GL_RGBA16F : GL_RGBA32F); + theFormats.Append (theGlContext->arbTexHalfFloat ? GL_RGBA16F : GL_RGBA32F); + return true; + } + + return false; // color combination does not exist +} diff --git a/src/OpenGl/OpenGl_Workspace.cxx b/src/OpenGl/OpenGl_Workspace.cxx index f059750646..0fb379582d 100644 --- a/src/OpenGl/OpenGl_Workspace.cxx +++ b/src/OpenGl/OpenGl_Workspace.cxx @@ -715,7 +715,7 @@ const OpenGl_AspectFace* OpenGl_Workspace::ApplyAspectFace() } else { - myGlContext->SetShadingMaterial (myAspectFaceSet, myHighlightStyle, myUseDepthWrite, NamedStatus); + myGlContext->SetShadingMaterial (myAspectFaceSet, myHighlightStyle, NamedStatus); } if (myAspectFaceSet->Aspect()->ToMapTexture()) @@ -1107,15 +1107,16 @@ Standard_Boolean OpenGl_Workspace::BufferDump (const Handle(OpenGl_FrameBuffer)& } // ======================================================================= -// function : CanRender +// function : ShouldRender // purpose : // ======================================================================= -Standard_Boolean OpenGl_RaytraceFilter::CanRender (const OpenGl_Element* theElement) +Standard_Boolean OpenGl_RaytraceFilter::ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace, + const OpenGl_Element* theElement) { Standard_Boolean aPrevFilterResult = Standard_True; if (!myPrevRenderFilter.IsNull()) { - aPrevFilterResult = myPrevRenderFilter->CanRender (theElement); + aPrevFilterResult = myPrevRenderFilter->ShouldRender (theWorkspace, theElement); } return aPrevFilterResult && !OpenGl_Raytrace::IsRaytracedElement (theElement); diff --git a/src/OpenGl/OpenGl_Workspace.hxx b/src/OpenGl/OpenGl_Workspace.hxx index 0723828136..34f66aacd3 100644 --- a/src/OpenGl/OpenGl_Workspace.hxx +++ b/src/OpenGl/OpenGl_Workspace.hxx @@ -62,7 +62,8 @@ public: //! Checks whether the element can be rendered or not. //! @param theElement [in] the element to check. //! @return True if element can be rendered. - virtual Standard_Boolean CanRender (const OpenGl_Element* theElement) Standard_OVERRIDE; + virtual Standard_Boolean ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace, + const OpenGl_Element* theElement) Standard_OVERRIDE; private: diff --git a/src/Shaders/PhongShading.fs b/src/Shaders/PhongShading.fs index 925e5d2f2b..439b793f2f 100755 --- a/src/Shaders/PhongShading.fs +++ b/src/Shaders/PhongShading.fs @@ -166,10 +166,11 @@ vec4 computeLighting (in vec3 theNormal, vec4 aMaterialDiffuse = gl_FrontFacing ? occFrontMaterial_Diffuse() : occBackMaterial_Diffuse(); vec4 aMaterialSpecular = gl_FrontFacing ? occFrontMaterial_Specular() : occBackMaterial_Specular(); vec4 aMaterialEmission = gl_FrontFacing ? occFrontMaterial_Emission() : occBackMaterial_Emission(); - return vec4 (Ambient, 1.0) * aMaterialAmbient - + vec4 (Diffuse, 1.0) * aMaterialDiffuse - + vec4 (Specular, 1.0) * aMaterialSpecular - + aMaterialEmission; + vec3 aColor = Ambient * aMaterialAmbient.rgb + + Diffuse * aMaterialDiffuse.rgb + + Specular * aMaterialSpecular.rgb + + aMaterialEmission.rgb; + return vec4 (aColor, aMaterialDiffuse.a); } //! Entry point to the Fragment Shader @@ -185,7 +186,14 @@ void main() } } - gl_FragColor = computeLighting (normalize (Normal), + occFragColor = computeLighting (normalize (Normal), normalize (View), Position); + + if (occOitEnableWrite != 0) + { + float aWeight = occFragColor.a * clamp (1e+2 * pow (1.0 - gl_FragCoord.z * occOitDepthWeight, 3.0), 1e-2, 1e+2); + occFragCoverage.r = occFragColor.a * aWeight; + occFragColor = vec4 (occFragColor.rgb * occFragColor.a * aWeight, occFragColor.a); + } } diff --git a/src/Shaders/Shaders_Declarations_glsl.pxx b/src/Shaders/Shaders_Declarations_glsl.pxx index da738498f8..4e030f5e65 100644 --- a/src/Shaders/Shaders_Declarations_glsl.pxx +++ b/src/Shaders/Shaders_Declarations_glsl.pxx @@ -50,8 +50,16 @@ static const char Shaders_Declarations_glsl[] = " THE_ATTRIBUTE vec4 occVertColor;\n" "#elif (__VERSION__ >= 130)\n" " out vec4 occFragColor;\n" + " #ifdef OCC_enable_draw_buffers\n" + " out vec4 occFragCoverage;\n" + " #endif\n" "#else\n" - " #define occFragColor gl_FragColor\n" + " #ifdef OCC_enable_draw_buffers\n" + " #define occFragColor gl_FragData[0]\n" + " #define occFragCoverage gl_FragData[1]\n" + " #else\n" + " #define occFragColor gl_FragColor\n" + " #endif\n" "#endif\n" "\n" "// Matrix state\n" @@ -113,6 +121,10 @@ static const char Shaders_Declarations_glsl[] = "uniform vec4 occTexTrsf2d[2]; //!< 2D texture transformation parameters\n" "uniform float occPointSize; //!< point size\n" "\n" + "//! Parameters of blended order-independent transparency rendering algorithm\n" + "uniform int occOitEnableWrite; //!< Enable bit for writing color (occFragColor), coverage (occFragCoverage) buffers of OIT processing\n" + "uniform float occOitDepthWeight; //!< Influence of the depth component to the coverage of the accumulated fragment\n" + "\n" "//! Parameters of clipping planes\n" "uniform vec4 occClipPlaneEquations[THE_MAX_CLIP_PLANES];\n" "uniform THE_PREC_ENUM int occClipPlaneCount; //!< Total number of clip planes\n"; diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index ce91b42a55..3692b6204a 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -9065,6 +9065,8 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI, } theDI << "\n"; theDI << "msaa: " << aParams.NbMsaaSamples << "\n"; + theDI << "oit: " << (aParams.IsOitEnabled ? "on" : "off") << "\n"; + theDI << "oitDepthWeight: " << aParams.OitDepthWeight << "\n"; theDI << "rayDepth: " << aParams.RaytracingDepth << "\n"; theDI << "fsaa: " << (aParams.IsAntialiasingEnabled ? "on" : "off") << "\n"; theDI << "shadows: " << (aParams.IsShadowEnabled ? "on" : "off") << "\n"; @@ -9171,6 +9173,46 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI, aParams.NbMsaaSamples = aNbSamples; } } + else if (aFlag == "-oit") + { + if (toPrint) + { + theDI << (aParams.IsOitEnabled ? "on" : "off") << " "; + continue; + } + Standard_Boolean toEnable = Standard_True; + if (++anArgIter < theArgNb + && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable)) + { + --anArgIter; + } + aParams.IsOitEnabled = toEnable; + } + else if (aFlag == "-oitdepth" + || aFlag == "-oitdepthweight") + { + if (toPrint) + { + theDI << aParams.OitDepthWeight << " "; + continue; + } + else if (++anArgIter >= theArgNb) + { + std::cerr << "Error: wrong syntax at argument '" << anArg << "'\n"; + return 1; + } + const Standard_Real aWeight = Draw::Atof (theArgVec[anArgIter]); + + if (aWeight < 0.0 || aWeight > 1.0) + { + std::cerr << "Error: invalid value of order-indepedent transparency depth weight " << aWeight << ". Should be within range [0.0; 1.0]\n"; + return 1; + } + else + { + aParams.OitDepthWeight = static_cast (aWeight); + } + } else if (aFlag == "-raydepth" || aFlag == "-ray_depth") { @@ -10926,6 +10968,8 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands) "\n Manages rendering parameters: " "\n '-raster' Disables GPU ray-tracing" "\n '-msaa 0..4' Specifies number of samples for MSAA" + "\n '-oit on|off' Enables/disables blended order-independent transparency" + "\n '-oitDepthWeight 0.0-1.0' Defines influence of fragment depth to its coverage" "\n '-rayTrace' Enables GPU ray-tracing" "\n '-rayDepth 0..10' Defines maximum ray-tracing depth" "\n '-shadows on|off' Enables/disables shadows rendering"