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.
17 #include <Standard_ShortReal.hxx>
19 #include <Graphic3d_Vec4.hxx>
20 #include <Graphic3d_Camera.hxx>
22 #include <Standard_Atomic.hxx>
23 #include <Standard_Assert.hxx>
25 #include <NCollection_Sequence.hxx>
30 // (degrees -> radians) * 0.5
31 static const Standard_Real DTR_HALF = 0.5 * 0.0174532925;
33 // default property values
34 static const Standard_Real DEFAULT_ZNEAR = 0.001;
35 static const Standard_Real DEFAULT_ZFAR = 3000.0;
37 // atomic state counter
38 static volatile Standard_Integer THE_STATE_COUNTER = 0;
40 // minimum camera distance
41 static const Standard_Real MIN_DISTANCE = Pow (0.1, ShortRealDigits() - 2);
43 // z-range tolerance compatible with for floating point.
44 static Standard_Real zEpsilon()
49 // relative z-range tolerance compatible with for floating point.
50 static Standard_Real zEpsilon (const Standard_Real theValue)
56 Standard_Real aLogRadix = Log10 (Abs (theValue)) / Log10 (FLT_RADIX);
57 Standard_Real aExp = Floor (aLogRadix);
58 return FLT_EPSILON * Pow (FLT_RADIX, aExp);
62 // =======================================================================
63 // function : Graphic3d_Camera
65 // =======================================================================
66 Graphic3d_Camera::Graphic3d_Camera()
67 : myUp (0.0, 1.0, 0.0),
68 myEye (0.0, 0.0, -1500.0),
69 myCenter (0.0, 0.0, 0.0),
70 myAxialScale (1.0, 1.0, 1.0),
71 myProjType (Projection_Orthographic),
73 myZNear (DEFAULT_ZNEAR),
74 myZFar (DEFAULT_ZFAR),
78 myZFocusType (FocusType_Relative),
80 myIODType (IODType_Relative)
82 myProjectionState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
83 myOrientationState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
86 // =======================================================================
87 // function : Graphic3d_Camera
89 // =======================================================================
90 Graphic3d_Camera::Graphic3d_Camera (const Handle(Graphic3d_Camera)& theOther)
95 // =======================================================================
96 // function : CopyMappingData
98 // =======================================================================
99 void Graphic3d_Camera::CopyMappingData (const Handle(Graphic3d_Camera)& theOtherCamera)
101 myFOVy = theOtherCamera->myFOVy;
102 myZNear = theOtherCamera->myZNear;
103 myZFar = theOtherCamera->myZFar;
104 myAspect = theOtherCamera->myAspect;
105 myScale = theOtherCamera->myScale;
106 myZFocus = theOtherCamera->myZFocus;
107 myZFocusType = theOtherCamera->myZFocusType;
108 myIOD = theOtherCamera->myIOD;
109 myIODType = theOtherCamera->myIODType;
110 myProjType = theOtherCamera->myProjType;
111 myProjectionState = theOtherCamera->myProjectionState;
113 InvalidateProjection();
116 // =======================================================================
117 // function : CopyOrientationData
119 // =======================================================================
120 void Graphic3d_Camera::CopyOrientationData (const Handle(Graphic3d_Camera)& theOtherCamera)
122 myUp = theOtherCamera->myUp;
123 myEye = theOtherCamera->myEye;
124 myCenter = theOtherCamera->myCenter;
125 myAxialScale = theOtherCamera->myAxialScale;
126 myOrientationState = theOtherCamera->myOrientationState;
128 InvalidateOrientation();
131 // =======================================================================
134 // =======================================================================
135 void Graphic3d_Camera::Copy (const Handle(Graphic3d_Camera)& theOther)
137 CopyMappingData (theOther);
138 CopyOrientationData (theOther);
141 // =======================================================================
144 // =======================================================================
145 void Graphic3d_Camera::SetEye (const gp_Pnt& theEye)
148 InvalidateOrientation();
151 // =======================================================================
152 // function : SetCenter
154 // =======================================================================
155 void Graphic3d_Camera::SetCenter (const gp_Pnt& theCenter)
157 myCenter = theCenter;
158 InvalidateOrientation();
161 // =======================================================================
164 // =======================================================================
165 void Graphic3d_Camera::SetUp (const gp_Dir& theUp)
168 InvalidateOrientation();
171 // =======================================================================
172 // function : SetAxialScale
174 // =======================================================================
175 void Graphic3d_Camera::SetAxialScale (const gp_XYZ& theAxialScale)
177 myAxialScale = theAxialScale;
178 InvalidateOrientation();
181 // =======================================================================
182 // function : SetDistance
184 // =======================================================================
185 void Graphic3d_Camera::SetDistance (const Standard_Real theDistance)
187 gp_Vec aCenter2Eye (Direction());
188 aCenter2Eye.Reverse();
190 // Camera should have non-zero distance.
191 aCenter2Eye.Scale (Max (theDistance, MIN_DISTANCE));
192 SetEye (Center().Translated (aCenter2Eye));
195 // =======================================================================
196 // function : Distance
198 // =======================================================================
199 Standard_Real Graphic3d_Camera::Distance() const
201 return myEye.Distance (myCenter);
204 // =======================================================================
205 // function : SetDirection
207 // =======================================================================
208 void Graphic3d_Camera::SetDirection (const gp_Dir& theDir)
210 gp_Vec aScaledDir (theDir);
211 aScaledDir.Scale (Distance());
212 aScaledDir.Reverse();
213 SetEye (Center().Translated (aScaledDir));
216 // =======================================================================
217 // function : Direction
219 // =======================================================================
220 gp_Dir Graphic3d_Camera::Direction() const
222 return gp_Dir (gp_Vec (myEye, myCenter));
225 // =======================================================================
226 // function : SetScale
228 // =======================================================================
229 void Graphic3d_Camera::SetScale (const Standard_Real theScale)
235 case Projection_Perspective :
236 case Projection_Stereo :
237 case Projection_MonoLeftEye :
238 case Projection_MonoRightEye :
240 Standard_Real aDistance = theScale * 0.5 / Tan(myFOVy * M_PI / 360.0);
241 SetDistance (aDistance);
248 InvalidateProjection();
251 // =======================================================================
254 // =======================================================================
255 Standard_Real Graphic3d_Camera::Scale() const
259 case Projection_Orthographic :
262 // case Projection_Perspective :
263 // case Projection_Stereo :
264 // case Projection_MonoLeftEye :
265 // case Projection_MonoRightEye :
267 return Distance() * 2.0 * Tan (myFOVy * M_PI / 360.0);
271 // =======================================================================
272 // function : SetProjectionType
274 // =======================================================================
275 void Graphic3d_Camera::SetProjectionType (const Projection theProjectionType)
277 Projection anOldType = myProjType;
279 if (anOldType == theProjectionType)
284 if (anOldType == Projection_Orthographic)
286 if (myZNear <= RealEpsilon())
288 myZNear = DEFAULT_ZNEAR;
290 if (myZFar <= RealEpsilon())
292 myZFar = DEFAULT_ZFAR;
296 myProjType = theProjectionType;
298 InvalidateProjection();
301 // =======================================================================
302 // function : SetFOVy
304 // =======================================================================
305 void Graphic3d_Camera::SetFOVy (const Standard_Real theFOVy)
308 InvalidateProjection();
311 // =======================================================================
312 // function : SetZRange
314 // =======================================================================
315 void Graphic3d_Camera::SetZRange (const Standard_Real theZNear,
316 const Standard_Real theZFar)
318 Standard_ASSERT_RAISE (theZFar > theZNear, "ZFar should be greater than ZNear");
319 if (!IsOrthographic())
321 Standard_ASSERT_RAISE (theZNear > 0.0, "Only positive Z-Near is allowed for perspective camera");
322 Standard_ASSERT_RAISE (theZFar > 0.0, "Only positive Z-Far is allowed for perspective camera");
328 InvalidateProjection();
331 // =======================================================================
332 // function : SetAspect
334 // =======================================================================
335 void Graphic3d_Camera::SetAspect (const Standard_Real theAspect)
337 myAspect = theAspect;
338 InvalidateProjection();
341 // =======================================================================
342 // function : SetZFocus
344 // =======================================================================
345 void Graphic3d_Camera::SetZFocus(const FocusType theType, const Standard_Real theZFocus)
347 myZFocusType = theType;
348 myZFocus = theZFocus;
349 InvalidateProjection();
352 // =======================================================================
355 // =======================================================================
356 void Graphic3d_Camera::SetIOD (const IODType theType, const Standard_Real theIOD)
360 InvalidateProjection();
363 // =======================================================================
364 // function : OrthogonalizeUp
366 // =======================================================================
367 void Graphic3d_Camera::OrthogonalizeUp()
369 SetUp (OrthogonalizedUp());
372 // =======================================================================
373 // function : OrthogonalizedUp
375 // =======================================================================
376 gp_Dir Graphic3d_Camera::OrthogonalizedUp() const
378 gp_Dir aDir = Direction();
379 gp_Dir aLeft = aDir.Crossed (Up());
381 // recompute up as: up = left x direction
382 return aLeft.Crossed (aDir);
385 // =======================================================================
386 // function : Transform
388 // =======================================================================
389 void Graphic3d_Camera::Transform (const gp_Trsf& theTrsf)
391 myUp.Transform (theTrsf);
392 myEye.Transform (theTrsf);
393 myCenter.Transform (theTrsf);
394 InvalidateOrientation();
397 // =======================================================================
398 // function : safePointCast
400 // =======================================================================
401 static Graphic3d_Vec4d safePointCast (const gp_Pnt& thePnt)
403 Standard_Real aLim = 1e15f;
405 // have to deal with values greater then max float
406 gp_Pnt aSafePoint = thePnt;
407 const Standard_Real aBigFloat = aLim * 0.1f;
408 if (Abs (aSafePoint.X()) > aLim)
409 aSafePoint.SetX (aSafePoint.X() >= 0 ? aBigFloat : -aBigFloat);
410 if (Abs (aSafePoint.Y()) > aLim)
411 aSafePoint.SetY (aSafePoint.Y() >= 0 ? aBigFloat : -aBigFloat);
412 if (Abs (aSafePoint.Z()) > aLim)
413 aSafePoint.SetZ (aSafePoint.Z() >= 0 ? aBigFloat : -aBigFloat);
416 Graphic3d_Vec4d aPnt (aSafePoint.X(), aSafePoint.Y(), aSafePoint.Z(), 1.0);
421 // =======================================================================
422 // function : Project
424 // =======================================================================
425 gp_Pnt Graphic3d_Camera::Project (const gp_Pnt& thePnt) const
427 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
428 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
430 // use compatible type of point
431 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
433 aPnt = aViewMx * aPnt; // convert to view coordinate space
434 aPnt = aProjMx * aPnt; // convert to projection coordinate space
436 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
438 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
441 // =======================================================================
442 // function : UnProject
444 // =======================================================================
445 gp_Pnt Graphic3d_Camera::UnProject (const gp_Pnt& thePnt) const
447 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
448 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
450 Graphic3d_Mat4d aInvView;
451 Graphic3d_Mat4d aInvProj;
453 // this case should never happen
454 if (!aViewMx.Inverted (aInvView) || !aProjMx.Inverted (aInvProj))
456 return gp_Pnt (0.0, 0.0, 0.0);
459 // use compatible type of point
460 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
462 aPnt = aInvProj * aPnt; // convert to view coordinate space
463 aPnt = aInvView * aPnt; // convert to world coordinate space
465 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
467 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
470 // =======================================================================
471 // function : ConvertView2Proj
473 // =======================================================================
474 gp_Pnt Graphic3d_Camera::ConvertView2Proj (const gp_Pnt& thePnt) const
476 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
478 // use compatible type of point
479 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
481 aPnt = aProjMx * aPnt; // convert to projection coordinate space
483 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
485 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
488 // =======================================================================
489 // function : ConvertProj2View
491 // =======================================================================
492 gp_Pnt Graphic3d_Camera::ConvertProj2View (const gp_Pnt& thePnt) const
494 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
496 Graphic3d_Mat4d aInvProj;
498 // this case should never happen, but...
499 if (!aProjMx.Inverted (aInvProj))
501 return gp_Pnt (0, 0, 0);
504 // use compatible type of point
505 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
507 aPnt = aInvProj * aPnt; // convert to view coordinate space
509 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
511 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
514 // =======================================================================
515 // function : ConvertWorld2View
517 // =======================================================================
518 gp_Pnt Graphic3d_Camera::ConvertWorld2View (const gp_Pnt& thePnt) const
520 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
522 // use compatible type of point
523 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
525 aPnt = aViewMx * aPnt; // convert to view coordinate space
527 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
529 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
532 // =======================================================================
533 // function : ConvertView2World
535 // =======================================================================
536 gp_Pnt Graphic3d_Camera::ConvertView2World (const gp_Pnt& thePnt) const
538 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
540 Graphic3d_Mat4d aInvView;
542 if (!aViewMx.Inverted (aInvView))
544 return gp_Pnt(0, 0, 0);
547 // use compatible type of point
548 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
550 aPnt = aInvView * aPnt; // convert to world coordinate space
552 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
554 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
557 // =======================================================================
558 // function : ViewDimensions
560 // =======================================================================
561 gp_XYZ Graphic3d_Camera::ViewDimensions() const
563 // view plane dimensions
564 Standard_Real aSize = IsOrthographic() ? myScale : (2.0 * Distance() * Tan (DTR_HALF * myFOVy));
565 Standard_Real aSizeX, aSizeY;
568 aSizeX = aSize * myAspect;
574 aSizeY = aSize / myAspect;
578 return gp_XYZ (aSizeX, aSizeY, myZFar - myZNear);
581 // =======================================================================
582 // function : Frustum
584 // =======================================================================
585 void Graphic3d_Camera::Frustum (gp_Pln& theLeft,
590 gp_Pln& theFar) const
592 gp_Vec aProjection = gp_Vec (Direction());
593 gp_Vec anUp = OrthogonalizedUp();
594 gp_Vec aSide = aProjection ^ anUp;
596 Standard_ASSERT_RAISE (
597 !aProjection.IsParallel (anUp, Precision::Angular()),
598 "Can not derive SIDE = PROJ x UP - directions are parallel");
600 theNear = gp_Pln (Eye().Translated (aProjection * ZNear()), aProjection);
601 theFar = gp_Pln (Eye().Translated (aProjection * ZFar()), -aProjection);
603 Standard_Real aHScaleHor = Scale() * 0.5 * Aspect();
604 Standard_Real aHScaleVer = Scale() * 0.5;
606 gp_Pnt aPntLeft = Center().Translated (aHScaleHor * -aSide);
607 gp_Pnt aPntRight = Center().Translated (aHScaleHor * aSide);
608 gp_Pnt aPntBottom = Center().Translated (aHScaleVer * -anUp);
609 gp_Pnt aPntTop = Center().Translated (aHScaleVer * anUp);
611 gp_Vec aDirLeft = aSide;
612 gp_Vec aDirRight = -aSide;
613 gp_Vec aDirBottom = anUp;
614 gp_Vec aDirTop = -anUp;
615 if (!IsOrthographic())
617 Standard_Real aHFOVHor = ATan (Tan (DTR_HALF * FOVy()) * Aspect());
618 Standard_Real aHFOVVer = DTR_HALF * FOVy();
619 aDirLeft.Rotate (gp_Ax1 (gp::Origin(), anUp), aHFOVHor);
620 aDirRight.Rotate (gp_Ax1 (gp::Origin(), anUp), -aHFOVHor);
621 aDirBottom.Rotate (gp_Ax1 (gp::Origin(), aSide), -aHFOVVer);
622 aDirTop.Rotate (gp_Ax1 (gp::Origin(), aSide), aHFOVVer);
625 theLeft = gp_Pln (aPntLeft, aDirLeft);
626 theRight = gp_Pln (aPntRight, aDirRight);
627 theBottom = gp_Pln (aPntBottom, aDirBottom);
628 theTop = gp_Pln (aPntTop, aDirTop);
631 // =======================================================================
632 // function : OrientationMatrix
634 // =======================================================================
635 const Graphic3d_Mat4d& Graphic3d_Camera::OrientationMatrix() const
637 return *UpdateOrientation (myMatricesD).Orientation;
640 // =======================================================================
641 // function : OrientationMatrixF
643 // =======================================================================
644 const Graphic3d_Mat4& Graphic3d_Camera::OrientationMatrixF() const
646 return *UpdateOrientation (myMatricesF).Orientation;
649 // =======================================================================
650 // function : ProjectionMatrix
652 // =======================================================================
653 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionMatrix() const
655 return *UpdateProjection (myMatricesD).MProjection;
658 // =======================================================================
659 // function : ProjectionMatrixF
661 // =======================================================================
662 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionMatrixF() const
664 return *UpdateProjection (myMatricesF).MProjection;
667 // =======================================================================
668 // function : ProjectionStereoLeft
670 // =======================================================================
671 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoLeft() const
673 return *UpdateProjection (myMatricesD).LProjection;
676 // =======================================================================
677 // function : ProjectionStereoLeftF
679 // =======================================================================
680 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoLeftF() const
682 return *UpdateProjection (myMatricesF).LProjection;
685 // =======================================================================
686 // function : ProjectionStereoRight
688 // =======================================================================
689 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoRight() const
691 return *UpdateProjection (myMatricesD).RProjection;
694 // =======================================================================
695 // function : ProjectionStereoRightF
697 // =======================================================================
698 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoRightF() const
700 return *UpdateProjection (myMatricesF).RProjection;
703 // =======================================================================
704 // function : UpdateProjection
706 // =======================================================================
707 template <typename Elem_t>
708 Graphic3d_Camera::TransformMatrices<Elem_t>&
709 Graphic3d_Camera::UpdateProjection (TransformMatrices<Elem_t>& theMatrices) const
711 if (theMatrices.IsProjectionValid())
713 return theMatrices; // for inline accessors
716 theMatrices.InitProjection();
718 // sets top of frustum based on FOVy and near clipping plane
719 Elem_t aScale = static_cast<Elem_t> (myScale);
720 Elem_t aZNear = static_cast<Elem_t> (myZNear);
721 Elem_t aZFar = static_cast<Elem_t> (myZFar);
722 Elem_t anAspect = static_cast<Elem_t> (myAspect);
723 Elem_t aDXHalf = 0.0, aDYHalf = 0.0;
724 if (IsOrthographic())
726 aDXHalf = aScale * Elem_t (0.5);
727 aDYHalf = aScale * Elem_t (0.5);
731 aDXHalf = aZNear * Elem_t (Tan (DTR_HALF * myFOVy));
732 aDYHalf = aZNear * Elem_t (Tan (DTR_HALF * myFOVy));
744 // sets right of frustum based on aspect ratio
745 Elem_t aLeft = -aDXHalf;
746 Elem_t aRight = aDXHalf;
747 Elem_t aBot = -aDYHalf;
748 Elem_t aTop = aDYHalf;
750 Elem_t aIOD = myIODType == IODType_Relative
751 ? static_cast<Elem_t> (myIOD * Distance())
752 : static_cast<Elem_t> (myIOD);
754 Elem_t aFocus = myZFocusType == FocusType_Relative
755 ? static_cast<Elem_t> (myZFocus * Distance())
756 : static_cast<Elem_t> (myZFocus);
760 case Projection_Orthographic :
761 OrthoProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
764 case Projection_Perspective :
765 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
768 case Projection_MonoLeftEye :
770 StereoEyeProj (aLeft, aRight, aBot, aTop,
771 aZNear, aZFar, aIOD, aFocus,
772 Standard_True, *theMatrices.MProjection);
773 *theMatrices.LProjection = *theMatrices.MProjection;
777 case Projection_MonoRightEye :
779 StereoEyeProj (aLeft, aRight, aBot, aTop,
780 aZNear, aZFar, aIOD, aFocus,
781 Standard_False, *theMatrices.MProjection);
782 *theMatrices.RProjection = *theMatrices.MProjection;
786 case Projection_Stereo :
788 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
790 StereoEyeProj (aLeft, aRight, aBot, aTop,
791 aZNear, aZFar, aIOD, aFocus,
793 *theMatrices.LProjection);
795 StereoEyeProj (aLeft, aRight, aBot, aTop,
796 aZNear, aZFar, aIOD, aFocus,
798 *theMatrices.RProjection);
803 return theMatrices; // for inline accessors
806 // =======================================================================
807 // function : UpdateOrientation
809 // =======================================================================
810 template <typename Elem_t>
811 Graphic3d_Camera::TransformMatrices<Elem_t>&
812 Graphic3d_Camera::UpdateOrientation (TransformMatrices<Elem_t>& theMatrices) const
814 if (theMatrices.IsOrientationValid())
816 return theMatrices; // for inline accessors
819 theMatrices.InitOrientation();
821 NCollection_Vec3<Elem_t> anEye (static_cast<Elem_t> (myEye.X()),
822 static_cast<Elem_t> (myEye.Y()),
823 static_cast<Elem_t> (myEye.Z()));
825 NCollection_Vec3<Elem_t> aCenter (static_cast<Elem_t> (myCenter.X()),
826 static_cast<Elem_t> (myCenter.Y()),
827 static_cast<Elem_t> (myCenter.Z()));
829 NCollection_Vec3<Elem_t> anUp (static_cast<Elem_t> (myUp.X()),
830 static_cast<Elem_t> (myUp.Y()),
831 static_cast<Elem_t> (myUp.Z()));
833 NCollection_Vec3<Elem_t> anAxialScale (static_cast<Elem_t> (myAxialScale.X()),
834 static_cast<Elem_t> (myAxialScale.Y()),
835 static_cast<Elem_t> (myAxialScale.Z()));
837 LookOrientation (anEye, aCenter, anUp, anAxialScale, *theMatrices.Orientation);
839 return theMatrices; // for inline accessors
842 // =======================================================================
843 // function : InvalidateProjection
845 // =======================================================================
846 void Graphic3d_Camera::InvalidateProjection()
848 myMatricesD.ResetProjection();
849 myMatricesF.ResetProjection();
850 myProjectionState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
853 // =======================================================================
854 // function : InvalidateOrientation
856 // =======================================================================
857 void Graphic3d_Camera::InvalidateOrientation()
859 myMatricesD.ResetOrientation();
860 myMatricesF.ResetOrientation();
861 myOrientationState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
864 // =======================================================================
865 // function : OrthoProj
867 // =======================================================================
868 template <typename Elem_t>
869 void Graphic3d_Camera::OrthoProj (const Elem_t theLeft,
870 const Elem_t theRight,
871 const Elem_t theBottom,
873 const Elem_t theNear,
875 NCollection_Mat4<Elem_t>& theOutMx)
878 theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theRight - theLeft);
879 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
880 theOutMx.ChangeValue (0, 2) = Elem_t (0.0);
881 theOutMx.ChangeValue (0, 3) = - (theRight + theLeft) / (theRight - theLeft);
884 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
885 theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theTop - theBottom);
886 theOutMx.ChangeValue (1, 2) = Elem_t (0.0);
887 theOutMx.ChangeValue (1, 3) = - (theTop + theBottom) / (theTop - theBottom);
890 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
891 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
892 theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear);
893 theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear);
896 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
897 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
898 theOutMx.ChangeValue (3, 2) = Elem_t (0.0);
899 theOutMx.ChangeValue (3, 3) = Elem_t (1.0);
902 // =======================================================================
903 // function : PerspectiveProj
905 // =======================================================================
906 template <typename Elem_t>
907 void Graphic3d_Camera::PerspectiveProj (const Elem_t theLeft,
908 const Elem_t theRight,
909 const Elem_t theBottom,
911 const Elem_t theNear,
913 NCollection_Mat4<Elem_t>& theOutMx)
916 theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theRight - theLeft);
917 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
918 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
919 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
922 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
923 theOutMx.ChangeValue (1, 1) = (Elem_t (2.0) * theNear) / (theTop - theBottom);
924 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
925 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
928 theOutMx.ChangeValue (0, 2) = (theRight + theLeft) / (theRight - theLeft);
929 theOutMx.ChangeValue (1, 2) = (theTop + theBottom) / (theTop - theBottom);
930 theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear);
931 theOutMx.ChangeValue (3, 2) = Elem_t (-1.0);
934 theOutMx.ChangeValue (0, 3) = Elem_t (0.0);
935 theOutMx.ChangeValue (1, 3) = Elem_t (0.0);
936 theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear);
937 theOutMx.ChangeValue (3, 3) = Elem_t (0.0);
940 // =======================================================================
941 // function : StereoEyeProj
943 // =======================================================================
944 template <typename Elem_t>
945 void Graphic3d_Camera::StereoEyeProj (const Elem_t theLeft,
946 const Elem_t theRight,
947 const Elem_t theBottom,
949 const Elem_t theNear,
952 const Elem_t theZFocus,
953 const Standard_Boolean theIsLeft,
954 NCollection_Mat4<Elem_t>& theOutMx)
956 Elem_t aDx = theIsLeft ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD;
957 Elem_t aDXStereoShift = aDx * theNear / theZFocus;
959 // construct eye projection matrix
960 PerspectiveProj (theLeft + aDXStereoShift,
961 theRight + aDXStereoShift,
962 theBottom, theTop, theNear, theFar,
965 if (theIOD != Elem_t (0.0))
967 // X translation to cancel parallax
968 theOutMx.Translate (NCollection_Vec3<Elem_t> (aDx, Elem_t (0.0), Elem_t (0.0)));
972 // =======================================================================
973 // function : LookOrientation
975 // =======================================================================
976 template <typename Elem_t>
977 void Graphic3d_Camera::LookOrientation (const NCollection_Vec3<Elem_t>& theEye,
978 const NCollection_Vec3<Elem_t>& theLookAt,
979 const NCollection_Vec3<Elem_t>& theUpDir,
980 const NCollection_Vec3<Elem_t>& theAxialScale,
981 NCollection_Mat4<Elem_t>& theOutMx)
983 NCollection_Vec3<Elem_t> aForward = theLookAt - theEye;
984 aForward.Normalize();
986 // side = forward x up
987 NCollection_Vec3<Elem_t> aSide = NCollection_Vec3<Elem_t>::Cross (aForward, theUpDir);
990 // recompute up as: up = side x forward
991 NCollection_Vec3<Elem_t> anUp = NCollection_Vec3<Elem_t>::Cross (aSide, aForward);
993 NCollection_Mat4<Elem_t> aLookMx;
994 aLookMx.SetRow (0, aSide);
995 aLookMx.SetRow (1, anUp);
996 aLookMx.SetRow (2, -aForward);
998 theOutMx.InitIdentity();
999 theOutMx.Multiply (aLookMx);
1000 theOutMx.Translate (-theEye);
1002 NCollection_Mat4<Elem_t> anAxialScaleMx;
1003 anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x();
1004 anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y();
1005 anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z();
1007 theOutMx.Multiply (anAxialScaleMx);
1010 //=============================================================================
1011 //function : ZFitAll
1013 //=============================================================================
1014 void Graphic3d_Camera::ZFitAll (const Standard_Real theScaleFactor, const Bnd_Box& theMinMax, const Bnd_Box& theGraphicBB)
1016 Standard_ASSERT_RAISE (theScaleFactor > 0.0, "Zero or negative scale factor is not allowed.");
1018 // Method changes zNear and zFar parameters of camera so as to fit graphical structures
1019 // by their graphical boundaries. It precisely fits min max boundaries of primary application
1020 // objects (second argument), while it can sacrifice the real graphical boundaries of the
1021 // scene with infinite or helper objects (third argument) for the sake of perspective projection.
1022 if (theGraphicBB.IsVoid())
1024 SetZRange (DEFAULT_ZNEAR, DEFAULT_ZFAR);
1028 // Measure depth of boundary points from camera eye.
1029 NCollection_Sequence<gp_Pnt> aPntsToMeasure;
1031 Standard_Real aGraphicBB[6];
1032 theGraphicBB.Get (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2], aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]);
1034 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2]));
1035 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[5]));
1036 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[2]));
1037 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[5]));
1038 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[2]));
1039 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[5]));
1040 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[2]));
1041 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]));
1043 if (!theMinMax.IsVoid() && !theMinMax.IsWhole())
1045 Standard_Real aMinMax[6];
1046 theMinMax.Get (aMinMax[0], aMinMax[1], aMinMax[2], aMinMax[3], aMinMax[4], aMinMax[5]);
1048 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[2]));
1049 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[5]));
1050 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[2]));
1051 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[5]));
1052 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[2]));
1053 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[5]));
1054 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[2]));
1055 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[5]));
1058 // Camera eye plane.
1059 gp_Dir aCamDir = Direction();
1060 gp_Pnt aCamEye = myEye;
1061 gp_Pln aCamPln (aCamEye, aCamDir);
1063 Standard_Real aModelMinDist = RealLast();
1064 Standard_Real aModelMaxDist = RealFirst();
1065 Standard_Real aGraphicMinDist = RealLast();
1066 Standard_Real aGraphicMaxDist = RealFirst();
1068 const gp_XYZ& anAxialScale = myAxialScale;
1070 // Get minimum and maximum distances to the eye plane.
1071 Standard_Integer aCounter = 0;
1072 NCollection_Sequence<gp_Pnt>::Iterator aPntIt(aPntsToMeasure);
1073 for (; aPntIt.More(); aPntIt.Next())
1075 gp_Pnt aMeasurePnt = aPntIt.Value();
1077 aMeasurePnt = gp_Pnt (aMeasurePnt.X() * anAxialScale.X(),
1078 aMeasurePnt.Y() * anAxialScale.Y(),
1079 aMeasurePnt.Z() * anAxialScale.Z());
1081 Standard_Real aDistance = aCamPln.Distance (aMeasurePnt);
1083 // Check if the camera is intruded into the scene.
1084 if (aCamDir.IsOpposite (gp_Vec (aCamEye, aMeasurePnt), M_PI * 0.5))
1089 // The first eight points are from theGraphicBB, the last eight points are from theMinMax (can be absent).
1090 Standard_Real& aChangeMinDist = aCounter >= 8 ? aModelMinDist : aGraphicMinDist;
1091 Standard_Real& aChangeMaxDist = aCounter >= 8 ? aModelMaxDist : aGraphicMaxDist;
1092 aChangeMinDist = Min (aDistance, aChangeMinDist);
1093 aChangeMaxDist = Max (aDistance, aChangeMaxDist);
1097 // Compute depth of bounding box center.
1098 Standard_Real aMidDepth = (aGraphicMinDist + aGraphicMaxDist) * 0.5;
1099 Standard_Real aHalfDepth = (aGraphicMaxDist - aGraphicMinDist) * 0.5;
1101 // Compute enlarged or shrank near and far z ranges.
1102 Standard_Real aZNear = aMidDepth - aHalfDepth * theScaleFactor;
1103 Standard_Real aZFar = aMidDepth + aHalfDepth * theScaleFactor;
1105 if (!IsOrthographic())
1107 // Everything is behind the perspective camera.
1108 if (aZFar < zEpsilon())
1110 SetZRange (DEFAULT_ZNEAR, DEFAULT_ZFAR);
1114 // For better perspective the zNear value should not be less than zEpsilon (zFar).
1115 // If zNear computed by graphical boundaries do not meet the rule (e.g. it is negative
1116 // when computing it for grid) it could be increased up to minimum depth computed by
1117 // application min max values. This means that z-fit can sacrifice presentation of
1118 // non primary application graphical objects in favor of better perspective projection;
1119 if (aZNear < zEpsilon (aZFar))
1121 // Otherwise it should be increased up to zEpsilon (1.0) to avoid clipping of primary
1122 // graphical objects.
1123 if (aModelMinDist < zEpsilon (aZFar))
1125 aMidDepth = (aModelMinDist + aModelMaxDist) * 0.5;
1126 aHalfDepth = (aModelMinDist - aModelMaxDist) * 0.5;
1127 aZNear = Max (zEpsilon(), aMidDepth - aHalfDepth * theScaleFactor);
1131 aZNear = zEpsilon (aZFar);
1137 // Consider clipping errors due to double to single precision floating-point conversion.
1140 // Model to view transformation performs translation of points against eye position
1141 // in three dimensions. Both point coordinate and eye position values are converted from
1142 // double to single precision floating point numbers producing conversion errors.
1143 // Epsilon (Mod) * 3.0 should safely compensate precision error for z coordinate after
1144 // translation assuming that the:
1145 // Epsilon (Eye.Mod()) * 3.0 > Epsilon (Eye.X()) + Epsilon (Eye.Y()) + Epsilon (Eye.Z()).
1146 Standard_Real aEyeConf = 3.0 * zEpsilon (myEye.XYZ().Modulus());
1148 // Model to view transformation performs rotation of points according to view direction.
1149 // New z coordinate is computed as a multiplication of point's x, y, z coordinates by the
1150 // "forward" direction vector's x, y, z coordinates. Both point's and "z" direction vector's
1151 // values are converted from double to single precision floating point numbers producing
1152 // conversion errors.
1153 // Epsilon (Mod) * 6.0 should safely compensate the precision errors for the multiplication
1154 // of point coordinates by direction vector.
1155 gp_Pnt aGraphicMin = theGraphicBB.CornerMin();
1156 gp_Pnt aGraphicMax = theGraphicBB.CornerMax();
1158 Standard_Real aModelConf = 6.0 * zEpsilon (aGraphicMin.XYZ().Modulus()) +
1159 6.0 * zEpsilon (aGraphicMax.XYZ().Modulus());
1161 // Compensate floating point conversion errors by increasing zNear, zFar to avoid clipping.
1162 aZNear -= zEpsilon (aZNear) + aEyeConf + aModelConf;
1163 aZFar += zEpsilon (aZFar) + aEyeConf + aModelConf;
1165 if (!IsOrthographic())
1167 // Compensate zNear, zFar conversion errors for perspective projection.
1168 aZNear -= aZFar * zEpsilon (aZNear) / (aZFar - zEpsilon (aZNear));
1169 aZFar += zEpsilon (aZFar);
1171 // Ensure that after all the zNear is not a negative value.
1172 if (aZNear < zEpsilon())
1174 aZNear = zEpsilon();
1178 SetZRange (aZNear, aZFar);