1 // Created on: 2013-05-29
2 // Created by: Anton POLETAEV
3 // Copyright (c) 1999-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 <Graphic3d_Camera.hxx>
19 #include <gp_QuaternionNLerp.hxx>
20 #include <gp_QuaternionSLerp.hxx>
21 #include <Graphic3d_Vec4.hxx>
22 #include <Graphic3d_WorldViewProjState.hxx>
23 #include <NCollection_Sequence.hxx>
24 #include <Standard_ShortReal.hxx>
25 #include <Standard_Atomic.hxx>
26 #include <Standard_Assert.hxx>
28 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_Camera,Standard_Transient)
32 // (degrees -> radians) * 0.5
33 static const Standard_Real DTR_HALF = 0.5 * 0.0174532925;
35 // default property values
36 static const Standard_Real DEFAULT_ZNEAR = 0.001;
37 static const Standard_Real DEFAULT_ZFAR = 3000.0;
39 // atomic state counter
40 static volatile Standard_Integer THE_STATE_COUNTER = 0;
42 // z-range tolerance compatible with for floating point.
43 static Standard_Real zEpsilon()
48 // relative z-range tolerance compatible with for floating point.
49 static Standard_Real zEpsilon (const Standard_Real theValue)
51 Standard_Real anAbsValue = Abs (theValue);
52 if (anAbsValue <= (double)FLT_MIN)
56 Standard_Real aLogRadix = Log10 (anAbsValue) / Log10 (FLT_RADIX);
57 Standard_Real aExp = Floor (aLogRadix);
58 return FLT_EPSILON * Pow (FLT_RADIX, aExp);
61 //! Convert camera definition to Ax3
62 gp_Ax3 cameraToAx3 (const Graphic3d_Camera& theCamera)
64 const gp_Dir aBackDir = -theCamera.Direction();
65 const gp_Dir anXAxis (theCamera.Up().Crossed (aBackDir));
66 const gp_Dir anYAxis (aBackDir .Crossed (anXAxis));
67 const gp_Dir aZAxis (anXAxis .Crossed (anYAxis));
68 return gp_Ax3 (gp_Pnt (0.0, 0.0, 0.0), aZAxis, anXAxis);
72 // =======================================================================
73 // function : Graphic3d_Camera
75 // =======================================================================
76 Graphic3d_Camera::Graphic3d_Camera()
77 : myUp (0.0, 1.0, 0.0),
78 myDirection (0.0, 0.0, 1.0),
79 myEye (0.0, 0.0, -1500.0),
81 myAxialScale (1.0, 1.0, 1.0),
82 myProjType (Projection_Orthographic),
86 myFOVyTan (Tan (DTR_HALF * 45.0)),
87 myZNear (DEFAULT_ZNEAR),
88 myZFar (DEFAULT_ZFAR),
92 myZFocusType (FocusType_Relative),
94 myIODType (IODType_Relative),
95 myIsCustomProjMatM (false),
96 myIsCustomProjMatLR(false),
97 myIsCustomFrustomLR(false)
99 myWorldViewProjState.Initialize ((Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER),
100 (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER),
104 // =======================================================================
105 // function : Graphic3d_Camera
107 // =======================================================================
108 Graphic3d_Camera::Graphic3d_Camera (const Handle(Graphic3d_Camera)& theOther)
109 : myUp (0.0, 1.0, 0.0),
110 myDirection (0.0, 0.0, 1.0),
111 myEye (0.0, 0.0, -1500.0),
113 myAxialScale (1.0, 1.0, 1.0),
114 myProjType (Projection_Orthographic),
118 myFOVyTan (Tan (DTR_HALF * 45.0)),
119 myZNear (DEFAULT_ZNEAR),
120 myZFar (DEFAULT_ZFAR),
124 myZFocusType (FocusType_Relative),
126 myIODType (IODType_Relative),
127 myIsCustomProjMatM (false),
128 myIsCustomProjMatLR(false),
129 myIsCustomFrustomLR(false)
131 myWorldViewProjState.Initialize (this);
136 // =======================================================================
137 // function : CopyMappingData
139 // =======================================================================
140 void Graphic3d_Camera::CopyMappingData (const Handle(Graphic3d_Camera)& theOtherCamera)
142 SetProjectionType (theOtherCamera->ProjectionType());
143 SetFOVy (theOtherCamera->FOVy());
144 SetFOV2d (theOtherCamera->FOV2d());
145 SetZRange (theOtherCamera->ZNear(), theOtherCamera->ZFar());
146 SetAspect (theOtherCamera->Aspect());
147 SetScale (theOtherCamera->Scale());
148 SetZFocus (theOtherCamera->ZFocusType(), theOtherCamera->ZFocus());
149 SetIOD (theOtherCamera->GetIODType(), theOtherCamera->IOD());
150 SetTile (theOtherCamera->myTile);
152 ResetCustomProjection();
153 if (theOtherCamera->IsCustomStereoProjection())
155 SetCustomStereoProjection (theOtherCamera->myCustomProjMatL,
156 theOtherCamera->myCustomHeadToEyeMatL,
157 theOtherCamera->myCustomProjMatR,
158 theOtherCamera->myCustomHeadToEyeMatR);
160 else if (theOtherCamera->IsCustomStereoFrustum())
162 SetCustomStereoFrustums (theOtherCamera->myCustomFrustumL, theOtherCamera->myCustomFrustumR);
164 if (theOtherCamera->IsCustomMonoProjection())
166 SetCustomMonoProjection (theOtherCamera->myCustomProjMatM);
170 // =======================================================================
171 // function : CopyOrientationData
173 // =======================================================================
174 void Graphic3d_Camera::CopyOrientationData (const Handle(Graphic3d_Camera)& theOtherCamera)
176 if (!myEye.IsEqual (theOtherCamera->Eye(), 0.0)
177 || !myUp.IsEqual (theOtherCamera->Up(), 0.0)
178 || !myDirection.IsEqual (theOtherCamera->Direction(), 0.0)
179 || myDistance != theOtherCamera->Distance())
181 myEye = theOtherCamera->Eye();
182 myUp = theOtherCamera->Up();
183 myDirection = theOtherCamera->Direction();
184 myDistance = theOtherCamera->Distance();
185 InvalidateOrientation();
187 SetAxialScale (theOtherCamera->AxialScale());
190 // =======================================================================
193 // =======================================================================
194 void Graphic3d_Camera::Copy (const Handle(Graphic3d_Camera)& theOther)
196 CopyMappingData (theOther);
197 CopyOrientationData (theOther);
200 // =======================================================================
201 // function : MoveEyeTo
203 // =======================================================================
204 void Graphic3d_Camera::MoveEyeTo (const gp_Pnt& theEye)
206 if (myEye.IsEqual (theEye, 0.0))
212 InvalidateOrientation();
215 // =======================================================================
216 // function : SetEyeAndCenter
218 // =======================================================================
219 void Graphic3d_Camera::SetEyeAndCenter (const gp_Pnt& theEye,
220 const gp_Pnt& theCenter)
222 if (Eye() .IsEqual (theEye, 0.0)
223 && Center().IsEqual (theCenter, 0.0))
229 myDistance = theEye.Distance (theCenter);
230 if (myDistance > gp::Resolution())
232 myDirection = gp_Dir (theCenter.XYZ() - theEye.XYZ());
234 InvalidateOrientation();
237 // =======================================================================
240 // =======================================================================
241 void Graphic3d_Camera::SetEye (const gp_Pnt& theEye)
243 if (Eye().IsEqual (theEye, 0.0))
248 const gp_Pnt aCenter = Center();
250 myDistance = myEye.Distance (aCenter);
251 if (myDistance > gp::Resolution())
253 myDirection = gp_Dir (aCenter.XYZ() - myEye.XYZ());
255 InvalidateOrientation();
258 // =======================================================================
259 // function : SetCenter
261 // =======================================================================
262 void Graphic3d_Camera::SetCenter (const gp_Pnt& theCenter)
264 const Standard_Real aDistance = myEye.Distance (theCenter);
265 if (myDistance == aDistance)
270 myDistance = aDistance;
271 if (myDistance > gp::Resolution())
273 myDirection = gp_Dir (theCenter.XYZ() - myEye.XYZ());
275 InvalidateOrientation();
278 // =======================================================================
281 // =======================================================================
282 void Graphic3d_Camera::SetUp (const gp_Dir& theUp)
284 if (Up().IsEqual (theUp, 0.0))
290 InvalidateOrientation();
293 // =======================================================================
294 // function : SetAxialScale
296 // =======================================================================
297 void Graphic3d_Camera::SetAxialScale (const gp_XYZ& theAxialScale)
299 if (AxialScale().IsEqual (theAxialScale, 0.0))
304 myAxialScale = theAxialScale;
305 InvalidateOrientation();
308 // =======================================================================
309 // function : SetDistance
311 // =======================================================================
312 void Graphic3d_Camera::SetDistance (const Standard_Real theDistance)
314 if (myDistance == theDistance)
319 const gp_Pnt aCenter = Center();
320 myDistance = theDistance;
321 myEye = aCenter.XYZ() - myDirection.XYZ() * myDistance;
322 InvalidateOrientation();
325 // =======================================================================
326 // function : SetDirectionFromEye
328 // =======================================================================
329 void Graphic3d_Camera::SetDirectionFromEye (const gp_Dir& theDir)
331 if (myDirection.IsEqual (theDir, 0.0))
336 myDirection = theDir;
337 InvalidateOrientation();
340 // =======================================================================
341 // function : SetDirection
343 // =======================================================================
344 void Graphic3d_Camera::SetDirection (const gp_Dir& theDir)
346 if (myDirection.IsEqual (theDir, 0.0))
351 const gp_Pnt aCenter = Center();
352 myDirection = theDir;
353 myEye = aCenter.XYZ() - theDir.XYZ() * myDistance;
354 InvalidateOrientation();
357 // =======================================================================
358 // function : SetScale
360 // =======================================================================
361 void Graphic3d_Camera::SetScale (const Standard_Real theScale)
363 if (Scale() == theScale)
372 case Projection_Perspective :
373 case Projection_Stereo :
374 case Projection_MonoLeftEye :
375 case Projection_MonoRightEye :
377 Standard_Real aDistance = theScale * 0.5 / myFOVyTan;
378 SetDistance (aDistance);
385 InvalidateProjection();
388 // =======================================================================
391 // =======================================================================
392 Standard_Real Graphic3d_Camera::Scale() const
396 case Projection_Orthographic :
399 // case Projection_Perspective :
400 // case Projection_Stereo :
401 // case Projection_MonoLeftEye :
402 // case Projection_MonoRightEye :
404 return Distance() * 2.0 * myFOVyTan;
408 // =======================================================================
409 // function : SetProjectionType
411 // =======================================================================
412 void Graphic3d_Camera::SetProjectionType (const Projection theProjectionType)
414 Projection anOldType = ProjectionType();
416 if (anOldType == theProjectionType)
421 if (anOldType == Projection_Orthographic)
423 if (myZNear <= RealEpsilon())
425 myZNear = DEFAULT_ZNEAR;
427 if (myZFar <= RealEpsilon())
429 myZFar = DEFAULT_ZFAR;
433 myProjType = theProjectionType;
435 InvalidateProjection();
438 // =======================================================================
439 // function : SetFOVy
441 // =======================================================================
442 void Graphic3d_Camera::SetFOVy (const Standard_Real theFOVy)
444 if (FOVy() == theFOVy)
450 myFOVx = theFOVy * myAspect;
451 myFOVyTan = Tan(DTR_HALF * myFOVy);
453 InvalidateProjection();
456 // =======================================================================
457 // function : SetFOV2d
459 // =======================================================================
460 void Graphic3d_Camera::SetFOV2d (const Standard_Real theFOV)
462 if (FOV2d() == theFOV)
468 InvalidateProjection();
471 // =======================================================================
472 // function : SetZRange
474 // =======================================================================
475 void Graphic3d_Camera::SetZRange (const Standard_Real theZNear,
476 const Standard_Real theZFar)
478 Standard_ASSERT_RAISE (theZFar > theZNear, "ZFar should be greater than ZNear");
479 if (!IsOrthographic())
481 Standard_ASSERT_RAISE (theZNear > 0.0, "Only positive Z-Near is allowed for perspective camera");
482 Standard_ASSERT_RAISE (theZFar > 0.0, "Only positive Z-Far is allowed for perspective camera");
485 if (ZNear() == theZNear
486 && ZFar () == theZFar)
494 InvalidateProjection();
497 // =======================================================================
498 // function : SetAspect
500 // =======================================================================
501 void Graphic3d_Camera::SetAspect (const Standard_Real theAspect)
503 if (Aspect() == theAspect)
508 myAspect = theAspect;
509 myFOVx = myFOVy * theAspect;
511 InvalidateProjection();
514 // =======================================================================
515 // function : SetZFocus
517 // =======================================================================
518 void Graphic3d_Camera::SetZFocus(const FocusType theType, const Standard_Real theZFocus)
520 if (ZFocusType() == theType
521 && ZFocus () == theZFocus)
526 myZFocusType = theType;
527 myZFocus = theZFocus;
529 InvalidateProjection();
532 // =======================================================================
535 // =======================================================================
536 void Graphic3d_Camera::SetIOD (const IODType theType, const Standard_Real theIOD)
538 if (GetIODType() == theType
547 InvalidateProjection();
550 // =======================================================================
551 // function : SetTile
553 // =======================================================================
554 void Graphic3d_Camera::SetTile (const Graphic3d_CameraTile& theTile)
556 if (myTile == theTile)
562 InvalidateProjection();
565 // =======================================================================
566 // function : OrthogonalizeUp
568 // =======================================================================
569 void Graphic3d_Camera::OrthogonalizeUp()
571 SetUp (OrthogonalizedUp());
574 // =======================================================================
575 // function : OrthogonalizedUp
577 // =======================================================================
578 gp_Dir Graphic3d_Camera::OrthogonalizedUp() const
580 gp_Dir aDir = Direction();
581 gp_Dir aLeft = aDir.Crossed (Up());
583 // recompute up as: up = left x direction
584 return aLeft.Crossed (aDir);
587 // =======================================================================
588 // function : Transform
590 // =======================================================================
591 void Graphic3d_Camera::Transform (const gp_Trsf& theTrsf)
593 if (theTrsf.Form() == gp_Identity)
598 myUp .Transform (theTrsf);
599 myDirection.Transform (theTrsf);
600 myEye.Transform (theTrsf);
601 InvalidateOrientation();
604 // =======================================================================
605 // function : safePointCast
607 // =======================================================================
608 static Graphic3d_Vec4d safePointCast (const gp_Pnt& thePnt)
610 Standard_Real aLim = 1e15f;
612 // have to deal with values greater then max float
613 gp_Pnt aSafePoint = thePnt;
614 const Standard_Real aBigFloat = aLim * 0.1f;
615 if (Abs (aSafePoint.X()) > aLim)
616 aSafePoint.SetX (aSafePoint.X() >= 0 ? aBigFloat : -aBigFloat);
617 if (Abs (aSafePoint.Y()) > aLim)
618 aSafePoint.SetY (aSafePoint.Y() >= 0 ? aBigFloat : -aBigFloat);
619 if (Abs (aSafePoint.Z()) > aLim)
620 aSafePoint.SetZ (aSafePoint.Z() >= 0 ? aBigFloat : -aBigFloat);
623 Graphic3d_Vec4d aPnt (aSafePoint.X(), aSafePoint.Y(), aSafePoint.Z(), 1.0);
628 // =======================================================================
629 // function : Project
631 // =======================================================================
632 gp_Pnt Graphic3d_Camera::Project (const gp_Pnt& thePnt) const
634 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
635 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
637 // use compatible type of point
638 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
640 aPnt = aViewMx * aPnt; // convert to view coordinate space
641 aPnt = aProjMx * aPnt; // convert to projection coordinate space
643 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
645 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
648 // =======================================================================
649 // function : UnProject
651 // =======================================================================
652 gp_Pnt Graphic3d_Camera::UnProject (const gp_Pnt& thePnt) const
654 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
655 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
657 Graphic3d_Mat4d aInvView;
658 Graphic3d_Mat4d aInvProj;
660 // this case should never happen
661 if (!aViewMx.Inverted (aInvView) || !aProjMx.Inverted (aInvProj))
663 return gp_Pnt (0.0, 0.0, 0.0);
666 // use compatible type of point
667 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
669 aPnt = aInvProj * aPnt; // convert to view coordinate space
670 aPnt = aInvView * aPnt; // convert to world coordinate space
672 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
674 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
677 // =======================================================================
678 // function : ConvertView2Proj
680 // =======================================================================
681 gp_Pnt Graphic3d_Camera::ConvertView2Proj (const gp_Pnt& thePnt) const
683 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
685 // use compatible type of point
686 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
688 aPnt = aProjMx * aPnt; // convert to projection coordinate space
690 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
692 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
695 // =======================================================================
696 // function : ConvertProj2View
698 // =======================================================================
699 gp_Pnt Graphic3d_Camera::ConvertProj2View (const gp_Pnt& thePnt) const
701 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
703 Graphic3d_Mat4d aInvProj;
705 // this case should never happen, but...
706 if (!aProjMx.Inverted (aInvProj))
708 return gp_Pnt (0, 0, 0);
711 // use compatible type of point
712 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
714 aPnt = aInvProj * aPnt; // convert to view coordinate space
716 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
718 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
721 // =======================================================================
722 // function : ConvertWorld2View
724 // =======================================================================
725 gp_Pnt Graphic3d_Camera::ConvertWorld2View (const gp_Pnt& thePnt) const
727 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
729 // use compatible type of point
730 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
732 aPnt = aViewMx * aPnt; // convert to view coordinate space
734 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
736 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
739 // =======================================================================
740 // function : ConvertView2World
742 // =======================================================================
743 gp_Pnt Graphic3d_Camera::ConvertView2World (const gp_Pnt& thePnt) const
745 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
747 Graphic3d_Mat4d aInvView;
749 if (!aViewMx.Inverted (aInvView))
751 return gp_Pnt(0, 0, 0);
754 // use compatible type of point
755 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
757 aPnt = aInvView * aPnt; // convert to world coordinate space
759 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
761 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
764 // =======================================================================
765 // function : ViewDimensions
767 // =======================================================================
768 gp_XYZ Graphic3d_Camera::ViewDimensions (const Standard_Real theZValue) const
770 // view plane dimensions
771 Standard_Real aSize = IsOrthographic() ? myScale : (2.0 * theZValue * myFOVyTan);
772 Standard_Real aSizeX, aSizeY;
775 aSizeX = aSize * myAspect;
781 aSizeY = aSize / myAspect;
785 return gp_XYZ (aSizeX, aSizeY, myZFar - myZNear);
788 // =======================================================================
789 // function : Frustum
791 // =======================================================================
792 void Graphic3d_Camera::Frustum (gp_Pln& theLeft,
797 gp_Pln& theFar) const
799 gp_Vec aProjection = gp_Vec (Direction());
800 gp_Vec anUp = OrthogonalizedUp();
801 gp_Vec aSide = aProjection ^ anUp;
803 Standard_ASSERT_RAISE (
804 !aProjection.IsParallel (anUp, Precision::Angular()),
805 "Can not derive SIDE = PROJ x UP - directions are parallel");
807 theNear = gp_Pln (Eye().Translated (aProjection * ZNear()), aProjection);
808 theFar = gp_Pln (Eye().Translated (aProjection * ZFar()), -aProjection);
810 Standard_Real aHScaleHor = 0.0, aHScaleVer = 0.0;
813 aHScaleHor = Scale() * 0.5 * Aspect();
814 aHScaleVer = Scale() * 0.5;
818 aHScaleHor = Scale() * 0.5;
819 aHScaleVer = Scale() * 0.5 / Aspect();
822 gp_Pnt aPntLeft = Center().Translated (aHScaleHor * -aSide);
823 gp_Pnt aPntRight = Center().Translated (aHScaleHor * aSide);
824 gp_Pnt aPntBottom = Center().Translated (aHScaleVer * -anUp);
825 gp_Pnt aPntTop = Center().Translated (aHScaleVer * anUp);
827 gp_Vec aDirLeft = aSide;
828 gp_Vec aDirRight = -aSide;
829 gp_Vec aDirBottom = anUp;
830 gp_Vec aDirTop = -anUp;
831 if (!IsOrthographic())
833 Standard_Real aHFOVHor = ATan (Tan (DTR_HALF * FOVy()) * Aspect());
834 Standard_Real aHFOVVer = DTR_HALF * FOVy();
835 aDirLeft.Rotate (gp_Ax1 (gp::Origin(), anUp), aHFOVHor);
836 aDirRight.Rotate (gp_Ax1 (gp::Origin(), anUp), -aHFOVHor);
837 aDirBottom.Rotate (gp_Ax1 (gp::Origin(), aSide), -aHFOVVer);
838 aDirTop.Rotate (gp_Ax1 (gp::Origin(), aSide), aHFOVVer);
841 theLeft = gp_Pln (aPntLeft, aDirLeft);
842 theRight = gp_Pln (aPntRight, aDirRight);
843 theBottom = gp_Pln (aPntBottom, aDirBottom);
844 theTop = gp_Pln (aPntTop, aDirTop);
847 // =======================================================================
848 // function : OrientationMatrix
850 // =======================================================================
851 const Graphic3d_Mat4d& Graphic3d_Camera::OrientationMatrix() const
853 return UpdateOrientation (myMatricesD).Orientation;
856 // =======================================================================
857 // function : OrientationMatrixF
859 // =======================================================================
860 const Graphic3d_Mat4& Graphic3d_Camera::OrientationMatrixF() const
862 return UpdateOrientation (myMatricesF).Orientation;
865 // =======================================================================
866 // function : ProjectionMatrix
868 // =======================================================================
869 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionMatrix() const
871 return UpdateProjection (myMatricesD).MProjection;
874 // =======================================================================
875 // function : ProjectionMatrixF
877 // =======================================================================
878 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionMatrixF() const
880 return UpdateProjection (myMatricesF).MProjection;
883 // =======================================================================
884 // function : ProjectionStereoLeft
886 // =======================================================================
887 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoLeft() const
889 return UpdateProjection (myMatricesD).LProjection;
892 // =======================================================================
893 // function : ProjectionStereoLeftF
895 // =======================================================================
896 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoLeftF() const
898 return UpdateProjection (myMatricesF).LProjection;
901 // =======================================================================
902 // function : ProjectionStereoRight
904 // =======================================================================
905 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoRight() const
907 return UpdateProjection (myMatricesD).RProjection;
910 // =======================================================================
911 // function : ProjectionStereoRightF
913 // =======================================================================
914 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoRightF() const
916 return UpdateProjection (myMatricesF).RProjection;
919 // =======================================================================
920 // function : ResetCustomProjection
922 // =======================================================================
923 void Graphic3d_Camera::ResetCustomProjection()
925 if (myIsCustomFrustomLR
926 || myIsCustomProjMatLR
927 || myIsCustomProjMatM)
929 myIsCustomFrustomLR = false;
930 myIsCustomProjMatLR = false;
931 myIsCustomProjMatM = false;
932 InvalidateProjection();
936 // =======================================================================
937 // function : StereoProjection
939 // =======================================================================
940 void Graphic3d_Camera::StereoProjection (Graphic3d_Mat4d& theProjL,
941 Graphic3d_Mat4d& theHeadToEyeL,
942 Graphic3d_Mat4d& theProjR,
943 Graphic3d_Mat4d& theHeadToEyeR) const
945 stereoProjection (theProjL, theHeadToEyeL, theProjR, theHeadToEyeR);
948 // =======================================================================
949 // function : StereoProjectionF
951 // =======================================================================
952 void Graphic3d_Camera::StereoProjectionF (Graphic3d_Mat4& theProjL,
953 Graphic3d_Mat4& theHeadToEyeL,
954 Graphic3d_Mat4& theProjR,
955 Graphic3d_Mat4& theHeadToEyeR) const
957 stereoProjection (theProjL, theHeadToEyeL, theProjR, theHeadToEyeR);
960 // =======================================================================
961 // function : stereoProjection
963 // =======================================================================
964 template <typename Elem_t>
965 void Graphic3d_Camera::stereoProjection (NCollection_Mat4<Elem_t>& theProjL,
966 NCollection_Mat4<Elem_t>& theHeadToEyeL,
967 NCollection_Mat4<Elem_t>& theProjR,
968 NCollection_Mat4<Elem_t>& theHeadToEyeR) const
970 if (myIsCustomProjMatLR)
972 theProjL .ConvertFrom (myCustomProjMatL);
973 theHeadToEyeL.ConvertFrom (myCustomHeadToEyeMatL);
974 theProjR .ConvertFrom (myCustomProjMatR);
975 theHeadToEyeR.ConvertFrom (myCustomHeadToEyeMatR);
979 NCollection_Mat4<Elem_t> aDummy;
980 computeProjection (aDummy, theProjL, theProjR, false);
982 const Standard_Real aIOD = myIODType == IODType_Relative
987 // X translation to cancel parallax
988 theHeadToEyeL.InitIdentity();
989 theHeadToEyeL.SetColumn (3, NCollection_Vec3<Elem_t> (Elem_t ( 0.5 * aIOD), Elem_t (0.0), Elem_t (0.0)));
990 theHeadToEyeR.InitIdentity();
991 theHeadToEyeR.SetColumn (3, NCollection_Vec3<Elem_t> (Elem_t (-0.5 * aIOD), Elem_t (0.0), Elem_t (0.0)));
995 // =======================================================================
996 // function : SetCustomStereoFrustums
998 // =======================================================================
999 void Graphic3d_Camera::SetCustomStereoFrustums (const Aspect_FrustumLRBT<Standard_Real>& theFrustumL,
1000 const Aspect_FrustumLRBT<Standard_Real>& theFrustumR)
1002 myCustomFrustumL = theFrustumL;
1003 myCustomFrustumR = theFrustumR;
1004 myIsCustomFrustomLR = true;
1005 myIsCustomProjMatLR = false;
1006 InvalidateProjection();
1009 // =======================================================================
1010 // function : SetCustomStereoProjection
1012 // =======================================================================
1013 void Graphic3d_Camera::SetCustomStereoProjection (const Graphic3d_Mat4d& theProjL,
1014 const Graphic3d_Mat4d& theHeadToEyeL,
1015 const Graphic3d_Mat4d& theProjR,
1016 const Graphic3d_Mat4d& theHeadToEyeR)
1018 myCustomProjMatL = theProjL;
1019 myCustomProjMatR = theProjR;
1020 myCustomHeadToEyeMatL = theHeadToEyeL;
1021 myCustomHeadToEyeMatR = theHeadToEyeR;
1022 myIsCustomProjMatLR = true;
1023 myIsCustomFrustomLR = false;
1024 InvalidateProjection();
1027 // =======================================================================
1028 // function : SetCustomMonoProjection
1030 // =======================================================================
1031 void Graphic3d_Camera::SetCustomMonoProjection (const Graphic3d_Mat4d& theProj)
1033 myCustomProjMatM = theProj;
1034 myIsCustomProjMatM = true;
1035 InvalidateProjection();
1038 // =======================================================================
1039 // function : computeProjection
1041 // =======================================================================
1042 template <typename Elem_t>
1043 void Graphic3d_Camera::computeProjection (NCollection_Mat4<Elem_t>& theProjM,
1044 NCollection_Mat4<Elem_t>& theProjL,
1045 NCollection_Mat4<Elem_t>& theProjR,
1046 bool theToAddHeadToEye) const
1048 theProjM.InitIdentity();
1049 theProjL.InitIdentity();
1050 theProjR.InitIdentity();
1052 // sets top of frustum based on FOVy and near clipping plane
1053 Elem_t aScale = static_cast<Elem_t> (myScale);
1054 Elem_t aZNear = static_cast<Elem_t> (myZNear);
1055 Elem_t aZFar = static_cast<Elem_t> (myZFar);
1056 Elem_t anAspect = static_cast<Elem_t> (myAspect);
1057 Elem_t aDXHalf = 0.0, aDYHalf = 0.0;
1058 if (IsOrthographic())
1060 aDXHalf = aDYHalf = aScale * Elem_t (0.5);
1064 aDXHalf = aDYHalf = aZNear * Elem_t (myFOVyTan);
1069 aDXHalf *= anAspect;
1073 aDYHalf /= anAspect;
1076 // sets right of frustum based on aspect ratio
1077 Aspect_FrustumLRBT<Elem_t> anLRBT;
1078 anLRBT.Left = -aDXHalf;
1079 anLRBT.Right = aDXHalf;
1080 anLRBT.Bottom = -aDYHalf;
1081 anLRBT.Top = aDYHalf;
1083 Elem_t aIOD = myIODType == IODType_Relative
1084 ? static_cast<Elem_t> (myIOD * Distance())
1085 : static_cast<Elem_t> (myIOD);
1087 Elem_t aFocus = myZFocusType == FocusType_Relative
1088 ? static_cast<Elem_t> (myZFocus * Distance())
1089 : static_cast<Elem_t> (myZFocus);
1091 if (myTile.IsValid())
1093 const Elem_t aDXFull = Elem_t(2) * aDXHalf;
1094 const Elem_t aDYFull = Elem_t(2) * aDYHalf;
1095 const Graphic3d_Vec2i anOffset = myTile.OffsetLowerLeft();
1096 anLRBT.Left = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x()) / static_cast<Elem_t> (myTile.TotalSize.x());
1097 anLRBT.Right = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x() + myTile.TileSize.x()) / static_cast<Elem_t> (myTile.TotalSize.x());
1098 anLRBT.Bottom = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y()) / static_cast<Elem_t> (myTile.TotalSize.y());
1099 anLRBT.Top = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y() + myTile.TileSize.y()) / static_cast<Elem_t> (myTile.TotalSize.y());
1102 if (myIsCustomProjMatM)
1104 theProjM.ConvertFrom (myCustomProjMatM);
1108 case Projection_Orthographic:
1110 if (!myIsCustomProjMatM)
1112 orthoProj (theProjM, anLRBT, aZNear, aZFar);
1116 case Projection_Perspective:
1118 if (!myIsCustomProjMatM)
1120 perspectiveProj (theProjM, anLRBT, aZNear, aZFar);
1124 case Projection_MonoLeftEye:
1125 case Projection_MonoRightEye:
1126 case Projection_Stereo:
1128 if (!myIsCustomProjMatM)
1130 perspectiveProj (theProjM, anLRBT, aZNear, aZFar);
1132 if (myIsCustomProjMatLR)
1134 if (theToAddHeadToEye)
1136 theProjL.ConvertFrom (myCustomProjMatL * myCustomHeadToEyeMatL);
1137 theProjR.ConvertFrom (myCustomProjMatR * myCustomHeadToEyeMatR);
1141 theProjL.ConvertFrom (myCustomProjMatL);
1142 theProjR.ConvertFrom (myCustomProjMatR);
1145 else if (myIsCustomFrustomLR)
1147 anLRBT = Aspect_FrustumLRBT<Elem_t> (myCustomFrustumL).Multiplied (aZNear);
1148 perspectiveProj (theProjL, anLRBT, aZNear, aZFar);
1150 anLRBT = Aspect_FrustumLRBT<Elem_t> (myCustomFrustumR).Multiplied (aZNear);
1151 perspectiveProj (theProjR, anLRBT, aZNear, aZFar);
1155 stereoEyeProj (theProjL,
1156 anLRBT, aZNear, aZFar, aIOD, aFocus,
1158 stereoEyeProj (theProjR,
1159 anLRBT, aZNear, aZFar, aIOD, aFocus,
1163 if (theToAddHeadToEye
1164 && !myIsCustomProjMatLR
1165 && aIOD != Elem_t (0.0))
1167 // X translation to cancel parallax
1168 theProjL.Translate (NCollection_Vec3<Elem_t> (Elem_t ( 0.5) * aIOD, Elem_t (0.0), Elem_t (0.0)));
1169 theProjR.Translate (NCollection_Vec3<Elem_t> (Elem_t (-0.5) * aIOD, Elem_t (0.0), Elem_t (0.0)));
1174 if (myProjType == Projection_MonoLeftEye)
1176 theProjM = theProjL;
1178 else if (myProjType == Projection_MonoRightEye)
1180 theProjM = theProjR;
1184 // =======================================================================
1185 // function : UpdateOrientation
1187 // =======================================================================
1188 template <typename Elem_t>
1189 Graphic3d_Camera::TransformMatrices<Elem_t>&
1190 Graphic3d_Camera::UpdateOrientation (TransformMatrices<Elem_t>& theMatrices) const
1192 if (theMatrices.IsOrientationValid())
1194 return theMatrices; // for inline accessors
1197 theMatrices.InitOrientation();
1199 NCollection_Vec3<Elem_t> anEye (static_cast<Elem_t> (myEye.X()),
1200 static_cast<Elem_t> (myEye.Y()),
1201 static_cast<Elem_t> (myEye.Z()));
1203 NCollection_Vec3<Elem_t> aViewDir (static_cast<Elem_t> (myDirection.X()),
1204 static_cast<Elem_t> (myDirection.Y()),
1205 static_cast<Elem_t> (myDirection.Z()));
1207 NCollection_Vec3<Elem_t> anUp (static_cast<Elem_t> (myUp.X()),
1208 static_cast<Elem_t> (myUp.Y()),
1209 static_cast<Elem_t> (myUp.Z()));
1211 NCollection_Vec3<Elem_t> anAxialScale (static_cast<Elem_t> (myAxialScale.X()),
1212 static_cast<Elem_t> (myAxialScale.Y()),
1213 static_cast<Elem_t> (myAxialScale.Z()));
1215 LookOrientation (anEye, aViewDir, anUp, anAxialScale, theMatrices.Orientation);
1217 return theMatrices; // for inline accessors
1220 // =======================================================================
1221 // function : InvalidateProjection
1223 // =======================================================================
1224 void Graphic3d_Camera::InvalidateProjection()
1226 myMatricesD.ResetProjection();
1227 myMatricesF.ResetProjection();
1228 myWorldViewProjState.ProjectionState() = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
1231 // =======================================================================
1232 // function : InvalidateOrientation
1234 // =======================================================================
1235 void Graphic3d_Camera::InvalidateOrientation()
1237 myMatricesD.ResetOrientation();
1238 myMatricesF.ResetOrientation();
1239 myWorldViewProjState.WorldViewState() = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
1242 // =======================================================================
1243 // function : orthoProj
1245 // =======================================================================
1246 template <typename Elem_t>
1247 void Graphic3d_Camera::orthoProj (NCollection_Mat4<Elem_t>& theOutMx,
1248 const Aspect_FrustumLRBT<Elem_t>& theLRBT,
1249 const Elem_t theNear,
1250 const Elem_t theFar)
1253 theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theLRBT.Right - theLRBT.Left);
1254 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
1255 theOutMx.ChangeValue (0, 2) = Elem_t (0.0);
1256 theOutMx.ChangeValue (0, 3) = - (theLRBT.Right + theLRBT.Left) / (theLRBT.Right - theLRBT.Left);
1259 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
1260 theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theLRBT.Top - theLRBT.Bottom);
1261 theOutMx.ChangeValue (1, 2) = Elem_t (0.0);
1262 theOutMx.ChangeValue (1, 3) = - (theLRBT.Top + theLRBT.Bottom) / (theLRBT.Top - theLRBT.Bottom);
1265 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
1266 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
1267 theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear);
1268 theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear);
1271 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
1272 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
1273 theOutMx.ChangeValue (3, 2) = Elem_t (0.0);
1274 theOutMx.ChangeValue (3, 3) = Elem_t (1.0);
1277 // =======================================================================
1278 // function : PerspectiveProj
1280 // =======================================================================
1281 template <typename Elem_t>
1282 void Graphic3d_Camera::perspectiveProj (NCollection_Mat4<Elem_t>& theOutMx,
1283 const Aspect_FrustumLRBT<Elem_t>& theLRBT,
1284 const Elem_t theNear,
1285 const Elem_t theFar)
1288 theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theLRBT.Right - theLRBT.Left);
1289 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
1290 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
1291 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
1294 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
1295 theOutMx.ChangeValue (1, 1) = (Elem_t (2.0) * theNear) / (theLRBT.Top - theLRBT.Bottom);
1296 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
1297 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
1300 theOutMx.ChangeValue (0, 2) = (theLRBT.Right + theLRBT.Left) / (theLRBT.Right - theLRBT.Left);
1301 theOutMx.ChangeValue (1, 2) = (theLRBT.Top + theLRBT.Bottom) / (theLRBT.Top - theLRBT.Bottom);
1302 theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear);
1303 theOutMx.ChangeValue (3, 2) = Elem_t (-1.0);
1306 theOutMx.ChangeValue (0, 3) = Elem_t (0.0);
1307 theOutMx.ChangeValue (1, 3) = Elem_t (0.0);
1308 theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear);
1309 theOutMx.ChangeValue (3, 3) = Elem_t (0.0);
1312 // =======================================================================
1313 // function : StereoEyeProj
1315 // =======================================================================
1316 template <typename Elem_t>
1317 void Graphic3d_Camera::stereoEyeProj (NCollection_Mat4<Elem_t>& theOutMx,
1318 const Aspect_FrustumLRBT<Elem_t>& theLRBT,
1319 const Elem_t theNear,
1320 const Elem_t theFar,
1321 const Elem_t theIOD,
1322 const Elem_t theZFocus,
1323 const Aspect_Eye theEyeIndex)
1325 Elem_t aDx = theEyeIndex == Aspect_Eye_Left ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD;
1326 Elem_t aDXStereoShift = aDx * theNear / theZFocus;
1328 // construct eye projection matrix
1329 Aspect_FrustumLRBT<Elem_t> aLRBT = theLRBT;
1330 aLRBT.Left = theLRBT.Left + aDXStereoShift;
1331 aLRBT.Right = theLRBT.Right + aDXStereoShift;
1332 perspectiveProj (theOutMx, aLRBT, theNear, theFar);
1335 // =======================================================================
1336 // function : LookOrientation
1338 // =======================================================================
1339 template <typename Elem_t>
1340 void Graphic3d_Camera::LookOrientation (const NCollection_Vec3<Elem_t>& theEye,
1341 const NCollection_Vec3<Elem_t>& theFwdDir,
1342 const NCollection_Vec3<Elem_t>& theUpDir,
1343 const NCollection_Vec3<Elem_t>& theAxialScale,
1344 NCollection_Mat4<Elem_t>& theOutMx)
1346 NCollection_Vec3<Elem_t> aForward = theFwdDir;
1347 aForward.Normalize();
1349 // side = forward x up
1350 NCollection_Vec3<Elem_t> aSide = NCollection_Vec3<Elem_t>::Cross (aForward, theUpDir);
1353 // recompute up as: up = side x forward
1354 NCollection_Vec3<Elem_t> anUp = NCollection_Vec3<Elem_t>::Cross (aSide, aForward);
1356 NCollection_Mat4<Elem_t> aLookMx;
1357 aLookMx.SetRow (0, aSide);
1358 aLookMx.SetRow (1, anUp);
1359 aLookMx.SetRow (2, -aForward);
1361 theOutMx.InitIdentity();
1362 theOutMx.Multiply (aLookMx);
1363 theOutMx.Translate (-theEye);
1365 NCollection_Mat4<Elem_t> anAxialScaleMx;
1366 anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x();
1367 anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y();
1368 anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z();
1370 theOutMx.Multiply (anAxialScaleMx);
1373 //=============================================================================
1374 //function : ZFitAll
1376 //=============================================================================
1377 bool Graphic3d_Camera::ZFitAll (const Standard_Real theScaleFactor,
1378 const Bnd_Box& theMinMax,
1379 const Bnd_Box& theGraphicBB,
1380 Standard_Real& theZNear,
1381 Standard_Real& theZFar) const
1383 Standard_ASSERT_RAISE (theScaleFactor > 0.0, "Zero or negative scale factor is not allowed.");
1385 // Method changes zNear and zFar parameters of camera so as to fit graphical structures
1386 // by their graphical boundaries. It precisely fits min max boundaries of primary application
1387 // objects (second argument), while it can sacrifice the real graphical boundaries of the
1388 // scene with infinite or helper objects (third argument) for the sake of perspective projection.
1389 if (theGraphicBB.IsVoid())
1391 theZNear = DEFAULT_ZNEAR;
1392 theZFar = DEFAULT_ZFAR;
1396 // Measure depth of boundary points from camera eye.
1397 NCollection_Sequence<gp_Pnt> aPntsToMeasure;
1399 Standard_Real aGraphicBB[6];
1400 theGraphicBB.Get (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2], aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]);
1402 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2]));
1403 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[5]));
1404 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[2]));
1405 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[5]));
1406 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[2]));
1407 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[5]));
1408 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[2]));
1409 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]));
1411 Standard_Boolean isFiniteMinMax = !theMinMax.IsVoid() && !theMinMax.IsWhole();
1415 Standard_Real aMinMax[6];
1416 theMinMax.Get (aMinMax[0], aMinMax[1], aMinMax[2], aMinMax[3], aMinMax[4], aMinMax[5]);
1418 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[2]));
1419 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[5]));
1420 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[2]));
1421 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[5]));
1422 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[2]));
1423 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[5]));
1424 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[2]));
1425 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[5]));
1428 // Camera eye plane.
1429 gp_Dir aCamDir = Direction();
1430 gp_Pnt aCamEye = myEye;
1431 gp_Pln aCamPln (aCamEye, aCamDir);
1433 Standard_Real aModelMinDist = RealLast();
1434 Standard_Real aModelMaxDist = RealFirst();
1435 Standard_Real aGraphMinDist = RealLast();
1436 Standard_Real aGraphMaxDist = RealFirst();
1438 const gp_XYZ& anAxialScale = myAxialScale;
1440 // Get minimum and maximum distances to the eye plane.
1441 Standard_Integer aCounter = 0;
1442 NCollection_Sequence<gp_Pnt>::Iterator aPntIt(aPntsToMeasure);
1443 for (; aPntIt.More(); aPntIt.Next())
1445 gp_Pnt aMeasurePnt = aPntIt.Value();
1447 aMeasurePnt = gp_Pnt (aMeasurePnt.X() * anAxialScale.X(),
1448 aMeasurePnt.Y() * anAxialScale.Y(),
1449 aMeasurePnt.Z() * anAxialScale.Z());
1451 Standard_Real aDistance = aCamPln.Distance (aMeasurePnt);
1453 // Check if the camera is intruded into the scene.
1454 gp_Vec aVecToMeasurePnt (aCamEye, aMeasurePnt);
1455 if (aVecToMeasurePnt.Magnitude() > gp::Resolution()
1456 && aCamDir.IsOpposite (aVecToMeasurePnt, M_PI * 0.5))
1461 // The first eight points are from theGraphicBB, the last eight points are from theMinMax (can be absent).
1462 Standard_Real& aChangeMinDist = aCounter >= 8 ? aModelMinDist : aGraphMinDist;
1463 Standard_Real& aChangeMaxDist = aCounter >= 8 ? aModelMaxDist : aGraphMaxDist;
1464 aChangeMinDist = Min (aDistance, aChangeMinDist);
1465 aChangeMaxDist = Max (aDistance, aChangeMaxDist);
1469 // Compute depth of bounding box center.
1470 Standard_Real aMidDepth = (aGraphMinDist + aGraphMaxDist) * 0.5;
1471 Standard_Real aHalfDepth = (aGraphMaxDist - aGraphMinDist) * 0.5;
1473 // Compute enlarged or shrank near and far z ranges.
1474 Standard_Real aZNear = aMidDepth - aHalfDepth * theScaleFactor;
1475 Standard_Real aZFar = aMidDepth + aHalfDepth * theScaleFactor;
1477 if (!IsOrthographic())
1479 // Everything is behind the perspective camera.
1480 if (aZFar < zEpsilon())
1482 theZNear = DEFAULT_ZNEAR;
1483 theZFar = DEFAULT_ZFAR;
1489 // Consider clipping errors due to double to single precision floating-point conversion.
1492 // Model to view transformation performs translation of points against eye position
1493 // in three dimensions. Both point coordinate and eye position values are converted from
1494 // double to single precision floating point numbers producing conversion errors.
1495 // Epsilon (Mod) * 3.0 should safely compensate precision error for z coordinate after
1496 // translation assuming that the:
1497 // Epsilon (Eye.Mod()) * 3.0 > Epsilon (Eye.X()) + Epsilon (Eye.Y()) + Epsilon (Eye.Z()).
1498 Standard_Real aEyeConf = 3.0 * zEpsilon (myEye.XYZ().Modulus());
1500 // Model to view transformation performs rotation of points according to view direction.
1501 // New z coordinate is computed as a multiplication of point's x, y, z coordinates by the
1502 // "forward" direction vector's x, y, z coordinates. Both point's and "z" direction vector's
1503 // values are converted from double to single precision floating point numbers producing
1504 // conversion errors.
1505 // Epsilon (Mod) * 6.0 should safely compensate the precision errors for the multiplication
1506 // of point coordinates by direction vector.
1507 gp_Pnt aGraphicMin = theGraphicBB.CornerMin();
1508 gp_Pnt aGraphicMax = theGraphicBB.CornerMax();
1510 Standard_Real aModelConf = 6.0 * zEpsilon (aGraphicMin.XYZ().Modulus()) +
1511 6.0 * zEpsilon (aGraphicMax.XYZ().Modulus());
1513 // Compensate floating point conversion errors by increasing zNear, zFar to avoid clipping.
1514 aZNear -= zEpsilon (aZNear) + aEyeConf + aModelConf;
1515 aZFar += zEpsilon (aZFar) + aEyeConf + aModelConf;
1517 if (!IsOrthographic())
1519 // For perspective projection, the value of z in normalized device coordinates is non-linear
1520 // function of eye z coordinate. For fixed-point depth representation resolution of z in
1521 // model-view space will grow towards zFar plane and its scale depends mostly on how far is zNear
1522 // against camera's eye. The purpose of the code below is to select most appropriate zNear distance
1523 // to balance between clipping (less zNear, more chances to observe closely small models without clipping)
1524 // and resolution of depth. A well applicable criteria to this is a ratio between resolution of z at center
1525 // of model boundaries and the distance to that center point. The ratio is chosen empirically and validated
1526 // by tests database. It is considered to be ~0.001 (0.1%) for 24 bit depth buffer, for less depth bitness
1527 // the zNear will be placed similarly giving lower resolution.
1528 // Approximation of the formula for respectively large z range is:
1529 // zNear = [z * (1 + k) / (k * c)],
1531 // z - distance to center of model boundaries;
1532 // k - chosen ratio, c - capacity of depth buffer;
1533 // k = 0.001, k * c = 1677.216, (1 + k) / (k * c) ~ 5.97E-4
1535 // The function uses center of model boundaries computed from "theMinMax" boundaries (instead of using real
1536 // graphical boundaries of all displayed objects). That means that it can sacrifice resolution of presentation
1537 // of non primary ("infinite") application graphical objects in favor of better perspective projection of the
1538 // small applicative objects measured with "theMinMax" values.
1539 Standard_Real aZRange = isFiniteMinMax ? aModelMaxDist - aModelMinDist : aGraphMaxDist - aGraphMinDist;
1540 Standard_Real aZMin = isFiniteMinMax ? aModelMinDist : aGraphMinDist;
1541 Standard_Real aZ = aZMin < 0 ? aZRange / 2.0 : aZRange / 2.0 + aZMin;
1542 Standard_Real aZNearMin = aZ * 5.97E-4;
1543 if (aZNear < aZNearMin)
1545 // Clip zNear according to the minimum value matching the quality.
1554 // Compensate zNear conversion errors for perspective projection.
1555 aZNear -= aZFar * zEpsilon (aZNear) / (aZFar - zEpsilon (aZNear));
1558 // Compensate zFar conversion errors for perspective projection.
1559 aZFar += zEpsilon (aZFar);
1561 // Ensure that after all the zNear is not a negative value.
1562 if (aZNear < zEpsilon())
1564 aZNear = zEpsilon();
1566 Standard_ASSERT_RAISE (aZFar > aZNear, "ZFar should be greater than ZNear");
1571 Standard_ASSERT_RAISE (aZFar > aZNear, "ZFar should be greater than ZNear");
1575 //=============================================================================
1576 //function : Interpolate
1578 //=============================================================================
1579 void Graphic3d_Camera::Interpolate (const Handle(Graphic3d_Camera)& theStart,
1580 const Handle(Graphic3d_Camera)& theEnd,
1582 Handle(Graphic3d_Camera)& theCamera)
1584 if (Abs (theT - 1.0) < Precision::Confusion())
1586 // just copy end-point transformation
1587 theCamera->Copy (theEnd);
1591 theCamera->Copy (theStart);
1592 if (Abs (theT - 0.0) < Precision::Confusion())
1599 gp_Ax3 aCamStart = cameraToAx3 (*theStart);
1600 gp_Ax3 aCamEnd = cameraToAx3 (*theEnd);
1601 gp_Trsf aTrsfStart, aTrsfEnd;
1602 aTrsfStart.SetTransformation (aCamStart, gp::XOY());
1603 aTrsfEnd .SetTransformation (aCamEnd, gp::XOY());
1605 gp_Quaternion aRotStart = aTrsfStart.GetRotation();
1606 gp_Quaternion aRotEnd = aTrsfEnd .GetRotation();
1607 gp_Quaternion aRotDelta = aRotEnd * aRotStart.Inverted();
1608 gp_Quaternion aRot = gp_QuaternionNLerp::Interpolate (gp_Quaternion(), aRotDelta, theT);
1610 aTrsfRot.SetRotation (aRot);
1611 theCamera->Transform (aTrsfRot);
1614 // apply translation
1616 gp_XYZ aCenter = NCollection_Lerp<gp_XYZ>::Interpolate (theStart->Center().XYZ(), theEnd->Center().XYZ(), theT);
1617 gp_XYZ anEye = NCollection_Lerp<gp_XYZ>::Interpolate (theStart->Eye().XYZ(), theEnd->Eye().XYZ(), theT);
1618 gp_XYZ anAnchor = aCenter;
1619 Standard_Real aKc = 0.0;
1621 const Standard_Real aDeltaCenter = theStart->Center().Distance (theEnd->Center());
1622 const Standard_Real aDeltaEye = theStart->Eye() .Distance (theEnd->Eye());
1623 if (aDeltaEye <= gp::Resolution())
1628 else if (aDeltaCenter > gp::Resolution())
1630 aKc = aDeltaCenter / (aDeltaCenter + aDeltaEye);
1632 const gp_XYZ anAnchorStart = NCollection_Lerp<gp_XYZ>::Interpolate (theStart->Center().XYZ(), theStart->Eye().XYZ(), aKc);
1633 const gp_XYZ anAnchorEnd = NCollection_Lerp<gp_XYZ>::Interpolate (theEnd ->Center().XYZ(), theEnd ->Eye().XYZ(), aKc);
1634 anAnchor = NCollection_Lerp<gp_XYZ>::Interpolate (anAnchorStart, anAnchorEnd, theT);
1637 const gp_Vec aDirEyeToCenter = theCamera->Direction();
1638 const Standard_Real aDistEyeCenterStart = theStart->Eye().Distance (theStart->Center());
1639 const Standard_Real aDistEyeCenterEnd = theEnd ->Eye().Distance (theEnd ->Center());
1640 const Standard_Real aDistEyeCenter = NCollection_Lerp<Standard_Real>::Interpolate (aDistEyeCenterStart, aDistEyeCenterEnd, theT);
1641 aCenter = anAnchor + aDirEyeToCenter.XYZ() * aDistEyeCenter * aKc;
1642 anEye = anAnchor - aDirEyeToCenter.XYZ() * aDistEyeCenter * (1.0 - aKc);
1644 theCamera->SetEyeAndCenter (anEye, aCenter);
1648 if (Abs(theStart->Scale() - theEnd->Scale()) > Precision::Confusion()
1649 && theStart->IsOrthographic())
1651 const Standard_Real aScale = NCollection_Lerp<Standard_Real>::Interpolate (theStart->Scale(), theEnd->Scale(), theT);
1652 theCamera->SetScale (aScale);
1656 //=======================================================================
1657 //function : FrustumPoints
1659 //=======================================================================
1660 void Graphic3d_Camera::FrustumPoints (NCollection_Array1<Graphic3d_Vec3d>& thePoints,
1661 const Graphic3d_Mat4d& theModelWorld) const
1663 if (thePoints.Length() != FrustumVerticesNB)
1665 thePoints.Resize (0, FrustumVerticesNB, Standard_False);
1668 const Graphic3d_Mat4d& aProjectionMat = ProjectionMatrix();
1669 const Graphic3d_Mat4d aWorldViewMat = OrientationMatrix() * theModelWorld;
1671 Standard_Real nLeft = 0.0, nRight = 0.0, nTop = 0.0, nBottom = 0.0;
1672 Standard_Real fLeft = 0.0, fRight = 0.0, fTop = 0.0, fBottom = 0.0;
1673 Standard_Real aNear = 0.0, aFar = 0.0;
1674 if (!IsOrthographic())
1676 // handle perspective projection
1677 aNear = aProjectionMat.GetValue (2, 3) / (-1.0 + aProjectionMat.GetValue (2, 2));
1678 aFar = aProjectionMat.GetValue (2, 3) / ( 1.0 + aProjectionMat.GetValue (2, 2));
1680 nLeft = aNear * (aProjectionMat.GetValue (0, 2) - 1.0) / aProjectionMat.GetValue (0, 0);
1681 nRight = aNear * (aProjectionMat.GetValue (0, 2) + 1.0) / aProjectionMat.GetValue (0, 0);
1682 nTop = aNear * (aProjectionMat.GetValue (1, 2) + 1.0) / aProjectionMat.GetValue (1, 1);
1683 nBottom = aNear * (aProjectionMat.GetValue (1, 2) - 1.0) / aProjectionMat.GetValue (1, 1);
1685 fLeft = aFar * (aProjectionMat.GetValue (0, 2) - 1.0) / aProjectionMat.GetValue (0, 0);
1686 fRight = aFar * (aProjectionMat.GetValue (0, 2) + 1.0) / aProjectionMat.GetValue (0, 0);
1687 fTop = aFar * (aProjectionMat.GetValue (1, 2) + 1.0) / aProjectionMat.GetValue (1, 1);
1688 fBottom = aFar * (aProjectionMat.GetValue (1, 2) - 1.0) / aProjectionMat.GetValue (1, 1);
1692 // handle orthographic projection
1693 aNear = (1.0 / aProjectionMat.GetValue (2, 2)) * (aProjectionMat.GetValue (2, 3) + 1.0);
1694 aFar = (1.0 / aProjectionMat.GetValue (2, 2)) * (aProjectionMat.GetValue (2, 3) - 1.0);
1696 nLeft = ( 1.0 + aProjectionMat.GetValue (0, 3)) / (-aProjectionMat.GetValue (0, 0));
1698 nRight = ( 1.0 - aProjectionMat.GetValue (0, 3)) / aProjectionMat.GetValue (0, 0);
1700 nTop = ( 1.0 - aProjectionMat.GetValue (1, 3)) / aProjectionMat.GetValue (1, 1);
1702 nBottom = (-1.0 - aProjectionMat.GetValue (1, 3)) / aProjectionMat.GetValue (1, 1);
1706 Graphic3d_Vec4d aLeftTopNear (nLeft, nTop, -aNear, 1.0), aRightBottomFar (fRight, fBottom, -aFar, 1.0);
1707 Graphic3d_Vec4d aLeftBottomNear (nLeft, nBottom, -aNear, 1.0), aRightTopFar (fRight, fTop, -aFar, 1.0);
1708 Graphic3d_Vec4d aRightBottomNear (nRight, nBottom, -aNear, 1.0), aLeftTopFar (fLeft, fTop, -aFar, 1.0);
1709 Graphic3d_Vec4d aRightTopNear (nRight, nTop, -aNear, 1.0), aLeftBottomFar (fLeft, fBottom, -aFar, 1.0);
1711 Graphic3d_Mat4d anInvWorldView;
1712 aWorldViewMat.Inverted (anInvWorldView);
1714 Graphic3d_Vec4d aTmpPnt;
1715 aTmpPnt = anInvWorldView * aLeftTopNear;
1716 thePoints.SetValue (FrustumVert_LeftTopNear, aTmpPnt.xyz() / aTmpPnt.w());
1717 aTmpPnt = anInvWorldView * aRightBottomFar;
1718 thePoints.SetValue (FrustumVert_RightBottomFar, aTmpPnt.xyz() / aTmpPnt.w());
1719 aTmpPnt = anInvWorldView * aLeftBottomNear;
1720 thePoints.SetValue (FrustumVert_LeftBottomNear, aTmpPnt.xyz() / aTmpPnt.w());
1721 aTmpPnt = anInvWorldView * aRightTopFar;
1722 thePoints.SetValue (FrustumVert_RightTopFar, aTmpPnt.xyz() / aTmpPnt.w());
1723 aTmpPnt = anInvWorldView * aRightBottomNear;
1724 thePoints.SetValue (FrustumVert_RightBottomNear, aTmpPnt.xyz() / aTmpPnt.w());
1725 aTmpPnt = anInvWorldView * aLeftTopFar;
1726 thePoints.SetValue (FrustumVert_LeftTopFar, aTmpPnt.xyz() / aTmpPnt.w());
1727 aTmpPnt = anInvWorldView * aRightTopNear;
1728 thePoints.SetValue (FrustumVert_RightTopNear, aTmpPnt.xyz() / aTmpPnt.w());
1729 aTmpPnt = anInvWorldView * aLeftBottomFar;
1730 thePoints.SetValue (FrustumVert_LeftBottomFar, aTmpPnt.xyz() / aTmpPnt.w());
1733 //=======================================================================
1734 //function : DumpJson
1736 //=======================================================================
1737 void Graphic3d_Camera::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
1739 OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
1741 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myUp)
1742 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myDirection)
1743 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myEye)
1745 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDistance)
1747 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myAxialScale)
1748 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myProjType)
1749 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myFOVy)
1750 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myZNear)
1751 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myZFar)
1752 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myAspect)
1754 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myScale)
1755 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myZFocus)
1756 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myZFocusType)
1758 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIOD)
1759 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIODType)
1761 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myTile)
1762 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myMatricesD)
1763 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myMatricesF)
1764 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myWorldViewProjState)