From 0c44ae5c8a9aa49368d46eca0125f17315773488 Mon Sep 17 00:00:00 2001 From: hossamali Date: Fri, 23 Feb 2024 11:45:34 +0000 Subject: [PATCH] 0033607: Visualization - Implementation of hardware occlusion queries Hardware occlusion queries provides mechanism to answer whether or not any pixels would be drawn. as instance it can be used as visibility filter or acceleration for rendering complex scenes, by skipping occluded objects. Graphic3d_ViewOcclusionMask : Provide way to access occlusion test results for every graphical presentation per each defined view of the viewer Graphic3d_OcclusionQuery : provides generic access to occlusion query functionality. OpenGl_OcclusionQuery: provides OpenGL implementation for occlusion query Graphic3d_RenderingParams: provides way to enable or disable occlusion query AIS_InteractiveContext : reset view occlusion mask in new loaded objects Each view invalidate its occlusion query results if camera has changed. --- src/AIS/AIS_InteractiveContext.cxx | 2 + src/Graphic3d/FILES | 4 + src/Graphic3d/Graphic3d_CStructure.hxx | 13 +++ src/Graphic3d/Graphic3d_CView.cxx | 13 +++ src/Graphic3d/Graphic3d_CView.hxx | 3 + src/Graphic3d/Graphic3d_FrameStatsTimer.hxx | 3 +- src/Graphic3d/Graphic3d_OcclusionQuery.cxx | 49 ++++++++++ src/Graphic3d/Graphic3d_OcclusionQuery.hxx | 59 ++++++++++++ src/Graphic3d/Graphic3d_RenderingParams.cxx | 1 + src/Graphic3d/Graphic3d_RenderingParams.hxx | 10 ++ src/Graphic3d/Graphic3d_ViewOcclusionMask.cxx | 32 +++++++ src/Graphic3d/Graphic3d_ViewOcclusionMask.hxx | 78 ++++++++++++++++ src/OpenGl/FILES | 2 + src/OpenGl/OpenGl_LayerList.cxx | 92 +++++++++++++++++++ src/OpenGl/OpenGl_LayerList.hxx | 6 ++ src/OpenGl/OpenGl_OcclusionQuery.cxx | 59 ++++++++++++ src/OpenGl/OpenGl_OcclusionQuery.hxx | 51 ++++++++++ src/OpenGl/OpenGl_Structure.cxx | 11 +++ src/OpenGl/OpenGl_Structure.hxx | 3 + src/OpenGl/OpenGl_View.cxx | 29 +++++- src/OpenGl/OpenGl_View.hxx | 10 +- src/PrsMgr/PrsMgr_PresentableObject.cxx | 1 + src/PrsMgr/PrsMgr_PresentableObject.hxx | 5 + src/PrsMgr/PrsMgr_PresentationManager.cxx | 5 + src/V3d/V3d_Trihedron.cxx | 1 + src/V3d/V3d_Viewer.cxx | 1 + src/ViewerTest/ViewerTest_ViewerCommands.cxx | 69 ++++++++++++++ tests/v3d/occlusion/boxes | 29 ++++++ 28 files changed, 635 insertions(+), 6 deletions(-) create mode 100644 src/Graphic3d/Graphic3d_OcclusionQuery.cxx create mode 100644 src/Graphic3d/Graphic3d_OcclusionQuery.hxx create mode 100644 src/Graphic3d/Graphic3d_ViewOcclusionMask.cxx create mode 100644 src/Graphic3d/Graphic3d_ViewOcclusionMask.hxx create mode 100644 src/OpenGl/OpenGl_OcclusionQuery.cxx create mode 100644 src/OpenGl/OpenGl_OcclusionQuery.hxx create mode 100644 tests/v3d/occlusion/boxes diff --git a/src/AIS/AIS_InteractiveContext.cxx b/src/AIS/AIS_InteractiveContext.cxx index 13344563e9..044180b01d 100644 --- a/src/AIS/AIS_InteractiveContext.cxx +++ b/src/AIS/AIS_InteractiveContext.cxx @@ -438,6 +438,7 @@ void AIS_InteractiveContext::Display (const Handle(AIS_InteractiveObject)& theIO { setObjectStatus (theIObj, PrsMgr_DisplayStatus_Displayed, theDispMode, theSelectionMode); theIObj->ViewAffinity()->SetVisible (true); // reset view affinity mask + theIObj->ViewOcclusionMask()->SetVisible (true); // reset view occlusion mask myMainVwr->StructureManager()->RegisterObject (theIObj, theIObj->ViewAffinity()); myMainPM->Display(theIObj, theDispMode); if (theSelectionMode != -1) @@ -515,6 +516,7 @@ void AIS_InteractiveContext::Load (const Handle(AIS_InteractiveObject)& theIObj, GetDefModes (theIObj, aDispMode, aHiMod, aSelModeDef); setObjectStatus (theIObj, PrsMgr_DisplayStatus_Erased, aDispMode, theSelMode != -1 ? theSelMode : aSelModeDef); theIObj->ViewAffinity()->SetVisible (true); // reset view affinity mask + theIObj->ViewOcclusionMask()->SetVisible (true); // reset view occlusion mask myMainVwr->StructureManager()->RegisterObject (theIObj, theIObj->ViewAffinity()); } diff --git a/src/Graphic3d/FILES b/src/Graphic3d/FILES index ec1f20b4df..f83c2db19f 100755 --- a/src/Graphic3d/FILES +++ b/src/Graphic3d/FILES @@ -208,3 +208,7 @@ Graphic3d_Layer.cxx Graphic3d_Layer.hxx Graphic3d_ZLayerId.hxx Graphic3d_ZLayerSettings.hxx +Graphic3d_OcclusionQuery.hxx +Graphic3d_OcclusionQuery.cxx +Graphic3d_ViewOcclusionMask.hxx +Graphic3d_ViewOcclusionMask.cxx diff --git a/src/Graphic3d/Graphic3d_CStructure.hxx b/src/Graphic3d/Graphic3d_CStructure.hxx index 8138cd165f..0a4f2344a7 100644 --- a/src/Graphic3d/Graphic3d_CStructure.hxx +++ b/src/Graphic3d/Graphic3d_CStructure.hxx @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -164,6 +165,17 @@ public: //! The method is called during traverse of BVH tree. void MarkAsNotCulled() const { myIsCulled = Standard_False; } + //! Returns True if the structure occulded in specified view, otherwise + //! returns False. + Standard_Boolean IsOccluded(const Standard_Integer theViewId) const { + return (!OcclusionMask->IsVisible(theViewId)); + } + + //! Marks structure as Occluded by other strcuture in specified view,! + void SetOccluded(const Standard_Integer theViewId) const { + OcclusionMask->SetVisible(Standard_False, theViewId); + } + //! Returns whether check of object's bounding box clipping is enabled before drawing of object; TRUE by default. Standard_Boolean BndBoxClipCheck() const { return myBndBoxClipCheck; } @@ -218,6 +230,7 @@ public: public: Handle(Graphic3d_ViewAffinity) ViewAffinity; //!< view affinity mask + Handle(Graphic3d_ViewOcclusionMask) OcclusionMask; //!< view occlusion mask protected: diff --git a/src/Graphic3d/Graphic3d_CView.cxx b/src/Graphic3d/Graphic3d_CView.cxx index 59e0ee75a9..d396e3bf80 100644 --- a/src/Graphic3d/Graphic3d_CView.cxx +++ b/src/Graphic3d/Graphic3d_CView.cxx @@ -547,6 +547,19 @@ void Graphic3d_CView::DisplayedStructures (Graphic3d_MapOfStructure& theStructur } } +// ======================================================================= +// function : OccludedStructures +// purpose : +// ======================================================================= +void Graphic3d_CView::OccludedStructures(Graphic3d_MapOfStructure& theStructures) const +{ + for (Graphic3d_MapOfStructure::Iterator aStructIter (myStructsDisplayed); aStructIter.More(); aStructIter.Next()) + { + + if (aStructIter.Value()->CStructure()->IsOccluded(this->myId)) + theStructures.Add(aStructIter.Key()); + } +} // ======================================================================= // function : MinMaxValues // purpose : diff --git a/src/Graphic3d/Graphic3d_CView.hxx b/src/Graphic3d/Graphic3d_CView.hxx index 5fe56d4467..53351b7c08 100644 --- a/src/Graphic3d/Graphic3d_CView.hxx +++ b/src/Graphic3d/Graphic3d_CView.hxx @@ -130,6 +130,9 @@ public: //! Returns the set of structures displayed in this view. Standard_EXPORT void DisplayedStructures (Graphic3d_MapOfStructure& theStructures) const; + //! Returns number of occluded strcutures in the view + Standard_EXPORT void OccludedStructures(Graphic3d_MapOfStructure& theStructures) const; + //! Returns number of displayed structures in the view. virtual Standard_Integer NumberOfDisplayedStructures() const { return myStructsDisplayed.Extent(); } diff --git a/src/Graphic3d/Graphic3d_FrameStatsTimer.hxx b/src/Graphic3d/Graphic3d_FrameStatsTimer.hxx index a4aff6fa0a..7650c618b6 100644 --- a/src/Graphic3d/Graphic3d_FrameStatsTimer.hxx +++ b/src/Graphic3d/Graphic3d_FrameStatsTimer.hxx @@ -22,7 +22,8 @@ enum Graphic3d_FrameStatsTimer Graphic3d_FrameStatsTimer_CpuCulling, Graphic3d_FrameStatsTimer_CpuPicking, Graphic3d_FrameStatsTimer_CpuDynamics, + Graphic3d_FrameStatsTimer_OcclusionCulling, }; -enum { Graphic3d_FrameStatsTimer_NB = Graphic3d_FrameStatsTimer_CpuDynamics + 1 }; +enum { Graphic3d_FrameStatsTimer_NB = Graphic3d_FrameStatsTimer_OcclusionCulling + 1 }; #endif // _Graphic3d_FrameStatsTimer_HeaderFile diff --git a/src/Graphic3d/Graphic3d_OcclusionQuery.cxx b/src/Graphic3d/Graphic3d_OcclusionQuery.cxx new file mode 100644 index 0000000000..1df044772e --- /dev/null +++ b/src/Graphic3d/Graphic3d_OcclusionQuery.cxx @@ -0,0 +1,49 @@ +// Created on: 2024-02-20 +// Created by: Hossam Ali +// Copyright (c) 2024 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in +// OCCT distribution for complete text of the license and disclaimer of any +// warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include + +IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_OcclusionQuery, Standard_Transient) + +// ======================================================================= +// function : GetNumSamplesPassed +// purpose : +// ======================================================================= +unsigned int Graphic3d_OcclusionQuery::GetNumSamplesPassed() const { + return samplesPassed; +} + +// ======================================================================= +// function : AnySamplesPassed +// purpose : +// ======================================================================= +bool Graphic3d_OcclusionQuery::AnySamplesPassed() const { + return samplesPassed > 0; +} + +// ======================================================================= +// function : DumpJson +// purpose : +// ======================================================================= +void Graphic3d_OcclusionQuery::DumpJson(Standard_OStream &theOStream, + Standard_Integer) const { + OCCT_DUMP_TRANSIENT_CLASS_BEGIN(theOStream) + + OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, queryID) + OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, samplesPassed) +} \ No newline at end of file diff --git a/src/Graphic3d/Graphic3d_OcclusionQuery.hxx b/src/Graphic3d/Graphic3d_OcclusionQuery.hxx new file mode 100644 index 0000000000..a0426f0c00 --- /dev/null +++ b/src/Graphic3d/Graphic3d_OcclusionQuery.hxx @@ -0,0 +1,59 @@ +// Created on: 2024-02-20 +// Created by: Hossam Ali +// Copyright (c) 2024 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 _Graphic3d_OcclusionQuery_HeaderFile +#define _Graphic3d_OcclusionQuery_HeaderFile + +#include +#include +#include + +//! Base class provides access to occlusion query functionality. +class Graphic3d_OcclusionQuery : public Standard_Transient { +public: + //! Empty constructor. + Graphic3d_OcclusionQuery() : queryID(0), samplesPassed(0) {} + + //! Begins occlusion query. Until the query is ended, samples that pass the + //! rendering pipeline are counted. + Standard_EXPORT virtual void BeginQuery() const = 0; + + //! Ends occlusion query and caches the result - number of samples that passed + //! the rendering pipeline. + Standard_EXPORT virtual void EndQuery() = 0; + + //! Gets number of samples that have passed the rendering pipeline. + unsigned int GetNumSamplesPassed() const; + + //! Helper method that returns if any samples have passed the rendering + //! pipeline. + bool AnySamplesPassed() const; + + //! Dumps the content of me into the stream + Standard_EXPORT void DumpJson(Standard_OStream &theOStream, + Standard_Integer theDepth = -1) const; + +protected: + unsigned int queryID; // Query object ID + int samplesPassed; // Number of samples passed in last query + +public: + DEFINE_STANDARD_RTTIEXT(Graphic3d_OcclusionQuery, Standard_Transient) +}; + +DEFINE_STANDARD_HANDLE(Graphic3d_OcclusionQuery, Standard_Transient) + +#endif // _Graphic3d_OcclusionQuery_HeaderFile diff --git a/src/Graphic3d/Graphic3d_RenderingParams.cxx b/src/Graphic3d/Graphic3d_RenderingParams.cxx index 57a941386f..1b2d3789b5 100644 --- a/src/Graphic3d/Graphic3d_RenderingParams.cxx +++ b/src/Graphic3d/Graphic3d_RenderingParams.cxx @@ -65,6 +65,7 @@ void Graphic3d_RenderingParams::DumpJson (Standard_OStream& theOStream, Standard OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, CameraApertureRadius) OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, CameraFocalPlaneDist) OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, FrustumCullingState) + OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, OcculsionQueryState) OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, ToneMappingMethod) OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, Exposure) diff --git a/src/Graphic3d/Graphic3d_RenderingParams.hxx b/src/Graphic3d/Graphic3d_RenderingParams.hxx index d0ce9217c2..4bc1374bd9 100644 --- a/src/Graphic3d/Graphic3d_RenderingParams.hxx +++ b/src/Graphic3d/Graphic3d_RenderingParams.hxx @@ -92,6 +92,14 @@ public: FrustumCulling_NoUpdate //!< culling is active, but the list of culled entities is not updated }; + //! State of occulsion query + enum OcculsionQuery + { + OcculsionQuery_Off, //!< occulsion query is disabled + OcculsionQuery_On, //!< occulsion query is active + OcculsionQuery_NoUpdate //!< occulsion query is active, but the list of occulded entities is not updated + }; + public: //! Creates default rendering parameters. @@ -139,6 +147,7 @@ public: CameraApertureRadius (0.0f), CameraFocalPlaneDist (1.0f), FrustumCullingState (FrustumCulling_On), + OcculsionQueryState (OcculsionQuery_Off), ToneMappingMethod (Graphic3d_ToneMappingMethod_Disabled), Exposure (0.f), WhitePoint (1.f), @@ -249,6 +258,7 @@ public: //! @name Ray-Tracing/Path-Tracing parameters Standard_ShortReal CameraApertureRadius; //!< aperture radius of perspective camera used for depth-of-field, 0.0 by default (no DOF) (path tracing only) Standard_ShortReal CameraFocalPlaneDist; //!< focal distance of perspective camera used for depth-of field, 1.0 by default (path tracing only) FrustumCulling FrustumCullingState; //!< state of frustum culling optimization; FrustumCulling_On by default + OcculsionQuery OcculsionQueryState; //!< state of occulsion query; OcculsionQuery_OFF by default Graphic3d_ToneMappingMethod ToneMappingMethod; //!< specifies tone mapping method for path tracing, Graphic3d_ToneMappingMethod_Disabled by default Standard_ShortReal Exposure; //!< exposure value used for tone mapping (path tracing), 0.0 by default diff --git a/src/Graphic3d/Graphic3d_ViewOcclusionMask.cxx b/src/Graphic3d/Graphic3d_ViewOcclusionMask.cxx new file mode 100644 index 0000000000..b7e88cbab3 --- /dev/null +++ b/src/Graphic3d/Graphic3d_ViewOcclusionMask.cxx @@ -0,0 +1,32 @@ +// Created on: 2024-02-20 +// Created by: Hossam Ali +// Copyright (c) 2024 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in +// OCCT distribution for complete text of the license and disclaimer of any +// warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include + +IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ViewOcclusionMask, Standard_Transient) + +// ======================================================================= +// function : DumpJson +// purpose : +// ======================================================================= +void Graphic3d_ViewOcclusionMask::DumpJson(Standard_OStream &theOStream, + Standard_Integer) const { + OCCT_DUMP_TRANSIENT_CLASS_BEGIN(theOStream) + + OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, myMask) +} \ No newline at end of file diff --git a/src/Graphic3d/Graphic3d_ViewOcclusionMask.hxx b/src/Graphic3d/Graphic3d_ViewOcclusionMask.hxx new file mode 100644 index 0000000000..d71f245934 --- /dev/null +++ b/src/Graphic3d/Graphic3d_ViewOcclusionMask.hxx @@ -0,0 +1,78 @@ +// Created on: 2024-02-20 +// Created by: Hossam Ali +// Copyright (c) 2024 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 _Graphic3d_ViewOcclusionMask_HeaderFile +#define _Graphic3d_ViewOcclusionMask_HeaderFile + +#include +#include +#include + +//! Structure display state. +class Graphic3d_ViewOcclusionMask : public Standard_Transient +{ +public: + + //! Empty constructor. + Graphic3d_ViewOcclusionMask() + { + SetVisible (Standard_True); + } + + //! Return visibility flag. + bool IsVisible (const Standard_Integer theViewId) const + { + const unsigned int aBit = 1 << theViewId; + return (myMask & aBit) != 0; + } + + //! Setup visibility flag for all views. + void SetVisible (const Standard_Boolean theIsVisible) + { + ::memset (&myMask, theIsVisible ? 0xFF : 0x00, sizeof(myMask)); + } + + //! Setup visibility flag. + void SetVisible (const Standard_Integer theViewId, + const bool theIsVisible) + { + const unsigned int aBit = 1 << theViewId; + if (theIsVisible) + { + myMask |= aBit; + } + else + { + myMask &= ~aBit; + } + } + + //! Dumps the content of me into the stream + Standard_EXPORT void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const; + +private: + + unsigned int myMask; //!< affinity mask + +public: + + DEFINE_STANDARD_RTTIEXT(Graphic3d_ViewOcclusionMask,Standard_Transient) + +}; + +DEFINE_STANDARD_HANDLE(Graphic3d_ViewOcclusionMask, Standard_Transient) + +#endif // _Graphic3d_ViewOcclusionMask_HeaderFile diff --git a/src/OpenGl/FILES b/src/OpenGl/FILES index 990a881650..291dfc2a6e 100755 --- a/src/OpenGl/FILES +++ b/src/OpenGl/FILES @@ -153,3 +153,5 @@ OpenGl_TextBuilder.hxx OpenGl_TextBuilder.cxx OpenGl_HaltonSampler.hxx OpenGl_ShaderProgramDumpLevel.hxx +OpenGl_OcclusionQuery.hxx +OpenGl_OcclusionQuery.cxx diff --git a/src/OpenGl/OpenGl_LayerList.cxx b/src/OpenGl/OpenGl_LayerList.cxx index 52a494d0e2..54983a99eb 100644 --- a/src/OpenGl/OpenGl_LayerList.cxx +++ b/src/OpenGl/OpenGl_LayerList.cxx @@ -871,6 +871,98 @@ void OpenGl_LayerList::Render (const Handle(OpenGl_Workspace)& theWorkspace, theWorkspace->SetRenderFilter (aPrevFilter); } +//======================================================================= +//function : updateOcclusion +//purpose : update Occlsuion state for each struct in each layer +//======================================================================= +void OpenGl_LayerList::UpdateOcclusion( const Handle(OpenGl_Workspace) & theWorkspace, + const Standard_Boolean theToDrawImmediate, + const OpenGl_FrameBuffer *theReadDrawFbo, + const OpenGl_FrameBuffer *theOitAccumFbo) +{ + const Handle(OpenGl_Context) &aCtx = theWorkspace->GetGlContext(); + aCtx->core11fwd->glEnable(GL_DEPTH_TEST); + aCtx->core11fwd->glDepthFunc (GL_LESS); + + + // Remember global settings for glDepth mask and write mask + GLboolean aPrevColorMask; + GLboolean aPrevDepthMask; + aCtx->core11fwd->glGetBooleanv(GL_COLOR_WRITEMASK, &aPrevColorMask); + aCtx->core11fwd->glGetBooleanv(GL_DEPTH_WRITEMASK, &aPrevDepthMask); + + // Turn off writing to depth and color buffers + aCtx->core11fwd->glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + aCtx->core11fwd->glDepthMask(GL_FALSE); + + // Start record occlusion test computational cost + const Handle(OpenGl_FrameStats) &aStats = theWorkspace->GetGlContext()->FrameStats(); + OSD_Timer &aTimer = aStats->ActiveDataFrame().ChangeTimer( Graphic3d_FrameStatsTimer_OcclusionCulling); + aTimer.Start(); + + // Loop for all layers + for (NCollection_List::Iterator aLayerIter(myLayers); + aLayerIter.More(); aLayerIter.Next()) { + + const Handle(Graphic3d_Layer) &aLayer = aLayerIter.ChangeValue(); + + // Exclude frustum culled layer + if (aLayer->IsCulled()) + continue; + + /// TODO Change below to Graphic3d_Query + GLuint query_ID; + GLint samplesPassed; + + aCtx->core20->glGenQueries(1, &query_ID); + + // Render priority list + const Standard_Integer aViewId = theWorkspace->View()->Identification(); + + for (Standard_Integer aPriorityIter = Graphic3d_DisplayPriority_Bottom; aPriorityIter <= Graphic3d_DisplayPriority_Topmost; ++aPriorityIter) + { + const Graphic3d_IndexedMapOfStructure &aStructures = aLayer->Structures((Graphic3d_DisplayPriority)aPriorityIter); + for (OpenGl_Structure::StructIterator aStructIter(aStructures); aStructIter.More(); aStructIter.Next()) + { + const OpenGl_Structure *aStruct = aStructIter.Value(); + + // Exclude view frustum culled structs + if (aStruct->IsCulled() || !aStruct->IsVisible(aViewId)) + continue; + + // Begin occlusion query + aCtx->core20->glBeginQuery(GL_SAMPLES_PASSED, query_ID); + + // Dry rendering for conservative approximation of the complex object + aStruct->RenderOccluder(theWorkspace); + + // End query and count no of samples + aCtx->core20->glEndQuery(GL_SAMPLES_PASSED); + aCtx->core20->glGetQueryObjectiv(query_ID, GL_QUERY_RESULT, &samplesPassed); + + if (samplesPassed <= 0) + aStruct->SetOccluded(aViewId); + + std::cout << "layerID: " << aLayer->LayerId() + << " structureID: " << aStruct->Identification() + << " clocation: " << aStruct->BoundingBox().Center().z() + << " queryID: " << query_ID + << " sample passsed : " << samplesPassed << std::endl; + samplesPassed=0; + } + } + // Release query resources + aCtx->core20->glDeleteQueries(1, &query_ID); + } + + // Back to prev settings + aCtx->core11fwd->glDepthMask(aPrevDepthMask); + aCtx->core11fwd->glColorMask(aPrevColorMask, aPrevColorMask, aPrevColorMask, aPrevColorMask); + + aTimer.Stop(); + aStats->ActiveDataFrame()[Graphic3d_FrameStatsTimer_CpuCulling] = aTimer.UserTimeCPU(); +} + //======================================================================= //function : renderTransparent //purpose : Render transparent objects using blending operator. diff --git a/src/OpenGl/OpenGl_LayerList.hxx b/src/OpenGl/OpenGl_LayerList.hxx index 442364334d..00235c48b4 100644 --- a/src/OpenGl/OpenGl_LayerList.hxx +++ b/src/OpenGl/OpenGl_LayerList.hxx @@ -106,6 +106,12 @@ public: OpenGl_FrameBuffer* theReadDrawFbo, OpenGl_FrameBuffer* theOitAccumFbo) const; + //! Update occlusion test + Standard_EXPORT void UpdateOcclusion(const Handle(OpenGl_Workspace) & theWorkspace, + const Standard_Boolean theToDrawImmediate, + const OpenGl_FrameBuffer *theReadDrawFbo, + const OpenGl_FrameBuffer *theOitAccumFbo); + //! Returns the set of OpenGL Z-layers. const NCollection_List& Layers() const { return myLayers; } diff --git a/src/OpenGl/OpenGl_OcclusionQuery.cxx b/src/OpenGl/OpenGl_OcclusionQuery.cxx new file mode 100644 index 0000000000..325d8e1694 --- /dev/null +++ b/src/OpenGl/OpenGl_OcclusionQuery.cxx @@ -0,0 +1,59 @@ +// Created on: 2024-02-20 +// Created by: Hossam Ali +// Copyright (c) 2024 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in +// OCCT distribution for complete text of the license and disclaimer of any +// warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include "OpenGl_OcclusionQuery.hxx" + +#include +#include + +IMPLEMENT_STANDARD_RTTIEXT(OpenGl_OcclusionQuery, Graphic3d_OcclusionQuery) + +// ======================================================================= +// function : +// purpose : +// ======================================================================= +Standard_EXPORT +OpenGl_OcclusionQuery::OpenGl_OcclusionQuery(const Handle(OpenGl_Context) & + theCtx) + : aCtx(theCtx) { + aCtx->core15->glGenQueries(1, &queryID); +} + +// ======================================================================= +// function : +// purpose : +// ======================================================================= +Standard_EXPORT OpenGl_OcclusionQuery::~OpenGl_OcclusionQuery() { + aCtx->core15->glDeleteQueries(1, &queryID); + queryID = 0; +} + +// ======================================================================= +// function : BeginQuery() +// purpose : +// ======================================================================= +Standard_EXPORT void OpenGl_OcclusionQuery::BeginQuery() const { + aCtx->core15->glBeginQuery(GL_SAMPLES_PASSED, queryID); +} + +// ======================================================================= +// function : EndQuery() +// purpose : +// ======================================================================= +Standard_EXPORT void OpenGl_OcclusionQuery::EndQuery() { + aCtx->core15->glEndQuery(GL_SAMPLES_PASSED); + aCtx->core15->glGetQueryObjectiv(queryID, GL_QUERY_RESULT, &samplesPassed); +} diff --git a/src/OpenGl/OpenGl_OcclusionQuery.hxx b/src/OpenGl/OpenGl_OcclusionQuery.hxx new file mode 100644 index 0000000000..e2cee43879 --- /dev/null +++ b/src/OpenGl/OpenGl_OcclusionQuery.hxx @@ -0,0 +1,51 @@ +// Created on: 2024-02-20 +// Created by: Hossam Ali +// Copyright (c) 2024 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_View_HeaderFile +#define OpenGl_View_HeaderFile + +#include + +class OpenGl_Context; + +DEFINE_STANDARD_HANDLE(OpenGl_OcclusionQuery, Graphic3d_OcclusionQuery) + +//! Implementation of OpenGl view. +class OpenGl_OcclusionQuery : public Graphic3d_OcclusionQuery { + +public: + //! Constructor. + Standard_EXPORT OpenGl_OcclusionQuery(const Handle(OpenGl_Context) & theCtx); + + //! Default destructor. + Standard_EXPORT virtual ~OpenGl_OcclusionQuery(); + + //! Begins occlusion query. + Standard_EXPORT virtual void BeginQuery() const Standard_OVERRIDE; + + //! Ends occlusion query and caches the result + Standard_EXPORT virtual void EndQuery() Standard_OVERRIDE; + +public: + DEFINE_STANDARD_ALLOC + DEFINE_STANDARD_RTTIEXT(OpenGl_OcclusionQuery, + Graphic3d_OcclusionQuery) // Type definition + +private: + const Handle(OpenGl_Context) & aCtx; +}; + +#endif // _OpenGl_View_Header diff --git a/src/OpenGl/OpenGl_Structure.cxx b/src/OpenGl/OpenGl_Structure.cxx index d5c3c5270b..a89cf7eed6 100644 --- a/src/OpenGl/OpenGl_Structure.cxx +++ b/src/OpenGl/OpenGl_Structure.cxx @@ -626,6 +626,17 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con theWorkspace->SetHighlightStyle (Handle(Graphic3d_PresentationAttributes)()); } +// ======================================================================= +// function : RenderOccluder +// purpose : +// ======================================================================= +void OpenGl_Structure::RenderOccluder(const Handle(OpenGl_Workspace)& theWorkspace) const +{ + const Handle(OpenGl_Context) &aCtx = theWorkspace->GetGlContext(); + aCtx->ApplyModelViewMatrix(); + renderBoundingBox(theWorkspace); +} + // ======================================================================= // function : Release // purpose : diff --git a/src/OpenGl/OpenGl_Structure.hxx b/src/OpenGl/OpenGl_Structure.hxx index b770323783..d9f9820491 100644 --- a/src/OpenGl/OpenGl_Structure.hxx +++ b/src/OpenGl/OpenGl_Structure.hxx @@ -96,6 +96,9 @@ public: //! Renders the structure. Standard_EXPORT virtual void Render (const Handle(OpenGl_Workspace)& theWorkspace) const; + //! Render Occluder presenation of this structure + Standard_EXPORT void RenderOccluder(const Handle(OpenGl_Workspace)& theWorkspace) const; + //! Releases structure resources. Standard_EXPORT virtual void Release (const Handle(OpenGl_Context)& theGlCtx); diff --git a/src/OpenGl/OpenGl_View.cxx b/src/OpenGl/OpenGl_View.cxx index 7907795567..87d0b92070 100644 --- a/src/OpenGl/OpenGl_View.cxx +++ b/src/OpenGl/OpenGl_View.cxx @@ -1766,7 +1766,7 @@ void OpenGl_View::Redraw() aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK); aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(), aMainFbos[0] != NULL ? myRenderParams.RenderResolutionScale : 1.0f); - + redraw (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0], aMainFbosOit[0]); myBackBufferRestored = Standard_True; myIsImmediateDrawn = Standard_False; @@ -2129,8 +2129,8 @@ void OpenGl_View::redraw (const Graphic3d_Camera::Projection theProjection, aCtx->core11fwd->glClearColor (aBgColor.r(), aBgColor.g(), aBgColor.b(), aCtx->caps->buffersOpaqueAlpha ? 1.0f : 0.0f); aCtx->core11fwd->glClear (toClear); aCtx->SetColorMask (true); // restore default alpha component write state - - render (theProjection, theReadDrawFbo, theOitAccumFbo, Standard_False); + + render (theProjection, theReadDrawFbo, theOitAccumFbo, Standard_False); } // ======================================================================= @@ -2407,6 +2407,10 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection, { myAccumFrames = 0; myWorldViewProjState = aWVPState; + + // Invalidiate occlusion query if camera has changed. + if (myRenderParams.OcculsionQueryState == Graphic3d_RenderingParams::OcculsionQuery_On) + myRenderParams.OcculsionQueryState = Graphic3d_RenderingParams::OcculsionQuery_NoUpdate; } myLocalOrigin.SetCoord (0.0, 0.0, 0.0); @@ -2534,6 +2538,19 @@ void OpenGl_View::InvalidateBVHData (const Graphic3d_ZLayerId theLayerId) myZLayers.InvalidateBVHData (theLayerId); } +//======================================================================= +//function : updateOcclusionState +//purpose : +//======================================================================= +void OpenGl_View::updateOcclusion(OpenGl_FrameBuffer* theReadDrawFbo, + OpenGl_FrameBuffer* theOitAccumFbo, + const Standard_Boolean theToDrawImmediate) +{ + myZLayers.UpdateOcclusion(myWorkspace, theToDrawImmediate,theReadDrawFbo, theOitAccumFbo); + + // re-validate occlusion results + myRenderParams.OcculsionQueryState = Graphic3d_RenderingParams::OcculsionQuery_On; +} //======================================================================= //function : renderStructs //purpose : @@ -2547,13 +2564,17 @@ void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection, { return; } - + myZLayers.UpdateCulling (myWorkspace, theToDrawImmediate); if (myZLayers.NbStructures() <= 0) { return; } + // update occlusion here after update culling to ensure the frusrum culling updated + if (myRenderParams.OcculsionQueryState == Graphic3d_RenderingParams::OcculsionQuery_NoUpdate) + updateOcclusion(theReadDrawFbo, theOitAccumFbo, theToDrawImmediate); + Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext(); Standard_Boolean toRenderGL = theToDrawImmediate || myRenderParams.Method != Graphic3d_RM_RAYTRACING || diff --git a/src/OpenGl/OpenGl_View.hxx b/src/OpenGl/OpenGl_View.hxx index 17768a06d1..c2051252ad 100644 --- a/src/OpenGl/OpenGl_View.hxx +++ b/src/OpenGl/OpenGl_View.hxx @@ -380,6 +380,14 @@ protected: //! @name Rendering of GL graphics (with prepared drawing buffer). Standard_EXPORT virtual void drawBackground (const Handle(OpenGl_Workspace)& theWorkspace, Graphic3d_Camera::Projection theProjection); + //! Update occlusion state for the set of structures presented in the view + //! @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 updateOcclusion(OpenGl_FrameBuffer* theReadDrawFbo, + OpenGl_FrameBuffer* theOitAccumFbo, + const Standard_Boolean theToDrawImmediate); + //! 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. @@ -389,7 +397,7 @@ protected: //! @name Rendering of GL graphics (with prepared drawing buffer). OpenGl_FrameBuffer* theReadDrawFbo, OpenGl_FrameBuffer* theOitAccumFbo, const Standard_Boolean theToDrawImmediate); - + //! Renders trihedron. void renderTrihedron (const Handle(OpenGl_Workspace) &theWorkspace); diff --git a/src/PrsMgr/PrsMgr_PresentableObject.cxx b/src/PrsMgr/PrsMgr_PresentableObject.cxx index b723891b86..8d540a8bbb 100644 --- a/src/PrsMgr/PrsMgr_PresentableObject.cxx +++ b/src/PrsMgr/PrsMgr_PresentableObject.cxx @@ -46,6 +46,7 @@ const gp_Trsf& PrsMgr_PresentableObject::getIdentityTrsf() PrsMgr_PresentableObject::PrsMgr_PresentableObject (const PrsMgr_TypeOfPresentation3d theType) : myParent (NULL), myViewAffinity (new Graphic3d_ViewAffinity()), + myViewOcclusionMask(new Graphic3d_ViewOcclusionMask()), myDrawer (new Prs3d_Drawer()), myTypeOfPresentation3d (theType), myDisplayStatus (PrsMgr_DisplayStatus_None), diff --git a/src/PrsMgr/PrsMgr_PresentableObject.hxx b/src/PrsMgr/PrsMgr_PresentableObject.hxx index bf739ef2b9..0ad92e01a2 100644 --- a/src/PrsMgr/PrsMgr_PresentableObject.hxx +++ b/src/PrsMgr/PrsMgr_PresentableObject.hxx @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -72,6 +73,9 @@ public: //! Return view affinity mask. const Handle(Graphic3d_ViewAffinity)& ViewAffinity() const { return myViewAffinity; } + + //! Return view occlusion mask. + const Handle(Graphic3d_ViewOcclusionMask)& ViewOcclusionMask() const { return myViewOcclusionMask; } //! Returns true if the Interactive Object has display mode setting overriding global setting (within Interactive Context). Standard_Boolean HasDisplayMode() const { return myDrawer->DisplayMode() != -1; } @@ -522,6 +526,7 @@ protected: PrsMgr_PresentableObject* myParent; //!< pointer to the parent object PrsMgr_Presentations myPresentations; //!< list of presentations Handle(Graphic3d_ViewAffinity) myViewAffinity; //!< view affinity mask + Handle(Graphic3d_ViewOcclusionMask) myViewOcclusionMask; //!< view occlusion mask Handle(Graphic3d_SequenceOfHClipPlane) myClipPlanes; //!< sequence of object-specific clipping planes Handle(Prs3d_Drawer) myDrawer; //!< main presentation attributes Handle(Prs3d_Drawer) myHilightDrawer; //!< (optional) custom presentation attributes for highlighting selected object diff --git a/src/PrsMgr/PrsMgr_PresentationManager.cxx b/src/PrsMgr/PrsMgr_PresentationManager.cxx index 09f5a5bffe..28fbcc299b 100644 --- a/src/PrsMgr/PrsMgr_PresentationManager.cxx +++ b/src/PrsMgr/PrsMgr_PresentationManager.cxx @@ -395,6 +395,7 @@ void PrsMgr_PresentationManager::displayImmediate (const Handle(V3d_Viewer)& the { aShadowPrs->CStructure()->ViewAffinity = new Graphic3d_ViewAffinity(); aShadowPrs->CStructure()->ViewAffinity->SetVisible (Standard_False); + aShadowPrs->CStructure()->OcclusionMask =new Graphic3d_ViewOcclusionMask(); aShadowPrs->Display(); } @@ -522,6 +523,10 @@ Handle(PrsMgr_Presentation) PrsMgr_PresentationManager::Presentation (const Hand thePrsObj->Presentations().Append (aPrs); thePrsObj->Fill (this, aPrs, theMode); + // update object occlusion state by passing occlusion state handle to + // underlaying graphic strcutures + aPrs->CStructure()->OcclusionMask = thePrsObj->ViewOcclusionMask(); + // set layer index accordingly to object's presentations aPrs->SetUpdateStatus (Standard_False); return aPrs; diff --git a/src/V3d/V3d_Trihedron.cxx b/src/V3d/V3d_Trihedron.cxx index 29c04ba8c3..5c457d3d15 100644 --- a/src/V3d/V3d_Trihedron.cxx +++ b/src/V3d/V3d_Trihedron.cxx @@ -256,6 +256,7 @@ void V3d_Trihedron::Display (const V3d_View& theView) myStructure->CStructure()->ViewAffinity = new Graphic3d_ViewAffinity(); myStructure->CStructure()->ViewAffinity->SetVisible (Standard_False); myStructure->CStructure()->ViewAffinity->SetVisible (theView.View()->Identification(), true); + myStructure->CStructure()->OcclusionMask = new Graphic3d_ViewOcclusionMask(); myToCompute = Standard_True; } if (myToCompute) diff --git a/src/V3d/V3d_Viewer.cxx b/src/V3d/V3d_Viewer.cxx index 896d612d0b..2e9fe9ba8c 100644 --- a/src/V3d/V3d_Viewer.cxx +++ b/src/V3d/V3d_Viewer.cxx @@ -879,6 +879,7 @@ void V3d_Viewer::ShowGridEcho (const Handle(V3d_View)& theView, myGridEchoStructure->CStructure()->ViewAffinity = new Graphic3d_ViewAffinity(); myGridEchoStructure->CStructure()->ViewAffinity->SetVisible (Standard_False); myGridEchoStructure->CStructure()->ViewAffinity->SetVisible (theView->View()->Identification(), true); + myGridEchoStructure->CStructure()->OcclusionMask = new Graphic3d_ViewOcclusionMask(); myGridEchoStructure->Display(); } diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index d700adce80..33a8f8ef09 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -13992,6 +13992,70 @@ static int VChangeMouseGesture (Draw_Interpretor&, return 0; } +//============================================================================== +//function : VOccluded +//purpose : Returns number of Occluded objects +//============================================================================== +static Standard_Integer VNbOccluded(Draw_Interpretor & /*theDi*/, + Standard_Integer theArgNb, + const char **theArgVec) { + NCollection_List aViewList; + if (theArgNb > 1) + { + TCollection_AsciiString anArg (theArgVec[1]); + anArg.UpperCase(); + if (anArg.IsEqual ("ALL") + || anArg.IsEqual ("*")) + { + for (ViewerTest_ViewerCommandsViewMap::Iterator anIter (ViewerTest_myViews); + anIter.More(); anIter.Next()) + { + aViewList.Append (anIter.Key1()); + } + if (aViewList.IsEmpty()) + { + std::cout << "No views available\n"; + return 0; + } + } + else + { + ViewerTest_Names aViewName (theArgVec[1]); + if (!ViewerTest_myViews.IsBound1 (aViewName.GetViewName())) + { + Message::SendFail() << "Error: the view with name '" << theArgVec[1] << "' does not exist"; + return 1; + } + aViewList.Append (aViewName.GetViewName()); + } + } + else + { + // query from the active view + if (ViewerTest::CurrentView().IsNull()) + { + Message::SendFail ("Error: no active view"); + return 1; + } + aViewList.Append (ViewerTest_myViews.Find2 (ViewerTest::CurrentView())); + } + + for (NCollection_List::Iterator anIter(aViewList); + anIter.More(); anIter.Next()) { + Handle(V3d_View) aView = ViewerTest_myViews.Find1(anIter.Value()); + aView->ChangeRenderingParams().OcculsionQueryState = Graphic3d_RenderingParams::OcculsionQuery_NoUpdate; + aView->Redraw(); + + Graphic3d_MapOfStructure aOcculdedStructs; + aView->View()->OccludedStructures(aOcculdedStructs); + + printf("No Occluded Objects in view id: %d --> %d\n", + aView->View()->Identification(), aOcculdedStructs.Extent()); + } + + return 0; +} + //======================================================================= //function : ViewerTest_ExitProc //purpose : @@ -15018,4 +15082,9 @@ Changes the gesture for the mouse button. -button the mouse button; -gesture the new gesture for the button. )" /* [vchangemousegesture] */); + + addCmd("vnboccluded", VNbOccluded, /* [vnboccluded] */ R"( +vnboccluded ALL - print nb of occluded objects for all created views +vnboccluded [view_id] print nb of occluded objects for specified view_id . +)" /* [vnboccluded] */); } diff --git a/tests/v3d/occlusion/boxes b/tests/v3d/occlusion/boxes new file mode 100644 index 0000000000..8f63023104 --- /dev/null +++ b/tests/v3d/occlusion/boxes @@ -0,0 +1,29 @@ +puts "==============================================================================================" +puts "CR33607: Visualization - Test occlusion query on two boxes using two orthographic projections" +puts "==============================================================================================" + +pload MODELING VISUALIZATION +vclear +vclose ALL + +box b 10 10 10 +box c 12 0 0 10 10 10 + +# check left side +vinit name=View1 +vsetdispmode 1 +vdisplay b c +vright +vfit +vzoom 0.5 + +# check front side +vinit name=View2 +vsetdispmode 1 +vdisplay b c +vfront +vfit + +#run occlusion query for each view +vnboccluded View1 +vnboccluded View2 -- 2.39.5