1 // Created on: 2014-03-31
2 // Created by: Danila ULYANOV
3 // Copyright (c) 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_Layer.hxx>
18 #include <OpenGl_BVHTreeSelector.hxx>
19 #include <OpenGl_Structure.hxx>
20 #include <OpenGl_ShaderManager.hxx>
21 #include <OpenGl_View.hxx>
22 #include <OpenGl_Workspace.hxx>
23 #include <Graphic3d_GraphicDriver.hxx>
25 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Layer, Standard_Transient)
27 // =======================================================================
28 // function : OpenGl_Layer
30 // =======================================================================
31 OpenGl_Layer::OpenGl_Layer (const Standard_Integer theNbPriorities,
32 const Handle(Select3D_BVHBuilder3d)& theBuilder)
33 : myArray (0, theNbPriorities - 1),
35 myNbStructuresNotCulled (0),
36 myBVHPrimitivesTrsfPers (theBuilder),
37 myBVHIsLeftChildQueuedFirst (Standard_True),
38 myIsBVHPrimitivesNeedsReset (Standard_False)
40 myIsBoundingBoxNeedsReset[0] = myIsBoundingBoxNeedsReset[1] = true;
43 // =======================================================================
44 // function : ~OpenGl_Layer
46 // =======================================================================
47 OpenGl_Layer::~OpenGl_Layer()
52 // =======================================================================
55 // =======================================================================
56 void OpenGl_Layer::Add (const OpenGl_Structure* theStruct,
57 const Standard_Integer thePriority,
58 Standard_Boolean isForChangePriority)
60 const Standard_Integer anIndex = Min (Max (thePriority, 0), myArray.Length() - 1);
61 if (theStruct == NULL)
66 myArray (anIndex).Add (theStruct);
67 if (theStruct->IsAlwaysRendered())
69 theStruct->MarkAsNotCulled();
70 if (!isForChangePriority)
72 myAlwaysRenderedMap.Add (theStruct);
75 else if (!isForChangePriority)
77 if (theStruct->TransformPersistence().IsNull())
79 myBVHPrimitives.Add (theStruct);
83 myBVHPrimitivesTrsfPers.Add (theStruct);
89 // =======================================================================
92 // =======================================================================
93 bool OpenGl_Layer::Remove (const OpenGl_Structure* theStruct,
94 Standard_Integer& thePriority,
95 Standard_Boolean isForChangePriority)
97 if (theStruct == NULL)
103 const Standard_Integer aNbPriorities = myArray.Length();
104 for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
106 OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
108 const Standard_Integer anIndex = aStructures.FindIndex (theStruct);
111 aStructures.Swap (anIndex, aStructures.Size());
112 aStructures.RemoveLast();
114 if (!isForChangePriority)
116 Standard_Boolean isAlwaysRend = theStruct->IsAlwaysRendered();
119 if (!myBVHPrimitives.Remove (theStruct))
121 if (!myBVHPrimitivesTrsfPers.Remove (theStruct))
123 isAlwaysRend = Standard_True;
129 const Standard_Integer anIndex2 = myAlwaysRenderedMap.FindIndex (theStruct);
132 myAlwaysRenderedMap.Swap (myAlwaysRenderedMap.Size(), anIndex2);
133 myAlwaysRenderedMap.RemoveLast();
138 thePriority = aPriorityIter;
147 // =======================================================================
148 // function : InvalidateBVHData
150 // =======================================================================
151 void OpenGl_Layer::InvalidateBVHData()
153 myIsBVHPrimitivesNeedsReset = Standard_True;
156 //! Calculate a finite bounding box of infinite object as its middle point.
157 inline Graphic3d_BndBox3d centerOfinfiniteBndBox (const Graphic3d_BndBox3d& theBndBox)
159 // bounding borders of infinite line has been calculated as own point in center of this line
160 const Graphic3d_Vec3d aDiagVec = theBndBox.CornerMax() - theBndBox.CornerMin();
161 return aDiagVec.SquareModulus() >= 500000.0 * 500000.0
162 ? Graphic3d_BndBox3d ((theBndBox.CornerMin() + theBndBox.CornerMax()) * 0.5)
163 : Graphic3d_BndBox3d();
166 //! Return true if at least one vertex coordinate out of float range.
167 inline bool isInfiniteBndBox (const Graphic3d_BndBox3d& theBndBox)
169 return Abs (theBndBox.CornerMax().x()) >= ShortRealLast()
170 || Abs (theBndBox.CornerMax().y()) >= ShortRealLast()
171 || Abs (theBndBox.CornerMax().z()) >= ShortRealLast()
172 || Abs (theBndBox.CornerMin().x()) >= ShortRealLast()
173 || Abs (theBndBox.CornerMin().y()) >= ShortRealLast()
174 || Abs (theBndBox.CornerMin().z()) >= ShortRealLast();
177 // =======================================================================
178 // function : BoundingBox
180 // =======================================================================
181 Bnd_Box OpenGl_Layer::BoundingBox (const Standard_Integer theViewId,
182 const Handle(Graphic3d_Camera)& theCamera,
183 const Standard_Integer theWindowWidth,
184 const Standard_Integer theWindowHeight,
185 const Standard_Boolean theToIncludeAuxiliary) const
189 const Standard_Integer aBoxId = !theToIncludeAuxiliary ? 0 : 1;
190 const Graphic3d_Mat4d& aProjectionMat = theCamera->ProjectionMatrix();
191 const Graphic3d_Mat4d& aWorldViewMat = theCamera->OrientationMatrix();
192 if (myIsBoundingBoxNeedsReset[aBoxId])
194 // Recompute layer bounding box
195 myBoundingBox[aBoxId].SetVoid();
197 for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
199 const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value();
200 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
202 const OpenGl_Structure* aStructure = aStructIter.Value();
203 if (!aStructure->IsVisible (theViewId))
208 // "FitAll" operation ignores object with transform persistence parameter
209 // but adds transform persistence point in a bounding box of layer (only zoom pers. objects).
210 if (!aStructure->TransformPersistence().IsNull())
212 if (!theToIncludeAuxiliary
213 && aStructure->TransformPersistence()->IsZoomOrRotate())
215 const gp_Pnt anAnchor = aStructure->TransformPersistence()->AnchorPoint();
216 myBoundingBox[aBoxId].Add (anAnchor);
219 // Panning and 2d persistence apply changes to projection or/and its translation components.
220 // It makes them incompatible with z-fitting algorithm. Ignored by now.
221 else if (!theToIncludeAuxiliary
222 || aStructure->TransformPersistence()->IsTrihedronOr2d())
228 Graphic3d_BndBox3d aBox = aStructure->BoundingBox();
234 if (aStructure->IsInfinite
235 && !theToIncludeAuxiliary)
237 // include center of infinite object
238 aBox = centerOfinfiniteBndBox (aBox);
241 if (!aStructure->TransformPersistence().IsNull())
243 aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
246 // skip too big boxes to prevent float overflow at camera parameters calculation
248 && !isInfiniteBndBox (aBox))
250 myBoundingBox[aBoxId].Add (gp_Pnt (aBox.CornerMin().x(), aBox.CornerMin().y(), aBox.CornerMin().z()));
251 myBoundingBox[aBoxId].Add (gp_Pnt (aBox.CornerMax().x(), aBox.CornerMax().y(), aBox.CornerMax().z()));
256 myIsBoundingBoxNeedsReset[aBoxId] = false;
259 Bnd_Box aResBox = myBoundingBox[aBoxId];
260 if (!theToIncludeAuxiliary
261 || myAlwaysRenderedMap.IsEmpty())
266 // add transformation-persistent objects which depend on camera position (and thus can not be cached) for operations like Z-fit
267 for (NCollection_IndexedMap<const OpenGl_Structure*>::Iterator aStructIter (myAlwaysRenderedMap); aStructIter.More(); aStructIter.Next())
269 const OpenGl_Structure* aStructure = aStructIter.Value();
270 if (!aStructure->IsVisible (theViewId))
274 else if (aStructure->TransformPersistence().IsNull()
275 || !aStructure->TransformPersistence()->IsTrihedronOr2d())
280 Graphic3d_BndBox3d aBox = aStructure->BoundingBox();
286 aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
288 && !isInfiniteBndBox (aBox))
290 aResBox.Add (gp_Pnt (aBox.CornerMin().x(), aBox.CornerMin().y(), aBox.CornerMin().z()));
291 aResBox.Add (gp_Pnt (aBox.CornerMax().x(), aBox.CornerMax().y(), aBox.CornerMax().z()));
298 // =======================================================================
299 // function : considerZoomPersistenceObjects
301 // =======================================================================
302 Standard_Real OpenGl_Layer::considerZoomPersistenceObjects (const Standard_Integer theViewId,
303 const Handle(Graphic3d_Camera)& theCamera,
304 Standard_Integer theWindowWidth,
305 Standard_Integer theWindowHeight) const
307 if (NbOfTransformPersistenceObjects() == 0)
312 const Graphic3d_Mat4d& aProjectionMat = theCamera->ProjectionMatrix();
313 const Graphic3d_Mat4d& aWorldViewMat = theCamera->OrientationMatrix();
314 Standard_Real aMaxCoef = -std::numeric_limits<double>::max();
316 for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
318 const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value();
319 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
321 const OpenGl_Structure* aStructure = aStructIter.Value();
322 if (!aStructure->IsVisible (theViewId)
323 || aStructure->TransformPersistence().IsNull()
324 || !aStructure->TransformPersistence()->IsZoomOrRotate())
329 Graphic3d_BndBox3d aBox = aStructure->BoundingBox();
335 aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
337 const BVH_Vec3d& aCornerMin = aBox.CornerMin();
338 const BVH_Vec3d& aCornerMax = aBox.CornerMax();
339 const Standard_Integer aNbOfPoints = 8;
340 const gp_Pnt aPoints[aNbOfPoints] = { gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMin.z()),
341 gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMax.z()),
342 gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMin.z()),
343 gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMax.z()),
344 gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMin.z()),
345 gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMax.z()),
346 gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMin.z()),
347 gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMax.z()) };
348 gp_Pnt aConvertedPoints[aNbOfPoints];
349 Standard_Real aConvertedMinX = std::numeric_limits<double>::max();
350 Standard_Real aConvertedMaxX = -std::numeric_limits<double>::max();
351 Standard_Real aConvertedMinY = std::numeric_limits<double>::max();
352 Standard_Real aConvertedMaxY = -std::numeric_limits<double>::max();
353 for (Standard_Integer anIdx = 0; anIdx < aNbOfPoints; ++anIdx)
355 aConvertedPoints[anIdx] = theCamera->Project (aPoints[anIdx]);
357 aConvertedMinX = Min (aConvertedMinX, aConvertedPoints[anIdx].X());
358 aConvertedMaxX = Max (aConvertedMaxX, aConvertedPoints[anIdx].X());
360 aConvertedMinY = Min (aConvertedMinY, aConvertedPoints[anIdx].Y());
361 aConvertedMaxY = Max (aConvertedMaxY, aConvertedPoints[anIdx].Y());
364 const Standard_Boolean isBigObject = (Abs (aConvertedMaxX - aConvertedMinX) > 2.0) // width of zoom pers. object greater than width of window
365 || (Abs (aConvertedMaxY - aConvertedMinY) > 2.0); // height of zoom pers. object greater than height of window
366 const Standard_Boolean isAlreadyInScreen = (aConvertedMinX > -1.0 && aConvertedMinX < 1.0)
367 && (aConvertedMaxX > -1.0 && aConvertedMaxX < 1.0)
368 && (aConvertedMinY > -1.0 && aConvertedMinY < 1.0)
369 && (aConvertedMaxY > -1.0 && aConvertedMaxY < 1.0);
370 if (isBigObject || isAlreadyInScreen)
375 const gp_Pnt aTPPoint = aStructure->TransformPersistence()->AnchorPoint();
376 gp_Pnt aConvertedTPPoint = theCamera->Project (aTPPoint);
377 aConvertedTPPoint.SetZ (0.0);
379 if (aConvertedTPPoint.Coord().Modulus() < Precision::Confusion())
384 Standard_Real aShiftX = 0.0;
385 if (aConvertedMinX < -1.0)
387 aShiftX = ((aConvertedMaxX < -1.0) ? (-(1.0 + aConvertedMaxX) + (aConvertedMaxX - aConvertedMinX)) : -(1.0 + aConvertedMinX));
389 else if (aConvertedMaxX > 1.0)
391 aShiftX = ((aConvertedMinX > 1.0) ? ((aConvertedMinX - 1.0) + (aConvertedMaxX - aConvertedMinX)) : (aConvertedMaxX - 1.0));
394 Standard_Real aShiftY = 0.0;
395 if (aConvertedMinY < -1.0)
397 aShiftY = ((aConvertedMaxY < -1.0) ? (-(1.0 + aConvertedMaxY) + (aConvertedMaxY - aConvertedMinY)) : -(1.0 + aConvertedMinY));
399 else if (aConvertedMaxY > 1.0)
401 aShiftY = ((aConvertedMinY > 1.0) ? ((aConvertedMinY - 1.0) + (aConvertedMaxY - aConvertedMinY)) : (aConvertedMaxY - 1.0));
404 const Standard_Real aDifX = Abs (aConvertedTPPoint.X()) - aShiftX;
405 const Standard_Real aDifY = Abs (aConvertedTPPoint.Y()) - aShiftY;
406 if (aDifX > Precision::Confusion())
408 aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.X()) / aDifX);
410 if (aDifY > Precision::Confusion())
412 aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.Y()) / aDifY);
417 return (aMaxCoef > 0.0) ? aMaxCoef : 1.0;
420 // =======================================================================
421 // function : renderAll
423 // =======================================================================
424 void OpenGl_Layer::renderAll (const Handle(OpenGl_Workspace)& theWorkspace) const
426 const Standard_Integer aViewId = theWorkspace->View()->Identification();
427 for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
429 const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value();
430 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
432 const OpenGl_Structure* aStruct = aStructIter.Value();
433 if (aStruct->IsCulled()
434 || !aStruct->IsVisible (aViewId))
439 aStruct->Render (theWorkspace);
444 // =======================================================================
445 // function : updateBVH
447 // =======================================================================
448 void OpenGl_Layer::updateBVH() const
450 if (!myIsBVHPrimitivesNeedsReset)
455 myBVHPrimitives.Clear();
456 myBVHPrimitivesTrsfPers.Clear();
457 myAlwaysRenderedMap.Clear();
458 myIsBVHPrimitivesNeedsReset = Standard_False;
459 for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
461 const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value();
462 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
464 const OpenGl_Structure* aStruct = aStructIter.Value();
465 if (aStruct->IsAlwaysRendered())
467 aStruct->MarkAsNotCulled();
468 myAlwaysRenderedMap.Add (aStruct);
470 else if (aStruct->TransformPersistence().IsNull())
472 myBVHPrimitives.Add (aStruct);
476 myBVHPrimitivesTrsfPers.Add (aStruct);
482 // =======================================================================
483 // function : UpdateCulling
485 // =======================================================================
486 void OpenGl_Layer::UpdateCulling (const Standard_Integer theViewId,
487 const OpenGl_BVHTreeSelector& theSelector,
488 const Graphic3d_RenderingParams::FrustumCulling theFrustumCullingState)
492 myNbStructuresNotCulled = myNbStructures;
493 if (theFrustumCullingState != Graphic3d_RenderingParams::FrustumCulling_NoUpdate)
495 Standard_Boolean toTraverse =
496 (theFrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On);
497 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (myBVHPrimitives.Structures()); aStructIter.More(); aStructIter.Next())
499 const OpenGl_Structure* aStruct = aStructIter.Value();
500 aStruct->SetCulled (toTraverse);
502 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (myBVHPrimitivesTrsfPers.Structures()); aStructIter.More(); aStructIter.Next())
504 const OpenGl_Structure* aStruct = aStructIter.Value();
505 aStruct->SetCulled (toTraverse);
509 if (theFrustumCullingState != Graphic3d_RenderingParams::FrustumCulling_On)
513 if (myBVHPrimitives .Size() == 0
514 && myBVHPrimitivesTrsfPers.Size() == 0)
519 myNbStructuresNotCulled = myAlwaysRenderedMap.Extent();
520 OpenGl_BVHTreeSelector::CullingContext aCullCtx;
521 theSelector.SetCullingDistance(aCullCtx, myLayerSettings.CullingDistance());
522 theSelector.SetCullingSize (aCullCtx, myLayerSettings.CullingSize());
523 for (Standard_Integer aBVHTreeIdx = 0; aBVHTreeIdx < 2; ++aBVHTreeIdx)
525 const Standard_Boolean isTrsfPers = aBVHTreeIdx == 1;
526 opencascade::handle<BVH_Tree<Standard_Real, 3> > aBVHTree;
529 if (myBVHPrimitivesTrsfPers.Size() == 0)
532 const OpenGl_Mat4d& aProjection = theSelector.ProjectionMatrix();
533 const OpenGl_Mat4d& aWorldView = theSelector.WorldViewMatrix();
534 const Graphic3d_WorldViewProjState& aWVPState = theSelector.WorldViewProjState();
535 const Standard_Integer aViewportWidth = theSelector.ViewportWidth();
536 const Standard_Integer aViewportHeight = theSelector.ViewportHeight();
538 aBVHTree = myBVHPrimitivesTrsfPers.BVH (theSelector.Camera(), aProjection, aWorldView, aViewportWidth, aViewportHeight, aWVPState);
542 if (myBVHPrimitives.Size() == 0)
545 aBVHTree = myBVHPrimitives.BVH();
548 if (theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (0), aBVHTree->MaxPoint (0)))
553 Standard_Integer aStack[BVH_Constants_MaxTreeDepth];
554 Standard_Integer aHead = -1;
555 Standard_Integer aNode = 0; // a root node
558 if (!aBVHTree->IsOuter (aNode))
560 const Standard_Integer aLeftChildIdx = aBVHTree->Child<0> (aNode);
561 const Standard_Integer aRightChildIdx = aBVHTree->Child<1> (aNode);
562 const Standard_Boolean isLeftChildIn = !theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (aLeftChildIdx), aBVHTree->MaxPoint (aLeftChildIdx));
563 const Standard_Boolean isRightChildIn = !theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (aRightChildIdx), aBVHTree->MaxPoint (aRightChildIdx));
567 aNode = myBVHIsLeftChildQueuedFirst ? aLeftChildIdx : aRightChildIdx;
568 aStack[++aHead] = myBVHIsLeftChildQueuedFirst ? aRightChildIdx : aLeftChildIdx;
569 myBVHIsLeftChildQueuedFirst = !myBVHIsLeftChildQueuedFirst;
571 else if (isLeftChildIn
574 aNode = isLeftChildIn ? aLeftChildIdx : aRightChildIdx;
583 aNode = aStack[aHead--];
588 Standard_Integer aIdx = aBVHTree->BegPrimitive (aNode);
589 const OpenGl_Structure* aStruct = isTrsfPers
590 ? myBVHPrimitivesTrsfPers.GetStructureById (aIdx)
591 : myBVHPrimitives.GetStructureById (aIdx);
592 if (aStruct->IsVisible (theViewId))
594 aStruct->MarkAsNotCulled();
595 ++myNbStructuresNotCulled;
602 aNode = aStack[aHead--];
608 // =======================================================================
611 // =======================================================================
612 Standard_Boolean OpenGl_Layer::Append (const OpenGl_Layer& theOther)
614 // the source priority list shouldn't have more priorities
615 const Standard_Integer aNbPriorities = theOther.NbPriorities();
616 if (aNbPriorities > NbPriorities())
618 return Standard_False;
621 // add all structures to destination priority list
622 for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
624 const OpenGl_IndexedMapOfStructure& aStructures = theOther.myArray (aPriorityIter);
625 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
627 Add (aStructIter.Value(), aPriorityIter);
631 return Standard_True;
634 //=======================================================================
635 //function : SetLayerSettings
637 //=======================================================================
638 void OpenGl_Layer::SetLayerSettings (const Graphic3d_ZLayerSettings& theSettings)
640 const Standard_Boolean toUpdateTrsf = !myLayerSettings.Origin().IsEqual (theSettings.Origin(), gp::Resolution());
641 myLayerSettings = theSettings;
644 for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
646 OpenGl_IndexedMapOfStructure& aStructures = aMapIter.ChangeValue();
647 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
649 OpenGl_Structure* aStructure = const_cast<OpenGl_Structure*> (aStructIter.Value());
650 aStructure->updateLayerTransformation();
656 //=======================================================================
659 //=======================================================================
660 void OpenGl_Layer::Render (const Handle(OpenGl_Workspace)& theWorkspace,
661 const OpenGl_GlobalLayerSettings& theDefaultSettings) const
663 const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
664 // myLayerSettings.ToClearDepth() is handled outside
667 if (myLayerSettings.ToEnableDepthTest())
669 // assuming depth test is enabled by default
670 glDepthFunc (theDefaultSettings.DepthFunc);
674 glDepthFunc (GL_ALWAYS);
677 // save environment texture
678 Handle(OpenGl_TextureSet) anEnvironmentTexture = theWorkspace->EnvironmentTexture();
679 if (!myLayerSettings.UseEnvironmentTexture())
681 theWorkspace->SetEnvironmentTexture (Handle(OpenGl_TextureSet)());
684 // handle depth offset
685 const Graphic3d_PolygonOffset anAppliedOffsetParams = theWorkspace->SetDefaultPolygonOffset (myLayerSettings.PolygonOffset());
687 // handle depth write
688 theWorkspace->UseDepthWrite() = myLayerSettings.ToEnableDepthWrite() && theDefaultSettings.DepthMask == GL_TRUE;
689 glDepthMask (theWorkspace->UseDepthWrite() ? GL_TRUE : GL_FALSE);
691 const Standard_Boolean hasLocalCS = !myLayerSettings.OriginTransformation().IsNull();
692 const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager();
693 Handle(Graphic3d_LightSet) aLightsBack = aManager->LightSourceState().LightSources();
694 const bool hasOwnLights = aCtx->ColorMask() && !myLayerSettings.Lights().IsNull() && myLayerSettings.Lights() != aLightsBack;
697 myLayerSettings.Lights()->UpdateRevision();
698 aManager->UpdateLightSourceStateTo (myLayerSettings.Lights());
701 const Handle(Graphic3d_Camera)& aWorldCamera = theWorkspace->View()->Camera();
704 // Apply local camera transformation.
705 // The vertex position is computed by the following formula in GLSL program:
706 // gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;
708 // occProjectionMatrix - matrix defining orthographic/perspective/stereographic projection
709 // occWorldViewMatrix - world-view matrix defining Camera position and orientation
710 // occModelWorldMatrix - model-world matrix defining Object transformation from local coordinate system to the world coordinate system
711 // occVertex - input vertex position
713 // Since double precision is quite expensive on modern GPUs, and not available on old hardware,
714 // all these values are passed with single float precision to the shader.
715 // As result, single precision become insufficient for handling objects far from the world origin.
717 // Several approaches can be used to solve precision issues:
718 // - [Broute force] migrate to double precision for all matrices and vertex position.
719 // This is too expensive for most hardware.
720 // - Store only translation part with double precision and pass it to GLSL program.
721 // This requires modified GLSL programs for computing transformation
722 // and extra packing mechanism for hardware not supporting double precision natively.
723 // This solution is less expensive then previous one.
724 // - Move translation part of occModelWorldMatrix into occWorldViewMatrix.
725 // The main idea here is that while moving Camera towards the object,
726 // Camera translation part and Object translation part will compensate each other
727 // to fit into single float precision.
728 // But this operation should be performed with double precision - this is why we are moving
729 // translation part of occModelWorldMatrix to occWorldViewMatrix.
731 // All approaches might be useful in different scenarios, but for the moment we consider the last one as main scenario.
732 // Here we do the trick:
733 // - OpenGl_Layer defines the Local Origin, which is expected to be the center of objects stored within it.
734 // This Local Origin is included into occWorldViewMatrix during rendering.
735 // - OpenGl_Structure defines Object local transformation occModelWorldMatrix with subtracted Local Origin of the Layer.
736 // This means that Object itself should be defined within either Local Transformation equal or near to Local Origin of the Layer.
737 theWorkspace->View()->SetLocalOrigin (myLayerSettings.Origin());
739 NCollection_Mat4<Standard_Real> aWorldView = aWorldCamera->OrientationMatrix();
740 Graphic3d_TransformUtils::Translate (aWorldView, myLayerSettings.Origin().X(), myLayerSettings.Origin().Y(), myLayerSettings.Origin().Z());
742 NCollection_Mat4<Standard_ShortReal> aWorldViewF;
743 aWorldViewF.ConvertFrom (aWorldView);
744 aCtx->WorldViewState.SetCurrent (aWorldViewF);
745 aCtx->ShaderManager()->UpdateClippingState();
746 aCtx->ShaderManager()->UpdateLightSourceState();
749 // render priority list
750 renderAll (theWorkspace);
754 aManager->UpdateLightSourceStateTo (aLightsBack);
758 aCtx->ShaderManager()->RevertClippingState();
759 aCtx->ShaderManager()->UpdateLightSourceState();
761 aCtx->WorldViewState.SetCurrent (aWorldCamera->OrientationMatrixF());
762 theWorkspace->View() ->SetLocalOrigin (gp_XYZ (0.0, 0.0, 0.0));
765 // always restore polygon offset between layers rendering
766 theWorkspace->SetDefaultPolygonOffset (anAppliedOffsetParams);
768 // restore environment texture
769 if (!myLayerSettings.UseEnvironmentTexture())
771 theWorkspace->SetEnvironmentTexture (anEnvironmentTexture);