1 // Created on: 2012-02-02
2 // Created by: Anton POLETAEV
3 // Copyright (c) 2012-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <OpenGl_GlCore15.hxx>
18 #include <BVH_LinearBuilder.hxx>
19 #include <OpenGl_FrameBuffer.hxx>
20 #include <OpenGl_LayerList.hxx>
21 #include <OpenGl_ShaderManager.hxx>
22 #include <OpenGl_Structure.hxx>
23 #include <OpenGl_VertexBuffer.hxx>
24 #include <OpenGl_View.hxx>
25 #include <OpenGl_Workspace.hxx>
27 #include <Graphic3d_GraphicDriver.hxx>
31 //! Auxiliary class extending sequence iterator with index.
32 class OpenGl_IndexedLayerIterator : public NCollection_List<Handle(Graphic3d_Layer)>::Iterator
36 OpenGl_IndexedLayerIterator (const NCollection_List<Handle(Graphic3d_Layer)>& theSeq)
37 : NCollection_List<Handle(Graphic3d_Layer)>::Iterator (theSeq),
40 //! Return index of current position.
41 Standard_Integer Index() const { return myIndex; }
43 //! Move to the next position.
46 NCollection_List<Handle(Graphic3d_Layer)>::Iterator::Next();
51 Standard_Integer myIndex;
54 //! Iterator through layers with filter.
55 class OpenGl_FilteredIndexedLayerIterator
59 OpenGl_FilteredIndexedLayerIterator (const NCollection_List<Handle(Graphic3d_Layer)>& theSeq,
60 Standard_Boolean theToDrawImmediate,
61 OpenGl_LayerFilter theLayersToProcess)
63 myLayersToProcess (theLayersToProcess),
64 myToDrawImmediate (theToDrawImmediate)
69 //! Return true if iterator points to the valid value.
70 bool More() const { return myIter.More(); }
72 //! Return layer at current position.
73 const OpenGl_Layer& Value() const { return *myIter.Value(); }
75 //! Return index of current position.
76 Standard_Integer Index() const { return myIter.Index(); }
78 //! Go to the next item.
86 //! Look for the nearest item passing filters.
89 for (; myIter.More(); myIter.Next())
91 const Handle(Graphic3d_Layer)& aLayer = myIter.Value();
92 if (aLayer->IsImmediate() != myToDrawImmediate)
97 switch (myLayersToProcess)
103 case OpenGl_LF_Upper:
105 if (aLayer->LayerId() != Graphic3d_ZLayerId_BotOSD
106 && (!aLayer->LayerSettings().IsRaytracable()
107 || aLayer->IsImmediate()))
113 case OpenGl_LF_Bottom:
115 if (aLayer->LayerId() == Graphic3d_ZLayerId_BotOSD
116 && !aLayer->LayerSettings().IsRaytracable())
122 case OpenGl_LF_RayTracable:
124 if (aLayer->LayerSettings().IsRaytracable()
125 && !aLayer->IsImmediate())
135 OpenGl_IndexedLayerIterator myIter;
136 OpenGl_LayerFilter myLayersToProcess;
137 Standard_Boolean myToDrawImmediate;
141 struct OpenGl_GlobalLayerSettings
147 //=======================================================================
148 //function : OpenGl_LayerList
149 //purpose : Constructor
150 //=======================================================================
152 OpenGl_LayerList::OpenGl_LayerList (const Standard_Integer theNbPriorities)
153 : myBVHBuilder (new BVH_LinearBuilder<Standard_Real, 3> (BVH_Constants_LeafNodeSizeSingle, BVH_Constants_MaxTreeDepth)),
154 myNbPriorities (theNbPriorities),
156 myImmediateNbStructures (0),
157 myModifStateOfRaytraceable (0)
162 //=======================================================================
163 //function : ~OpenGl_LayerList
164 //purpose : Destructor
165 //=======================================================================
167 OpenGl_LayerList::~OpenGl_LayerList()
171 //=======================================================================
172 //function : SetFrustumCullingBVHBuilder
174 //=======================================================================
175 void OpenGl_LayerList::SetFrustumCullingBVHBuilder (const Handle(Select3D_BVHBuilder3d)& theBuilder)
177 myBVHBuilder = theBuilder;
178 for (NCollection_List<Handle(Graphic3d_Layer)>::Iterator aLayerIter (myLayers); aLayerIter.More(); aLayerIter.Next())
180 aLayerIter.ChangeValue()->SetFrustumCullingBVHBuilder (theBuilder);
184 //=======================================================================
185 //function : InsertLayerBefore
187 //=======================================================================
188 void OpenGl_LayerList::InsertLayerBefore (const Graphic3d_ZLayerId theNewLayerId,
189 const Graphic3d_ZLayerSettings& theSettings,
190 const Graphic3d_ZLayerId theLayerAfter)
192 if (myLayerIds.IsBound (theNewLayerId))
197 Handle(Graphic3d_Layer) aNewLayer = new Graphic3d_Layer (theNewLayerId, myNbPriorities, myBVHBuilder);
198 aNewLayer->SetLayerSettings (theSettings);
200 Handle(Graphic3d_Layer) anOtherLayer;
201 if (theLayerAfter != Graphic3d_ZLayerId_UNKNOWN
202 && myLayerIds.Find (theLayerAfter, anOtherLayer))
204 for (NCollection_List<Handle(Graphic3d_Layer)>::Iterator aLayerIter (myLayers); aLayerIter.More(); aLayerIter.Next())
206 if (aLayerIter.Value() == anOtherLayer)
208 myLayers.InsertBefore (aNewLayer, aLayerIter);
215 myLayers.Prepend (aNewLayer);
218 myLayerIds.Bind (theNewLayerId, aNewLayer);
219 myTransparentToProcess.Allocate (myLayers.Size());
222 //=======================================================================
223 //function : InsertLayerAfter
225 //=======================================================================
226 void OpenGl_LayerList::InsertLayerAfter (const Graphic3d_ZLayerId theNewLayerId,
227 const Graphic3d_ZLayerSettings& theSettings,
228 const Graphic3d_ZLayerId theLayerBefore)
230 if (myLayerIds.IsBound (theNewLayerId))
235 Handle(Graphic3d_Layer) aNewLayer = new Graphic3d_Layer (theNewLayerId, myNbPriorities, myBVHBuilder);
236 aNewLayer->SetLayerSettings (theSettings);
238 Handle(Graphic3d_Layer) anOtherLayer;
239 if (theLayerBefore != Graphic3d_ZLayerId_UNKNOWN
240 && myLayerIds.Find (theLayerBefore, anOtherLayer))
242 for (NCollection_List<Handle(Graphic3d_Layer)>::Iterator aLayerIter (myLayers); aLayerIter.More(); aLayerIter.Next())
244 if (aLayerIter.Value() == anOtherLayer)
246 myLayers.InsertAfter (aNewLayer, aLayerIter);
253 myLayers.Append (aNewLayer);
256 myLayerIds.Bind (theNewLayerId, aNewLayer);
257 myTransparentToProcess.Allocate (myLayers.Size());
260 //=======================================================================
261 //function : RemoveLayer
263 //=======================================================================
264 void OpenGl_LayerList::RemoveLayer (const Graphic3d_ZLayerId theLayerId)
266 Handle(Graphic3d_Layer) aLayerToRemove;
268 || !myLayerIds.Find (theLayerId, aLayerToRemove))
273 // move all displayed structures to first layer
274 myLayerIds.Find (Graphic3d_ZLayerId_Default)->Append (*aLayerToRemove);
277 myLayers.Remove (aLayerToRemove);
278 myLayerIds.UnBind (theLayerId);
280 myTransparentToProcess.Allocate (myLayers.Size());
283 //=======================================================================
284 //function : AddStructure
286 //=======================================================================
288 void OpenGl_LayerList::AddStructure (const OpenGl_Structure* theStruct,
289 const Graphic3d_ZLayerId theLayerId,
290 const Standard_Integer thePriority,
291 Standard_Boolean isForChangePriority)
293 // add structure to associated layer,
294 // if layer doesn't exists, display structure in default layer
295 const Handle(Graphic3d_Layer)* aLayerPtr = myLayerIds.Seek (theLayerId);
296 const Handle(Graphic3d_Layer)& aLayer = aLayerPtr != NULL ? *aLayerPtr : myLayerIds.Find (Graphic3d_ZLayerId_Default);
297 aLayer->Add (theStruct, thePriority, isForChangePriority);
299 if (aLayer->IsImmediate())
301 ++myImmediateNbStructures;
304 // Note: In ray-tracing mode we don't modify modification
305 // state here. It is redundant, because the possible changes
306 // will be handled in the loop for structures
309 //=======================================================================
310 //function : RemoveStructure
312 //=======================================================================
314 void OpenGl_LayerList::RemoveStructure (const OpenGl_Structure* theStructure)
316 const Graphic3d_ZLayerId aLayerId = theStructure->ZLayer();
317 const Handle(Graphic3d_Layer)* aLayerPtr = myLayerIds.Seek (aLayerId);
318 const Handle(Graphic3d_Layer)& aLayer = aLayerPtr != NULL ? *aLayerPtr : myLayerIds.Find (Graphic3d_ZLayerId_Default);
320 Standard_Integer aPriority = -1;
322 // remove structure from associated list
323 // if the structure is not found there,
324 // scan through layers and remove it
325 if (aLayer->Remove (theStructure, aPriority))
328 if (aLayer->IsImmediate())
330 --myImmediateNbStructures;
333 if (aLayer->LayerSettings().IsRaytracable()
334 && theStructure->IsRaytracable())
336 ++myModifStateOfRaytraceable;
342 // scan through layers and remove it
343 for (NCollection_List<Handle(Graphic3d_Layer)>::Iterator aLayerIter (myLayers); aLayerIter.More(); aLayerIter.Next())
345 const Handle(Graphic3d_Layer)& aLayerEx = aLayerIter.ChangeValue();
346 if (aLayerEx == aLayer)
351 if (aLayerEx->Remove (theStructure, aPriority))
354 if (aLayerEx->IsImmediate())
356 --myImmediateNbStructures;
359 if (aLayerEx->LayerSettings().IsRaytracable()
360 && theStructure->IsRaytracable())
362 ++myModifStateOfRaytraceable;
369 //=======================================================================
370 //function : InvalidateBVHData
372 //=======================================================================
373 void OpenGl_LayerList::InvalidateBVHData (const Graphic3d_ZLayerId theLayerId)
375 const Handle(Graphic3d_Layer)* aLayerPtr = myLayerIds.Seek (theLayerId);
376 const Handle(Graphic3d_Layer)& aLayer = aLayerPtr != NULL ? *aLayerPtr : myLayerIds.Find (Graphic3d_ZLayerId_Default);
377 aLayer->InvalidateBVHData();
380 //=======================================================================
381 //function : ChangeLayer
383 //=======================================================================
385 void OpenGl_LayerList::ChangeLayer (const OpenGl_Structure* theStructure,
386 const Graphic3d_ZLayerId theOldLayerId,
387 const Graphic3d_ZLayerId theNewLayerId)
389 const Handle(Graphic3d_Layer)* aLayerPtr = myLayerIds.Seek (theOldLayerId);
390 const Handle(Graphic3d_Layer)& aLayer = aLayerPtr != NULL ? *aLayerPtr : myLayerIds.Find (Graphic3d_ZLayerId_Default);
392 Standard_Integer aPriority = -1;
394 // take priority and remove structure from list found by <theOldLayerId>
395 // if the structure is not found there, scan through all other layers
396 if (aLayer->Remove (theStructure, aPriority, Standard_False))
398 if (aLayer->LayerSettings().IsRaytracable()
399 && !aLayer->LayerSettings().IsImmediate()
400 && theStructure->IsRaytracable())
402 ++myModifStateOfRaytraceable;
406 if (aLayer->IsImmediate())
408 --myImmediateNbStructures;
411 // isForChangePriority should be Standard_False below, because we want
412 // the BVH tree in the target layer to be updated with theStructure
413 AddStructure (theStructure, theNewLayerId, aPriority);
417 // scan through layers and remove it
418 for (NCollection_List<Handle(Graphic3d_Layer)>::Iterator aLayerIter (myLayers); aLayerIter.More(); aLayerIter.Next())
420 const Handle(OpenGl_Layer)& aLayerEx = aLayerIter.ChangeValue();
421 if (aLayerEx == aLayer)
426 // try to remove structure and get priority value from this layer
427 if (aLayerEx->Remove (theStructure, aPriority, Standard_True))
429 if (aLayerEx->LayerSettings().IsRaytracable()
430 && !aLayerEx->LayerSettings().IsImmediate()
431 && theStructure->IsRaytracable())
433 ++myModifStateOfRaytraceable;
437 if (aLayerEx->IsImmediate())
439 --myImmediateNbStructures;
442 // isForChangePriority should be Standard_False below, because we want
443 // the BVH tree in the target layer to be updated with theStructure
444 AddStructure (theStructure, theNewLayerId, aPriority);
450 //=======================================================================
451 //function : ChangePriority
453 //=======================================================================
454 void OpenGl_LayerList::ChangePriority (const OpenGl_Structure* theStructure,
455 const Graphic3d_ZLayerId theLayerId,
456 const Standard_Integer theNewPriority)
458 const Handle(Graphic3d_Layer)* aLayerPtr = myLayerIds.Seek (theLayerId);
459 const Handle(Graphic3d_Layer)& aLayer = aLayerPtr != NULL ? *aLayerPtr : myLayerIds.Find (Graphic3d_ZLayerId_Default);
461 Standard_Integer anOldPriority = -1;
463 if (aLayer->Remove (theStructure, anOldPriority, Standard_True))
466 if (aLayer->IsImmediate())
468 --myImmediateNbStructures;
471 AddStructure (theStructure, theLayerId, theNewPriority, Standard_True);
475 for (NCollection_List<Handle(Graphic3d_Layer)>::Iterator aLayerIter (myLayers); aLayerIter.More(); aLayerIter.Next())
477 const Handle(OpenGl_Layer)& aLayerEx = aLayerIter.ChangeValue();
478 if (aLayerEx == aLayer)
483 if (aLayerEx->Remove (theStructure, anOldPriority, Standard_True))
486 if (aLayerEx->IsImmediate())
488 --myImmediateNbStructures;
491 AddStructure (theStructure, theLayerId, theNewPriority, Standard_True);
497 //=======================================================================
498 //function : SetLayerSettings
500 //=======================================================================
501 void OpenGl_LayerList::SetLayerSettings (const Graphic3d_ZLayerId theLayerId,
502 const Graphic3d_ZLayerSettings& theSettings)
504 Graphic3d_Layer& aLayer = Layer (theLayerId);
505 if (aLayer.LayerSettings().IsRaytracable() != theSettings.IsRaytracable()
506 && aLayer.NbStructures() != 0)
508 ++myModifStateOfRaytraceable;
510 if (aLayer.LayerSettings().IsImmediate() != theSettings.IsImmediate())
512 if (theSettings.IsImmediate())
514 myImmediateNbStructures += aLayer.NbStructures();
518 myImmediateNbStructures -= aLayer.NbStructures();
521 aLayer.SetLayerSettings (theSettings);
524 //=======================================================================
525 //function : UpdateCulling
527 //=======================================================================
528 void OpenGl_LayerList::UpdateCulling (const Handle(OpenGl_Workspace)& theWorkspace,
529 const Standard_Boolean theToDrawImmediate)
531 const Handle(OpenGl_FrameStats)& aStats = theWorkspace->GetGlContext()->FrameStats();
532 OSD_Timer& aTimer = aStats->ActiveDataFrame().ChangeTimer (Graphic3d_FrameStatsTimer_CpuCulling);
535 const Standard_Integer aViewId = theWorkspace->View()->Identification();
536 const Graphic3d_CullingTool& aSelector = theWorkspace->View()->BVHTreeSelector();
537 for (NCollection_List<Handle(Graphic3d_Layer)>::Iterator aLayerIter (myLayers); aLayerIter.More(); aLayerIter.Next())
539 const Handle(Graphic3d_Layer)& aLayer = aLayerIter.ChangeValue();
540 if (aLayer->IsImmediate() != theToDrawImmediate)
545 aLayer->UpdateCulling (aViewId, aSelector, theWorkspace->View()->RenderingParams().FrustumCullingState);
549 aStats->ActiveDataFrame()[Graphic3d_FrameStatsTimer_CpuCulling] = aTimer.UserTimeCPU();
552 //=======================================================================
553 //function : renderLayer
555 //=======================================================================
556 void OpenGl_LayerList::renderLayer (const Handle(OpenGl_Workspace)& theWorkspace,
557 const OpenGl_GlobalLayerSettings& theDefaultSettings,
558 const Graphic3d_Layer& theLayer) const
560 const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
562 const Graphic3d_ZLayerSettings& aLayerSettings = theLayer.LayerSettings();
563 // aLayerSettings.ToClearDepth() is handled outside
566 if (aLayerSettings.ToEnableDepthTest())
568 // assuming depth test is enabled by default
569 glDepthFunc (theDefaultSettings.DepthFunc);
573 glDepthFunc (GL_ALWAYS);
576 // save environment texture
577 Handle(OpenGl_TextureSet) anEnvironmentTexture = theWorkspace->EnvironmentTexture();
578 if (!aLayerSettings.UseEnvironmentTexture())
580 theWorkspace->SetEnvironmentTexture (Handle(OpenGl_TextureSet)());
583 // handle depth offset
584 const Graphic3d_PolygonOffset anAppliedOffsetParams = theWorkspace->SetDefaultPolygonOffset (aLayerSettings.PolygonOffset());
586 // handle depth write
587 theWorkspace->UseDepthWrite() = aLayerSettings.ToEnableDepthWrite() && theDefaultSettings.DepthMask == GL_TRUE;
588 glDepthMask (theWorkspace->UseDepthWrite() ? GL_TRUE : GL_FALSE);
590 const Standard_Boolean hasLocalCS = !aLayerSettings.OriginTransformation().IsNull();
591 const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager();
592 Handle(Graphic3d_LightSet) aLightsBack = aManager->LightSourceState().LightSources();
593 const bool hasOwnLights = aCtx->ColorMask() && !aLayerSettings.Lights().IsNull() && aLayerSettings.Lights() != aLightsBack;
596 aLayerSettings.Lights()->UpdateRevision();
597 aManager->UpdateLightSourceStateTo (aLayerSettings.Lights(), theWorkspace->View()->SpecIBLMapLevels());
600 const Handle(Graphic3d_Camera)& aWorldCamera = theWorkspace->View()->Camera();
603 // Apply local camera transformation.
604 // The vertex position is computed by the following formula in GLSL program:
605 // gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;
607 // occProjectionMatrix - matrix defining orthographic/perspective/stereographic projection
608 // occWorldViewMatrix - world-view matrix defining Camera position and orientation
609 // occModelWorldMatrix - model-world matrix defining Object transformation from local coordinate system to the world coordinate system
610 // occVertex - input vertex position
612 // Since double precision is quite expensive on modern GPUs, and not available on old hardware,
613 // all these values are passed with single float precision to the shader.
614 // As result, single precision become insufficient for handling objects far from the world origin.
616 // Several approaches can be used to solve precision issues:
617 // - [Broute force] migrate to double precision for all matrices and vertex position.
618 // This is too expensive for most hardware.
619 // - Store only translation part with double precision and pass it to GLSL program.
620 // This requires modified GLSL programs for computing transformation
621 // and extra packing mechanism for hardware not supporting double precision natively.
622 // This solution is less expensive then previous one.
623 // - Move translation part of occModelWorldMatrix into occWorldViewMatrix.
624 // The main idea here is that while moving Camera towards the object,
625 // Camera translation part and Object translation part will compensate each other
626 // to fit into single float precision.
627 // But this operation should be performed with double precision - this is why we are moving
628 // translation part of occModelWorldMatrix to occWorldViewMatrix.
630 // All approaches might be useful in different scenarios, but for the moment we consider the last one as main scenario.
631 // Here we do the trick:
632 // - OpenGl_Layer defines the Local Origin, which is expected to be the center of objects stored within it.
633 // This Local Origin is included into occWorldViewMatrix during rendering.
634 // - OpenGl_Structure defines Object local transformation occModelWorldMatrix with subtracted Local Origin of the Layer.
635 // This means that Object itself should be defined within either Local Transformation equal or near to Local Origin of the Layer.
636 theWorkspace->View()->SetLocalOrigin (aLayerSettings.Origin());
638 NCollection_Mat4<Standard_Real> aWorldView = aWorldCamera->OrientationMatrix();
639 Graphic3d_TransformUtils::Translate (aWorldView, aLayerSettings.Origin().X(), aLayerSettings.Origin().Y(), aLayerSettings.Origin().Z());
641 NCollection_Mat4<Standard_ShortReal> aWorldViewF;
642 aWorldViewF.ConvertFrom (aWorldView);
643 aCtx->WorldViewState.SetCurrent (aWorldViewF);
644 aCtx->ShaderManager()->UpdateClippingState();
645 aCtx->ShaderManager()->UpdateLightSourceState();
648 // render priority list
649 const Standard_Integer aViewId = theWorkspace->View()->Identification();
650 for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (theLayer.ArrayOfStructures()); aMapIter.More(); aMapIter.Next())
652 const Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.Value();
653 for (OpenGl_Structure::StructIterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
655 const OpenGl_Structure* aStruct = aStructIter.Value();
656 if (aStruct->IsCulled()
657 || !aStruct->IsVisible (aViewId))
662 aStruct->Render (theWorkspace);
668 aManager->UpdateLightSourceStateTo (aLightsBack, theWorkspace->View()->SpecIBLMapLevels());
672 aCtx->ShaderManager()->RevertClippingState();
673 aCtx->ShaderManager()->UpdateLightSourceState();
675 aCtx->WorldViewState.SetCurrent (aWorldCamera->OrientationMatrixF());
676 theWorkspace->View() ->SetLocalOrigin (gp_XYZ (0.0, 0.0, 0.0));
679 // always restore polygon offset between layers rendering
680 theWorkspace->SetDefaultPolygonOffset (anAppliedOffsetParams);
682 // restore environment texture
683 if (!aLayerSettings.UseEnvironmentTexture())
685 theWorkspace->SetEnvironmentTexture (anEnvironmentTexture);
689 //=======================================================================
692 //=======================================================================
693 void OpenGl_LayerList::Render (const Handle(OpenGl_Workspace)& theWorkspace,
694 const Standard_Boolean theToDrawImmediate,
695 const OpenGl_LayerFilter theLayersToProcess,
696 OpenGl_FrameBuffer* theReadDrawFbo,
697 OpenGl_FrameBuffer* theOitAccumFbo) const
699 // Remember global settings for glDepth function and write mask.
700 OpenGl_GlobalLayerSettings aPrevSettings;
702 const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
703 aCtx->core11fwd->glGetIntegerv (GL_DEPTH_FUNC, &aPrevSettings.DepthFunc);
704 aCtx->core11fwd->glGetBooleanv (GL_DEPTH_WRITEMASK, &aPrevSettings.DepthMask);
705 OpenGl_GlobalLayerSettings aDefaultSettings = aPrevSettings;
707 // Two render filters are used to support transparency draw. Opaque filter accepts
708 // only non-transparent OpenGl elements of a layer and counts number of skipped
709 // transparent ones. If the counter has positive value the layer is added into
710 // transparency post-processing stack. At the end of drawing or once the depth
711 // buffer is to be cleared the layers in the stack should be drawn using
712 // blending and depth mask settings and another transparency filter which accepts
713 // only transparent OpenGl elements of a layer. The stack <myTransparentToProcess>
714 // was preallocated before going into this method and has enough space to keep
715 // maximum number of references to layers, therefore it will not increase memory
716 // fragmentation during regular rendering.
717 const Standard_Integer aPrevFilter = theWorkspace->RenderFilter() & ~(Standard_Integer )(OpenGl_RenderFilter_OpaqueOnly | OpenGl_RenderFilter_TransparentOnly);
718 theWorkspace->SetRenderFilter (aPrevFilter | OpenGl_RenderFilter_OpaqueOnly);
720 myTransparentToProcess.Clear();
722 OpenGl_LayerStack::iterator aStackIter (myTransparentToProcess.Origin());
723 Standard_Integer aClearDepthLayerPrev = -1, aClearDepthLayer = -1;
724 const bool toPerformDepthPrepass = theWorkspace->View()->RenderingParams().ToEnableDepthPrepass
725 && aPrevSettings.DepthMask == GL_TRUE;
726 const Handle(Graphic3d_LightSet) aLightsBack = aCtx->ShaderManager()->LightSourceState().LightSources();
727 for (OpenGl_FilteredIndexedLayerIterator aLayerIterStart (myLayers, theToDrawImmediate, theLayersToProcess); aLayerIterStart.More();)
729 bool hasSkippedDepthLayers = false;
730 for (int aPassIter = toPerformDepthPrepass ? 0 : 2; aPassIter < 3; ++aPassIter)
734 aCtx->SetColorMask (false);
735 aCtx->ShaderManager()->UpdateLightSourceStateTo (Handle(Graphic3d_LightSet)(), theWorkspace->View()->SpecIBLMapLevels());
736 aDefaultSettings.DepthFunc = aPrevSettings.DepthFunc;
737 aDefaultSettings.DepthMask = GL_TRUE;
739 else if (aPassIter == 1)
741 if (!hasSkippedDepthLayers)
745 aCtx->SetColorMask (true);
746 aCtx->ShaderManager()->UpdateLightSourceStateTo (aLightsBack, theWorkspace->View()->SpecIBLMapLevels());
747 aDefaultSettings = aPrevSettings;
749 else if (aPassIter == 2)
751 aCtx->SetColorMask (true);
752 aCtx->ShaderManager()->UpdateLightSourceStateTo (aLightsBack, theWorkspace->View()->SpecIBLMapLevels());
753 if (toPerformDepthPrepass)
755 aDefaultSettings.DepthFunc = GL_EQUAL;
756 aDefaultSettings.DepthMask = GL_FALSE;
760 OpenGl_FilteredIndexedLayerIterator aLayerIter (aLayerIterStart);
761 for (; aLayerIter.More(); aLayerIter.Next())
763 const OpenGl_Layer& aLayer = aLayerIter.Value();
765 // make sure to clear depth of previous layers even if layer has no structures
766 if (aLayer.LayerSettings().ToClearDepth())
768 aClearDepthLayer = aLayerIter.Index();
770 if (aLayer.IsCulled())
774 else if (aClearDepthLayer > aClearDepthLayerPrev)
776 // At this point the depth buffer may be set to clear by previous configuration of layers or configuration of the current layer.
777 // Additional rendering pass to handle transparent elements of recently drawn layers require use of current depth
778 // buffer so we put remaining layers for processing as one bunch before erasing the depth buffer.
781 aLayerIterStart = aLayerIter;
785 aClearDepthLayer = -1;
789 else if (aPassIter == 0
790 && !aLayer.LayerSettings().ToRenderInDepthPrepass())
792 hasSkippedDepthLayers = true;
795 else if (aPassIter == 1
796 && aLayer.LayerSettings().ToRenderInDepthPrepass())
801 // Render opaque OpenGl elements of a layer and count the number of skipped.
802 // If a layer has skipped (e.g. transparent) elements it should be added into
803 // the transparency post-processing stack.
804 theWorkspace->ResetSkippedCounter();
806 renderLayer (theWorkspace, aDefaultSettings, aLayer);
809 && theWorkspace->NbSkippedTransparentElements() > 0)
811 myTransparentToProcess.Push (&aLayer);
815 && !aLayerIter.More())
817 aLayerIterStart = aLayerIter;
821 if (!myTransparentToProcess.IsEmpty())
823 renderTransparent (theWorkspace, aStackIter, aPrevSettings, theReadDrawFbo, theOitAccumFbo);
825 if (aClearDepthLayer > aClearDepthLayerPrev)
827 aClearDepthLayerPrev = aClearDepthLayer;
828 glDepthMask (GL_TRUE);
829 glClear (GL_DEPTH_BUFFER_BIT);
833 aCtx->core11fwd->glDepthMask (aPrevSettings.DepthMask);
834 aCtx->core11fwd->glDepthFunc (aPrevSettings.DepthFunc);
836 theWorkspace->SetRenderFilter (aPrevFilter);
839 //=======================================================================
840 //function : renderTransparent
841 //purpose : Render transparent objects using blending operator.
842 //=======================================================================
843 void OpenGl_LayerList::renderTransparent (const Handle(OpenGl_Workspace)& theWorkspace,
844 OpenGl_LayerStack::iterator& theLayerIter,
845 const OpenGl_GlobalLayerSettings& theGlobalSettings,
846 OpenGl_FrameBuffer* theReadDrawFbo,
847 OpenGl_FrameBuffer* theOitAccumFbo) const
849 // Blended order-independent transparency algorithm require several preconditions
850 // to be enabled. It should be requested by user, at least two outputs from
851 // fragment shader should be supported by GPU, so is the given framebuffer
852 // should contain two additional color buffers to handle accumulated color channels,
853 // blended alpha channel and weight factors - these accumulation buffers are required
854 // to implement commuting blend operator (at least OpenGl 2.0 should be available).
855 const bool isEnabledOit = theOitAccumFbo != NULL
856 && theOitAccumFbo->NbColorBuffers() >= 2
857 && theOitAccumFbo->ColorTexture (0)->IsValid()
858 && theOitAccumFbo->ColorTexture (1)->IsValid();
860 // Check if current iterator has already reached the end of the stack.
861 // This should happen if no additional layers has been added to
862 // the processing stack after last transparency pass.
863 if (theLayerIter == myTransparentToProcess.Back())
868 const Handle(OpenGl_Context) aCtx = theWorkspace->GetGlContext();
869 const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager();
870 OpenGl_View* aView = theWorkspace->View();
871 const float aDepthFactor = aView != NULL ? aView->RenderingParams().OitDepthFactor : 0.0f;
873 const Standard_Integer aPrevFilter = theWorkspace->RenderFilter() & ~(Standard_Integer )(OpenGl_RenderFilter_OpaqueOnly | OpenGl_RenderFilter_TransparentOnly);
874 theWorkspace->SetRenderFilter (aPrevFilter | OpenGl_RenderFilter_TransparentOnly);
876 aCtx->core11fwd->glEnable (GL_BLEND);
880 aManager->SetOitState (true, aDepthFactor);
882 theOitAccumFbo->BindBuffer (aCtx);
884 static const Standard_Integer aDrawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT0 + 1 };
885 aCtx->SetDrawBuffers (2, aDrawBuffers);
886 aCtx->core11fwd->glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
887 aCtx->core11fwd->glClear (GL_COLOR_BUFFER_BIT);
888 aCtx->core15fwd->glBlendFuncSeparate (GL_ONE, GL_ONE, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
892 aCtx->core11fwd->glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
895 // During blended order-independent transparency pass the depth test
896 // should be enabled to discard fragments covered by opaque geometry
897 // and depth writing should be disabled, because transparent fragments
898 // overal each other with non unitary coverage factor.
899 OpenGl_GlobalLayerSettings aGlobalSettings = theGlobalSettings;
900 aGlobalSettings.DepthMask = GL_FALSE;
901 aCtx->core11fwd->glDepthMask (GL_FALSE);
903 for (; theLayerIter != myTransparentToProcess.Back(); ++theLayerIter)
905 renderLayer (theWorkspace, aGlobalSettings, *(*theLayerIter));
908 // Revert state of rendering.
911 aManager->SetOitState (false, aDepthFactor);
912 theOitAccumFbo->UnbindBuffer (aCtx);
915 theReadDrawFbo->BindBuffer (aCtx);
918 static const Standard_Integer aDrawBuffers[] = { GL_COLOR_ATTACHMENT0 };
919 aCtx->SetDrawBuffers (1, aDrawBuffers);
922 theWorkspace->SetRenderFilter (aPrevFilter | OpenGl_RenderFilter_OpaqueOnly);
925 const Standard_Boolean isMSAA = theReadDrawFbo && theReadDrawFbo->NbSamples() > 0;
926 OpenGl_VertexBuffer* aVerts = theWorkspace->View()->initBlitQuad (Standard_False);
927 if (aVerts->IsValid() && aManager->BindOitCompositingProgram (isMSAA))
929 aCtx->core11fwd->glDepthFunc (GL_ALWAYS);
930 aCtx->core11fwd->glDepthMask (GL_FALSE);
932 // Bind full screen quad buffer and framebuffer resources.
933 aVerts->BindVertexAttrib (aCtx, Graphic3d_TOA_POS);
935 const Handle(OpenGl_TextureSet) aTextureBack = aCtx->BindTextures (Handle(OpenGl_TextureSet)());
937 theOitAccumFbo->ColorTexture (0)->Bind (aCtx, Graphic3d_TextureUnit_0);
938 theOitAccumFbo->ColorTexture (1)->Bind (aCtx, Graphic3d_TextureUnit_1);
940 // Draw full screen quad with special shader to compose the buffers.
941 aCtx->core11fwd->glBlendFunc (GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
942 aCtx->core11fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
944 // Unbind OpenGL texture objects and shader program.
945 aVerts->UnbindVertexAttrib (aCtx, Graphic3d_TOA_POS);
946 theOitAccumFbo->ColorTexture (1)->Unbind (aCtx, Graphic3d_TextureUnit_1);
947 theOitAccumFbo->ColorTexture (0)->Unbind (aCtx, Graphic3d_TextureUnit_0);
948 aCtx->BindProgram (NULL);
950 if (!aTextureBack.IsNull())
952 aCtx->BindTextures (aTextureBack);
957 aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
958 "Initialization of OIT compositing pass has failed.\n"
959 " Blended order-independent transparency will not be available.\n");
962 Standard_Boolean& aOITFlag = isMSAA ? aView->myToDisableOITMSAA : aView->myToDisableOIT;
963 aOITFlag = Standard_True;
968 aCtx->core11fwd->glDisable (GL_BLEND);
969 aCtx->core11fwd->glBlendFunc (GL_ONE, GL_ZERO);
970 aCtx->core11fwd->glDepthMask (theGlobalSettings.DepthMask);
971 aCtx->core11fwd->glDepthFunc (theGlobalSettings.DepthFunc);