1 // Created on: 2013-05-29
2 // Created by: Anton POLETAEV
3 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <Graphic3d_Camera.hxx>
19 #include <gp_QuaternionNLerp.hxx>
20 #include <gp_QuaternionSLerp.hxx>
21 #include <Graphic3d_Vec4.hxx>
22 #include <Graphic3d_WorldViewProjState.hxx>
23 #include <NCollection_Sequence.hxx>
24 #include <Standard_ShortReal.hxx>
25 #include <Standard_Atomic.hxx>
26 #include <Standard_Assert.hxx>
28 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_Camera,Standard_Transient)
32 // (degrees -> radians) * 0.5
33 static const Standard_Real DTR_HALF = 0.5 * 0.0174532925;
35 // default property values
36 static const Standard_Real DEFAULT_ZNEAR = 0.001;
37 static const Standard_Real DEFAULT_ZFAR = 3000.0;
39 // atomic state counter
40 static volatile Standard_Integer THE_STATE_COUNTER = 0;
42 // z-range tolerance compatible with for floating point.
43 static Standard_Real zEpsilon()
48 // relative z-range tolerance compatible with for floating point.
49 static Standard_Real zEpsilon (const Standard_Real theValue)
51 Standard_Real anAbsValue = Abs (theValue);
52 if (anAbsValue <= (double)FLT_MIN)
56 Standard_Real aLogRadix = Log10 (anAbsValue) / Log10 (FLT_RADIX);
57 Standard_Real aExp = Floor (aLogRadix);
58 return FLT_EPSILON * Pow (FLT_RADIX, aExp);
61 //! Convert camera definition to Ax3
62 gp_Ax3 cameraToAx3 (const Graphic3d_Camera& theCamera)
64 const gp_Dir aBackDir = -theCamera.Direction();
65 const gp_Dir anXAxis (theCamera.Up().Crossed (aBackDir));
66 const gp_Dir anYAxis (aBackDir .Crossed (anXAxis));
67 const gp_Dir aZAxis (anXAxis .Crossed (anYAxis));
68 return gp_Ax3 (gp_Pnt (0.0, 0.0, 0.0), aZAxis, anXAxis);
72 // =======================================================================
73 // function : Graphic3d_Camera
75 // =======================================================================
76 Graphic3d_Camera::Graphic3d_Camera()
77 : myUp (0.0, 1.0, 0.0),
78 myDirection (0.0, 0.0, 1.0),
79 myEye (0.0, 0.0, -1500.0),
81 myAxialScale (1.0, 1.0, 1.0),
82 myProjType (Projection_Orthographic),
84 myFOVyTan (Tan (DTR_HALF * 45.0)),
85 myZNear (DEFAULT_ZNEAR),
86 myZFar (DEFAULT_ZFAR),
90 myZFocusType (FocusType_Relative),
92 myIODType (IODType_Relative)
94 myWorldViewProjState.Initialize ((Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER),
95 (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER),
99 // =======================================================================
100 // function : Graphic3d_Camera
102 // =======================================================================
103 Graphic3d_Camera::Graphic3d_Camera (const Handle(Graphic3d_Camera)& theOther)
104 : myUp (0.0, 1.0, 0.0),
105 myDirection (0.0, 0.0, 1.0),
106 myEye (0.0, 0.0, -1500.0),
108 myAxialScale (1.0, 1.0, 1.0),
109 myProjType (Projection_Orthographic),
111 myFOVyTan (Tan (DTR_HALF * 45.0)),
112 myZNear (DEFAULT_ZNEAR),
113 myZFar (DEFAULT_ZFAR),
117 myZFocusType (FocusType_Relative),
119 myIODType (IODType_Relative)
121 myWorldViewProjState.Initialize (this);
126 // =======================================================================
127 // function : CopyMappingData
129 // =======================================================================
130 void Graphic3d_Camera::CopyMappingData (const Handle(Graphic3d_Camera)& theOtherCamera)
132 SetFOVy (theOtherCamera->FOVy());
133 SetZRange (theOtherCamera->ZNear(), theOtherCamera->ZFar());
134 SetAspect (theOtherCamera->Aspect());
135 SetScale (theOtherCamera->Scale());
136 SetZFocus (theOtherCamera->ZFocusType(), theOtherCamera->ZFocus());
137 SetIOD (theOtherCamera->GetIODType(), theOtherCamera->IOD());
138 SetProjectionType (theOtherCamera->ProjectionType());
139 SetTile (theOtherCamera->myTile);
142 // =======================================================================
143 // function : CopyOrientationData
145 // =======================================================================
146 void Graphic3d_Camera::CopyOrientationData (const Handle(Graphic3d_Camera)& theOtherCamera)
148 if (!myEye.IsEqual (theOtherCamera->Eye(), 0.0)
149 || !myUp.IsEqual (theOtherCamera->Up(), 0.0)
150 || !myDirection.IsEqual (theOtherCamera->Direction(), 0.0)
151 || myDistance != theOtherCamera->Distance())
153 myEye = theOtherCamera->Eye();
154 myUp = theOtherCamera->Up();
155 myDirection = theOtherCamera->Direction();
156 myDistance = theOtherCamera->Distance();
157 InvalidateOrientation();
159 SetAxialScale (theOtherCamera->AxialScale());
162 // =======================================================================
165 // =======================================================================
166 void Graphic3d_Camera::Copy (const Handle(Graphic3d_Camera)& theOther)
168 CopyMappingData (theOther);
169 CopyOrientationData (theOther);
172 // =======================================================================
173 // function : MoveEyeTo
175 // =======================================================================
176 void Graphic3d_Camera::MoveEyeTo (const gp_Pnt& theEye)
178 if (myEye.IsEqual (theEye, 0.0))
184 InvalidateOrientation();
187 // =======================================================================
188 // function : SetEyeAndCenter
190 // =======================================================================
191 void Graphic3d_Camera::SetEyeAndCenter (const gp_Pnt& theEye,
192 const gp_Pnt& theCenter)
194 if (Eye() .IsEqual (theEye, 0.0)
195 && Center().IsEqual (theCenter, 0.0))
201 myDistance = theEye.Distance (theCenter);
202 if (myDistance > gp::Resolution())
204 myDirection = gp_Dir (theCenter.XYZ() - theEye.XYZ());
206 InvalidateOrientation();
209 // =======================================================================
212 // =======================================================================
213 void Graphic3d_Camera::SetEye (const gp_Pnt& theEye)
215 if (Eye().IsEqual (theEye, 0.0))
220 const gp_Pnt aCenter = Center();
222 myDistance = myEye.Distance (aCenter);
223 if (myDistance > gp::Resolution())
225 myDirection = gp_Dir (aCenter.XYZ() - myEye.XYZ());
227 InvalidateOrientation();
230 // =======================================================================
231 // function : SetCenter
233 // =======================================================================
234 void Graphic3d_Camera::SetCenter (const gp_Pnt& theCenter)
236 const Standard_Real aDistance = myEye.Distance (theCenter);
237 if (myDistance == aDistance)
242 myDistance = aDistance;
243 if (myDistance > gp::Resolution())
245 myDirection = gp_Dir (theCenter.XYZ() - myEye.XYZ());
247 InvalidateOrientation();
250 // =======================================================================
253 // =======================================================================
254 void Graphic3d_Camera::SetUp (const gp_Dir& theUp)
256 if (Up().IsEqual (theUp, 0.0))
262 InvalidateOrientation();
265 // =======================================================================
266 // function : SetAxialScale
268 // =======================================================================
269 void Graphic3d_Camera::SetAxialScale (const gp_XYZ& theAxialScale)
271 if (AxialScale().IsEqual (theAxialScale, 0.0))
276 myAxialScale = theAxialScale;
277 InvalidateOrientation();
280 // =======================================================================
281 // function : SetDistance
283 // =======================================================================
284 void Graphic3d_Camera::SetDistance (const Standard_Real theDistance)
286 if (myDistance == theDistance)
291 const gp_Pnt aCenter = Center();
292 myDistance = theDistance;
293 myEye = aCenter.XYZ() - myDirection.XYZ() * myDistance;
294 InvalidateOrientation();
297 // =======================================================================
298 // function : SetDirectionFromEye
300 // =======================================================================
301 void Graphic3d_Camera::SetDirectionFromEye (const gp_Dir& theDir)
303 if (myDirection.IsEqual (theDir, 0.0))
308 myDirection = theDir;
309 InvalidateOrientation();
312 // =======================================================================
313 // function : SetDirection
315 // =======================================================================
316 void Graphic3d_Camera::SetDirection (const gp_Dir& theDir)
318 if (myDirection.IsEqual (theDir, 0.0))
323 const gp_Pnt aCenter = Center();
324 myDirection = theDir;
325 myEye = aCenter.XYZ() - theDir.XYZ() * myDistance;
326 InvalidateOrientation();
329 // =======================================================================
330 // function : SetScale
332 // =======================================================================
333 void Graphic3d_Camera::SetScale (const Standard_Real theScale)
335 if (Scale() == theScale)
344 case Projection_Perspective :
345 case Projection_Stereo :
346 case Projection_MonoLeftEye :
347 case Projection_MonoRightEye :
349 Standard_Real aDistance = theScale * 0.5 / myFOVyTan;
350 SetDistance (aDistance);
357 InvalidateProjection();
360 // =======================================================================
363 // =======================================================================
364 Standard_Real Graphic3d_Camera::Scale() const
368 case Projection_Orthographic :
371 // case Projection_Perspective :
372 // case Projection_Stereo :
373 // case Projection_MonoLeftEye :
374 // case Projection_MonoRightEye :
376 return Distance() * 2.0 * myFOVyTan;
380 // =======================================================================
381 // function : SetProjectionType
383 // =======================================================================
384 void Graphic3d_Camera::SetProjectionType (const Projection theProjectionType)
386 Projection anOldType = ProjectionType();
388 if (anOldType == theProjectionType)
393 if (anOldType == Projection_Orthographic)
395 if (myZNear <= RealEpsilon())
397 myZNear = DEFAULT_ZNEAR;
399 if (myZFar <= RealEpsilon())
401 myZFar = DEFAULT_ZFAR;
405 myProjType = theProjectionType;
407 InvalidateProjection();
410 // =======================================================================
411 // function : SetFOVy
413 // =======================================================================
414 void Graphic3d_Camera::SetFOVy (const Standard_Real theFOVy)
416 if (FOVy() == theFOVy)
422 myFOVyTan = Tan(DTR_HALF * myFOVy);
424 InvalidateProjection();
427 // =======================================================================
428 // function : SetZRange
430 // =======================================================================
431 void Graphic3d_Camera::SetZRange (const Standard_Real theZNear,
432 const Standard_Real theZFar)
434 Standard_ASSERT_RAISE (theZFar > theZNear, "ZFar should be greater than ZNear");
435 if (!IsOrthographic())
437 Standard_ASSERT_RAISE (theZNear > 0.0, "Only positive Z-Near is allowed for perspective camera");
438 Standard_ASSERT_RAISE (theZFar > 0.0, "Only positive Z-Far is allowed for perspective camera");
441 if (ZNear() == theZNear
442 && ZFar () == theZFar)
450 InvalidateProjection();
453 // =======================================================================
454 // function : SetAspect
456 // =======================================================================
457 void Graphic3d_Camera::SetAspect (const Standard_Real theAspect)
459 if (Aspect() == theAspect)
464 myAspect = theAspect;
466 InvalidateProjection();
469 // =======================================================================
470 // function : SetZFocus
472 // =======================================================================
473 void Graphic3d_Camera::SetZFocus(const FocusType theType, const Standard_Real theZFocus)
475 if (ZFocusType() == theType
476 && ZFocus () == theZFocus)
481 myZFocusType = theType;
482 myZFocus = theZFocus;
484 InvalidateProjection();
487 // =======================================================================
490 // =======================================================================
491 void Graphic3d_Camera::SetIOD (const IODType theType, const Standard_Real theIOD)
493 if (GetIODType() == theType
502 InvalidateProjection();
505 // =======================================================================
506 // function : SetTile
508 // =======================================================================
509 void Graphic3d_Camera::SetTile (const Graphic3d_CameraTile& theTile)
511 if (myTile == theTile)
517 InvalidateProjection();
520 // =======================================================================
521 // function : OrthogonalizeUp
523 // =======================================================================
524 void Graphic3d_Camera::OrthogonalizeUp()
526 SetUp (OrthogonalizedUp());
529 // =======================================================================
530 // function : OrthogonalizedUp
532 // =======================================================================
533 gp_Dir Graphic3d_Camera::OrthogonalizedUp() const
535 gp_Dir aDir = Direction();
536 gp_Dir aLeft = aDir.Crossed (Up());
538 // recompute up as: up = left x direction
539 return aLeft.Crossed (aDir);
542 // =======================================================================
543 // function : Transform
545 // =======================================================================
546 void Graphic3d_Camera::Transform (const gp_Trsf& theTrsf)
548 if (theTrsf.Form() == gp_Identity)
553 myUp .Transform (theTrsf);
554 myDirection.Transform (theTrsf);
555 myEye.Transform (theTrsf);
556 InvalidateOrientation();
559 // =======================================================================
560 // function : safePointCast
562 // =======================================================================
563 static Graphic3d_Vec4d safePointCast (const gp_Pnt& thePnt)
565 Standard_Real aLim = 1e15f;
567 // have to deal with values greater then max float
568 gp_Pnt aSafePoint = thePnt;
569 const Standard_Real aBigFloat = aLim * 0.1f;
570 if (Abs (aSafePoint.X()) > aLim)
571 aSafePoint.SetX (aSafePoint.X() >= 0 ? aBigFloat : -aBigFloat);
572 if (Abs (aSafePoint.Y()) > aLim)
573 aSafePoint.SetY (aSafePoint.Y() >= 0 ? aBigFloat : -aBigFloat);
574 if (Abs (aSafePoint.Z()) > aLim)
575 aSafePoint.SetZ (aSafePoint.Z() >= 0 ? aBigFloat : -aBigFloat);
578 Graphic3d_Vec4d aPnt (aSafePoint.X(), aSafePoint.Y(), aSafePoint.Z(), 1.0);
583 // =======================================================================
584 // function : Project
586 // =======================================================================
587 gp_Pnt Graphic3d_Camera::Project (const gp_Pnt& thePnt) const
589 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
590 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
592 // use compatible type of point
593 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
595 aPnt = aViewMx * aPnt; // convert to view coordinate space
596 aPnt = aProjMx * aPnt; // convert to projection coordinate space
598 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
600 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
603 // =======================================================================
604 // function : UnProject
606 // =======================================================================
607 gp_Pnt Graphic3d_Camera::UnProject (const gp_Pnt& thePnt) const
609 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
610 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
612 Graphic3d_Mat4d aInvView;
613 Graphic3d_Mat4d aInvProj;
615 // this case should never happen
616 if (!aViewMx.Inverted (aInvView) || !aProjMx.Inverted (aInvProj))
618 return gp_Pnt (0.0, 0.0, 0.0);
621 // use compatible type of point
622 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
624 aPnt = aInvProj * aPnt; // convert to view coordinate space
625 aPnt = aInvView * aPnt; // convert to world coordinate space
627 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
629 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
632 // =======================================================================
633 // function : ConvertView2Proj
635 // =======================================================================
636 gp_Pnt Graphic3d_Camera::ConvertView2Proj (const gp_Pnt& thePnt) const
638 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
640 // use compatible type of point
641 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
643 aPnt = aProjMx * aPnt; // convert to projection coordinate space
645 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
647 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
650 // =======================================================================
651 // function : ConvertProj2View
653 // =======================================================================
654 gp_Pnt Graphic3d_Camera::ConvertProj2View (const gp_Pnt& thePnt) const
656 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
658 Graphic3d_Mat4d aInvProj;
660 // this case should never happen, but...
661 if (!aProjMx.Inverted (aInvProj))
663 return gp_Pnt (0, 0, 0);
666 // use compatible type of point
667 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
669 aPnt = aInvProj * aPnt; // convert to view coordinate space
671 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
673 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
676 // =======================================================================
677 // function : ConvertWorld2View
679 // =======================================================================
680 gp_Pnt Graphic3d_Camera::ConvertWorld2View (const gp_Pnt& thePnt) const
682 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
684 // use compatible type of point
685 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
687 aPnt = aViewMx * aPnt; // convert to view coordinate space
689 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
691 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
694 // =======================================================================
695 // function : ConvertView2World
697 // =======================================================================
698 gp_Pnt Graphic3d_Camera::ConvertView2World (const gp_Pnt& thePnt) const
700 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
702 Graphic3d_Mat4d aInvView;
704 if (!aViewMx.Inverted (aInvView))
706 return gp_Pnt(0, 0, 0);
709 // use compatible type of point
710 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
712 aPnt = aInvView * aPnt; // convert to world coordinate space
714 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
716 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
719 // =======================================================================
720 // function : ViewDimensions
722 // =======================================================================
723 gp_XYZ Graphic3d_Camera::ViewDimensions (const Standard_Real theZValue) const
725 // view plane dimensions
726 Standard_Real aSize = IsOrthographic() ? myScale : (2.0 * theZValue * myFOVyTan);
727 Standard_Real aSizeX, aSizeY;
730 aSizeX = aSize * myAspect;
736 aSizeY = aSize / myAspect;
740 return gp_XYZ (aSizeX, aSizeY, myZFar - myZNear);
743 // =======================================================================
744 // function : Frustum
746 // =======================================================================
747 void Graphic3d_Camera::Frustum (gp_Pln& theLeft,
752 gp_Pln& theFar) const
754 gp_Vec aProjection = gp_Vec (Direction());
755 gp_Vec anUp = OrthogonalizedUp();
756 gp_Vec aSide = aProjection ^ anUp;
758 Standard_ASSERT_RAISE (
759 !aProjection.IsParallel (anUp, Precision::Angular()),
760 "Can not derive SIDE = PROJ x UP - directions are parallel");
762 theNear = gp_Pln (Eye().Translated (aProjection * ZNear()), aProjection);
763 theFar = gp_Pln (Eye().Translated (aProjection * ZFar()), -aProjection);
765 Standard_Real aHScaleHor = 0.0, aHScaleVer = 0.0;
768 aHScaleHor = Scale() * 0.5 * Aspect();
769 aHScaleVer = Scale() * 0.5;
773 aHScaleHor = Scale() * 0.5;
774 aHScaleVer = Scale() * 0.5 / Aspect();
777 gp_Pnt aPntLeft = Center().Translated (aHScaleHor * -aSide);
778 gp_Pnt aPntRight = Center().Translated (aHScaleHor * aSide);
779 gp_Pnt aPntBottom = Center().Translated (aHScaleVer * -anUp);
780 gp_Pnt aPntTop = Center().Translated (aHScaleVer * anUp);
782 gp_Vec aDirLeft = aSide;
783 gp_Vec aDirRight = -aSide;
784 gp_Vec aDirBottom = anUp;
785 gp_Vec aDirTop = -anUp;
786 if (!IsOrthographic())
788 Standard_Real aHFOVHor = ATan (Tan (DTR_HALF * FOVy()) * Aspect());
789 Standard_Real aHFOVVer = DTR_HALF * FOVy();
790 aDirLeft.Rotate (gp_Ax1 (gp::Origin(), anUp), aHFOVHor);
791 aDirRight.Rotate (gp_Ax1 (gp::Origin(), anUp), -aHFOVHor);
792 aDirBottom.Rotate (gp_Ax1 (gp::Origin(), aSide), -aHFOVVer);
793 aDirTop.Rotate (gp_Ax1 (gp::Origin(), aSide), aHFOVVer);
796 theLeft = gp_Pln (aPntLeft, aDirLeft);
797 theRight = gp_Pln (aPntRight, aDirRight);
798 theBottom = gp_Pln (aPntBottom, aDirBottom);
799 theTop = gp_Pln (aPntTop, aDirTop);
802 // =======================================================================
803 // function : OrientationMatrix
805 // =======================================================================
806 const Graphic3d_Mat4d& Graphic3d_Camera::OrientationMatrix() const
808 return UpdateOrientation (myMatricesD).Orientation;
811 // =======================================================================
812 // function : OrientationMatrixF
814 // =======================================================================
815 const Graphic3d_Mat4& Graphic3d_Camera::OrientationMatrixF() const
817 return UpdateOrientation (myMatricesF).Orientation;
820 // =======================================================================
821 // function : ProjectionMatrix
823 // =======================================================================
824 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionMatrix() const
826 return UpdateProjection (myMatricesD).MProjection;
829 // =======================================================================
830 // function : ProjectionMatrixF
832 // =======================================================================
833 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionMatrixF() const
835 return UpdateProjection (myMatricesF).MProjection;
838 // =======================================================================
839 // function : ProjectionStereoLeft
841 // =======================================================================
842 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoLeft() const
844 return UpdateProjection (myMatricesD).LProjection;
847 // =======================================================================
848 // function : ProjectionStereoLeftF
850 // =======================================================================
851 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoLeftF() const
853 return UpdateProjection (myMatricesF).LProjection;
856 // =======================================================================
857 // function : ProjectionStereoRight
859 // =======================================================================
860 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoRight() const
862 return UpdateProjection (myMatricesD).RProjection;
865 // =======================================================================
866 // function : ProjectionStereoRightF
868 // =======================================================================
869 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoRightF() const
871 return UpdateProjection (myMatricesF).RProjection;
874 // =======================================================================
875 // function : UpdateProjection
877 // =======================================================================
878 template <typename Elem_t>
879 Graphic3d_Camera::TransformMatrices<Elem_t>&
880 Graphic3d_Camera::UpdateProjection (TransformMatrices<Elem_t>& theMatrices) const
882 if (theMatrices.IsProjectionValid())
884 return theMatrices; // for inline accessors
887 theMatrices.InitProjection();
889 // sets top of frustum based on FOVy and near clipping plane
890 Elem_t aScale = static_cast<Elem_t> (myScale);
891 Elem_t aZNear = static_cast<Elem_t> (myZNear);
892 Elem_t aZFar = static_cast<Elem_t> (myZFar);
893 Elem_t anAspect = static_cast<Elem_t> (myAspect);
894 Elem_t aDXHalf = 0.0, aDYHalf = 0.0;
895 if (IsOrthographic())
897 aDXHalf = aScale * Elem_t (0.5);
898 aDYHalf = aScale * Elem_t (0.5);
902 aDXHalf = aZNear * Elem_t (myFOVyTan);
903 aDYHalf = aZNear * Elem_t (myFOVyTan);
915 // sets right of frustum based on aspect ratio
916 Elem_t aLeft = -aDXHalf;
917 Elem_t aRight = aDXHalf;
918 Elem_t aBot = -aDYHalf;
919 Elem_t aTop = aDYHalf;
921 Elem_t aIOD = myIODType == IODType_Relative
922 ? static_cast<Elem_t> (myIOD * Distance())
923 : static_cast<Elem_t> (myIOD);
925 Elem_t aFocus = myZFocusType == FocusType_Relative
926 ? static_cast<Elem_t> (myZFocus * Distance())
927 : static_cast<Elem_t> (myZFocus);
929 if (myTile.IsValid())
931 const Elem_t aDXFull = Elem_t(2) * aDXHalf;
932 const Elem_t aDYFull = Elem_t(2) * aDYHalf;
933 const Graphic3d_Vec2i anOffset = myTile.OffsetLowerLeft();
934 aLeft = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x()) / static_cast<Elem_t> (myTile.TotalSize.x());
935 aRight = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x() + myTile.TileSize.x()) / static_cast<Elem_t> (myTile.TotalSize.x());
936 aBot = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y()) / static_cast<Elem_t> (myTile.TotalSize.y());
937 aTop = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y() + myTile.TileSize.y()) / static_cast<Elem_t> (myTile.TotalSize.y());
942 case Projection_Orthographic :
943 OrthoProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, theMatrices.MProjection);
946 case Projection_Perspective :
947 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, theMatrices.MProjection);
950 case Projection_MonoLeftEye :
952 StereoEyeProj (aLeft, aRight, aBot, aTop,
953 aZNear, aZFar, aIOD, aFocus,
954 Standard_True, theMatrices.MProjection);
955 theMatrices.LProjection = theMatrices.MProjection;
959 case Projection_MonoRightEye :
961 StereoEyeProj (aLeft, aRight, aBot, aTop,
962 aZNear, aZFar, aIOD, aFocus,
963 Standard_False, theMatrices.MProjection);
964 theMatrices.RProjection = theMatrices.MProjection;
968 case Projection_Stereo :
970 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, theMatrices.MProjection);
972 StereoEyeProj (aLeft, aRight, aBot, aTop,
973 aZNear, aZFar, aIOD, aFocus,
975 theMatrices.LProjection);
977 StereoEyeProj (aLeft, aRight, aBot, aTop,
978 aZNear, aZFar, aIOD, aFocus,
980 theMatrices.RProjection);
985 return theMatrices; // for inline accessors
988 // =======================================================================
989 // function : UpdateOrientation
991 // =======================================================================
992 template <typename Elem_t>
993 Graphic3d_Camera::TransformMatrices<Elem_t>&
994 Graphic3d_Camera::UpdateOrientation (TransformMatrices<Elem_t>& theMatrices) const
996 if (theMatrices.IsOrientationValid())
998 return theMatrices; // for inline accessors
1001 theMatrices.InitOrientation();
1003 NCollection_Vec3<Elem_t> anEye (static_cast<Elem_t> (myEye.X()),
1004 static_cast<Elem_t> (myEye.Y()),
1005 static_cast<Elem_t> (myEye.Z()));
1007 NCollection_Vec3<Elem_t> aViewDir (static_cast<Elem_t> (myDirection.X()),
1008 static_cast<Elem_t> (myDirection.Y()),
1009 static_cast<Elem_t> (myDirection.Z()));
1011 NCollection_Vec3<Elem_t> anUp (static_cast<Elem_t> (myUp.X()),
1012 static_cast<Elem_t> (myUp.Y()),
1013 static_cast<Elem_t> (myUp.Z()));
1015 NCollection_Vec3<Elem_t> anAxialScale (static_cast<Elem_t> (myAxialScale.X()),
1016 static_cast<Elem_t> (myAxialScale.Y()),
1017 static_cast<Elem_t> (myAxialScale.Z()));
1019 LookOrientation (anEye, aViewDir, anUp, anAxialScale, theMatrices.Orientation);
1021 return theMatrices; // for inline accessors
1024 // =======================================================================
1025 // function : InvalidateProjection
1027 // =======================================================================
1028 void Graphic3d_Camera::InvalidateProjection()
1030 myMatricesD.ResetProjection();
1031 myMatricesF.ResetProjection();
1032 myWorldViewProjState.ProjectionState() = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
1035 // =======================================================================
1036 // function : InvalidateOrientation
1038 // =======================================================================
1039 void Graphic3d_Camera::InvalidateOrientation()
1041 myMatricesD.ResetOrientation();
1042 myMatricesF.ResetOrientation();
1043 myWorldViewProjState.WorldViewState() = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
1046 // =======================================================================
1047 // function : OrthoProj
1049 // =======================================================================
1050 template <typename Elem_t>
1051 void Graphic3d_Camera::OrthoProj (const Elem_t theLeft,
1052 const Elem_t theRight,
1053 const Elem_t theBottom,
1054 const Elem_t theTop,
1055 const Elem_t theNear,
1056 const Elem_t theFar,
1057 NCollection_Mat4<Elem_t>& theOutMx)
1060 theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theRight - theLeft);
1061 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
1062 theOutMx.ChangeValue (0, 2) = Elem_t (0.0);
1063 theOutMx.ChangeValue (0, 3) = - (theRight + theLeft) / (theRight - theLeft);
1066 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
1067 theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theTop - theBottom);
1068 theOutMx.ChangeValue (1, 2) = Elem_t (0.0);
1069 theOutMx.ChangeValue (1, 3) = - (theTop + theBottom) / (theTop - theBottom);
1072 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
1073 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
1074 theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear);
1075 theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear);
1078 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
1079 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
1080 theOutMx.ChangeValue (3, 2) = Elem_t (0.0);
1081 theOutMx.ChangeValue (3, 3) = Elem_t (1.0);
1084 // =======================================================================
1085 // function : PerspectiveProj
1087 // =======================================================================
1088 template <typename Elem_t>
1089 void Graphic3d_Camera::PerspectiveProj (const Elem_t theLeft,
1090 const Elem_t theRight,
1091 const Elem_t theBottom,
1092 const Elem_t theTop,
1093 const Elem_t theNear,
1094 const Elem_t theFar,
1095 NCollection_Mat4<Elem_t>& theOutMx)
1098 theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theRight - theLeft);
1099 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
1100 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
1101 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
1104 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
1105 theOutMx.ChangeValue (1, 1) = (Elem_t (2.0) * theNear) / (theTop - theBottom);
1106 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
1107 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
1110 theOutMx.ChangeValue (0, 2) = (theRight + theLeft) / (theRight - theLeft);
1111 theOutMx.ChangeValue (1, 2) = (theTop + theBottom) / (theTop - theBottom);
1112 theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear);
1113 theOutMx.ChangeValue (3, 2) = Elem_t (-1.0);
1116 theOutMx.ChangeValue (0, 3) = Elem_t (0.0);
1117 theOutMx.ChangeValue (1, 3) = Elem_t (0.0);
1118 theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear);
1119 theOutMx.ChangeValue (3, 3) = Elem_t (0.0);
1122 // =======================================================================
1123 // function : StereoEyeProj
1125 // =======================================================================
1126 template <typename Elem_t>
1127 void Graphic3d_Camera::StereoEyeProj (const Elem_t theLeft,
1128 const Elem_t theRight,
1129 const Elem_t theBottom,
1130 const Elem_t theTop,
1131 const Elem_t theNear,
1132 const Elem_t theFar,
1133 const Elem_t theIOD,
1134 const Elem_t theZFocus,
1135 const Standard_Boolean theIsLeft,
1136 NCollection_Mat4<Elem_t>& theOutMx)
1138 Elem_t aDx = theIsLeft ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD;
1139 Elem_t aDXStereoShift = aDx * theNear / theZFocus;
1141 // construct eye projection matrix
1142 PerspectiveProj (theLeft + aDXStereoShift,
1143 theRight + aDXStereoShift,
1144 theBottom, theTop, theNear, theFar,
1147 if (theIOD != Elem_t (0.0))
1149 // X translation to cancel parallax
1150 theOutMx.Translate (NCollection_Vec3<Elem_t> (aDx, Elem_t (0.0), Elem_t (0.0)));
1154 // =======================================================================
1155 // function : LookOrientation
1157 // =======================================================================
1158 template <typename Elem_t>
1159 void Graphic3d_Camera::LookOrientation (const NCollection_Vec3<Elem_t>& theEye,
1160 const NCollection_Vec3<Elem_t>& theFwdDir,
1161 const NCollection_Vec3<Elem_t>& theUpDir,
1162 const NCollection_Vec3<Elem_t>& theAxialScale,
1163 NCollection_Mat4<Elem_t>& theOutMx)
1165 NCollection_Vec3<Elem_t> aForward = theFwdDir;
1166 aForward.Normalize();
1168 // side = forward x up
1169 NCollection_Vec3<Elem_t> aSide = NCollection_Vec3<Elem_t>::Cross (aForward, theUpDir);
1172 // recompute up as: up = side x forward
1173 NCollection_Vec3<Elem_t> anUp = NCollection_Vec3<Elem_t>::Cross (aSide, aForward);
1175 NCollection_Mat4<Elem_t> aLookMx;
1176 aLookMx.SetRow (0, aSide);
1177 aLookMx.SetRow (1, anUp);
1178 aLookMx.SetRow (2, -aForward);
1180 theOutMx.InitIdentity();
1181 theOutMx.Multiply (aLookMx);
1182 theOutMx.Translate (-theEye);
1184 NCollection_Mat4<Elem_t> anAxialScaleMx;
1185 anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x();
1186 anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y();
1187 anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z();
1189 theOutMx.Multiply (anAxialScaleMx);
1192 //=============================================================================
1193 //function : ZFitAll
1195 //=============================================================================
1196 bool Graphic3d_Camera::ZFitAll (const Standard_Real theScaleFactor,
1197 const Bnd_Box& theMinMax,
1198 const Bnd_Box& theGraphicBB,
1199 Standard_Real& theZNear,
1200 Standard_Real& theZFar) const
1202 Standard_ASSERT_RAISE (theScaleFactor > 0.0, "Zero or negative scale factor is not allowed.");
1204 // Method changes zNear and zFar parameters of camera so as to fit graphical structures
1205 // by their graphical boundaries. It precisely fits min max boundaries of primary application
1206 // objects (second argument), while it can sacrifice the real graphical boundaries of the
1207 // scene with infinite or helper objects (third argument) for the sake of perspective projection.
1208 if (theGraphicBB.IsVoid())
1210 theZNear = DEFAULT_ZNEAR;
1211 theZFar = DEFAULT_ZFAR;
1215 // Measure depth of boundary points from camera eye.
1216 NCollection_Sequence<gp_Pnt> aPntsToMeasure;
1218 Standard_Real aGraphicBB[6];
1219 theGraphicBB.Get (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2], aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]);
1221 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2]));
1222 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[5]));
1223 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[2]));
1224 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[5]));
1225 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[2]));
1226 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[5]));
1227 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[2]));
1228 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]));
1230 Standard_Boolean isFiniteMinMax = !theMinMax.IsVoid() && !theMinMax.IsWhole();
1234 Standard_Real aMinMax[6];
1235 theMinMax.Get (aMinMax[0], aMinMax[1], aMinMax[2], aMinMax[3], aMinMax[4], aMinMax[5]);
1237 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[2]));
1238 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[5]));
1239 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[2]));
1240 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[5]));
1241 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[2]));
1242 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[5]));
1243 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[2]));
1244 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[5]));
1247 // Camera eye plane.
1248 gp_Dir aCamDir = Direction();
1249 gp_Pnt aCamEye = myEye;
1250 gp_Pln aCamPln (aCamEye, aCamDir);
1252 Standard_Real aModelMinDist = RealLast();
1253 Standard_Real aModelMaxDist = RealFirst();
1254 Standard_Real aGraphMinDist = RealLast();
1255 Standard_Real aGraphMaxDist = RealFirst();
1257 const gp_XYZ& anAxialScale = myAxialScale;
1259 // Get minimum and maximum distances to the eye plane.
1260 Standard_Integer aCounter = 0;
1261 NCollection_Sequence<gp_Pnt>::Iterator aPntIt(aPntsToMeasure);
1262 for (; aPntIt.More(); aPntIt.Next())
1264 gp_Pnt aMeasurePnt = aPntIt.Value();
1266 aMeasurePnt = gp_Pnt (aMeasurePnt.X() * anAxialScale.X(),
1267 aMeasurePnt.Y() * anAxialScale.Y(),
1268 aMeasurePnt.Z() * anAxialScale.Z());
1270 Standard_Real aDistance = aCamPln.Distance (aMeasurePnt);
1272 // Check if the camera is intruded into the scene.
1273 gp_Vec aVecToMeasurePnt (aCamEye, aMeasurePnt);
1274 if (aVecToMeasurePnt.Magnitude() > gp::Resolution()
1275 && aCamDir.IsOpposite (aVecToMeasurePnt, M_PI * 0.5))
1280 // The first eight points are from theGraphicBB, the last eight points are from theMinMax (can be absent).
1281 Standard_Real& aChangeMinDist = aCounter >= 8 ? aModelMinDist : aGraphMinDist;
1282 Standard_Real& aChangeMaxDist = aCounter >= 8 ? aModelMaxDist : aGraphMaxDist;
1283 aChangeMinDist = Min (aDistance, aChangeMinDist);
1284 aChangeMaxDist = Max (aDistance, aChangeMaxDist);
1288 // Compute depth of bounding box center.
1289 Standard_Real aMidDepth = (aGraphMinDist + aGraphMaxDist) * 0.5;
1290 Standard_Real aHalfDepth = (aGraphMaxDist - aGraphMinDist) * 0.5;
1292 // Compute enlarged or shrank near and far z ranges.
1293 Standard_Real aZNear = aMidDepth - aHalfDepth * theScaleFactor;
1294 Standard_Real aZFar = aMidDepth + aHalfDepth * theScaleFactor;
1296 if (!IsOrthographic())
1298 // Everything is behind the perspective camera.
1299 if (aZFar < zEpsilon())
1301 theZNear = DEFAULT_ZNEAR;
1302 theZFar = DEFAULT_ZFAR;
1308 // Consider clipping errors due to double to single precision floating-point conversion.
1311 // Model to view transformation performs translation of points against eye position
1312 // in three dimensions. Both point coordinate and eye position values are converted from
1313 // double to single precision floating point numbers producing conversion errors.
1314 // Epsilon (Mod) * 3.0 should safely compensate precision error for z coordinate after
1315 // translation assuming that the:
1316 // Epsilon (Eye.Mod()) * 3.0 > Epsilon (Eye.X()) + Epsilon (Eye.Y()) + Epsilon (Eye.Z()).
1317 Standard_Real aEyeConf = 3.0 * zEpsilon (myEye.XYZ().Modulus());
1319 // Model to view transformation performs rotation of points according to view direction.
1320 // New z coordinate is computed as a multiplication of point's x, y, z coordinates by the
1321 // "forward" direction vector's x, y, z coordinates. Both point's and "z" direction vector's
1322 // values are converted from double to single precision floating point numbers producing
1323 // conversion errors.
1324 // Epsilon (Mod) * 6.0 should safely compensate the precision errors for the multiplication
1325 // of point coordinates by direction vector.
1326 gp_Pnt aGraphicMin = theGraphicBB.CornerMin();
1327 gp_Pnt aGraphicMax = theGraphicBB.CornerMax();
1329 Standard_Real aModelConf = 6.0 * zEpsilon (aGraphicMin.XYZ().Modulus()) +
1330 6.0 * zEpsilon (aGraphicMax.XYZ().Modulus());
1332 // Compensate floating point conversion errors by increasing zNear, zFar to avoid clipping.
1333 aZNear -= zEpsilon (aZNear) + aEyeConf + aModelConf;
1334 aZFar += zEpsilon (aZFar) + aEyeConf + aModelConf;
1336 if (!IsOrthographic())
1338 // For perspective projection, the value of z in normalized device coordinates is non-linear
1339 // function of eye z coordinate. For fixed-point depth representation resolution of z in
1340 // model-view space will grow towards zFar plane and its scale depends mostly on how far is zNear
1341 // against camera's eye. The purpose of the code below is to select most appropriate zNear distance
1342 // to balance between clipping (less zNear, more chances to observe closely small models without clipping)
1343 // and resolution of depth. A well applicable criteria to this is a ratio between resolution of z at center
1344 // of model boundaries and the distance to that center point. The ratio is chosen empirically and validated
1345 // by tests database. It is considered to be ~0.001 (0.1%) for 24 bit depth buffer, for less depth bitness
1346 // the zNear will be placed similarly giving lower resolution.
1347 // Approximation of the formula for respectively large z range is:
1348 // zNear = [z * (1 + k) / (k * c)],
1350 // z - distance to center of model boundaries;
1351 // k - chosen ratio, c - capacity of depth buffer;
1352 // k = 0.001, k * c = 1677.216, (1 + k) / (k * c) ~ 5.97E-4
1354 // The function uses center of model boundaries computed from "theMinMax" boundaries (instead of using real
1355 // graphical boundaries of all displayed objects). That means that it can sacrifice resolution of presentation
1356 // of non primary ("infinite") application graphical objects in favor of better perspective projection of the
1357 // small applicative objects measured with "theMinMax" values.
1358 Standard_Real aZRange = isFiniteMinMax ? aModelMaxDist - aModelMinDist : aGraphMaxDist - aGraphMinDist;
1359 Standard_Real aZMin = isFiniteMinMax ? aModelMinDist : aGraphMinDist;
1360 Standard_Real aZ = aZMin < 0 ? aZRange / 2.0 : aZRange / 2.0 + aZMin;
1361 Standard_Real aZNearMin = aZ * 5.97E-4;
1362 if (aZNear < aZNearMin)
1364 // Clip zNear according to the minimum value matching the quality.
1373 // Compensate zNear conversion errors for perspective projection.
1374 aZNear -= aZFar * zEpsilon (aZNear) / (aZFar - zEpsilon (aZNear));
1377 // Compensate zFar conversion errors for perspective projection.
1378 aZFar += zEpsilon (aZFar);
1380 // Ensure that after all the zNear is not a negative value.
1381 if (aZNear < zEpsilon())
1383 aZNear = zEpsilon();
1385 Standard_ASSERT_RAISE (aZFar > aZNear, "ZFar should be greater than ZNear");
1390 Standard_ASSERT_RAISE (aZFar > aZNear, "ZFar should be greater than ZNear");
1394 //=============================================================================
1395 //function : Interpolate
1397 //=============================================================================
1399 Standard_EXPORT void NCollection_Lerp<Handle(Graphic3d_Camera)>::Interpolate (const double theT,
1400 Handle(Graphic3d_Camera)& theCamera) const
1402 if (Abs (theT - 1.0) < Precision::Confusion())
1404 // just copy end-point transformation
1405 theCamera->Copy (myEnd);
1409 theCamera->Copy (myStart);
1410 if (Abs (theT - 0.0) < Precision::Confusion())
1417 gp_Ax3 aCamStart = cameraToAx3 (*myStart);
1418 gp_Ax3 aCamEnd = cameraToAx3 (*myEnd);
1419 gp_Trsf aTrsfStart, aTrsfEnd;
1420 aTrsfStart.SetTransformation (aCamStart, gp::XOY());
1421 aTrsfEnd .SetTransformation (aCamEnd, gp::XOY());
1423 gp_Quaternion aRotStart = aTrsfStart.GetRotation();
1424 gp_Quaternion aRotEnd = aTrsfEnd .GetRotation();
1425 gp_Quaternion aRotDelta = aRotEnd * aRotStart.Inverted();
1426 gp_Quaternion aRot = gp_QuaternionNLerp::Interpolate (gp_Quaternion(), aRotDelta, theT);
1428 aTrsfRot.SetRotation (aRot);
1429 theCamera->Transform (aTrsfRot);
1432 // apply translation
1434 gp_XYZ aCenter = NCollection_Lerp<gp_XYZ>::Interpolate (myStart->Center().XYZ(), myEnd->Center().XYZ(), theT);
1435 gp_XYZ anEye = NCollection_Lerp<gp_XYZ>::Interpolate (myStart->Eye().XYZ(), myEnd->Eye().XYZ(), theT);
1436 gp_XYZ anAnchor = aCenter;
1437 Standard_Real aKc = 0.0;
1439 const Standard_Real aDeltaCenter = myStart->Center().Distance (myEnd->Center());
1440 const Standard_Real aDeltaEye = myStart->Eye() .Distance (myEnd->Eye());
1441 if (aDeltaEye <= gp::Resolution())
1446 else if (aDeltaCenter > gp::Resolution())
1448 aKc = aDeltaCenter / (aDeltaCenter + aDeltaEye);
1450 const gp_XYZ anAnchorStart = NCollection_Lerp<gp_XYZ>::Interpolate (myStart->Center().XYZ(), myStart->Eye().XYZ(), aKc);
1451 const gp_XYZ anAnchorEnd = NCollection_Lerp<gp_XYZ>::Interpolate (myEnd ->Center().XYZ(), myEnd ->Eye().XYZ(), aKc);
1452 anAnchor = NCollection_Lerp<gp_XYZ>::Interpolate (anAnchorStart, anAnchorEnd, theT);
1455 const gp_Vec aDirEyeToCenter = theCamera->Direction();
1456 const Standard_Real aDistEyeCenterStart = myStart->Eye().Distance (myStart->Center());
1457 const Standard_Real aDistEyeCenterEnd = myEnd ->Eye().Distance (myEnd ->Center());
1458 const Standard_Real aDistEyeCenter = NCollection_Lerp<Standard_Real>::Interpolate (aDistEyeCenterStart, aDistEyeCenterEnd, theT);
1459 aCenter = anAnchor + aDirEyeToCenter.XYZ() * aDistEyeCenter * aKc;
1460 anEye = anAnchor - aDirEyeToCenter.XYZ() * aDistEyeCenter * (1.0 - aKc);
1462 theCamera->SetEyeAndCenter (anEye, aCenter);
1466 if (Abs(myStart->Scale() - myEnd->Scale()) > Precision::Confusion()
1467 && myStart->IsOrthographic())
1469 const Standard_Real aScale = NCollection_Lerp<Standard_Real>::Interpolate (myStart->Scale(), myEnd->Scale(), theT);
1470 theCamera->SetScale (aScale);
1474 //=======================================================================
1475 //function : FrustumPoints
1477 //=======================================================================
1478 void Graphic3d_Camera::FrustumPoints (NCollection_Array1<Graphic3d_Vec3d>& thePoints) const
1480 if (thePoints.Length() != FrustumVerticesNB)
1482 thePoints.Resize (0, FrustumVerticesNB, Standard_False);
1485 const Graphic3d_Mat4d& aProjectionMat = ProjectionMatrix();
1486 const Graphic3d_Mat4d& aWorldViewMat = OrientationMatrix();
1488 Standard_Real nLeft = 0.0, nRight = 0.0, nTop = 0.0, nBottom = 0.0;
1489 Standard_Real fLeft = 0.0, fRight = 0.0, fTop = 0.0, fBottom = 0.0;
1490 Standard_Real aNear = 0.0, aFar = 0.0;
1491 if (!IsOrthographic())
1493 // handle perspective projection
1494 aNear = aProjectionMat.GetValue (2, 3) / (-1.0 + aProjectionMat.GetValue (2, 2));
1495 aFar = aProjectionMat.GetValue (2, 3) / ( 1.0 + aProjectionMat.GetValue (2, 2));
1497 nLeft = aNear * (aProjectionMat.GetValue (0, 2) - 1.0) / aProjectionMat.GetValue (0, 0);
1498 nRight = aNear * (aProjectionMat.GetValue (0, 2) + 1.0) / aProjectionMat.GetValue (0, 0);
1499 nTop = aNear * (aProjectionMat.GetValue (1, 2) + 1.0) / aProjectionMat.GetValue (1, 1);
1500 nBottom = aNear * (aProjectionMat.GetValue (1, 2) - 1.0) / aProjectionMat.GetValue (1, 1);
1502 fLeft = aFar * (aProjectionMat.GetValue (0, 2) - 1.0) / aProjectionMat.GetValue (0, 0);
1503 fRight = aFar * (aProjectionMat.GetValue (0, 2) + 1.0) / aProjectionMat.GetValue (0, 0);
1504 fTop = aFar * (aProjectionMat.GetValue (1, 2) + 1.0) / aProjectionMat.GetValue (1, 1);
1505 fBottom = aFar * (aProjectionMat.GetValue (1, 2) - 1.0) / aProjectionMat.GetValue (1, 1);
1509 // handle orthographic projection
1510 aNear = (1.0 / aProjectionMat.GetValue (2, 2)) * (aProjectionMat.GetValue (2, 3) + 1.0);
1511 aFar = (1.0 / aProjectionMat.GetValue (2, 2)) * (aProjectionMat.GetValue (2, 3) - 1.0);
1513 nLeft = ( 1.0 + aProjectionMat.GetValue (0, 3)) / (-aProjectionMat.GetValue (0, 0));
1515 nRight = ( 1.0 - aProjectionMat.GetValue (0, 3)) / aProjectionMat.GetValue (0, 0);
1517 nTop = ( 1.0 - aProjectionMat.GetValue (1, 3)) / aProjectionMat.GetValue (1, 1);
1519 nBottom = (-1.0 - aProjectionMat.GetValue (1, 3)) / aProjectionMat.GetValue (1, 1);
1523 Graphic3d_Vec4d aLeftTopNear (nLeft, nTop, -aNear, 1.0), aRightBottomFar (fRight, fBottom, -aFar, 1.0);
1524 Graphic3d_Vec4d aLeftBottomNear (nLeft, nBottom, -aNear, 1.0), aRightTopFar (fRight, fTop, -aFar, 1.0);
1525 Graphic3d_Vec4d aRightBottomNear (nRight, nBottom, -aNear, 1.0), aLeftTopFar (fLeft, fTop, -aFar, 1.0);
1526 Graphic3d_Vec4d aRightTopNear (nRight, nTop, -aNear, 1.0), aLeftBottomFar (fLeft, fBottom, -aFar, 1.0);
1528 Graphic3d_Mat4d anInvWorldView;
1529 aWorldViewMat.Inverted (anInvWorldView);
1531 Graphic3d_Vec4d aTmpPnt;
1532 aTmpPnt = anInvWorldView * aLeftTopNear;
1533 thePoints.SetValue (FrustumVert_LeftTopNear, aTmpPnt.xyz() / aTmpPnt.w());
1534 aTmpPnt = anInvWorldView * aRightBottomFar;
1535 thePoints.SetValue (FrustumVert_RightBottomFar, aTmpPnt.xyz() / aTmpPnt.w());
1536 aTmpPnt = anInvWorldView * aLeftBottomNear;
1537 thePoints.SetValue (FrustumVert_LeftBottomNear, aTmpPnt.xyz() / aTmpPnt.w());
1538 aTmpPnt = anInvWorldView * aRightTopFar;
1539 thePoints.SetValue (FrustumVert_RightTopFar, aTmpPnt.xyz() / aTmpPnt.w());
1540 aTmpPnt = anInvWorldView * aRightBottomNear;
1541 thePoints.SetValue (FrustumVert_RightBottomNear, aTmpPnt.xyz() / aTmpPnt.w());
1542 aTmpPnt = anInvWorldView * aLeftTopFar;
1543 thePoints.SetValue (FrustumVert_LeftTopFar, aTmpPnt.xyz() / aTmpPnt.w());
1544 aTmpPnt = anInvWorldView * aRightTopNear;
1545 thePoints.SetValue (FrustumVert_RightTopNear, aTmpPnt.xyz() / aTmpPnt.w());
1546 aTmpPnt = anInvWorldView * aLeftBottomFar;
1547 thePoints.SetValue (FrustumVert_LeftBottomFar, aTmpPnt.xyz() / aTmpPnt.w());