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 // =======================================================================
26 // function : OpenGl_Layer
28 // =======================================================================
29 OpenGl_Layer::OpenGl_Layer (const Standard_Integer theNbPriorities)
30 : myArray (0, theNbPriorities - 1),
32 myBVHIsLeftChildQueuedFirst (Standard_True),
33 myIsBVHPrimitivesNeedsReset (Standard_False)
35 myIsBoundingBoxNeedsReset[0] = myIsBoundingBoxNeedsReset[1] = true;
38 // =======================================================================
39 // function : ~OpenGl_Layer
41 // =======================================================================
42 OpenGl_Layer::~OpenGl_Layer()
47 // =======================================================================
50 // =======================================================================
51 void OpenGl_Layer::Add (const OpenGl_Structure* theStruct,
52 const Standard_Integer thePriority,
53 Standard_Boolean isForChangePriority)
55 const Standard_Integer anIndex = Min (Max (thePriority, 0), myArray.Length() - 1);
56 if (theStruct == NULL)
61 myArray (anIndex).Add (theStruct);
62 if (theStruct->IsAlwaysRendered())
64 theStruct->MarkAsNotCulled();
65 if (!isForChangePriority)
67 myAlwaysRenderedMap.Add (theStruct);
70 else if (!isForChangePriority)
72 if (theStruct->TransformPersistence().IsNull())
74 myBVHPrimitives.Add (theStruct);
78 myBVHPrimitivesTrsfPers.Add (theStruct);
84 // =======================================================================
87 // =======================================================================
88 bool OpenGl_Layer::Remove (const OpenGl_Structure* theStruct,
89 Standard_Integer& thePriority,
90 Standard_Boolean isForChangePriority)
92 if (theStruct == NULL)
98 const Standard_Integer aNbPriorities = myArray.Length();
99 for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
101 OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
103 const Standard_Integer anIndex = aStructures.FindIndex (theStruct);
106 aStructures.Swap (anIndex, aStructures.Size());
107 aStructures.RemoveLast();
109 if (!isForChangePriority)
111 Standard_Boolean isAlwaysRend = theStruct->IsAlwaysRendered();
114 if (!myBVHPrimitives.Remove (theStruct))
116 if (!myBVHPrimitivesTrsfPers.Remove (theStruct))
118 isAlwaysRend = Standard_True;
124 const Standard_Integer anIndex2 = myAlwaysRenderedMap.FindIndex (theStruct);
127 myAlwaysRenderedMap.Swap (myAlwaysRenderedMap.Size(), anIndex2);
128 myAlwaysRenderedMap.RemoveLast();
133 thePriority = aPriorityIter;
142 // =======================================================================
143 // function : InvalidateBVHData
145 // =======================================================================
146 void OpenGl_Layer::InvalidateBVHData() const
148 myIsBVHPrimitivesNeedsReset = Standard_True;
151 //! Calculate a finite bounding box of infinite object as its middle point.
152 inline Graphic3d_BndBox3d centerOfinfiniteBndBox (const Graphic3d_BndBox3d& theBndBox)
154 // bounding borders of infinite line has been calculated as own point in center of this line
155 const Graphic3d_Vec3d aDiagVec = theBndBox.CornerMax() - theBndBox.CornerMin();
156 return aDiagVec.SquareModulus() >= 500000.0 * 500000.0
157 ? Graphic3d_BndBox3d ((theBndBox.CornerMin() + theBndBox.CornerMax()) * 0.5)
158 : Graphic3d_BndBox3d();
161 //! Return true if at least one vertex coordinate out of float range.
162 inline bool isInfiniteBndBox (const Graphic3d_BndBox3d& theBndBox)
164 return Abs (theBndBox.CornerMax().x()) >= ShortRealLast()
165 || Abs (theBndBox.CornerMax().y()) >= ShortRealLast()
166 || Abs (theBndBox.CornerMax().z()) >= ShortRealLast()
167 || Abs (theBndBox.CornerMin().x()) >= ShortRealLast()
168 || Abs (theBndBox.CornerMin().y()) >= ShortRealLast()
169 || Abs (theBndBox.CornerMin().z()) >= ShortRealLast();
172 // =======================================================================
173 // function : BoundingBox
175 // =======================================================================
176 Bnd_Box OpenGl_Layer::BoundingBox (const Standard_Integer theViewId,
177 const Handle(Graphic3d_Camera)& theCamera,
178 const Standard_Integer theWindowWidth,
179 const Standard_Integer theWindowHeight,
180 const Standard_Boolean theToIncludeAuxiliary) const
184 const Standard_Integer aBoxId = !theToIncludeAuxiliary ? 0 : 1;
185 const Graphic3d_Mat4d& aProjectionMat = theCamera->ProjectionMatrix();
186 const Graphic3d_Mat4d& aWorldViewMat = theCamera->OrientationMatrix();
187 if (myIsBoundingBoxNeedsReset[aBoxId])
189 // Recompute layer bounding box
190 myBoundingBox[aBoxId].SetVoid();
192 for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
194 const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value();
195 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
197 const OpenGl_Structure* aStructure = aStructIter.Value();
198 if (!aStructure->IsVisible (theViewId))
203 // "FitAll" operation ignores object with transform persistence parameter
204 // but adds transform persistence point in a bounding box of layer (only zoom pers. objects).
205 if (!aStructure->TransformPersistence().IsNull())
207 if (!theToIncludeAuxiliary
208 && aStructure->TransformPersistence()->IsZoomOrRotate())
210 const gp_Pnt anAnchor = aStructure->TransformPersistence()->AnchorPoint();
211 myBoundingBox[aBoxId].Add (anAnchor);
214 // Panning and 2d persistence apply changes to projection or/and its translation components.
215 // It makes them incompatible with z-fitting algorithm. Ignored by now.
216 else if (!theToIncludeAuxiliary
217 || aStructure->TransformPersistence()->IsTrihedronOr2d())
223 Graphic3d_BndBox3d aBox = aStructure->BoundingBox();
229 if (aStructure->IsInfinite
230 && !theToIncludeAuxiliary)
232 // include center of infinite object
233 aBox = centerOfinfiniteBndBox (aBox);
236 if (!aStructure->TransformPersistence().IsNull())
238 aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
241 // skip too big boxes to prevent float overflow at camera parameters calculation
243 && !isInfiniteBndBox (aBox))
245 myBoundingBox[aBoxId].Add (gp_Pnt (aBox.CornerMin().x(), aBox.CornerMin().y(), aBox.CornerMin().z()));
246 myBoundingBox[aBoxId].Add (gp_Pnt (aBox.CornerMax().x(), aBox.CornerMax().y(), aBox.CornerMax().z()));
251 myIsBoundingBoxNeedsReset[aBoxId] = false;
254 Bnd_Box aResBox = myBoundingBox[aBoxId];
255 if (!theToIncludeAuxiliary
256 || myAlwaysRenderedMap.IsEmpty())
261 // add transformation-persistent objects which depend on camera position (and thus can not be cached) for operations like Z-fit
262 for (NCollection_IndexedMap<const OpenGl_Structure*>::Iterator aStructIter (myAlwaysRenderedMap); aStructIter.More(); aStructIter.Next())
264 const OpenGl_Structure* aStructure = aStructIter.Value();
265 if (!aStructure->IsVisible (theViewId))
269 else if (aStructure->TransformPersistence().IsNull()
270 || !aStructure->TransformPersistence()->IsTrihedronOr2d())
275 Graphic3d_BndBox3d aBox = aStructure->BoundingBox();
281 aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
283 && !isInfiniteBndBox (aBox))
285 aResBox.Add (gp_Pnt (aBox.CornerMin().x(), aBox.CornerMin().y(), aBox.CornerMin().z()));
286 aResBox.Add (gp_Pnt (aBox.CornerMax().x(), aBox.CornerMax().y(), aBox.CornerMax().z()));
293 // =======================================================================
294 // function : considerZoomPersistenceObjects
296 // =======================================================================
297 Standard_Real OpenGl_Layer::considerZoomPersistenceObjects (const Standard_Integer theViewId,
298 const Handle(Graphic3d_Camera)& theCamera,
299 Standard_Integer theWindowWidth,
300 Standard_Integer theWindowHeight) const
302 if (NbOfTransformPersistenceObjects() == 0)
307 const Graphic3d_Mat4d& aProjectionMat = theCamera->ProjectionMatrix();
308 const Graphic3d_Mat4d& aWorldViewMat = theCamera->OrientationMatrix();
309 Standard_Real aMaxCoef = -std::numeric_limits<double>::max();
311 for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
313 const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value();
314 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
316 const OpenGl_Structure* aStructure = aStructIter.Value();
317 if (!aStructure->IsVisible (theViewId)
318 || aStructure->TransformPersistence().IsNull()
319 || !aStructure->TransformPersistence()->IsZoomOrRotate())
324 Graphic3d_BndBox3d aBox = aStructure->BoundingBox();
330 aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
332 const BVH_Vec3d& aCornerMin = aBox.CornerMin();
333 const BVH_Vec3d& aCornerMax = aBox.CornerMax();
334 const Standard_Integer aNbOfPoints = 8;
335 const gp_Pnt aPoints[aNbOfPoints] = { gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMin.z()),
336 gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMax.z()),
337 gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMin.z()),
338 gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMax.z()),
339 gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMin.z()),
340 gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMax.z()),
341 gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMin.z()),
342 gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMax.z()) };
343 gp_Pnt aConvertedPoints[aNbOfPoints];
344 Standard_Real aConvertedMinX = std::numeric_limits<double>::max();
345 Standard_Real aConvertedMaxX = -std::numeric_limits<double>::max();
346 Standard_Real aConvertedMinY = std::numeric_limits<double>::max();
347 Standard_Real aConvertedMaxY = -std::numeric_limits<double>::max();
348 for (Standard_Integer anIdx = 0; anIdx < aNbOfPoints; ++anIdx)
350 aConvertedPoints[anIdx] = theCamera->Project (aPoints[anIdx]);
352 aConvertedMinX = Min (aConvertedMinX, aConvertedPoints[anIdx].X());
353 aConvertedMaxX = Max (aConvertedMaxX, aConvertedPoints[anIdx].X());
355 aConvertedMinY = Min (aConvertedMinY, aConvertedPoints[anIdx].Y());
356 aConvertedMaxY = Max (aConvertedMaxY, aConvertedPoints[anIdx].Y());
359 const Standard_Boolean isBigObject = (Abs (aConvertedMaxX - aConvertedMinX) > 2.0) // width of zoom pers. object greater than width of window
360 || (Abs (aConvertedMaxY - aConvertedMinY) > 2.0); // height of zoom pers. object greater than height of window
361 const Standard_Boolean isAlreadyInScreen = (aConvertedMinX > -1.0 && aConvertedMinX < 1.0)
362 && (aConvertedMaxX > -1.0 && aConvertedMaxX < 1.0)
363 && (aConvertedMinY > -1.0 && aConvertedMinY < 1.0)
364 && (aConvertedMaxY > -1.0 && aConvertedMaxY < 1.0);
365 if (isBigObject || isAlreadyInScreen)
370 const gp_Pnt aTPPoint = aStructure->TransformPersistence()->AnchorPoint();
371 gp_Pnt aConvertedTPPoint = theCamera->Project (aTPPoint);
372 aConvertedTPPoint.SetZ (0.0);
374 if (aConvertedTPPoint.Coord().Modulus() < Precision::Confusion())
379 Standard_Real aShiftX = 0.0;
380 if (aConvertedMinX < -1.0)
382 aShiftX = ((aConvertedMaxX < -1.0) ? (-(1.0 + aConvertedMaxX) + (aConvertedMaxX - aConvertedMinX)) : -(1.0 + aConvertedMinX));
384 else if (aConvertedMaxX > 1.0)
386 aShiftX = ((aConvertedMinX > 1.0) ? ((aConvertedMinX - 1.0) + (aConvertedMaxX - aConvertedMinX)) : (aConvertedMaxX - 1.0));
389 Standard_Real aShiftY = 0.0;
390 if (aConvertedMinY < -1.0)
392 aShiftY = ((aConvertedMaxY < -1.0) ? (-(1.0 + aConvertedMaxY) + (aConvertedMaxY - aConvertedMinY)) : -(1.0 + aConvertedMinY));
394 else if (aConvertedMaxY > 1.0)
396 aShiftY = ((aConvertedMinY > 1.0) ? ((aConvertedMinY - 1.0) + (aConvertedMaxY - aConvertedMinY)) : (aConvertedMaxY - 1.0));
399 const Standard_Real aDifX = Abs (aConvertedTPPoint.X()) - aShiftX;
400 const Standard_Real aDifY = Abs (aConvertedTPPoint.Y()) - aShiftY;
401 if (aDifX > Precision::Confusion())
403 aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.X()) / aDifX);
405 if (aDifY > Precision::Confusion())
407 aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.Y()) / aDifY);
412 return (aMaxCoef > 0.0) ? aMaxCoef : 1.0;
415 // =======================================================================
416 // function : renderAll
418 // =======================================================================
419 void OpenGl_Layer::renderAll (const Handle(OpenGl_Workspace)& theWorkspace) const
421 const Standard_Integer aViewId = theWorkspace->View()->Identification();
422 for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
424 const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value();
425 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
427 const OpenGl_Structure* aStruct = aStructIter.Value();
428 if (!aStruct->IsVisible())
432 else if (!aStruct->ViewAffinity.IsNull()
433 && !aStruct->ViewAffinity->IsVisible (aViewId))
438 aStruct->Render (theWorkspace);
443 // =======================================================================
444 // function : updateBVH
446 // =======================================================================
447 void OpenGl_Layer::updateBVH() const
449 if (!myIsBVHPrimitivesNeedsReset)
454 myBVHPrimitives.Clear();
455 myBVHPrimitivesTrsfPers.Clear();
456 myAlwaysRenderedMap.Clear();
457 myIsBVHPrimitivesNeedsReset = Standard_False;
458 for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
460 const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value();
461 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
463 const OpenGl_Structure* aStruct = aStructIter.Value();
464 if (aStruct->IsAlwaysRendered())
466 aStruct->MarkAsNotCulled();
467 myAlwaysRenderedMap.Add (aStruct);
469 else if (aStruct->TransformPersistence().IsNull())
471 myBVHPrimitives.Add (aStruct);
475 myBVHPrimitivesTrsfPers.Add (aStruct);
481 // =======================================================================
482 // function : renderTraverse
484 // =======================================================================
485 void OpenGl_Layer::renderTraverse (const Handle(OpenGl_Workspace)& theWorkspace) const
489 OpenGl_BVHTreeSelector& aSelector = theWorkspace->View()->BVHTreeSelector();
490 traverse (aSelector);
492 const Standard_Integer aViewId = theWorkspace->View()->Identification();
493 for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
495 const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value();
496 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
498 const OpenGl_Structure* aStruct = aStructIter.Value();
499 if (aStruct->IsCulled()
500 || !aStruct->IsVisible (aViewId))
505 aStruct->Render (theWorkspace);
506 aStruct->ResetCullingStatus();
511 // =======================================================================
512 // function : traverse
514 // =======================================================================
515 void OpenGl_Layer::traverse (OpenGl_BVHTreeSelector& theSelector) const
517 // handle a case when all objects are infinite
518 if (myBVHPrimitives .Size() == 0
519 && myBVHPrimitivesTrsfPers.Size() == 0)
522 theSelector.CacheClipPtsProjections();
524 NCollection_Handle<BVH_Tree<Standard_Real, 3> > aBVHTree;
526 for (Standard_Integer aBVHTreeIdx = 0; aBVHTreeIdx < 2; ++aBVHTreeIdx)
528 const Standard_Boolean isTrsfPers = aBVHTreeIdx == 1;
531 if (myBVHPrimitivesTrsfPers.Size() == 0)
534 const OpenGl_Mat4d& aProjection = theSelector.ProjectionMatrix();
535 const OpenGl_Mat4d& aWorldView = theSelector.WorldViewMatrix();
536 const Graphic3d_WorldViewProjState& aWVPState = theSelector.WorldViewProjState();
537 const Standard_Integer aViewportWidth = theSelector.ViewportWidth();
538 const Standard_Integer aViewportHeight = theSelector.ViewportHeight();
540 aBVHTree = myBVHPrimitivesTrsfPers.BVH (theSelector.Camera(), aProjection, aWorldView, aViewportWidth, aViewportHeight, aWVPState);
544 if (myBVHPrimitives.Size() == 0)
547 aBVHTree = myBVHPrimitives.BVH();
550 Standard_Integer aNode = 0; // a root node
552 if (!theSelector.Intersect (aBVHTree->MinPoint (0),
553 aBVHTree->MaxPoint (0)))
558 Standard_Integer aStack[32];
559 Standard_Integer aHead = -1;
562 if (!aBVHTree->IsOuter (aNode))
564 const Standard_Integer aLeftChildIdx = aBVHTree->Child<0> (aNode);
565 const Standard_Integer aRightChildIdx = aBVHTree->Child<1> (aNode);
566 const Standard_Boolean isLeftChildIn = theSelector.Intersect (aBVHTree->MinPoint (aLeftChildIdx),
567 aBVHTree->MaxPoint (aLeftChildIdx));
568 const Standard_Boolean isRightChildIn = theSelector.Intersect (aBVHTree->MinPoint (aRightChildIdx),
569 aBVHTree->MaxPoint (aRightChildIdx));
573 aNode = myBVHIsLeftChildQueuedFirst ? aLeftChildIdx : aRightChildIdx;
574 aStack[++aHead] = myBVHIsLeftChildQueuedFirst ? aRightChildIdx : aLeftChildIdx;
575 myBVHIsLeftChildQueuedFirst = !myBVHIsLeftChildQueuedFirst;
577 else if (isLeftChildIn
580 aNode = isLeftChildIn ? aLeftChildIdx : aRightChildIdx;
589 aNode = aStack[aHead--];
594 Standard_Integer aIdx = aBVHTree->BegPrimitive (aNode);
595 const OpenGl_Structure* aStruct =
596 isTrsfPers ? myBVHPrimitivesTrsfPers.GetStructureById (aIdx)
597 : myBVHPrimitives.GetStructureById (aIdx);
598 aStruct->MarkAsNotCulled();
604 aNode = aStack[aHead--];
610 // =======================================================================
613 // =======================================================================
614 Standard_Boolean OpenGl_Layer::Append (const OpenGl_Layer& theOther)
616 // the source priority list shouldn't have more priorities
617 const Standard_Integer aNbPriorities = theOther.NbPriorities();
618 if (aNbPriorities > NbPriorities())
620 return Standard_False;
623 // add all structures to destination priority list
624 for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
626 const OpenGl_IndexedMapOfStructure& aStructures = theOther.myArray (aPriorityIter);
627 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
629 Add (aStructIter.Value(), aPriorityIter);
633 return Standard_True;
636 //=======================================================================
637 //function : SetLayerSettings
639 //=======================================================================
640 void OpenGl_Layer::SetLayerSettings (const Graphic3d_ZLayerSettings& theSettings)
642 const Standard_Boolean toUpdateTrsf = !myLayerSettings.Origin().IsEqual (theSettings.Origin(), gp::Resolution());
643 myLayerSettings = theSettings;
646 for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
648 OpenGl_IndexedMapOfStructure& aStructures = aMapIter.ChangeValue();
649 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
651 OpenGl_Structure* aStructure = const_cast<OpenGl_Structure*> (aStructIter.Value());
652 aStructure->updateLayerTransformation();
658 //=======================================================================
661 //=======================================================================
662 void OpenGl_Layer::Render (const Handle(OpenGl_Workspace)& theWorkspace,
663 const OpenGl_GlobalLayerSettings& theDefaultSettings) const
665 const Graphic3d_PolygonOffset anAppliedOffsetParams = theWorkspace->AppliedPolygonOffset();
666 // myLayerSettings.ToClearDepth() is handled outside
669 if (myLayerSettings.ToEnableDepthTest())
671 // assuming depth test is enabled by default
672 glDepthFunc (theDefaultSettings.DepthFunc);
676 glDepthFunc (GL_ALWAYS);
679 // save environment texture
680 Handle(OpenGl_Texture) anEnvironmentTexture = theWorkspace->EnvironmentTexture();
681 if (!myLayerSettings.UseEnvironmentTexture())
683 theWorkspace->SetEnvironmentTexture (Handle(OpenGl_Texture)());
686 // handle depth offset
687 theWorkspace->SetPolygonOffset (myLayerSettings.PolygonOffset());
689 // handle depth write
690 theWorkspace->UseDepthWrite() = myLayerSettings.ToEnableDepthWrite();
691 glDepthMask (theWorkspace->UseDepthWrite() ? GL_TRUE : GL_FALSE);
693 const Standard_Boolean hasLocalCS = !myLayerSettings.OriginTransformation().IsNull();
694 const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
695 const Handle(Graphic3d_Camera)& aWorldCamera = theWorkspace->View()->Camera();
696 Handle(Graphic3d_Camera) aCameraBack;
699 // Apply local camera transformation.
700 // The vertex position is computed by the following formula in GLSL program:
701 // gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;
703 // occProjectionMatrix - matrix defining orthographic/perspective/stereographic projection
704 // occWorldViewMatrix - world-view matrix defining Camera position and orientation
705 // occModelWorldMatrix - model-world matrix defining Object transformation from local coordinate system to the world coordinate system
706 // occVertex - input vertex position
708 // Since double precision is quite expensive on modern GPUs, and not available on old hardware,
709 // all these values are passed with single float precision to the shader.
710 // As result, single precision become insufficient for handling objects far from the world origin.
712 // Several approaches can be used to solve precision issues:
713 // - [Broute force] migrate to double precision for all matrices and vertex position.
714 // This is too expensive for most hardware.
715 // - Store only translation part with double precision and pass it to GLSL program.
716 // This requires modified GLSL programs for computing transformation
717 // and extra packing mechanism for hardware not supporting double precision natively.
718 // This solution is less expensive then previous one.
719 // - Move translation part of occModelWorldMatrix into occWorldViewMatrix.
720 // The main idea here is that while moving Camera towards the object,
721 // Camera translation part and Object translation part will compensate each other
722 // to fit into single float precision.
723 // But this operation should be performed with double precision - this is why we are moving
724 // translation part of occModelWorldMatrix to occWorldViewMatrix.
726 // All approaches might be useful in different scenarios, but for the moment we consider the last one as main scenario.
727 // Here we do the trick:
728 // - OpenGl_Layer defines the Local Origin, which is expected to be the center of objects stored within it.
729 // This Local Origin is included into occWorldViewMatrix during rendering.
730 // - OpenGl_Structure defines Object local transformation occModelWorldMatrix with subtracted Local Origin of the Layer.
731 // This means that Object itself should be defined within either Local Transformation equal or near to Local Origin of the Layer.
732 theWorkspace->View()->SetLocalOrigin (myLayerSettings.Origin());
734 NCollection_Mat4<Standard_Real> aWorldView = aWorldCamera->OrientationMatrix();
735 Graphic3d_TransformUtils::Translate (aWorldView, myLayerSettings.Origin().X(), myLayerSettings.Origin().Y(), myLayerSettings.Origin().Z());
737 NCollection_Mat4<Standard_ShortReal> aWorldViewF;
738 aWorldViewF.ConvertFrom (aWorldView);
739 aCtx->WorldViewState.SetCurrent (aWorldViewF);
740 aCtx->ShaderManager()->UpdateClippingState();
741 aCtx->ShaderManager()->UpdateLightSourceState();
744 // render priority list
745 theWorkspace->IsCullingEnabled() ? renderTraverse (theWorkspace) : renderAll (theWorkspace);
749 aCtx->ShaderManager()->RevertClippingState();
750 aCtx->ShaderManager()->UpdateLightSourceState();
752 aCtx->WorldViewState.SetCurrent (aWorldCamera->OrientationMatrixF());
753 theWorkspace->View() ->SetLocalOrigin (gp_XYZ (0.0, 0.0, 0.0));
756 // always restore polygon offset between layers rendering
757 theWorkspace->SetPolygonOffset (anAppliedOffsetParams);
759 // restore environment texture
760 if (!myLayerSettings.UseEnvironmentTexture())
762 theWorkspace->SetEnvironmentTexture (anEnvironmentTexture);