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 aDYHalf = 0.0;
698 if (IsOrthographic())
700 aDYHalf = aScale * Elem_t (0.5);
704 aDYHalf = aZNear * Elem_t (Tan (DTR_HALF * myFOVy));
707 // sets right of frustum based on aspect ratio
708 Elem_t aDXHalf = anAspect * aDYHalf;
709 Elem_t aLeft = -aDXHalf;
710 Elem_t aRight = aDXHalf;
711 Elem_t aBot = -aDYHalf;
712 Elem_t aTop = aDYHalf;
714 Elem_t aIOD = myIODType == IODType_Relative
715 ? static_cast<Elem_t> (myIOD * Distance())
716 : static_cast<Elem_t> (myIOD);
718 Elem_t aFocus = myZFocusType == FocusType_Relative
719 ? static_cast<Elem_t> (myZFocus * Distance())
720 : static_cast<Elem_t> (myZFocus);
724 case Projection_Orthographic :
725 OrthoProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
728 case Projection_Perspective :
729 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
732 case Projection_MonoLeftEye :
734 StereoEyeProj (aLeft, aRight, aBot, aTop,
735 aZNear, aZFar, aIOD, aFocus,
736 Standard_True, *theMatrices.MProjection);
737 *theMatrices.LProjection = *theMatrices.MProjection;
741 case Projection_MonoRightEye :
743 StereoEyeProj (aLeft, aRight, aBot, aTop,
744 aZNear, aZFar, aIOD, aFocus,
745 Standard_False, *theMatrices.MProjection);
746 *theMatrices.RProjection = *theMatrices.MProjection;
750 case Projection_Stereo :
752 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
754 StereoEyeProj (aLeft, aRight, aBot, aTop,
755 aZNear, aZFar, aIOD, aFocus,
757 *theMatrices.LProjection);
759 StereoEyeProj (aLeft, aRight, aBot, aTop,
760 aZNear, aZFar, aIOD, aFocus,
762 *theMatrices.RProjection);
767 return theMatrices; // for inline accessors
770 // =======================================================================
771 // function : UpdateOrientation
773 // =======================================================================
774 template <typename Elem_t>
775 Graphic3d_Camera::TransformMatrices<Elem_t>&
776 Graphic3d_Camera::UpdateOrientation (TransformMatrices<Elem_t>& theMatrices) const
778 if (theMatrices.IsOrientationValid())
780 return theMatrices; // for inline accessors
783 theMatrices.InitOrientation();
785 NCollection_Vec3<Elem_t> anEye (static_cast<Elem_t> (myEye.X()),
786 static_cast<Elem_t> (myEye.Y()),
787 static_cast<Elem_t> (myEye.Z()));
789 NCollection_Vec3<Elem_t> aCenter (static_cast<Elem_t> (myCenter.X()),
790 static_cast<Elem_t> (myCenter.Y()),
791 static_cast<Elem_t> (myCenter.Z()));
793 NCollection_Vec3<Elem_t> anUp (static_cast<Elem_t> (myUp.X()),
794 static_cast<Elem_t> (myUp.Y()),
795 static_cast<Elem_t> (myUp.Z()));
797 NCollection_Vec3<Elem_t> anAxialScale (static_cast<Elem_t> (myAxialScale.X()),
798 static_cast<Elem_t> (myAxialScale.Y()),
799 static_cast<Elem_t> (myAxialScale.Z()));
801 LookOrientation (anEye, aCenter, anUp, anAxialScale, *theMatrices.Orientation);
803 return theMatrices; // for inline accessors
806 // =======================================================================
807 // function : InvalidateProjection
809 // =======================================================================
810 void Graphic3d_Camera::InvalidateProjection()
812 myMatricesD.ResetProjection();
813 myMatricesF.ResetProjection();
814 myProjectionState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
817 // =======================================================================
818 // function : InvalidateOrientation
820 // =======================================================================
821 void Graphic3d_Camera::InvalidateOrientation()
823 myMatricesD.ResetOrientation();
824 myMatricesF.ResetOrientation();
825 myOrientationState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
828 // =======================================================================
829 // function : OrthoProj
831 // =======================================================================
832 template <typename Elem_t>
833 void Graphic3d_Camera::OrthoProj (const Elem_t theLeft,
834 const Elem_t theRight,
835 const Elem_t theBottom,
837 const Elem_t theNear,
839 NCollection_Mat4<Elem_t>& theOutMx)
842 theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theRight - theLeft);
843 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
844 theOutMx.ChangeValue (0, 2) = Elem_t (0.0);
845 theOutMx.ChangeValue (0, 3) = - (theRight + theLeft) / (theRight - theLeft);
848 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
849 theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theTop - theBottom);
850 theOutMx.ChangeValue (1, 2) = Elem_t (0.0);
851 theOutMx.ChangeValue (1, 3) = - (theTop + theBottom) / (theTop - theBottom);
854 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
855 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
856 theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear);
857 theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear);
860 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
861 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
862 theOutMx.ChangeValue (3, 2) = Elem_t (0.0);
863 theOutMx.ChangeValue (3, 3) = Elem_t (1.0);
866 // =======================================================================
867 // function : PerspectiveProj
869 // =======================================================================
870 template <typename Elem_t>
871 void Graphic3d_Camera::PerspectiveProj (const Elem_t theLeft,
872 const Elem_t theRight,
873 const Elem_t theBottom,
875 const Elem_t theNear,
877 NCollection_Mat4<Elem_t>& theOutMx)
880 theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theRight - theLeft);
881 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
882 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
883 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
886 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
887 theOutMx.ChangeValue (1, 1) = (Elem_t (2.0) * theNear) / (theTop - theBottom);
888 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
889 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
892 theOutMx.ChangeValue (0, 2) = (theRight + theLeft) / (theRight - theLeft);
893 theOutMx.ChangeValue (1, 2) = (theTop + theBottom) / (theTop - theBottom);
894 theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear);
895 theOutMx.ChangeValue (3, 2) = Elem_t (-1.0);
898 theOutMx.ChangeValue (0, 3) = Elem_t (0.0);
899 theOutMx.ChangeValue (1, 3) = Elem_t (0.0);
900 theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear);
901 theOutMx.ChangeValue (3, 3) = Elem_t (0.0);
904 // =======================================================================
905 // function : StereoEyeProj
907 // =======================================================================
908 template <typename Elem_t>
909 void Graphic3d_Camera::StereoEyeProj (const Elem_t theLeft,
910 const Elem_t theRight,
911 const Elem_t theBottom,
913 const Elem_t theNear,
916 const Elem_t theZFocus,
917 const Standard_Boolean theIsLeft,
918 NCollection_Mat4<Elem_t>& theOutMx)
920 Elem_t aDx = theIsLeft ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD;
921 Elem_t aDXStereoShift = aDx * theNear / theZFocus;
923 // construct eye projection matrix
924 PerspectiveProj (theLeft + aDXStereoShift,
925 theRight + aDXStereoShift,
926 theBottom, theTop, theNear, theFar,
929 if (theIOD != Elem_t (0.0))
931 // X translation to cancel parallax
932 theOutMx.Translate (NCollection_Vec3<Elem_t> (aDx, Elem_t (0.0), Elem_t (0.0)));
936 // =======================================================================
937 // function : LookOrientation
939 // =======================================================================
940 template <typename Elem_t>
941 void Graphic3d_Camera::LookOrientation (const NCollection_Vec3<Elem_t>& theEye,
942 const NCollection_Vec3<Elem_t>& theLookAt,
943 const NCollection_Vec3<Elem_t>& theUpDir,
944 const NCollection_Vec3<Elem_t>& theAxialScale,
945 NCollection_Mat4<Elem_t>& theOutMx)
947 NCollection_Vec3<Elem_t> aForward = theLookAt - theEye;
948 aForward.Normalize();
950 // side = forward x up
951 NCollection_Vec3<Elem_t> aSide = NCollection_Vec3<Elem_t>::Cross (aForward, theUpDir);
954 // recompute up as: up = side x forward
955 NCollection_Vec3<Elem_t> anUp = NCollection_Vec3<Elem_t>::Cross (aSide, aForward);
957 NCollection_Mat4<Elem_t> aLookMx;
958 aLookMx.SetRow (0, aSide);
959 aLookMx.SetRow (1, anUp);
960 aLookMx.SetRow (2, -aForward);
962 theOutMx.InitIdentity();
963 theOutMx.Multiply (aLookMx);
964 theOutMx.Translate (-theEye);
966 NCollection_Mat4<Elem_t> anAxialScaleMx;
967 anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x();
968 anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y();
969 anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z();
971 theOutMx.Multiply (anAxialScaleMx);
974 //=============================================================================
977 //=============================================================================
978 void Graphic3d_Camera::ZFitAll (const Standard_Real theScaleFactor, const Bnd_Box& theMinMax, const Bnd_Box& theGraphicBB)
980 Standard_ASSERT_RAISE (theScaleFactor > 0.0, "Zero or negative scale factor is not allowed.");
982 // Method changes ZNear and ZFar planes of camera so as to fit the graphical structures
983 // by their real boundaries (computed ignoring infinite flag) into the viewing volume.
984 // In addition to the graphical boundaries, the usual min max used for fitting perspective
985 // camera. To avoid numeric errors for perspective camera the negative ZNear values are
986 // fixed using tolerance distance, relative to boundaries size. The tolerance distance
987 // should be computed using information on boundaries of primary application actors,
988 // (e.g. representing the displayed model) - to ensure that they are not unreasonably clipped.
989 const Standard_ShortReal anEpsilon = 1e-4f;
991 if (theGraphicBB.IsVoid())
993 // Precision factor used to add meaningful tolerance to
994 // ZNear, ZFar values in order to avoid equality after type conversion
995 // to ShortReal matrices type.
997 Standard_Real aZFar = Distance() * 3.0;
998 Standard_Real aZNear = 0.0;
1000 if (!IsOrthographic())
1002 if (aZFar < anEpsilon)
1005 aZFar = anEpsilon * 2.0;
1007 else if (aZNear < aZFar * anEpsilon)
1009 aZNear = aZFar * anEpsilon;
1013 SetZRange (aZNear, aZFar);
1017 // Measure depth of boundary points from camera eye
1018 NCollection_Sequence<gp_Pnt> aPntsToMeasure;
1020 Standard_Real aGraphicBB[6]; // real graphical boundaries (not accounting infinite flag).
1021 theGraphicBB.Get (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2], aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]);
1023 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2]));
1024 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[5]));
1025 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[2]));
1026 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[5]));
1027 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[2]));
1028 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[5]));
1029 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[2]));
1030 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]));
1032 if (!theMinMax.IsVoid() && !theMinMax.IsWhole())
1034 Standard_Real aMinMax[6]; // applicative min max boundaries
1035 theMinMax.Get (aMinMax[0], aMinMax[1], aMinMax[2], aMinMax[3], aMinMax[4], aMinMax[5]);
1037 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[2]));
1038 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[5]));
1039 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[2]));
1040 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[5]));
1041 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[2]));
1042 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[5]));
1043 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[2]));
1044 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[5]));
1048 gp_Dir aCamDir = Direction();
1049 gp_Pnt aCamEye = myEye;
1050 gp_Pln aCamPln (aCamEye, aCamDir);
1052 Standard_Real aModelMinDist = RealLast();
1053 Standard_Real aModelMaxDist = RealFirst();
1054 Standard_Real aGraphicMinDist = RealLast();
1055 Standard_Real aGraphicMaxDist = RealFirst();
1057 const gp_XYZ& anAxialScale = myAxialScale;
1059 // Get minimum and maximum distances to the eye plane
1060 Standard_Integer aCounter = 0;
1061 NCollection_Sequence<gp_Pnt>::Iterator aPntIt(aPntsToMeasure);
1062 for (; aPntIt.More(); aPntIt.Next())
1064 gp_Pnt aMeasurePnt = aPntIt.Value();
1066 aMeasurePnt = gp_Pnt (aMeasurePnt.X() * anAxialScale.X(),
1067 aMeasurePnt.Y() * anAxialScale.Y(),
1068 aMeasurePnt.Z() * anAxialScale.Z());
1070 Standard_Real aDistance = aCamPln.Distance (aMeasurePnt);
1072 // Check if the camera is intruded into the scene
1073 if (aCamDir.IsOpposite (gp_Vec (aCamEye, aMeasurePnt), M_PI * 0.5))
1078 // the first eight points are from theGraphicBB, the last eight points are from theMinMax
1079 // (they can be absent).
1080 Standard_Real& aChangeMinDist = aCounter >= 8 ? aModelMinDist : aGraphicMinDist;
1081 Standard_Real& aChangeMaxDist = aCounter >= 8 ? aModelMaxDist : aGraphicMaxDist;
1082 aChangeMinDist = Min (aDistance, aChangeMinDist);
1083 aChangeMaxDist = Max (aDistance, aChangeMaxDist);
1087 // Compute depth of bounding box center
1088 Standard_Real aMidDepth = (aGraphicMinDist + aGraphicMaxDist) * 0.5;
1089 Standard_Real aHalfDepth = (aGraphicMaxDist - aGraphicMinDist) * 0.5;
1091 // Compute enlarged or shrank near and far z ranges
1092 Standard_Real aZNear = aMidDepth - aHalfDepth * theScaleFactor;
1093 Standard_Real aZFar = aMidDepth + aHalfDepth * theScaleFactor;
1094 Standard_Real aZRange = Abs (aZFar - aZNear);
1095 Standard_Real aZConf = Max (static_cast <Standard_Real> (anEpsilon * aZRange),
1096 static_cast <Standard_Real> (anEpsilon));
1098 aZNear -= Abs (aZNear) * anEpsilon + aZConf;
1099 aZFar += Abs (aZFar) * anEpsilon + aZConf;
1101 if (!IsOrthographic())
1103 if (aZFar > anEpsilon)
1105 // Choose between model distance and graphical distance, as the model boundaries
1106 // might be infinite if all structures have infinite flag.
1107 const Standard_Real aGraphicDepth = aGraphicMaxDist >= aGraphicMinDist
1108 ? aGraphicMaxDist - aGraphicMinDist : RealLast();
1110 const Standard_Real aModelDepth = aModelMaxDist >= aModelMinDist
1111 ? aModelMaxDist - aModelMinDist : RealLast();
1113 const Standard_Real aMinDepth = Min (aModelDepth, aGraphicDepth);
1114 const Standard_Real aZTol = Max (static_cast<Standard_Real> (anEpsilon * Abs (aMinDepth)),
1115 static_cast<Standard_Real> (anEpsilon));
1124 aZFar = anEpsilon * 2.0;
1128 if (aZFar < (aZNear + Abs (aZFar) * anEpsilon))
1130 aZFar = aZNear + Abs (aZFar) * anEpsilon;
1133 SetZRange (aZNear, aZFar);