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>
27 IMPLEMENT_STANDARD_HANDLE(Graphic3d_Camera, Standard_Transient)
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 // minimum camera distance
43 static const Standard_Real MIN_DISTANCE = Pow (0.1, ShortRealDigits() - 2);
46 // =======================================================================
47 // function : Graphic3d_Camera
49 // =======================================================================
50 Graphic3d_Camera::Graphic3d_Camera()
51 : myUp (0.0, 1.0, 0.0),
52 myEye (0.0, 0.0, -1500.0),
53 myCenter (0.0, 0.0, 0.0),
54 myAxialScale (1.0, 1.0, 1.0),
55 myProjType (Projection_Orthographic),
57 myZNear (DEFAULT_ZNEAR),
58 myZFar (DEFAULT_ZFAR),
62 myZFocusType (FocusType_Relative),
64 myIODType (IODType_Relative)
66 myProjectionState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
67 myOrientationState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
70 // =======================================================================
71 // function : Graphic3d_Camera
73 // =======================================================================
74 Graphic3d_Camera::Graphic3d_Camera (const Handle(Graphic3d_Camera)& theOther)
79 // =======================================================================
80 // function : CopyMappingData
82 // =======================================================================
83 void Graphic3d_Camera::CopyMappingData (const Handle(Graphic3d_Camera)& theOtherCamera)
85 myFOVy = theOtherCamera->myFOVy;
86 myZNear = theOtherCamera->myZNear;
87 myZFar = theOtherCamera->myZFar;
88 myAspect = theOtherCamera->myAspect;
89 myScale = theOtherCamera->myScale;
90 myZFocus = theOtherCamera->myZFocus;
91 myZFocusType = theOtherCamera->myZFocusType;
92 myIOD = theOtherCamera->myIOD;
93 myIODType = theOtherCamera->myIODType;
94 myProjType = theOtherCamera->myProjType;
95 myProjectionState = theOtherCamera->myProjectionState;
97 InvalidateProjection();
100 // =======================================================================
101 // function : CopyOrientationData
103 // =======================================================================
104 void Graphic3d_Camera::CopyOrientationData (const Handle(Graphic3d_Camera)& theOtherCamera)
106 myUp = theOtherCamera->myUp;
107 myEye = theOtherCamera->myEye;
108 myCenter = theOtherCamera->myCenter;
109 myAxialScale = theOtherCamera->myAxialScale;
110 myOrientationState = theOtherCamera->myOrientationState;
112 InvalidateOrientation();
115 // =======================================================================
118 // =======================================================================
119 void Graphic3d_Camera::Copy (const Handle(Graphic3d_Camera)& theOther)
121 CopyMappingData (theOther);
122 CopyOrientationData (theOther);
125 // =======================================================================
128 // =======================================================================
129 void Graphic3d_Camera::SetEye (const gp_Pnt& theEye)
132 InvalidateOrientation();
135 // =======================================================================
136 // function : SetCenter
138 // =======================================================================
139 void Graphic3d_Camera::SetCenter (const gp_Pnt& theCenter)
141 myCenter = theCenter;
142 InvalidateOrientation();
145 // =======================================================================
148 // =======================================================================
149 void Graphic3d_Camera::SetUp (const gp_Dir& theUp)
152 InvalidateOrientation();
155 // =======================================================================
156 // function : SetAxialScale
158 // =======================================================================
159 void Graphic3d_Camera::SetAxialScale (const gp_XYZ& theAxialScale)
161 myAxialScale = theAxialScale;
162 InvalidateOrientation();
165 // =======================================================================
166 // function : SetDistance
168 // =======================================================================
169 void Graphic3d_Camera::SetDistance (const Standard_Real theDistance)
171 gp_Vec aCenter2Eye (Direction());
172 aCenter2Eye.Reverse();
174 // Camera should have non-zero distance.
175 aCenter2Eye.Scale (Max (theDistance, MIN_DISTANCE));
176 SetEye (Center().Translated (aCenter2Eye));
179 // =======================================================================
180 // function : Distance
182 // =======================================================================
183 Standard_Real Graphic3d_Camera::Distance() const
185 return myEye.Distance (myCenter);
188 // =======================================================================
189 // function : SetDirection
191 // =======================================================================
192 void Graphic3d_Camera::SetDirection (const gp_Dir& theDir)
194 gp_Vec aScaledDir (theDir);
195 aScaledDir.Scale (Distance());
196 aScaledDir.Reverse();
197 SetEye (Center().Translated (aScaledDir));
200 // =======================================================================
201 // function : Direction
203 // =======================================================================
204 gp_Dir Graphic3d_Camera::Direction() const
206 return gp_Dir (gp_Vec (myEye, myCenter));
209 // =======================================================================
210 // function : SetScale
212 // =======================================================================
213 void Graphic3d_Camera::SetScale (const Standard_Real theScale)
219 case Projection_Perspective :
220 case Projection_Stereo :
221 case Projection_MonoLeftEye :
222 case Projection_MonoRightEye :
224 Standard_Real aDistance = theScale * 0.5 / Tan(myFOVy * M_PI / 360.0);
225 SetDistance (aDistance);
232 InvalidateProjection();
235 // =======================================================================
238 // =======================================================================
239 Standard_Real Graphic3d_Camera::Scale() const
243 case Projection_Orthographic :
246 // case Projection_Perspective :
247 // case Projection_Stereo :
248 // case Projection_MonoLeftEye :
249 // case Projection_MonoRightEye :
251 return Distance() * 2.0 * Tan (myFOVy * M_PI / 360.0);
255 // =======================================================================
256 // function : SetProjectionType
258 // =======================================================================
259 void Graphic3d_Camera::SetProjectionType (const Projection theProjectionType)
261 Projection anOldType = myProjType;
263 if (anOldType == theProjectionType)
268 if (anOldType == Projection_Orthographic)
270 if (myZNear <= RealEpsilon())
272 myZNear = DEFAULT_ZNEAR;
274 if (myZFar <= RealEpsilon())
276 myZFar = DEFAULT_ZFAR;
280 myProjType = theProjectionType;
282 InvalidateProjection();
285 // =======================================================================
286 // function : SetFOVy
288 // =======================================================================
289 void Graphic3d_Camera::SetFOVy (const Standard_Real theFOVy)
292 InvalidateProjection();
295 // =======================================================================
296 // function : SetZRange
298 // =======================================================================
299 void Graphic3d_Camera::SetZRange (const Standard_Real theZNear,
300 const Standard_Real theZFar)
302 Standard_ASSERT_RAISE (theZFar > theZNear, "ZFar should be greater than ZNear");
303 if (!IsOrthographic())
305 Standard_ASSERT_RAISE (theZNear > 0.0, "Only positive Z-Near is allowed for perspective camera");
306 Standard_ASSERT_RAISE (theZFar > 0.0, "Only positive Z-Far is allowed for perspective camera");
312 InvalidateProjection();
315 // =======================================================================
316 // function : SetAspect
318 // =======================================================================
319 void Graphic3d_Camera::SetAspect (const Standard_Real theAspect)
321 myAspect = theAspect;
322 InvalidateProjection();
325 // =======================================================================
326 // function : SetZFocus
328 // =======================================================================
329 void Graphic3d_Camera::SetZFocus(const FocusType theType, const Standard_Real theZFocus)
331 myZFocusType = theType;
332 myZFocus = theZFocus;
333 InvalidateProjection();
336 // =======================================================================
339 // =======================================================================
340 void Graphic3d_Camera::SetIOD (const IODType theType, const Standard_Real theIOD)
344 InvalidateProjection();
347 // =======================================================================
348 // function : OrthogonalizeUp
350 // =======================================================================
351 void Graphic3d_Camera::OrthogonalizeUp()
353 SetUp (OrthogonalizedUp());
356 // =======================================================================
357 // function : OrthogonalizedUp
359 // =======================================================================
360 gp_Dir Graphic3d_Camera::OrthogonalizedUp() const
362 gp_Dir aDir = Direction();
363 gp_Dir aLeft = aDir.Crossed (Up());
365 // recompute up as: up = left x direction
366 return aLeft.Crossed (aDir);
369 // =======================================================================
370 // function : Transform
372 // =======================================================================
373 void Graphic3d_Camera::Transform (const gp_Trsf& theTrsf)
375 myUp.Transform (theTrsf);
376 myEye.Transform (theTrsf);
377 myCenter.Transform (theTrsf);
378 InvalidateOrientation();
381 // =======================================================================
382 // function : safePointCast
384 // =======================================================================
385 static Graphic3d_Vec4d safePointCast (const gp_Pnt& thePnt)
387 Standard_Real aLim = 1e15f;
389 // have to deal with values greater then max float
390 gp_Pnt aSafePoint = thePnt;
391 const Standard_Real aBigFloat = aLim * 0.1f;
392 if (Abs (aSafePoint.X()) > aLim)
393 aSafePoint.SetX (aSafePoint.X() >= 0 ? aBigFloat : -aBigFloat);
394 if (Abs (aSafePoint.Y()) > aLim)
395 aSafePoint.SetY (aSafePoint.Y() >= 0 ? aBigFloat : -aBigFloat);
396 if (Abs (aSafePoint.Z()) > aLim)
397 aSafePoint.SetZ (aSafePoint.Z() >= 0 ? aBigFloat : -aBigFloat);
400 Graphic3d_Vec4d aPnt (aSafePoint.X(), aSafePoint.Y(), aSafePoint.Z(), 1.0);
405 // =======================================================================
406 // function : Project
408 // =======================================================================
409 gp_Pnt Graphic3d_Camera::Project (const gp_Pnt& thePnt) const
411 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
412 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
414 // use compatible type of point
415 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
417 aPnt = aViewMx * aPnt; // convert to view coordinate space
418 aPnt = aProjMx * aPnt; // convert to projection coordinate space
420 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
422 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
425 // =======================================================================
426 // function : UnProject
428 // =======================================================================
429 gp_Pnt Graphic3d_Camera::UnProject (const gp_Pnt& thePnt) const
431 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
432 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
434 Graphic3d_Mat4d aInvView;
435 Graphic3d_Mat4d aInvProj;
437 // this case should never happen
438 if (!aViewMx.Inverted (aInvView) || !aProjMx.Inverted (aInvProj))
440 return gp_Pnt (0.0, 0.0, 0.0);
443 // use compatible type of point
444 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
446 aPnt = aInvProj * aPnt; // convert to view coordinate space
447 aPnt = aInvView * aPnt; // convert to world coordinate space
449 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
451 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
454 // =======================================================================
455 // function : ConvertView2Proj
457 // =======================================================================
458 gp_Pnt Graphic3d_Camera::ConvertView2Proj (const gp_Pnt& thePnt) const
460 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
462 // use compatible type of point
463 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
465 aPnt = aProjMx * aPnt; // convert to projection coordinate space
467 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
469 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
472 // =======================================================================
473 // function : ConvertProj2View
475 // =======================================================================
476 gp_Pnt Graphic3d_Camera::ConvertProj2View (const gp_Pnt& thePnt) const
478 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
480 Graphic3d_Mat4d aInvProj;
482 // this case should never happen, but...
483 if (!aProjMx.Inverted (aInvProj))
485 return gp_Pnt (0, 0, 0);
488 // use compatible type of point
489 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
491 aPnt = aInvProj * aPnt; // convert to view coordinate space
493 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
495 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
498 // =======================================================================
499 // function : ConvertWorld2View
501 // =======================================================================
502 gp_Pnt Graphic3d_Camera::ConvertWorld2View (const gp_Pnt& thePnt) const
504 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
506 // use compatible type of point
507 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
509 aPnt = aViewMx * aPnt; // convert to view coordinate space
511 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
513 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
516 // =======================================================================
517 // function : ConvertView2World
519 // =======================================================================
520 gp_Pnt Graphic3d_Camera::ConvertView2World (const gp_Pnt& thePnt) const
522 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
524 Graphic3d_Mat4d aInvView;
526 if (!aViewMx.Inverted (aInvView))
528 return gp_Pnt(0, 0, 0);
531 // use compatible type of point
532 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
534 aPnt = aInvView * aPnt; // convert to world coordinate space
536 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
538 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
541 // =======================================================================
542 // function : ViewDimensions
544 // =======================================================================
545 gp_XYZ Graphic3d_Camera::ViewDimensions() const
547 // view plane dimensions
548 Standard_Real aSizeY = IsOrthographic() ? myScale : (2.0 * Distance() * Tan (DTR_HALF * myFOVy));
549 Standard_Real aSizeX = myAspect * aSizeY;
552 return gp_XYZ (aSizeX, aSizeY, myZFar - myZNear);
555 // =======================================================================
556 // function : Frustum
558 // =======================================================================
559 void Graphic3d_Camera::Frustum (gp_Pln& theLeft,
564 gp_Pln& theFar) const
566 gp_Vec aProjection = gp_Vec (Direction());
567 gp_Vec anUp = OrthogonalizedUp();
568 gp_Vec aSide = aProjection ^ anUp;
570 Standard_ASSERT_RAISE (
571 !aProjection.IsParallel (anUp, Precision::Angular()),
572 "Can not derive SIDE = PROJ x UP - directions are parallel");
574 theNear = gp_Pln (Eye().Translated (aProjection * ZNear()), aProjection);
575 theFar = gp_Pln (Eye().Translated (aProjection * ZFar()), -aProjection);
577 Standard_Real aHScaleHor = Scale() * 0.5 * Aspect();
578 Standard_Real aHScaleVer = Scale() * 0.5;
580 gp_Pnt aPntLeft = Center().Translated (aHScaleHor * -aSide);
581 gp_Pnt aPntRight = Center().Translated (aHScaleHor * aSide);
582 gp_Pnt aPntBottom = Center().Translated (aHScaleVer * -anUp);
583 gp_Pnt aPntTop = Center().Translated (aHScaleVer * anUp);
585 gp_Vec aDirLeft = aSide;
586 gp_Vec aDirRight = -aSide;
587 gp_Vec aDirBottom = anUp;
588 gp_Vec aDirTop = -anUp;
589 if (!IsOrthographic())
591 Standard_Real aHFOVHor = ATan (Tan (DTR_HALF * FOVy()) * Aspect());
592 Standard_Real aHFOVVer = DTR_HALF * FOVy();
593 aDirLeft.Rotate (gp_Ax1 (gp::Origin(), anUp), aHFOVHor);
594 aDirRight.Rotate (gp_Ax1 (gp::Origin(), anUp), -aHFOVHor);
595 aDirBottom.Rotate (gp_Ax1 (gp::Origin(), aSide), -aHFOVVer);
596 aDirTop.Rotate (gp_Ax1 (gp::Origin(), aSide), aHFOVVer);
599 theLeft = gp_Pln (aPntLeft, aDirLeft);
600 theRight = gp_Pln (aPntRight, aDirRight);
601 theBottom = gp_Pln (aPntBottom, aDirBottom);
602 theTop = gp_Pln (aPntTop, aDirTop);
605 // =======================================================================
606 // function : OrientationMatrix
608 // =======================================================================
609 const Graphic3d_Mat4d& Graphic3d_Camera::OrientationMatrix() const
611 return *UpdateOrientation (myMatricesD).Orientation;
614 // =======================================================================
615 // function : OrientationMatrixF
617 // =======================================================================
618 const Graphic3d_Mat4& Graphic3d_Camera::OrientationMatrixF() const
620 return *UpdateOrientation (myMatricesF).Orientation;
623 // =======================================================================
624 // function : ProjectionMatrix
626 // =======================================================================
627 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionMatrix() const
629 return *UpdateProjection (myMatricesD).MProjection;
632 // =======================================================================
633 // function : ProjectionMatrixF
635 // =======================================================================
636 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionMatrixF() const
638 return *UpdateProjection (myMatricesF).MProjection;
641 // =======================================================================
642 // function : ProjectionStereoLeft
644 // =======================================================================
645 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoLeft() const
647 return *UpdateProjection (myMatricesD).LProjection;
650 // =======================================================================
651 // function : ProjectionStereoLeftF
653 // =======================================================================
654 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoLeftF() const
656 return *UpdateProjection (myMatricesF).LProjection;
659 // =======================================================================
660 // function : ProjectionStereoRight
662 // =======================================================================
663 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoRight() const
665 return *UpdateProjection (myMatricesD).RProjection;
668 // =======================================================================
669 // function : ProjectionStereoRightF
671 // =======================================================================
672 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoRightF() const
674 return *UpdateProjection (myMatricesF).RProjection;
677 // =======================================================================
678 // function : UpdateProjection
680 // =======================================================================
681 template <typename Elem_t>
682 Graphic3d_Camera::TransformMatrices<Elem_t>&
683 Graphic3d_Camera::UpdateProjection (TransformMatrices<Elem_t>& theMatrices) const
685 if (theMatrices.IsProjectionValid())
687 return theMatrices; // for inline accessors
690 theMatrices.InitProjection();
692 // sets top of frustum based on FOVy and near clipping plane
693 Elem_t aScale = static_cast<Elem_t> (myScale);
694 Elem_t aZNear = static_cast<Elem_t> (myZNear);
695 Elem_t aZFar = static_cast<Elem_t> (myZFar);
696 Elem_t anAspect = static_cast<Elem_t> (myAspect);
697 Elem_t aDXHalf = 0.0, aDYHalf = 0.0;
698 if (IsOrthographic())
700 aDXHalf = aScale * Elem_t (0.5);
701 aDYHalf = aScale * Elem_t (0.5);
705 aDXHalf = aZNear * Elem_t (Tan (DTR_HALF * myFOVy));
706 aDYHalf = aZNear * Elem_t (Tan (DTR_HALF * myFOVy));
718 // sets right of frustum based on aspect ratio
719 Elem_t aLeft = -aDXHalf;
720 Elem_t aRight = aDXHalf;
721 Elem_t aBot = -aDYHalf;
722 Elem_t aTop = aDYHalf;
724 Elem_t aIOD = myIODType == IODType_Relative
725 ? static_cast<Elem_t> (myIOD * Distance())
726 : static_cast<Elem_t> (myIOD);
728 Elem_t aFocus = myZFocusType == FocusType_Relative
729 ? static_cast<Elem_t> (myZFocus * Distance())
730 : static_cast<Elem_t> (myZFocus);
734 case Projection_Orthographic :
735 OrthoProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
738 case Projection_Perspective :
739 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
742 case Projection_MonoLeftEye :
744 StereoEyeProj (aLeft, aRight, aBot, aTop,
745 aZNear, aZFar, aIOD, aFocus,
746 Standard_True, *theMatrices.MProjection);
747 *theMatrices.LProjection = *theMatrices.MProjection;
751 case Projection_MonoRightEye :
753 StereoEyeProj (aLeft, aRight, aBot, aTop,
754 aZNear, aZFar, aIOD, aFocus,
755 Standard_False, *theMatrices.MProjection);
756 *theMatrices.RProjection = *theMatrices.MProjection;
760 case Projection_Stereo :
762 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
764 StereoEyeProj (aLeft, aRight, aBot, aTop,
765 aZNear, aZFar, aIOD, aFocus,
767 *theMatrices.LProjection);
769 StereoEyeProj (aLeft, aRight, aBot, aTop,
770 aZNear, aZFar, aIOD, aFocus,
772 *theMatrices.RProjection);
777 return theMatrices; // for inline accessors
780 // =======================================================================
781 // function : UpdateOrientation
783 // =======================================================================
784 template <typename Elem_t>
785 Graphic3d_Camera::TransformMatrices<Elem_t>&
786 Graphic3d_Camera::UpdateOrientation (TransformMatrices<Elem_t>& theMatrices) const
788 if (theMatrices.IsOrientationValid())
790 return theMatrices; // for inline accessors
793 theMatrices.InitOrientation();
795 NCollection_Vec3<Elem_t> anEye (static_cast<Elem_t> (myEye.X()),
796 static_cast<Elem_t> (myEye.Y()),
797 static_cast<Elem_t> (myEye.Z()));
799 NCollection_Vec3<Elem_t> aCenter (static_cast<Elem_t> (myCenter.X()),
800 static_cast<Elem_t> (myCenter.Y()),
801 static_cast<Elem_t> (myCenter.Z()));
803 NCollection_Vec3<Elem_t> anUp (static_cast<Elem_t> (myUp.X()),
804 static_cast<Elem_t> (myUp.Y()),
805 static_cast<Elem_t> (myUp.Z()));
807 NCollection_Vec3<Elem_t> anAxialScale (static_cast<Elem_t> (myAxialScale.X()),
808 static_cast<Elem_t> (myAxialScale.Y()),
809 static_cast<Elem_t> (myAxialScale.Z()));
811 LookOrientation (anEye, aCenter, anUp, anAxialScale, *theMatrices.Orientation);
813 return theMatrices; // for inline accessors
816 // =======================================================================
817 // function : InvalidateProjection
819 // =======================================================================
820 void Graphic3d_Camera::InvalidateProjection()
822 myMatricesD.ResetProjection();
823 myMatricesF.ResetProjection();
824 myProjectionState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
827 // =======================================================================
828 // function : InvalidateOrientation
830 // =======================================================================
831 void Graphic3d_Camera::InvalidateOrientation()
833 myMatricesD.ResetOrientation();
834 myMatricesF.ResetOrientation();
835 myOrientationState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
838 // =======================================================================
839 // function : OrthoProj
841 // =======================================================================
842 template <typename Elem_t>
843 void Graphic3d_Camera::OrthoProj (const Elem_t theLeft,
844 const Elem_t theRight,
845 const Elem_t theBottom,
847 const Elem_t theNear,
849 NCollection_Mat4<Elem_t>& theOutMx)
852 theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theRight - theLeft);
853 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
854 theOutMx.ChangeValue (0, 2) = Elem_t (0.0);
855 theOutMx.ChangeValue (0, 3) = - (theRight + theLeft) / (theRight - theLeft);
858 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
859 theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theTop - theBottom);
860 theOutMx.ChangeValue (1, 2) = Elem_t (0.0);
861 theOutMx.ChangeValue (1, 3) = - (theTop + theBottom) / (theTop - theBottom);
864 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
865 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
866 theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear);
867 theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear);
870 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
871 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
872 theOutMx.ChangeValue (3, 2) = Elem_t (0.0);
873 theOutMx.ChangeValue (3, 3) = Elem_t (1.0);
876 // =======================================================================
877 // function : PerspectiveProj
879 // =======================================================================
880 template <typename Elem_t>
881 void Graphic3d_Camera::PerspectiveProj (const Elem_t theLeft,
882 const Elem_t theRight,
883 const Elem_t theBottom,
885 const Elem_t theNear,
887 NCollection_Mat4<Elem_t>& theOutMx)
890 theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theRight - theLeft);
891 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
892 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
893 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
896 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
897 theOutMx.ChangeValue (1, 1) = (Elem_t (2.0) * theNear) / (theTop - theBottom);
898 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
899 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
902 theOutMx.ChangeValue (0, 2) = (theRight + theLeft) / (theRight - theLeft);
903 theOutMx.ChangeValue (1, 2) = (theTop + theBottom) / (theTop - theBottom);
904 theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear);
905 theOutMx.ChangeValue (3, 2) = Elem_t (-1.0);
908 theOutMx.ChangeValue (0, 3) = Elem_t (0.0);
909 theOutMx.ChangeValue (1, 3) = Elem_t (0.0);
910 theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear);
911 theOutMx.ChangeValue (3, 3) = Elem_t (0.0);
914 // =======================================================================
915 // function : StereoEyeProj
917 // =======================================================================
918 template <typename Elem_t>
919 void Graphic3d_Camera::StereoEyeProj (const Elem_t theLeft,
920 const Elem_t theRight,
921 const Elem_t theBottom,
923 const Elem_t theNear,
926 const Elem_t theZFocus,
927 const Standard_Boolean theIsLeft,
928 NCollection_Mat4<Elem_t>& theOutMx)
930 Elem_t aDx = theIsLeft ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD;
931 Elem_t aDXStereoShift = aDx * theNear / theZFocus;
933 // construct eye projection matrix
934 PerspectiveProj (theLeft + aDXStereoShift,
935 theRight + aDXStereoShift,
936 theBottom, theTop, theNear, theFar,
939 if (theIOD != Elem_t (0.0))
941 // X translation to cancel parallax
942 theOutMx.Translate (NCollection_Vec3<Elem_t> (aDx, Elem_t (0.0), Elem_t (0.0)));
946 // =======================================================================
947 // function : LookOrientation
949 // =======================================================================
950 template <typename Elem_t>
951 void Graphic3d_Camera::LookOrientation (const NCollection_Vec3<Elem_t>& theEye,
952 const NCollection_Vec3<Elem_t>& theLookAt,
953 const NCollection_Vec3<Elem_t>& theUpDir,
954 const NCollection_Vec3<Elem_t>& theAxialScale,
955 NCollection_Mat4<Elem_t>& theOutMx)
957 NCollection_Vec3<Elem_t> aForward = theLookAt - theEye;
958 aForward.Normalize();
960 // side = forward x up
961 NCollection_Vec3<Elem_t> aSide = NCollection_Vec3<Elem_t>::Cross (aForward, theUpDir);
964 // recompute up as: up = side x forward
965 NCollection_Vec3<Elem_t> anUp = NCollection_Vec3<Elem_t>::Cross (aSide, aForward);
967 NCollection_Mat4<Elem_t> aLookMx;
968 aLookMx.SetRow (0, aSide);
969 aLookMx.SetRow (1, anUp);
970 aLookMx.SetRow (2, -aForward);
972 theOutMx.InitIdentity();
973 theOutMx.Multiply (aLookMx);
974 theOutMx.Translate (-theEye);
976 NCollection_Mat4<Elem_t> anAxialScaleMx;
977 anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x();
978 anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y();
979 anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z();
981 theOutMx.Multiply (anAxialScaleMx);
984 //=============================================================================
987 //=============================================================================
988 void Graphic3d_Camera::ZFitAll (const Standard_Real theScaleFactor, const Bnd_Box& theMinMax, const Bnd_Box& theGraphicBB)
990 Standard_ASSERT_RAISE (theScaleFactor > 0.0, "Zero or negative scale factor is not allowed.");
992 // Method changes ZNear and ZFar planes of camera so as to fit the graphical structures
993 // by their real boundaries (computed ignoring infinite flag) into the viewing volume.
994 // In addition to the graphical boundaries, the usual min max used for fitting perspective
995 // camera. To avoid numeric errors for perspective camera the negative ZNear values are
996 // fixed using tolerance distance, relative to boundaries size. The tolerance distance
997 // should be computed using information on boundaries of primary application actors,
998 // (e.g. representing the displayed model) - to ensure that they are not unreasonably clipped.
999 const Standard_ShortReal anEpsilon = 1e-4f;
1001 if (theGraphicBB.IsVoid())
1003 // Precision factor used to add meaningful tolerance to
1004 // ZNear, ZFar values in order to avoid equality after type conversion
1005 // to ShortReal matrices type.
1007 Standard_Real aZFar = Distance() * 3.0;
1008 Standard_Real aZNear = 0.0;
1010 if (!IsOrthographic())
1012 if (aZFar < anEpsilon)
1015 aZFar = anEpsilon * 2.0;
1017 else if (aZNear < aZFar * anEpsilon)
1019 aZNear = aZFar * anEpsilon;
1023 SetZRange (aZNear, aZFar);
1027 // Measure depth of boundary points from camera eye
1028 NCollection_Sequence<gp_Pnt> aPntsToMeasure;
1030 Standard_Real aGraphicBB[6]; // real graphical boundaries (not accounting infinite flag).
1031 theGraphicBB.Get (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2], aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]);
1033 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2]));
1034 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[5]));
1035 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[2]));
1036 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[5]));
1037 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[2]));
1038 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[5]));
1039 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[2]));
1040 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]));
1042 if (!theMinMax.IsVoid() && !theMinMax.IsWhole())
1044 Standard_Real aMinMax[6]; // applicative min max boundaries
1045 theMinMax.Get (aMinMax[0], aMinMax[1], aMinMax[2], aMinMax[3], aMinMax[4], aMinMax[5]);
1047 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[2]));
1048 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[5]));
1049 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[2]));
1050 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[5]));
1051 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[2]));
1052 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[5]));
1053 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[2]));
1054 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[5]));
1058 gp_Dir aCamDir = Direction();
1059 gp_Pnt aCamEye = myEye;
1060 gp_Pln aCamPln (aCamEye, aCamDir);
1062 Standard_Real aModelMinDist = RealLast();
1063 Standard_Real aModelMaxDist = RealFirst();
1064 Standard_Real aGraphicMinDist = RealLast();
1065 Standard_Real aGraphicMaxDist = RealFirst();
1067 const gp_XYZ& anAxialScale = myAxialScale;
1069 // Get minimum and maximum distances to the eye plane
1070 Standard_Integer aCounter = 0;
1071 NCollection_Sequence<gp_Pnt>::Iterator aPntIt(aPntsToMeasure);
1072 for (; aPntIt.More(); aPntIt.Next())
1074 gp_Pnt aMeasurePnt = aPntIt.Value();
1076 aMeasurePnt = gp_Pnt (aMeasurePnt.X() * anAxialScale.X(),
1077 aMeasurePnt.Y() * anAxialScale.Y(),
1078 aMeasurePnt.Z() * anAxialScale.Z());
1080 Standard_Real aDistance = aCamPln.Distance (aMeasurePnt);
1082 // Check if the camera is intruded into the scene
1083 if (aCamDir.IsOpposite (gp_Vec (aCamEye, aMeasurePnt), M_PI * 0.5))
1088 // the first eight points are from theGraphicBB, the last eight points are from theMinMax
1089 // (they 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;
1104 Standard_Real aZRange = Abs (aZFar - aZNear);
1105 Standard_Real aZConf = Max (static_cast <Standard_Real> (anEpsilon * aZRange),
1106 static_cast <Standard_Real> (anEpsilon));
1108 aZNear -= Abs (aZNear) * anEpsilon + aZConf;
1109 aZFar += Abs (aZFar) * anEpsilon + aZConf;
1111 if (!IsOrthographic())
1113 if (aZFar > anEpsilon)
1115 // Choose between model distance and graphical distance, as the model boundaries
1116 // might be infinite if all structures have infinite flag.
1117 const Standard_Real aGraphicDepth = aGraphicMaxDist >= aGraphicMinDist
1118 ? aGraphicMaxDist - aGraphicMinDist : RealLast();
1120 const Standard_Real aModelDepth = aModelMaxDist >= aModelMinDist
1121 ? aModelMaxDist - aModelMinDist : RealLast();
1123 const Standard_Real aMinDepth = Min (aModelDepth, aGraphicDepth);
1124 const Standard_Real aZTol = Max (static_cast<Standard_Real> (anEpsilon * Abs (aMinDepth)),
1125 static_cast<Standard_Real> (anEpsilon));
1134 aZFar = anEpsilon * 2.0;
1138 if (aZFar < (aZNear + Abs (aZFar) * anEpsilon))
1140 aZFar = aZNear + Abs (aZFar) * anEpsilon;
1143 SetZRange (aZNear, aZFar);