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.
}
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();
aGroup->SetGroupPrimitivesAspect (anAreaAsp);
}
}
- aPrs->ResetDisplayPriority();
}
myRecomputeEveryPrs = Standard_False; // no mode to recalculate :only viewer update
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();
aGroup->SetGroupPrimitivesAspect (anAreaAsp);
}
}
-
- if (!IsTransparent())
- {
- aPrs->ResetDisplayPriority();
- }
}
myRecomputeEveryPrs = Standard_False; // no mode to recalculate - only viewer update
Graphic3d_RenderingParams()
: Method (Graphic3d_RM_RASTERIZATION),
NbMsaaSamples (0),
+ IsOitEnabled (Standard_True),
+ OitDepthWeight (0.0f),
// ray tracing parameters
IsGlobalIlluminationEnabled (Standard_False),
RaytracingDepth (THE_DEFAULT_DEPTH),
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)
OpenGl_IndexBuffer.hxx
OpenGl_Layer.cxx
OpenGl_Layer.hxx
+OpenGl_OitUniformState.hxx
OpenGl_RenderFilter.cxx
OpenGl_RenderFilter.hxx
OpenGl_Sampler.cxx
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.
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);
// 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()
// 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);
// 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<const OpenGl_PrimitiveArray*> (theElement);
+ if (!myFilter.IsNull() && !myFilter->ShouldRender (theWorkspace, theGlElement))
+ {
+ return Standard_False;
+ }
+
+ const OpenGl_PrimitiveArray* aPArray = dynamic_cast<const OpenGl_PrimitiveArray*> (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;
}
//! 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
arbNPTW (Standard_False),
arbTexRG (Standard_False),
arbTexFloat (Standard_False),
+ arbTexHalfFloat (Standard_False),
+ arbSampleShading (Standard_False),
arbTexBindless (NULL),
arbTBO (NULL),
arbTboRGB32 (Standard_False),
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),
#endif
myToCullBackFaces (false),
myReadBuffer (0),
- myDrawBuffer (0),
+ myDrawBuffers (1),
myDefaultVao (0),
myIsGlDebugCtx (Standard_False),
myResolutionRatio (1.0f)
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 :
::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
}
myGlVerMajor = 0;
myGlVerMinor = 0;
myMaxMsaaSamples = 0;
+ myMaxDrawBuffers = 1;
ReadGlVersion (myGlVerMajor, myGlVerMinor);
myVendor = (const char* )::glGetString (GL_VENDOR);
if (!caps->ffpEnable
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");
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);
}
}
+ 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);
// 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);
// =======================================================================
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())
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);
}
}
#include <Aspect_TypeOfLine.hxx>
#include <NCollection_DataMap.hxx>
#include <Graphic3d_DiagnosticInfo.hxx>
-#include <NCollection_Map.hxx>
+#include <NCollection_Array1.hxx>
#include <NCollection_Handle.hxx>
#include <NCollection_List.hxx>
+#include <NCollection_Map.hxx>
+#include <NCollection_SparseArray.hxx>
#include <Message.hxx>
#include <OpenGl_Caps.hxx>
#include <OpenGl_LineAttributes.hxx>
#include <NCollection_Shared.hxx>
+#include <vector>
+
//! Forward declarations
#if defined(__APPLE__)
#import <TargetConditionals.h>
//! @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; }
//! 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)
{
//! 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.
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
typedef NCollection_Shared< NCollection_DataMap<TCollection_AsciiString, Standard_Integer> > OpenGl_DelayReleaseMap;
typedef NCollection_Shared< NCollection_DataMap<TCollection_AsciiString, Handle(OpenGl_Resource)> > OpenGl_ResourcesMap;
typedef NCollection_Shared< NCollection_List<Handle(OpenGl_Resource)> > OpenGl_ResourcesStack;
+ typedef NCollection_SparseArray<Standard_Integer> OpenGl_DrawBuffers;
Handle(OpenGl_ResourcesMap) mySharedResources; //!< shared resources with unique identification key
Handle(OpenGl_DelayReleaseMap) myDelayed; //!< shared resources for delayed release
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
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
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
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;
}
#include <Standard_Assert.hxx>
#include <TCollection_ExtendedString.hxx>
+#include <algorithm>
+
IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer,OpenGl_Resource)
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;
+ }
}
// =======================================================================
: 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());
}
// =======================================================================
// 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;
// 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
// 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))
}
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,
// 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
}
// =======================================================================
-// function : Init
+// function : InitLazy
// purpose :
// =======================================================================
Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
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);
}
// =======================================================================
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;
Release (theGlCtx.operator->());
myIsOwnBuffer = true;
+ myIsOwnDepth = true;
// setup viewport sizes as is
myVPSizeX = theSizeX;
{
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)
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,
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,
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;
#include <OpenGl_Resource.hxx>
#include <OpenGl_Texture.hxx>
+#include <NCollection_Vector.hxx>
+
class OpenGl_FrameBuffer;
DEFINE_STANDARD_HANDLE(OpenGl_FrameBuffer, OpenGl_Resource)
+//! Short declaration of useful collection types.
+typedef NCollection_Vector<GLint> OpenGl_ColorFormats;
+
//! Class implements FrameBuffer Object (FBO) resource
//! intended for off-screen rendering.
class OpenGl_FrameBuffer : public OpenGl_Resource
{
-
public:
//! Helpful constants
public:
- //! Empty constructor
+ //! Constructor.
Standard_EXPORT OpenGl_FrameBuffer();
//! Destructor
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.
//! 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.
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,
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,
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,
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.
protected:
+ typedef NCollection_Vector<Handle(OpenGl_Texture)> 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:
#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))
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);
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();
#include <Graphic3d_Camera.hxx>
#include <OpenGl_GlCore11.hxx>
-
struct OpenGl_GlobalLayerSettings
{
GLint DepthFunc;
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
-#include <OpenGl_GlCore11.hxx>
+#include <OpenGl_GlCore15.hxx>
+#include <OpenGl_FrameBuffer.hxx>
#include <OpenGl_LayerList.hxx>
+#include <OpenGl_ShaderManager.hxx>
#include <OpenGl_Structure.hxx>
+#include <OpenGl_VertexBuffer.hxx>
+#include <OpenGl_View.hxx>
#include <OpenGl_Workspace.hxx>
#include <Graphic3d_GraphicDriver.hxx>
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));
myLayerIds.Bind (Graphic3d_ZLayerId_TopOSD, myLayers.Upper());
myDefaultLayerIndex = myLayerIds.Find (Graphic3d_ZLayerId_Default);
+
+ myTransparentToProcess.Allocate (myLayers.Length());
}
//=======================================================================
// add the new layer
myLayers.Append (OpenGl_Layer (myNbPriorities));
myLayerIds.Bind (theLayerId, myLayers.Length());
+
+ myTransparentToProcess.Allocate (myLayers.Length());
}
//=======================================================================
}
myDefaultLayerIndex = myLayerIds.Find (Graphic3d_ZLayerId_Default);
+
+ myTransparentToProcess.Allocate (myLayers.Length());
}
//=======================================================================
//=======================================================================
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 <myTransparentToProcess>
+ // 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)
{
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)
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<const OpenGl_PrimitiveArray*> (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<const OpenGl_PrimitiveArray*> (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<const OpenGl_AspectFace*> (theGlElement) != NULL;
+ }
+
+ return Standard_False;
}
#include <OpenGl_Layer.hxx>
#include <OpenGl_LayerFilter.hxx>
+#include <NCollection_Array1.hxx>
+#include <NCollection_Handle.hxx>
#include <NCollection_Sequence.hxx>
#include <NCollection_DataMap.hxx>
//! 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; }
//! 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<const OpenGl_Layer*>::iterator iterator;
+
+ //! Reallocate internal buffer of the stack.
+ void Allocate (const Standard_Integer theSize)
+ {
+ if (theSize > 0)
+ {
+ myStackSpace = new NCollection_Array1<const OpenGl_Layer*> (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<NCollection_Array1<const OpenGl_Layer*> > 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
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
--- /dev/null
+// 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 <OpenGl_ShaderStates.hxx>
+
+//! 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
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);
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
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
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
}
#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);";
+
}
// =======================================================================
}
}
+// =======================================================================
+// 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
PushProjectionState (aProgram);
PushLightSourceState (aProgram);
PushMaterialState (aProgram);
+ PushOitUniformState (aProgram);
}
// =======================================================================
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 :
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)
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)
EOL"{"
+ aSrcFragExtraMain
+ aSrcFragMainGetColor
+ + aSrcFragWriteOit
+ EOL"}";
#if !defined(GL_ES_VERSION_2_0)
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)
{
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()
EOL"{"
+ aSrcFragExtraMain
+ EOL" occFragColor = getColor();"
- EOL"}";
+ + aSrcFragWriteOit
+ + EOL"}";
#if !defined(GL_ES_VERSION_2_0)
if (myContext->core32 != NULL)
#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)
{
aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
}
}
+ if ((theBits & OpenGl_PO_WriteOit) != 0)
+ {
+ aSrcFragWriteOit += THE_FRAG_write_oit_buffers;
+ }
aSrcVert = TCollection_AsciiString()
+ THE_FUNC_transformNormal
EOL"{"
+ aSrcFragExtraMain
+ EOL" occFragColor = getColor();"
- EOL"}";
+ + aSrcFragWriteOit
+ + EOL"}";
#if !defined(GL_ES_VERSION_2_0)
if (myContext->core32 != NULL)
#include <NCollection_DataMap.hxx>
#include <NCollection_Sequence.hxx>
-#include <OpenGl_SetOfShaderPrograms.hxx>
-#include <OpenGl_ShaderStates.hxx>
#include <OpenGl_AspectFace.hxx>
#include <OpenGl_AspectLine.hxx>
-#include <OpenGl_AspectText.hxx>
#include <OpenGl_AspectMarker.hxx>
+#include <OpenGl_AspectText.hxx>
+#include <OpenGl_OitUniformState.hxx>
+#include <OpenGl_SetOfShaderPrograms.hxx>
+#include <OpenGl_ShaderStates.hxx>
#include <OpenGl_MaterialState.hxx>
#include <OpenGl_Texture.hxx>
&& 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)
{
//! 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.
{
aBits |= OpenGl_PO_VertColor;
}
+
+ if (myOitUniformState.ToEnableWrite())
+ {
+ aBits |= OpenGl_PO_WriteOit;
+ }
+
return aBits;
}
//! 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);
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
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
"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
}
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:
"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;
}
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,
OpenGl_PROJECTION_STATE,
OpenGl_MATERIAL_STATE,
OpenGl_SURF_DETAIL_STATE,
+ OpenGL_OIT_UNIFORM_STATE,
OpenGl_UniformStateType_NB
};
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;
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),
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();
}
// =======================================================================
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);
}
//! 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.
//!
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.
//! 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)
//! 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.
//! 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;
//! 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;
friend class OpenGl_GraphicDriver;
friend class OpenGl_Workspace;
+ friend class OpenGl_LayerList;
};
#endif // _OpenGl_View_Header
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())
if (myHasFboBlit
&& (myTransientDrawToFront
|| aProjectType == Graphic3d_Camera::Projection_Stereo
- || aNbSamples != 0))
+ || aNbSamples != 0
+ || toUseOit))
{
if (myMainSceneFbos[0]->GetVPSizeX() != aSizeX
|| myMainSceneFbos[0]->GetVPSizeY() != aSizeY
{
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
}
}
+ // 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] =
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;
}
#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;
}
}
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)
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;
}
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)
toSwap = redrawImmediate (Graphic3d_Camera::Projection_MonoLeftEye,
aMainFbos[0],
anImmFbos[0],
+ anImmFbosOit[0],
Standard_True) || toSwap;
if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
&& toSwap
toSwap = redrawImmediate (Graphic3d_Camera::Projection_MonoRightEye,
aMainFbos[1],
anImmFbos[1],
+ anImmFbosOit[1],
Standard_True) || toSwap;
if (anImmFbos[0] != NULL)
{
{
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)
toSwap = redrawImmediate (aProjectType,
aMainFbo,
anImmFbo,
+ anImmFboOit,
Standard_True) || toSwap;
if (anImmFbo != NULL
&& anImmFbo != aFrameBuffer)
// 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)
glClear (toClear);
- render (theProjection, theReadDrawFbo, Standard_False);
+ render (theProjection, theReadDrawFbo, theOitAccumFbo, Standard_False);
}
// =======================================================================
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();
glClearDepthf (1.0f);
#endif
- render (theProjection, theDrawFbo, Standard_True);
+ render (theProjection, theDrawFbo, theOitAccumFbo, Standard_True);
return !toCopyBackToFront;
}
//=======================================================================
void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
OpenGl_FrameBuffer* theOutputFBO,
+ OpenGl_FrameBuffer* theOitAccumFbo,
const Standard_Boolean theToDrawImmediate)
{
// ==================================
myWorkspace->SetEnvironmentTexture (myTextureEnv);
- renderScene (theProjection, theOutputFBO, theToDrawImmediate);
+ renderScene (theProjection, theOutputFBO, theOitAccumFbo, theToDrawImmediate);
myWorkspace->SetEnvironmentTexture (Handle(OpenGl_Texture)());
//=======================================================================
void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection,
OpenGl_FrameBuffer* theReadDrawFbo,
+ OpenGl_FrameBuffer* theOitAccumFbo,
const Standard_Boolean theToDrawImmediate)
{
if ( myZLayers.NbStructures() <= 0 )
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);
{
}
// 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());
}
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);
}
}
// 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;
//=======================================================================
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();
myWorkspace->NamedStatus &= ~(OPENGL_NS_2NDPASSNEED | OPENGL_NS_2NDPASSDO);
// First pass
- renderStructs (theProjection, theReadDrawFbo, theToDrawImmediate);
+ renderStructs (theProjection, theReadDrawFbo, theOitAccumFbo, theToDrawImmediate);
myWorkspace->DisableTexture();
// Second pass
glEnable (GL_DEPTH_TEST);
// Render the view
- renderStructs (theProjection, theReadDrawFbo, theToDrawImmediate);
+ renderStructs (theProjection, theReadDrawFbo, theOitAccumFbo, theToDrawImmediate);
myWorkspace->DisableTexture();
// Restore properties back
#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
+}
}
else
{
- myGlContext->SetShadingMaterial (myAspectFaceSet, myHighlightStyle, myUseDepthWrite, NamedStatus);
+ myGlContext->SetShadingMaterial (myAspectFaceSet, myHighlightStyle, NamedStatus);
}
if (myAspectFaceSet->Aspect()->ToMapTexture())
}
// =======================================================================
-// 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);
//! 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:
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
}
}
- 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);
+ }
}
" 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"
"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";
}
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";
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<Standard_ShortReal> (aWeight);
+ }
+ }
else if (aFlag == "-raydepth"
|| aFlag == "-ray_depth")
{
"\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"