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 SetFOVy (theOtherCamera->FOVy());
143 SetFOV2d (theOtherCamera->FOV2d());
144 SetZRange (theOtherCamera->ZNear(), theOtherCamera->ZFar());
145 SetAspect (theOtherCamera->Aspect());
146 SetScale (theOtherCamera->Scale());
147 SetZFocus (theOtherCamera->ZFocusType(), theOtherCamera->ZFocus());
148 SetIOD (theOtherCamera->GetIODType(), theOtherCamera->IOD());
149 SetProjectionType (theOtherCamera->ProjectionType());
150 SetTile (theOtherCamera->myTile);
152 ResetCustomProjection();
153 if (theOtherCamera->IsCustomStereoProjection())
155 SetCustomStereoProjection (theOtherCamera->myCustomProjMatL, theOtherCamera->myCustomProjMatR);
157 else if (theOtherCamera->IsCustomStereoFrustum())
159 SetCustomStereoFrustums (theOtherCamera->myCustomFrustumL, theOtherCamera->myCustomFrustumR);
161 if (theOtherCamera->IsCustomMonoProjection())
163 SetCustomMonoProjection (theOtherCamera->myCustomProjMatM);
167 // =======================================================================
168 // function : CopyOrientationData
170 // =======================================================================
171 void Graphic3d_Camera::CopyOrientationData (const Handle(Graphic3d_Camera)& theOtherCamera)
173 if (!myEye.IsEqual (theOtherCamera->Eye(), 0.0)
174 || !myUp.IsEqual (theOtherCamera->Up(), 0.0)
175 || !myDirection.IsEqual (theOtherCamera->Direction(), 0.0)
176 || myDistance != theOtherCamera->Distance())
178 myEye = theOtherCamera->Eye();
179 myUp = theOtherCamera->Up();
180 myDirection = theOtherCamera->Direction();
181 myDistance = theOtherCamera->Distance();
182 InvalidateOrientation();
184 SetAxialScale (theOtherCamera->AxialScale());
187 // =======================================================================
190 // =======================================================================
191 void Graphic3d_Camera::Copy (const Handle(Graphic3d_Camera)& theOther)
193 CopyMappingData (theOther);
194 CopyOrientationData (theOther);
197 // =======================================================================
198 // function : MoveEyeTo
200 // =======================================================================
201 void Graphic3d_Camera::MoveEyeTo (const gp_Pnt& theEye)
203 if (myEye.IsEqual (theEye, 0.0))
209 InvalidateOrientation();
212 // =======================================================================
213 // function : SetEyeAndCenter
215 // =======================================================================
216 void Graphic3d_Camera::SetEyeAndCenter (const gp_Pnt& theEye,
217 const gp_Pnt& theCenter)
219 if (Eye() .IsEqual (theEye, 0.0)
220 && Center().IsEqual (theCenter, 0.0))
226 myDistance = theEye.Distance (theCenter);
227 if (myDistance > gp::Resolution())
229 myDirection = gp_Dir (theCenter.XYZ() - theEye.XYZ());
231 InvalidateOrientation();
234 // =======================================================================
237 // =======================================================================
238 void Graphic3d_Camera::SetEye (const gp_Pnt& theEye)
240 if (Eye().IsEqual (theEye, 0.0))
245 const gp_Pnt aCenter = Center();
247 myDistance = myEye.Distance (aCenter);
248 if (myDistance > gp::Resolution())
250 myDirection = gp_Dir (aCenter.XYZ() - myEye.XYZ());
252 InvalidateOrientation();
255 // =======================================================================
256 // function : SetCenter
258 // =======================================================================
259 void Graphic3d_Camera::SetCenter (const gp_Pnt& theCenter)
261 const Standard_Real aDistance = myEye.Distance (theCenter);
262 if (myDistance == aDistance)
267 myDistance = aDistance;
268 if (myDistance > gp::Resolution())
270 myDirection = gp_Dir (theCenter.XYZ() - myEye.XYZ());
272 InvalidateOrientation();
275 // =======================================================================
278 // =======================================================================
279 void Graphic3d_Camera::SetUp (const gp_Dir& theUp)
281 if (Up().IsEqual (theUp, 0.0))
287 InvalidateOrientation();
290 // =======================================================================
291 // function : SetAxialScale
293 // =======================================================================
294 void Graphic3d_Camera::SetAxialScale (const gp_XYZ& theAxialScale)
296 if (AxialScale().IsEqual (theAxialScale, 0.0))
301 myAxialScale = theAxialScale;
302 InvalidateOrientation();
305 // =======================================================================
306 // function : SetDistance
308 // =======================================================================
309 void Graphic3d_Camera::SetDistance (const Standard_Real theDistance)
311 if (myDistance == theDistance)
316 const gp_Pnt aCenter = Center();
317 myDistance = theDistance;
318 myEye = aCenter.XYZ() - myDirection.XYZ() * myDistance;
319 InvalidateOrientation();
322 // =======================================================================
323 // function : SetDirectionFromEye
325 // =======================================================================
326 void Graphic3d_Camera::SetDirectionFromEye (const gp_Dir& theDir)
328 if (myDirection.IsEqual (theDir, 0.0))
333 myDirection = theDir;
334 InvalidateOrientation();
337 // =======================================================================
338 // function : SetDirection
340 // =======================================================================
341 void Graphic3d_Camera::SetDirection (const gp_Dir& theDir)
343 if (myDirection.IsEqual (theDir, 0.0))
348 const gp_Pnt aCenter = Center();
349 myDirection = theDir;
350 myEye = aCenter.XYZ() - theDir.XYZ() * myDistance;
351 InvalidateOrientation();
354 // =======================================================================
355 // function : SetScale
357 // =======================================================================
358 void Graphic3d_Camera::SetScale (const Standard_Real theScale)
360 if (Scale() == theScale)
369 case Projection_Perspective :
370 case Projection_Stereo :
371 case Projection_MonoLeftEye :
372 case Projection_MonoRightEye :
374 Standard_Real aDistance = theScale * 0.5 / myFOVyTan;
375 SetDistance (aDistance);
382 InvalidateProjection();
385 // =======================================================================
388 // =======================================================================
389 Standard_Real Graphic3d_Camera::Scale() const
393 case Projection_Orthographic :
396 // case Projection_Perspective :
397 // case Projection_Stereo :
398 // case Projection_MonoLeftEye :
399 // case Projection_MonoRightEye :
401 return Distance() * 2.0 * myFOVyTan;
405 // =======================================================================
406 // function : SetProjectionType
408 // =======================================================================
409 void Graphic3d_Camera::SetProjectionType (const Projection theProjectionType)
411 Projection anOldType = ProjectionType();
413 if (anOldType == theProjectionType)
418 if (anOldType == Projection_Orthographic)
420 if (myZNear <= RealEpsilon())
422 myZNear = DEFAULT_ZNEAR;
424 if (myZFar <= RealEpsilon())
426 myZFar = DEFAULT_ZFAR;
430 myProjType = theProjectionType;
432 InvalidateProjection();
435 // =======================================================================
436 // function : SetFOVy
438 // =======================================================================
439 void Graphic3d_Camera::SetFOVy (const Standard_Real theFOVy)
441 if (FOVy() == theFOVy)
447 myFOVx = theFOVy * myAspect;
448 myFOVyTan = Tan(DTR_HALF * myFOVy);
450 InvalidateProjection();
453 // =======================================================================
454 // function : SetFOV2d
456 // =======================================================================
457 void Graphic3d_Camera::SetFOV2d (const Standard_Real theFOV)
459 if (FOV2d() == theFOV)
465 InvalidateProjection();
468 // =======================================================================
469 // function : SetZRange
471 // =======================================================================
472 void Graphic3d_Camera::SetZRange (const Standard_Real theZNear,
473 const Standard_Real theZFar)
475 Standard_ASSERT_RAISE (theZFar > theZNear, "ZFar should be greater than ZNear");
476 if (!IsOrthographic())
478 Standard_ASSERT_RAISE (theZNear > 0.0, "Only positive Z-Near is allowed for perspective camera");
479 Standard_ASSERT_RAISE (theZFar > 0.0, "Only positive Z-Far is allowed for perspective camera");
482 if (ZNear() == theZNear
483 && ZFar () == theZFar)
491 InvalidateProjection();
494 // =======================================================================
495 // function : SetAspect
497 // =======================================================================
498 void Graphic3d_Camera::SetAspect (const Standard_Real theAspect)
500 if (Aspect() == theAspect)
505 myAspect = theAspect;
506 myFOVx = myFOVy * theAspect;
508 InvalidateProjection();
511 // =======================================================================
512 // function : SetZFocus
514 // =======================================================================
515 void Graphic3d_Camera::SetZFocus(const FocusType theType, const Standard_Real theZFocus)
517 if (ZFocusType() == theType
518 && ZFocus () == theZFocus)
523 myZFocusType = theType;
524 myZFocus = theZFocus;
526 InvalidateProjection();
529 // =======================================================================
532 // =======================================================================
533 void Graphic3d_Camera::SetIOD (const IODType theType, const Standard_Real theIOD)
535 if (GetIODType() == theType
544 InvalidateProjection();
547 // =======================================================================
548 // function : SetTile
550 // =======================================================================
551 void Graphic3d_Camera::SetTile (const Graphic3d_CameraTile& theTile)
553 if (myTile == theTile)
559 InvalidateProjection();
562 // =======================================================================
563 // function : OrthogonalizeUp
565 // =======================================================================
566 void Graphic3d_Camera::OrthogonalizeUp()
568 SetUp (OrthogonalizedUp());
571 // =======================================================================
572 // function : OrthogonalizedUp
574 // =======================================================================
575 gp_Dir Graphic3d_Camera::OrthogonalizedUp() const
577 gp_Dir aDir = Direction();
578 gp_Dir aLeft = aDir.Crossed (Up());
580 // recompute up as: up = left x direction
581 return aLeft.Crossed (aDir);
584 // =======================================================================
585 // function : Transform
587 // =======================================================================
588 void Graphic3d_Camera::Transform (const gp_Trsf& theTrsf)
590 if (theTrsf.Form() == gp_Identity)
595 myUp .Transform (theTrsf);
596 myDirection.Transform (theTrsf);
597 myEye.Transform (theTrsf);
598 InvalidateOrientation();
601 // =======================================================================
602 // function : safePointCast
604 // =======================================================================
605 static Graphic3d_Vec4d safePointCast (const gp_Pnt& thePnt)
607 Standard_Real aLim = 1e15f;
609 // have to deal with values greater then max float
610 gp_Pnt aSafePoint = thePnt;
611 const Standard_Real aBigFloat = aLim * 0.1f;
612 if (Abs (aSafePoint.X()) > aLim)
613 aSafePoint.SetX (aSafePoint.X() >= 0 ? aBigFloat : -aBigFloat);
614 if (Abs (aSafePoint.Y()) > aLim)
615 aSafePoint.SetY (aSafePoint.Y() >= 0 ? aBigFloat : -aBigFloat);
616 if (Abs (aSafePoint.Z()) > aLim)
617 aSafePoint.SetZ (aSafePoint.Z() >= 0 ? aBigFloat : -aBigFloat);
620 Graphic3d_Vec4d aPnt (aSafePoint.X(), aSafePoint.Y(), aSafePoint.Z(), 1.0);
625 // =======================================================================
626 // function : Project
628 // =======================================================================
629 gp_Pnt Graphic3d_Camera::Project (const gp_Pnt& thePnt) const
631 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
632 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
634 // use compatible type of point
635 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
637 aPnt = aViewMx * aPnt; // convert to view coordinate space
638 aPnt = aProjMx * aPnt; // convert to projection coordinate space
640 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
642 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
645 // =======================================================================
646 // function : UnProject
648 // =======================================================================
649 gp_Pnt Graphic3d_Camera::UnProject (const gp_Pnt& thePnt) const
651 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
652 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
654 Graphic3d_Mat4d aInvView;
655 Graphic3d_Mat4d aInvProj;
657 // this case should never happen
658 if (!aViewMx.Inverted (aInvView) || !aProjMx.Inverted (aInvProj))
660 return gp_Pnt (0.0, 0.0, 0.0);
663 // use compatible type of point
664 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
666 aPnt = aInvProj * aPnt; // convert to view coordinate space
667 aPnt = aInvView * aPnt; // convert to world coordinate space
669 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
671 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
674 // =======================================================================
675 // function : ConvertView2Proj
677 // =======================================================================
678 gp_Pnt Graphic3d_Camera::ConvertView2Proj (const gp_Pnt& thePnt) const
680 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
682 // use compatible type of point
683 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
685 aPnt = aProjMx * aPnt; // convert to projection coordinate space
687 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
689 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
692 // =======================================================================
693 // function : ConvertProj2View
695 // =======================================================================
696 gp_Pnt Graphic3d_Camera::ConvertProj2View (const gp_Pnt& thePnt) const
698 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
700 Graphic3d_Mat4d aInvProj;
702 // this case should never happen, but...
703 if (!aProjMx.Inverted (aInvProj))
705 return gp_Pnt (0, 0, 0);
708 // use compatible type of point
709 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
711 aPnt = aInvProj * aPnt; // convert to view coordinate space
713 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
715 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
718 // =======================================================================
719 // function : ConvertWorld2View
721 // =======================================================================
722 gp_Pnt Graphic3d_Camera::ConvertWorld2View (const gp_Pnt& thePnt) const
724 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
726 // use compatible type of point
727 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
729 aPnt = aViewMx * aPnt; // convert to view coordinate space
731 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
733 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
736 // =======================================================================
737 // function : ConvertView2World
739 // =======================================================================
740 gp_Pnt Graphic3d_Camera::ConvertView2World (const gp_Pnt& thePnt) const
742 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
744 Graphic3d_Mat4d aInvView;
746 if (!aViewMx.Inverted (aInvView))
748 return gp_Pnt(0, 0, 0);
751 // use compatible type of point
752 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
754 aPnt = aInvView * aPnt; // convert to world coordinate space
756 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
758 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
761 // =======================================================================
762 // function : ViewDimensions
764 // =======================================================================
765 gp_XYZ Graphic3d_Camera::ViewDimensions (const Standard_Real theZValue) const
767 // view plane dimensions
768 Standard_Real aSize = IsOrthographic() ? myScale : (2.0 * theZValue * myFOVyTan);
769 Standard_Real aSizeX, aSizeY;
772 aSizeX = aSize * myAspect;
778 aSizeY = aSize / myAspect;
782 return gp_XYZ (aSizeX, aSizeY, myZFar - myZNear);
785 // =======================================================================
786 // function : Frustum
788 // =======================================================================
789 void Graphic3d_Camera::Frustum (gp_Pln& theLeft,
794 gp_Pln& theFar) const
796 gp_Vec aProjection = gp_Vec (Direction());
797 gp_Vec anUp = OrthogonalizedUp();
798 gp_Vec aSide = aProjection ^ anUp;
800 Standard_ASSERT_RAISE (
801 !aProjection.IsParallel (anUp, Precision::Angular()),
802 "Can not derive SIDE = PROJ x UP - directions are parallel");
804 theNear = gp_Pln (Eye().Translated (aProjection * ZNear()), aProjection);
805 theFar = gp_Pln (Eye().Translated (aProjection * ZFar()), -aProjection);
807 Standard_Real aHScaleHor = 0.0, aHScaleVer = 0.0;
810 aHScaleHor = Scale() * 0.5 * Aspect();
811 aHScaleVer = Scale() * 0.5;
815 aHScaleHor = Scale() * 0.5;
816 aHScaleVer = Scale() * 0.5 / Aspect();
819 gp_Pnt aPntLeft = Center().Translated (aHScaleHor * -aSide);
820 gp_Pnt aPntRight = Center().Translated (aHScaleHor * aSide);
821 gp_Pnt aPntBottom = Center().Translated (aHScaleVer * -anUp);
822 gp_Pnt aPntTop = Center().Translated (aHScaleVer * anUp);
824 gp_Vec aDirLeft = aSide;
825 gp_Vec aDirRight = -aSide;
826 gp_Vec aDirBottom = anUp;
827 gp_Vec aDirTop = -anUp;
828 if (!IsOrthographic())
830 Standard_Real aHFOVHor = ATan (Tan (DTR_HALF * FOVy()) * Aspect());
831 Standard_Real aHFOVVer = DTR_HALF * FOVy();
832 aDirLeft.Rotate (gp_Ax1 (gp::Origin(), anUp), aHFOVHor);
833 aDirRight.Rotate (gp_Ax1 (gp::Origin(), anUp), -aHFOVHor);
834 aDirBottom.Rotate (gp_Ax1 (gp::Origin(), aSide), -aHFOVVer);
835 aDirTop.Rotate (gp_Ax1 (gp::Origin(), aSide), aHFOVVer);
838 theLeft = gp_Pln (aPntLeft, aDirLeft);
839 theRight = gp_Pln (aPntRight, aDirRight);
840 theBottom = gp_Pln (aPntBottom, aDirBottom);
841 theTop = gp_Pln (aPntTop, aDirTop);
844 // =======================================================================
845 // function : OrientationMatrix
847 // =======================================================================
848 const Graphic3d_Mat4d& Graphic3d_Camera::OrientationMatrix() const
850 return UpdateOrientation (myMatricesD).Orientation;
853 // =======================================================================
854 // function : OrientationMatrixF
856 // =======================================================================
857 const Graphic3d_Mat4& Graphic3d_Camera::OrientationMatrixF() const
859 return UpdateOrientation (myMatricesF).Orientation;
862 // =======================================================================
863 // function : ProjectionMatrix
865 // =======================================================================
866 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionMatrix() const
868 return UpdateProjection (myMatricesD).MProjection;
871 // =======================================================================
872 // function : ProjectionMatrixF
874 // =======================================================================
875 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionMatrixF() const
877 return UpdateProjection (myMatricesF).MProjection;
880 // =======================================================================
881 // function : ProjectionStereoLeft
883 // =======================================================================
884 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoLeft() const
886 return UpdateProjection (myMatricesD).LProjection;
889 // =======================================================================
890 // function : ProjectionStereoLeftF
892 // =======================================================================
893 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoLeftF() const
895 return UpdateProjection (myMatricesF).LProjection;
898 // =======================================================================
899 // function : ProjectionStereoRight
901 // =======================================================================
902 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoRight() const
904 return UpdateProjection (myMatricesD).RProjection;
907 // =======================================================================
908 // function : ProjectionStereoRightF
910 // =======================================================================
911 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoRightF() const
913 return UpdateProjection (myMatricesF).RProjection;
916 // =======================================================================
917 // function : ResetCustomProjection
919 // =======================================================================
920 void Graphic3d_Camera::ResetCustomProjection()
922 if (myIsCustomFrustomLR
923 || myIsCustomProjMatLR
924 || myIsCustomProjMatM)
926 myIsCustomFrustomLR = false;
927 myIsCustomProjMatLR = false;
928 myIsCustomProjMatM = false;
929 InvalidateProjection();
933 // =======================================================================
934 // function : SetCustomStereoFrustums
936 // =======================================================================
937 void Graphic3d_Camera::SetCustomStereoFrustums (const Aspect_FrustumLRBT<Standard_Real>& theFrustumL,
938 const Aspect_FrustumLRBT<Standard_Real>& theFrustumR)
940 myCustomFrustumL = theFrustumL;
941 myCustomFrustumR = theFrustumR;
942 myIsCustomFrustomLR = true;
943 myIsCustomProjMatLR = false;
944 InvalidateProjection();
947 // =======================================================================
948 // function : SetCustomStereoProjection
950 // =======================================================================
951 void Graphic3d_Camera::SetCustomStereoProjection (const Graphic3d_Mat4d& theProjL,
952 const Graphic3d_Mat4d& theProjR)
954 myCustomProjMatL = theProjL;
955 myCustomProjMatR = theProjR;
956 myIsCustomProjMatLR = true;
957 myIsCustomFrustomLR = false;
958 InvalidateProjection();
961 // =======================================================================
962 // function : SetCustomMonoProjection
964 // =======================================================================
965 void Graphic3d_Camera::SetCustomMonoProjection (const Graphic3d_Mat4d& theProj)
967 myCustomProjMatM = theProj;
968 myIsCustomProjMatM = true;
969 InvalidateProjection();
972 // =======================================================================
973 // function : UpdateProjection
975 // =======================================================================
976 template <typename Elem_t>
977 Graphic3d_Camera::TransformMatrices<Elem_t>&
978 Graphic3d_Camera::UpdateProjection (TransformMatrices<Elem_t>& theMatrices) const
980 if (theMatrices.IsProjectionValid())
982 return theMatrices; // for inline accessors
985 theMatrices.InitProjection();
987 // sets top of frustum based on FOVy and near clipping plane
988 Elem_t aScale = static_cast<Elem_t> (myScale);
989 Elem_t aZNear = static_cast<Elem_t> (myZNear);
990 Elem_t aZFar = static_cast<Elem_t> (myZFar);
991 Elem_t anAspect = static_cast<Elem_t> (myAspect);
992 Elem_t aDXHalf = 0.0, aDYHalf = 0.0;
993 if (IsOrthographic())
995 aDXHalf = aDYHalf = aScale * Elem_t (0.5);
999 aDXHalf = aDYHalf = aZNear * Elem_t (myFOVyTan);
1004 aDXHalf *= anAspect;
1008 aDYHalf /= anAspect;
1011 // sets right of frustum based on aspect ratio
1012 Aspect_FrustumLRBT<Elem_t> anLRBT;
1013 anLRBT.Left = -aDXHalf;
1014 anLRBT.Right = aDXHalf;
1015 anLRBT.Bottom = -aDYHalf;
1016 anLRBT.Top = aDYHalf;
1018 Elem_t aIOD = myIODType == IODType_Relative
1019 ? static_cast<Elem_t> (myIOD * Distance())
1020 : static_cast<Elem_t> (myIOD);
1022 Elem_t aFocus = myZFocusType == FocusType_Relative
1023 ? static_cast<Elem_t> (myZFocus * Distance())
1024 : static_cast<Elem_t> (myZFocus);
1026 if (myTile.IsValid())
1028 const Elem_t aDXFull = Elem_t(2) * aDXHalf;
1029 const Elem_t aDYFull = Elem_t(2) * aDYHalf;
1030 const Graphic3d_Vec2i anOffset = myTile.OffsetLowerLeft();
1031 anLRBT.Left = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x()) / static_cast<Elem_t> (myTile.TotalSize.x());
1032 anLRBT.Right = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x() + myTile.TileSize.x()) / static_cast<Elem_t> (myTile.TotalSize.x());
1033 anLRBT.Bottom = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y()) / static_cast<Elem_t> (myTile.TotalSize.y());
1034 anLRBT.Top = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y() + myTile.TileSize.y()) / static_cast<Elem_t> (myTile.TotalSize.y());
1037 if (myIsCustomProjMatM)
1039 theMatrices.MProjection.ConvertFrom (myCustomProjMatM);
1043 case Projection_Orthographic:
1045 if (!myIsCustomProjMatM)
1047 orthoProj (theMatrices.MProjection, anLRBT, aZNear, aZFar);
1051 case Projection_Perspective:
1053 if (!myIsCustomProjMatM)
1055 perspectiveProj (theMatrices.MProjection, anLRBT, aZNear, aZFar);
1059 case Projection_MonoLeftEye:
1060 case Projection_MonoRightEye:
1061 case Projection_Stereo:
1063 if (!myIsCustomProjMatM)
1065 perspectiveProj (theMatrices.MProjection, anLRBT, aZNear, aZFar);
1067 if (myIsCustomProjMatLR)
1069 theMatrices.LProjection.ConvertFrom (myCustomProjMatL);
1070 theMatrices.RProjection.ConvertFrom (myCustomProjMatR);
1072 else if (myIsCustomFrustomLR)
1074 anLRBT = Aspect_FrustumLRBT<Elem_t> (myCustomFrustumL).Multiplied (aZNear);
1075 perspectiveProj (theMatrices.LProjection, anLRBT, aZNear, aZFar);
1076 if (aIOD != Elem_t (0.0))
1078 theMatrices.LProjection.Translate (NCollection_Vec3<Elem_t> (Elem_t (0.5) * aIOD, Elem_t (0.0), Elem_t (0.0)));
1081 anLRBT = Aspect_FrustumLRBT<Elem_t> (myCustomFrustumR).Multiplied (aZNear);
1082 perspectiveProj (theMatrices.RProjection, anLRBT, aZNear, aZFar);
1083 if (aIOD != Elem_t (0.0))
1085 theMatrices.RProjection.Translate (NCollection_Vec3<Elem_t> (Elem_t (-0.5) * aIOD, Elem_t (0.0), Elem_t (0.0)));
1090 stereoEyeProj (theMatrices.LProjection,
1091 anLRBT, aZNear, aZFar, aIOD, aFocus,
1093 stereoEyeProj (theMatrices.RProjection,
1094 anLRBT, aZNear, aZFar, aIOD, aFocus,
1100 if (myProjType == Projection_MonoLeftEye)
1102 theMatrices.MProjection = theMatrices.LProjection;
1104 else if (myProjType == Projection_MonoRightEye)
1106 theMatrices.MProjection = theMatrices.RProjection;
1109 return theMatrices; // for inline accessors
1112 // =======================================================================
1113 // function : UpdateOrientation
1115 // =======================================================================
1116 template <typename Elem_t>
1117 Graphic3d_Camera::TransformMatrices<Elem_t>&
1118 Graphic3d_Camera::UpdateOrientation (TransformMatrices<Elem_t>& theMatrices) const
1120 if (theMatrices.IsOrientationValid())
1122 return theMatrices; // for inline accessors
1125 theMatrices.InitOrientation();
1127 NCollection_Vec3<Elem_t> anEye (static_cast<Elem_t> (myEye.X()),
1128 static_cast<Elem_t> (myEye.Y()),
1129 static_cast<Elem_t> (myEye.Z()));
1131 NCollection_Vec3<Elem_t> aViewDir (static_cast<Elem_t> (myDirection.X()),
1132 static_cast<Elem_t> (myDirection.Y()),
1133 static_cast<Elem_t> (myDirection.Z()));
1135 NCollection_Vec3<Elem_t> anUp (static_cast<Elem_t> (myUp.X()),
1136 static_cast<Elem_t> (myUp.Y()),
1137 static_cast<Elem_t> (myUp.Z()));
1139 NCollection_Vec3<Elem_t> anAxialScale (static_cast<Elem_t> (myAxialScale.X()),
1140 static_cast<Elem_t> (myAxialScale.Y()),
1141 static_cast<Elem_t> (myAxialScale.Z()));
1143 LookOrientation (anEye, aViewDir, anUp, anAxialScale, theMatrices.Orientation);
1145 return theMatrices; // for inline accessors
1148 // =======================================================================
1149 // function : InvalidateProjection
1151 // =======================================================================
1152 void Graphic3d_Camera::InvalidateProjection()
1154 myMatricesD.ResetProjection();
1155 myMatricesF.ResetProjection();
1156 myWorldViewProjState.ProjectionState() = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
1159 // =======================================================================
1160 // function : InvalidateOrientation
1162 // =======================================================================
1163 void Graphic3d_Camera::InvalidateOrientation()
1165 myMatricesD.ResetOrientation();
1166 myMatricesF.ResetOrientation();
1167 myWorldViewProjState.WorldViewState() = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
1170 // =======================================================================
1171 // function : orthoProj
1173 // =======================================================================
1174 template <typename Elem_t>
1175 void Graphic3d_Camera::orthoProj (NCollection_Mat4<Elem_t>& theOutMx,
1176 const Aspect_FrustumLRBT<Elem_t>& theLRBT,
1177 const Elem_t theNear,
1178 const Elem_t theFar)
1181 theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theLRBT.Right - theLRBT.Left);
1182 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
1183 theOutMx.ChangeValue (0, 2) = Elem_t (0.0);
1184 theOutMx.ChangeValue (0, 3) = - (theLRBT.Right + theLRBT.Left) / (theLRBT.Right - theLRBT.Left);
1187 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
1188 theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theLRBT.Top - theLRBT.Bottom);
1189 theOutMx.ChangeValue (1, 2) = Elem_t (0.0);
1190 theOutMx.ChangeValue (1, 3) = - (theLRBT.Top + theLRBT.Bottom) / (theLRBT.Top - theLRBT.Bottom);
1193 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
1194 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
1195 theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear);
1196 theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear);
1199 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
1200 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
1201 theOutMx.ChangeValue (3, 2) = Elem_t (0.0);
1202 theOutMx.ChangeValue (3, 3) = Elem_t (1.0);
1205 // =======================================================================
1206 // function : PerspectiveProj
1208 // =======================================================================
1209 template <typename Elem_t>
1210 void Graphic3d_Camera::perspectiveProj (NCollection_Mat4<Elem_t>& theOutMx,
1211 const Aspect_FrustumLRBT<Elem_t>& theLRBT,
1212 const Elem_t theNear,
1213 const Elem_t theFar)
1216 theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theLRBT.Right - theLRBT.Left);
1217 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
1218 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
1219 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
1222 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
1223 theOutMx.ChangeValue (1, 1) = (Elem_t (2.0) * theNear) / (theLRBT.Top - theLRBT.Bottom);
1224 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
1225 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
1228 theOutMx.ChangeValue (0, 2) = (theLRBT.Right + theLRBT.Left) / (theLRBT.Right - theLRBT.Left);
1229 theOutMx.ChangeValue (1, 2) = (theLRBT.Top + theLRBT.Bottom) / (theLRBT.Top - theLRBT.Bottom);
1230 theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear);
1231 theOutMx.ChangeValue (3, 2) = Elem_t (-1.0);
1234 theOutMx.ChangeValue (0, 3) = Elem_t (0.0);
1235 theOutMx.ChangeValue (1, 3) = Elem_t (0.0);
1236 theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear);
1237 theOutMx.ChangeValue (3, 3) = Elem_t (0.0);
1240 // =======================================================================
1241 // function : StereoEyeProj
1243 // =======================================================================
1244 template <typename Elem_t>
1245 void Graphic3d_Camera::stereoEyeProj (NCollection_Mat4<Elem_t>& theOutMx,
1246 const Aspect_FrustumLRBT<Elem_t>& theLRBT,
1247 const Elem_t theNear,
1248 const Elem_t theFar,
1249 const Elem_t theIOD,
1250 const Elem_t theZFocus,
1251 const Aspect_Eye theEyeIndex)
1253 Elem_t aDx = theEyeIndex == Aspect_Eye_Left ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD;
1254 Elem_t aDXStereoShift = aDx * theNear / theZFocus;
1256 // construct eye projection matrix
1257 Aspect_FrustumLRBT<Elem_t> aLRBT = theLRBT;
1258 aLRBT.Left = theLRBT.Left + aDXStereoShift;
1259 aLRBT.Right = theLRBT.Right + aDXStereoShift;
1260 perspectiveProj (theOutMx, aLRBT, theNear, theFar);
1262 if (theIOD != Elem_t (0.0))
1264 // X translation to cancel parallax
1265 theOutMx.Translate (NCollection_Vec3<Elem_t> (aDx, Elem_t (0.0), Elem_t (0.0)));
1269 // =======================================================================
1270 // function : LookOrientation
1272 // =======================================================================
1273 template <typename Elem_t>
1274 void Graphic3d_Camera::LookOrientation (const NCollection_Vec3<Elem_t>& theEye,
1275 const NCollection_Vec3<Elem_t>& theFwdDir,
1276 const NCollection_Vec3<Elem_t>& theUpDir,
1277 const NCollection_Vec3<Elem_t>& theAxialScale,
1278 NCollection_Mat4<Elem_t>& theOutMx)
1280 NCollection_Vec3<Elem_t> aForward = theFwdDir;
1281 aForward.Normalize();
1283 // side = forward x up
1284 NCollection_Vec3<Elem_t> aSide = NCollection_Vec3<Elem_t>::Cross (aForward, theUpDir);
1287 // recompute up as: up = side x forward
1288 NCollection_Vec3<Elem_t> anUp = NCollection_Vec3<Elem_t>::Cross (aSide, aForward);
1290 NCollection_Mat4<Elem_t> aLookMx;
1291 aLookMx.SetRow (0, aSide);
1292 aLookMx.SetRow (1, anUp);
1293 aLookMx.SetRow (2, -aForward);
1295 theOutMx.InitIdentity();
1296 theOutMx.Multiply (aLookMx);
1297 theOutMx.Translate (-theEye);
1299 NCollection_Mat4<Elem_t> anAxialScaleMx;
1300 anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x();
1301 anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y();
1302 anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z();
1304 theOutMx.Multiply (anAxialScaleMx);
1307 //=============================================================================
1308 //function : ZFitAll
1310 //=============================================================================
1311 bool Graphic3d_Camera::ZFitAll (const Standard_Real theScaleFactor,
1312 const Bnd_Box& theMinMax,
1313 const Bnd_Box& theGraphicBB,
1314 Standard_Real& theZNear,
1315 Standard_Real& theZFar) const
1317 Standard_ASSERT_RAISE (theScaleFactor > 0.0, "Zero or negative scale factor is not allowed.");
1319 // Method changes zNear and zFar parameters of camera so as to fit graphical structures
1320 // by their graphical boundaries. It precisely fits min max boundaries of primary application
1321 // objects (second argument), while it can sacrifice the real graphical boundaries of the
1322 // scene with infinite or helper objects (third argument) for the sake of perspective projection.
1323 if (theGraphicBB.IsVoid())
1325 theZNear = DEFAULT_ZNEAR;
1326 theZFar = DEFAULT_ZFAR;
1330 // Measure depth of boundary points from camera eye.
1331 NCollection_Sequence<gp_Pnt> aPntsToMeasure;
1333 Standard_Real aGraphicBB[6];
1334 theGraphicBB.Get (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2], aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]);
1336 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2]));
1337 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[5]));
1338 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[2]));
1339 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[5]));
1340 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[2]));
1341 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[5]));
1342 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[2]));
1343 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]));
1345 Standard_Boolean isFiniteMinMax = !theMinMax.IsVoid() && !theMinMax.IsWhole();
1349 Standard_Real aMinMax[6];
1350 theMinMax.Get (aMinMax[0], aMinMax[1], aMinMax[2], aMinMax[3], aMinMax[4], aMinMax[5]);
1352 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[2]));
1353 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[5]));
1354 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[2]));
1355 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[5]));
1356 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[2]));
1357 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[5]));
1358 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[2]));
1359 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[5]));
1362 // Camera eye plane.
1363 gp_Dir aCamDir = Direction();
1364 gp_Pnt aCamEye = myEye;
1365 gp_Pln aCamPln (aCamEye, aCamDir);
1367 Standard_Real aModelMinDist = RealLast();
1368 Standard_Real aModelMaxDist = RealFirst();
1369 Standard_Real aGraphMinDist = RealLast();
1370 Standard_Real aGraphMaxDist = RealFirst();
1372 const gp_XYZ& anAxialScale = myAxialScale;
1374 // Get minimum and maximum distances to the eye plane.
1375 Standard_Integer aCounter = 0;
1376 NCollection_Sequence<gp_Pnt>::Iterator aPntIt(aPntsToMeasure);
1377 for (; aPntIt.More(); aPntIt.Next())
1379 gp_Pnt aMeasurePnt = aPntIt.Value();
1381 aMeasurePnt = gp_Pnt (aMeasurePnt.X() * anAxialScale.X(),
1382 aMeasurePnt.Y() * anAxialScale.Y(),
1383 aMeasurePnt.Z() * anAxialScale.Z());
1385 Standard_Real aDistance = aCamPln.Distance (aMeasurePnt);
1387 // Check if the camera is intruded into the scene.
1388 gp_Vec aVecToMeasurePnt (aCamEye, aMeasurePnt);
1389 if (aVecToMeasurePnt.Magnitude() > gp::Resolution()
1390 && aCamDir.IsOpposite (aVecToMeasurePnt, M_PI * 0.5))
1395 // The first eight points are from theGraphicBB, the last eight points are from theMinMax (can be absent).
1396 Standard_Real& aChangeMinDist = aCounter >= 8 ? aModelMinDist : aGraphMinDist;
1397 Standard_Real& aChangeMaxDist = aCounter >= 8 ? aModelMaxDist : aGraphMaxDist;
1398 aChangeMinDist = Min (aDistance, aChangeMinDist);
1399 aChangeMaxDist = Max (aDistance, aChangeMaxDist);
1403 // Compute depth of bounding box center.
1404 Standard_Real aMidDepth = (aGraphMinDist + aGraphMaxDist) * 0.5;
1405 Standard_Real aHalfDepth = (aGraphMaxDist - aGraphMinDist) * 0.5;
1407 // Compute enlarged or shrank near and far z ranges.
1408 Standard_Real aZNear = aMidDepth - aHalfDepth * theScaleFactor;
1409 Standard_Real aZFar = aMidDepth + aHalfDepth * theScaleFactor;
1411 if (!IsOrthographic())
1413 // Everything is behind the perspective camera.
1414 if (aZFar < zEpsilon())
1416 theZNear = DEFAULT_ZNEAR;
1417 theZFar = DEFAULT_ZFAR;
1423 // Consider clipping errors due to double to single precision floating-point conversion.
1426 // Model to view transformation performs translation of points against eye position
1427 // in three dimensions. Both point coordinate and eye position values are converted from
1428 // double to single precision floating point numbers producing conversion errors.
1429 // Epsilon (Mod) * 3.0 should safely compensate precision error for z coordinate after
1430 // translation assuming that the:
1431 // Epsilon (Eye.Mod()) * 3.0 > Epsilon (Eye.X()) + Epsilon (Eye.Y()) + Epsilon (Eye.Z()).
1432 Standard_Real aEyeConf = 3.0 * zEpsilon (myEye.XYZ().Modulus());
1434 // Model to view transformation performs rotation of points according to view direction.
1435 // New z coordinate is computed as a multiplication of point's x, y, z coordinates by the
1436 // "forward" direction vector's x, y, z coordinates. Both point's and "z" direction vector's
1437 // values are converted from double to single precision floating point numbers producing
1438 // conversion errors.
1439 // Epsilon (Mod) * 6.0 should safely compensate the precision errors for the multiplication
1440 // of point coordinates by direction vector.
1441 gp_Pnt aGraphicMin = theGraphicBB.CornerMin();
1442 gp_Pnt aGraphicMax = theGraphicBB.CornerMax();
1444 Standard_Real aModelConf = 6.0 * zEpsilon (aGraphicMin.XYZ().Modulus()) +
1445 6.0 * zEpsilon (aGraphicMax.XYZ().Modulus());
1447 // Compensate floating point conversion errors by increasing zNear, zFar to avoid clipping.
1448 aZNear -= zEpsilon (aZNear) + aEyeConf + aModelConf;
1449 aZFar += zEpsilon (aZFar) + aEyeConf + aModelConf;
1451 if (!IsOrthographic())
1453 // For perspective projection, the value of z in normalized device coordinates is non-linear
1454 // function of eye z coordinate. For fixed-point depth representation resolution of z in
1455 // model-view space will grow towards zFar plane and its scale depends mostly on how far is zNear
1456 // against camera's eye. The purpose of the code below is to select most appropriate zNear distance
1457 // to balance between clipping (less zNear, more chances to observe closely small models without clipping)
1458 // and resolution of depth. A well applicable criteria to this is a ratio between resolution of z at center
1459 // of model boundaries and the distance to that center point. The ratio is chosen empirically and validated
1460 // by tests database. It is considered to be ~0.001 (0.1%) for 24 bit depth buffer, for less depth bitness
1461 // the zNear will be placed similarly giving lower resolution.
1462 // Approximation of the formula for respectively large z range is:
1463 // zNear = [z * (1 + k) / (k * c)],
1465 // z - distance to center of model boundaries;
1466 // k - chosen ratio, c - capacity of depth buffer;
1467 // k = 0.001, k * c = 1677.216, (1 + k) / (k * c) ~ 5.97E-4
1469 // The function uses center of model boundaries computed from "theMinMax" boundaries (instead of using real
1470 // graphical boundaries of all displayed objects). That means that it can sacrifice resolution of presentation
1471 // of non primary ("infinite") application graphical objects in favor of better perspective projection of the
1472 // small applicative objects measured with "theMinMax" values.
1473 Standard_Real aZRange = isFiniteMinMax ? aModelMaxDist - aModelMinDist : aGraphMaxDist - aGraphMinDist;
1474 Standard_Real aZMin = isFiniteMinMax ? aModelMinDist : aGraphMinDist;
1475 Standard_Real aZ = aZMin < 0 ? aZRange / 2.0 : aZRange / 2.0 + aZMin;
1476 Standard_Real aZNearMin = aZ * 5.97E-4;
1477 if (aZNear < aZNearMin)
1479 // Clip zNear according to the minimum value matching the quality.
1488 // Compensate zNear conversion errors for perspective projection.
1489 aZNear -= aZFar * zEpsilon (aZNear) / (aZFar - zEpsilon (aZNear));
1492 // Compensate zFar conversion errors for perspective projection.
1493 aZFar += zEpsilon (aZFar);
1495 // Ensure that after all the zNear is not a negative value.
1496 if (aZNear < zEpsilon())
1498 aZNear = zEpsilon();
1500 Standard_ASSERT_RAISE (aZFar > aZNear, "ZFar should be greater than ZNear");
1505 Standard_ASSERT_RAISE (aZFar > aZNear, "ZFar should be greater than ZNear");
1509 //=============================================================================
1510 //function : Interpolate
1512 //=============================================================================
1514 Standard_EXPORT void NCollection_Lerp<Handle(Graphic3d_Camera)>::Interpolate (const double theT,
1515 Handle(Graphic3d_Camera)& theCamera) const
1517 if (Abs (theT - 1.0) < Precision::Confusion())
1519 // just copy end-point transformation
1520 theCamera->Copy (myEnd);
1524 theCamera->Copy (myStart);
1525 if (Abs (theT - 0.0) < Precision::Confusion())
1532 gp_Ax3 aCamStart = cameraToAx3 (*myStart);
1533 gp_Ax3 aCamEnd = cameraToAx3 (*myEnd);
1534 gp_Trsf aTrsfStart, aTrsfEnd;
1535 aTrsfStart.SetTransformation (aCamStart, gp::XOY());
1536 aTrsfEnd .SetTransformation (aCamEnd, gp::XOY());
1538 gp_Quaternion aRotStart = aTrsfStart.GetRotation();
1539 gp_Quaternion aRotEnd = aTrsfEnd .GetRotation();
1540 gp_Quaternion aRotDelta = aRotEnd * aRotStart.Inverted();
1541 gp_Quaternion aRot = gp_QuaternionNLerp::Interpolate (gp_Quaternion(), aRotDelta, theT);
1543 aTrsfRot.SetRotation (aRot);
1544 theCamera->Transform (aTrsfRot);
1547 // apply translation
1549 gp_XYZ aCenter = NCollection_Lerp<gp_XYZ>::Interpolate (myStart->Center().XYZ(), myEnd->Center().XYZ(), theT);
1550 gp_XYZ anEye = NCollection_Lerp<gp_XYZ>::Interpolate (myStart->Eye().XYZ(), myEnd->Eye().XYZ(), theT);
1551 gp_XYZ anAnchor = aCenter;
1552 Standard_Real aKc = 0.0;
1554 const Standard_Real aDeltaCenter = myStart->Center().Distance (myEnd->Center());
1555 const Standard_Real aDeltaEye = myStart->Eye() .Distance (myEnd->Eye());
1556 if (aDeltaEye <= gp::Resolution())
1561 else if (aDeltaCenter > gp::Resolution())
1563 aKc = aDeltaCenter / (aDeltaCenter + aDeltaEye);
1565 const gp_XYZ anAnchorStart = NCollection_Lerp<gp_XYZ>::Interpolate (myStart->Center().XYZ(), myStart->Eye().XYZ(), aKc);
1566 const gp_XYZ anAnchorEnd = NCollection_Lerp<gp_XYZ>::Interpolate (myEnd ->Center().XYZ(), myEnd ->Eye().XYZ(), aKc);
1567 anAnchor = NCollection_Lerp<gp_XYZ>::Interpolate (anAnchorStart, anAnchorEnd, theT);
1570 const gp_Vec aDirEyeToCenter = theCamera->Direction();
1571 const Standard_Real aDistEyeCenterStart = myStart->Eye().Distance (myStart->Center());
1572 const Standard_Real aDistEyeCenterEnd = myEnd ->Eye().Distance (myEnd ->Center());
1573 const Standard_Real aDistEyeCenter = NCollection_Lerp<Standard_Real>::Interpolate (aDistEyeCenterStart, aDistEyeCenterEnd, theT);
1574 aCenter = anAnchor + aDirEyeToCenter.XYZ() * aDistEyeCenter * aKc;
1575 anEye = anAnchor - aDirEyeToCenter.XYZ() * aDistEyeCenter * (1.0 - aKc);
1577 theCamera->SetEyeAndCenter (anEye, aCenter);
1581 if (Abs(myStart->Scale() - myEnd->Scale()) > Precision::Confusion()
1582 && myStart->IsOrthographic())
1584 const Standard_Real aScale = NCollection_Lerp<Standard_Real>::Interpolate (myStart->Scale(), myEnd->Scale(), theT);
1585 theCamera->SetScale (aScale);
1589 //=======================================================================
1590 //function : FrustumPoints
1592 //=======================================================================
1593 void Graphic3d_Camera::FrustumPoints (NCollection_Array1<Graphic3d_Vec3d>& thePoints,
1594 const Graphic3d_Mat4d& theModelWorld) const
1596 if (thePoints.Length() != FrustumVerticesNB)
1598 thePoints.Resize (0, FrustumVerticesNB, Standard_False);
1601 const Graphic3d_Mat4d& aProjectionMat = ProjectionMatrix();
1602 const Graphic3d_Mat4d aWorldViewMat = OrientationMatrix() * theModelWorld;
1604 Standard_Real nLeft = 0.0, nRight = 0.0, nTop = 0.0, nBottom = 0.0;
1605 Standard_Real fLeft = 0.0, fRight = 0.0, fTop = 0.0, fBottom = 0.0;
1606 Standard_Real aNear = 0.0, aFar = 0.0;
1607 if (!IsOrthographic())
1609 // handle perspective projection
1610 aNear = aProjectionMat.GetValue (2, 3) / (-1.0 + aProjectionMat.GetValue (2, 2));
1611 aFar = aProjectionMat.GetValue (2, 3) / ( 1.0 + aProjectionMat.GetValue (2, 2));
1613 nLeft = aNear * (aProjectionMat.GetValue (0, 2) - 1.0) / aProjectionMat.GetValue (0, 0);
1614 nRight = aNear * (aProjectionMat.GetValue (0, 2) + 1.0) / aProjectionMat.GetValue (0, 0);
1615 nTop = aNear * (aProjectionMat.GetValue (1, 2) + 1.0) / aProjectionMat.GetValue (1, 1);
1616 nBottom = aNear * (aProjectionMat.GetValue (1, 2) - 1.0) / aProjectionMat.GetValue (1, 1);
1618 fLeft = aFar * (aProjectionMat.GetValue (0, 2) - 1.0) / aProjectionMat.GetValue (0, 0);
1619 fRight = aFar * (aProjectionMat.GetValue (0, 2) + 1.0) / aProjectionMat.GetValue (0, 0);
1620 fTop = aFar * (aProjectionMat.GetValue (1, 2) + 1.0) / aProjectionMat.GetValue (1, 1);
1621 fBottom = aFar * (aProjectionMat.GetValue (1, 2) - 1.0) / aProjectionMat.GetValue (1, 1);
1625 // handle orthographic projection
1626 aNear = (1.0 / aProjectionMat.GetValue (2, 2)) * (aProjectionMat.GetValue (2, 3) + 1.0);
1627 aFar = (1.0 / aProjectionMat.GetValue (2, 2)) * (aProjectionMat.GetValue (2, 3) - 1.0);
1629 nLeft = ( 1.0 + aProjectionMat.GetValue (0, 3)) / (-aProjectionMat.GetValue (0, 0));
1631 nRight = ( 1.0 - aProjectionMat.GetValue (0, 3)) / aProjectionMat.GetValue (0, 0);
1633 nTop = ( 1.0 - aProjectionMat.GetValue (1, 3)) / aProjectionMat.GetValue (1, 1);
1635 nBottom = (-1.0 - aProjectionMat.GetValue (1, 3)) / aProjectionMat.GetValue (1, 1);
1639 Graphic3d_Vec4d aLeftTopNear (nLeft, nTop, -aNear, 1.0), aRightBottomFar (fRight, fBottom, -aFar, 1.0);
1640 Graphic3d_Vec4d aLeftBottomNear (nLeft, nBottom, -aNear, 1.0), aRightTopFar (fRight, fTop, -aFar, 1.0);
1641 Graphic3d_Vec4d aRightBottomNear (nRight, nBottom, -aNear, 1.0), aLeftTopFar (fLeft, fTop, -aFar, 1.0);
1642 Graphic3d_Vec4d aRightTopNear (nRight, nTop, -aNear, 1.0), aLeftBottomFar (fLeft, fBottom, -aFar, 1.0);
1644 Graphic3d_Mat4d anInvWorldView;
1645 aWorldViewMat.Inverted (anInvWorldView);
1647 Graphic3d_Vec4d aTmpPnt;
1648 aTmpPnt = anInvWorldView * aLeftTopNear;
1649 thePoints.SetValue (FrustumVert_LeftTopNear, aTmpPnt.xyz() / aTmpPnt.w());
1650 aTmpPnt = anInvWorldView * aRightBottomFar;
1651 thePoints.SetValue (FrustumVert_RightBottomFar, aTmpPnt.xyz() / aTmpPnt.w());
1652 aTmpPnt = anInvWorldView * aLeftBottomNear;
1653 thePoints.SetValue (FrustumVert_LeftBottomNear, aTmpPnt.xyz() / aTmpPnt.w());
1654 aTmpPnt = anInvWorldView * aRightTopFar;
1655 thePoints.SetValue (FrustumVert_RightTopFar, aTmpPnt.xyz() / aTmpPnt.w());
1656 aTmpPnt = anInvWorldView * aRightBottomNear;
1657 thePoints.SetValue (FrustumVert_RightBottomNear, aTmpPnt.xyz() / aTmpPnt.w());
1658 aTmpPnt = anInvWorldView * aLeftTopFar;
1659 thePoints.SetValue (FrustumVert_LeftTopFar, aTmpPnt.xyz() / aTmpPnt.w());
1660 aTmpPnt = anInvWorldView * aRightTopNear;
1661 thePoints.SetValue (FrustumVert_RightTopNear, aTmpPnt.xyz() / aTmpPnt.w());
1662 aTmpPnt = anInvWorldView * aLeftBottomFar;
1663 thePoints.SetValue (FrustumVert_LeftBottomFar, aTmpPnt.xyz() / aTmpPnt.w());
1666 //=======================================================================
1667 //function : DumpJson
1669 //=======================================================================
1670 void Graphic3d_Camera::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
1672 OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
1674 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myUp)
1675 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myDirection)
1676 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myEye)
1678 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDistance)