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 // minimum camera distance
43 static const Standard_Real MIN_DISTANCE = Pow (0.1, ShortRealDigits() - 2);
45 // z-range tolerance compatible with for floating point.
46 static Standard_Real zEpsilon()
51 // relative z-range tolerance compatible with for floating point.
52 static Standard_Real zEpsilon (const Standard_Real theValue)
54 Standard_Real anAbsValue = Abs (theValue);
55 if (anAbsValue <= (double)FLT_MIN)
59 Standard_Real aLogRadix = Log10 (anAbsValue) / Log10 (FLT_RADIX);
60 Standard_Real aExp = Floor (aLogRadix);
61 return FLT_EPSILON * Pow (FLT_RADIX, aExp);
64 //! Convert camera definition to Ax3
65 gp_Ax3 cameraToAx3 (const Graphic3d_Camera& theCamera)
67 const gp_Dir aBackDir(gp_Vec(theCamera.Center(), theCamera.Eye()));
68 const gp_Dir anXAxis (theCamera.Up().Crossed (aBackDir));
69 const gp_Dir anYAxis (aBackDir .Crossed (anXAxis));
70 const gp_Dir aZAxis (anXAxis .Crossed (anYAxis));
71 return gp_Ax3 (gp_Pnt (0.0, 0.0, 0.0), aZAxis, anXAxis);
75 // =======================================================================
76 // function : Graphic3d_Camera
78 // =======================================================================
79 Graphic3d_Camera::Graphic3d_Camera()
80 : myUp (0.0, 1.0, 0.0),
81 myEye (0.0, 0.0, -1500.0),
82 myCenter (0.0, 0.0, 0.0),
83 myAxialScale (1.0, 1.0, 1.0),
84 myProjType (Projection_Orthographic),
86 myFOVyTan (Tan (DTR_HALF * 45.0)),
87 myZNear (DEFAULT_ZNEAR),
88 myZFar (DEFAULT_ZFAR),
92 myZFocusType (FocusType_Relative),
94 myIODType (IODType_Relative)
96 myWorldViewProjState.Initialize ((Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER),
97 (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER),
101 // =======================================================================
102 // function : Graphic3d_Camera
104 // =======================================================================
105 Graphic3d_Camera::Graphic3d_Camera (const Handle(Graphic3d_Camera)& theOther)
106 : myUp (0.0, 1.0, 0.0),
107 myEye (0.0, 0.0, -1500.0),
108 myCenter (0.0, 0.0, 0.0),
109 myAxialScale (1.0, 1.0, 1.0),
110 myProjType (Projection_Orthographic),
112 myFOVyTan (Tan (DTR_HALF * 45.0)),
113 myZNear (DEFAULT_ZNEAR),
114 myZFar (DEFAULT_ZFAR),
118 myZFocusType (FocusType_Relative),
120 myIODType (IODType_Relative)
122 myWorldViewProjState.Initialize (this);
127 // =======================================================================
128 // function : CopyMappingData
130 // =======================================================================
131 void Graphic3d_Camera::CopyMappingData (const Handle(Graphic3d_Camera)& theOtherCamera)
133 SetFOVy (theOtherCamera->FOVy());
134 SetZRange (theOtherCamera->ZNear(), theOtherCamera->ZFar());
135 SetAspect (theOtherCamera->Aspect());
136 SetScale (theOtherCamera->Scale());
137 SetZFocus (theOtherCamera->ZFocusType(), theOtherCamera->ZFocus());
138 SetIOD (theOtherCamera->GetIODType(), theOtherCamera->IOD());
139 SetProjectionType (theOtherCamera->ProjectionType());
140 SetTile (theOtherCamera->myTile);
143 // =======================================================================
144 // function : CopyOrientationData
146 // =======================================================================
147 void Graphic3d_Camera::CopyOrientationData (const Handle(Graphic3d_Camera)& theOtherCamera)
149 SetUp (theOtherCamera->Up());
150 SetEye (theOtherCamera->Eye());
151 SetCenter (theOtherCamera->Center());
152 SetAxialScale (theOtherCamera->AxialScale());
155 // =======================================================================
158 // =======================================================================
159 void Graphic3d_Camera::Copy (const Handle(Graphic3d_Camera)& theOther)
161 CopyMappingData (theOther);
162 CopyOrientationData (theOther);
165 // =======================================================================
168 // =======================================================================
169 void Graphic3d_Camera::SetEye (const gp_Pnt& theEye)
171 if (Eye().IsEqual (theEye, 0.0))
177 InvalidateOrientation();
180 // =======================================================================
181 // function : SetCenter
183 // =======================================================================
184 void Graphic3d_Camera::SetCenter (const gp_Pnt& theCenter)
186 if (Center().IsEqual (theCenter, 0.0))
191 myCenter = theCenter;
192 InvalidateOrientation();
195 // =======================================================================
198 // =======================================================================
199 void Graphic3d_Camera::SetUp (const gp_Dir& theUp)
201 if (Up().IsEqual (theUp, 0.0))
207 InvalidateOrientation();
210 // =======================================================================
211 // function : SetAxialScale
213 // =======================================================================
214 void Graphic3d_Camera::SetAxialScale (const gp_XYZ& theAxialScale)
216 if (AxialScale().IsEqual (theAxialScale, 0.0))
221 myAxialScale = theAxialScale;
222 InvalidateOrientation();
225 // =======================================================================
226 // function : SetDistance
228 // =======================================================================
229 void Graphic3d_Camera::SetDistance (const Standard_Real theDistance)
231 if (Distance() == theDistance)
236 gp_Vec aCenter2Eye (Direction());
237 aCenter2Eye.Reverse();
239 // Camera should have non-zero distance.
240 aCenter2Eye.Scale (Max (theDistance, MIN_DISTANCE));
241 SetEye (Center().Translated (aCenter2Eye));
244 // =======================================================================
245 // function : Distance
247 // =======================================================================
248 Standard_Real Graphic3d_Camera::Distance() const
250 return myEye.Distance (myCenter);
253 // =======================================================================
254 // function : SetDirection
256 // =======================================================================
257 void Graphic3d_Camera::SetDirection (const gp_Dir& theDir)
259 if (Direction().IsEqual (theDir, 0.0))
264 gp_Vec aScaledDir (theDir);
265 aScaledDir.Scale (Distance());
266 aScaledDir.Reverse();
267 SetEye (Center().Translated (aScaledDir));
270 // =======================================================================
271 // function : Direction
273 // =======================================================================
274 gp_Dir Graphic3d_Camera::Direction() const
276 return gp_Dir (gp_Vec (myEye, myCenter));
279 // =======================================================================
280 // function : SetScale
282 // =======================================================================
283 void Graphic3d_Camera::SetScale (const Standard_Real theScale)
285 if (Scale() == theScale)
294 case Projection_Perspective :
295 case Projection_Stereo :
296 case Projection_MonoLeftEye :
297 case Projection_MonoRightEye :
299 Standard_Real aDistance = theScale * 0.5 / myFOVyTan;
300 SetDistance (aDistance);
307 InvalidateProjection();
310 // =======================================================================
313 // =======================================================================
314 Standard_Real Graphic3d_Camera::Scale() const
318 case Projection_Orthographic :
321 // case Projection_Perspective :
322 // case Projection_Stereo :
323 // case Projection_MonoLeftEye :
324 // case Projection_MonoRightEye :
326 return Distance() * 2.0 * myFOVyTan;
330 // =======================================================================
331 // function : SetProjectionType
333 // =======================================================================
334 void Graphic3d_Camera::SetProjectionType (const Projection theProjectionType)
336 Projection anOldType = ProjectionType();
338 if (anOldType == theProjectionType)
343 if (anOldType == Projection_Orthographic)
345 if (myZNear <= RealEpsilon())
347 myZNear = DEFAULT_ZNEAR;
349 if (myZFar <= RealEpsilon())
351 myZFar = DEFAULT_ZFAR;
355 myProjType = theProjectionType;
357 InvalidateProjection();
360 // =======================================================================
361 // function : SetFOVy
363 // =======================================================================
364 void Graphic3d_Camera::SetFOVy (const Standard_Real theFOVy)
366 if (FOVy() == theFOVy)
372 myFOVyTan = Tan(DTR_HALF * myFOVy);
374 InvalidateProjection();
377 // =======================================================================
378 // function : SetZRange
380 // =======================================================================
381 void Graphic3d_Camera::SetZRange (const Standard_Real theZNear,
382 const Standard_Real theZFar)
384 Standard_ASSERT_RAISE (theZFar > theZNear, "ZFar should be greater than ZNear");
385 if (!IsOrthographic())
387 Standard_ASSERT_RAISE (theZNear > 0.0, "Only positive Z-Near is allowed for perspective camera");
388 Standard_ASSERT_RAISE (theZFar > 0.0, "Only positive Z-Far is allowed for perspective camera");
391 if (ZNear() == theZNear
392 && ZFar () == theZFar)
400 InvalidateProjection();
403 // =======================================================================
404 // function : SetAspect
406 // =======================================================================
407 void Graphic3d_Camera::SetAspect (const Standard_Real theAspect)
409 if (Aspect() == theAspect)
414 myAspect = theAspect;
416 InvalidateProjection();
419 // =======================================================================
420 // function : SetZFocus
422 // =======================================================================
423 void Graphic3d_Camera::SetZFocus(const FocusType theType, const Standard_Real theZFocus)
425 if (ZFocusType() == theType
426 && ZFocus () == theZFocus)
431 myZFocusType = theType;
432 myZFocus = theZFocus;
434 InvalidateProjection();
437 // =======================================================================
440 // =======================================================================
441 void Graphic3d_Camera::SetIOD (const IODType theType, const Standard_Real theIOD)
443 if (GetIODType() == theType
452 InvalidateProjection();
455 // =======================================================================
456 // function : SetTile
458 // =======================================================================
459 void Graphic3d_Camera::SetTile (const Graphic3d_CameraTile& theTile)
461 if (myTile == theTile)
467 InvalidateProjection();
470 // =======================================================================
471 // function : OrthogonalizeUp
473 // =======================================================================
474 void Graphic3d_Camera::OrthogonalizeUp()
476 SetUp (OrthogonalizedUp());
479 // =======================================================================
480 // function : OrthogonalizedUp
482 // =======================================================================
483 gp_Dir Graphic3d_Camera::OrthogonalizedUp() const
485 gp_Dir aDir = Direction();
486 gp_Dir aLeft = aDir.Crossed (Up());
488 // recompute up as: up = left x direction
489 return aLeft.Crossed (aDir);
492 // =======================================================================
493 // function : Transform
495 // =======================================================================
496 void Graphic3d_Camera::Transform (const gp_Trsf& theTrsf)
498 if (theTrsf.Form() == gp_Identity)
503 SetUp (myUp.Transformed (theTrsf));
504 SetEye (myEye.Transformed (theTrsf));
505 SetCenter (myCenter.Transformed (theTrsf));
508 // =======================================================================
509 // function : safePointCast
511 // =======================================================================
512 static Graphic3d_Vec4d safePointCast (const gp_Pnt& thePnt)
514 Standard_Real aLim = 1e15f;
516 // have to deal with values greater then max float
517 gp_Pnt aSafePoint = thePnt;
518 const Standard_Real aBigFloat = aLim * 0.1f;
519 if (Abs (aSafePoint.X()) > aLim)
520 aSafePoint.SetX (aSafePoint.X() >= 0 ? aBigFloat : -aBigFloat);
521 if (Abs (aSafePoint.Y()) > aLim)
522 aSafePoint.SetY (aSafePoint.Y() >= 0 ? aBigFloat : -aBigFloat);
523 if (Abs (aSafePoint.Z()) > aLim)
524 aSafePoint.SetZ (aSafePoint.Z() >= 0 ? aBigFloat : -aBigFloat);
527 Graphic3d_Vec4d aPnt (aSafePoint.X(), aSafePoint.Y(), aSafePoint.Z(), 1.0);
532 // =======================================================================
533 // function : Project
535 // =======================================================================
536 gp_Pnt Graphic3d_Camera::Project (const gp_Pnt& thePnt) const
538 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
539 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
541 // use compatible type of point
542 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
544 aPnt = aViewMx * aPnt; // convert to view coordinate space
545 aPnt = aProjMx * aPnt; // convert to projection coordinate space
547 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
549 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
552 // =======================================================================
553 // function : UnProject
555 // =======================================================================
556 gp_Pnt Graphic3d_Camera::UnProject (const gp_Pnt& thePnt) const
558 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
559 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
561 Graphic3d_Mat4d aInvView;
562 Graphic3d_Mat4d aInvProj;
564 // this case should never happen
565 if (!aViewMx.Inverted (aInvView) || !aProjMx.Inverted (aInvProj))
567 return gp_Pnt (0.0, 0.0, 0.0);
570 // use compatible type of point
571 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
573 aPnt = aInvProj * aPnt; // convert to view coordinate space
574 aPnt = aInvView * aPnt; // convert to world coordinate space
576 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
578 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
581 // =======================================================================
582 // function : ConvertView2Proj
584 // =======================================================================
585 gp_Pnt Graphic3d_Camera::ConvertView2Proj (const gp_Pnt& thePnt) const
587 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
589 // use compatible type of point
590 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
592 aPnt = aProjMx * aPnt; // convert to projection coordinate space
594 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
596 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
599 // =======================================================================
600 // function : ConvertProj2View
602 // =======================================================================
603 gp_Pnt Graphic3d_Camera::ConvertProj2View (const gp_Pnt& thePnt) const
605 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
607 Graphic3d_Mat4d aInvProj;
609 // this case should never happen, but...
610 if (!aProjMx.Inverted (aInvProj))
612 return gp_Pnt (0, 0, 0);
615 // use compatible type of point
616 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
618 aPnt = aInvProj * aPnt; // convert to view coordinate space
620 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
622 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
625 // =======================================================================
626 // function : ConvertWorld2View
628 // =======================================================================
629 gp_Pnt Graphic3d_Camera::ConvertWorld2View (const gp_Pnt& thePnt) const
631 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
633 // use compatible type of point
634 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
636 aPnt = aViewMx * aPnt; // convert to view coordinate space
638 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
640 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
643 // =======================================================================
644 // function : ConvertView2World
646 // =======================================================================
647 gp_Pnt Graphic3d_Camera::ConvertView2World (const gp_Pnt& thePnt) const
649 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
651 Graphic3d_Mat4d aInvView;
653 if (!aViewMx.Inverted (aInvView))
655 return gp_Pnt(0, 0, 0);
658 // use compatible type of point
659 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
661 aPnt = aInvView * aPnt; // convert to world coordinate space
663 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
665 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
668 // =======================================================================
669 // function : ViewDimensions
671 // =======================================================================
672 gp_XYZ Graphic3d_Camera::ViewDimensions (const Standard_Real theZValue) const
674 // view plane dimensions
675 Standard_Real aSize = IsOrthographic() ? myScale : (2.0 * theZValue * myFOVyTan);
676 Standard_Real aSizeX, aSizeY;
679 aSizeX = aSize * myAspect;
685 aSizeY = aSize / myAspect;
689 return gp_XYZ (aSizeX, aSizeY, myZFar - myZNear);
692 // =======================================================================
693 // function : Frustum
695 // =======================================================================
696 void Graphic3d_Camera::Frustum (gp_Pln& theLeft,
701 gp_Pln& theFar) const
703 gp_Vec aProjection = gp_Vec (Direction());
704 gp_Vec anUp = OrthogonalizedUp();
705 gp_Vec aSide = aProjection ^ anUp;
707 Standard_ASSERT_RAISE (
708 !aProjection.IsParallel (anUp, Precision::Angular()),
709 "Can not derive SIDE = PROJ x UP - directions are parallel");
711 theNear = gp_Pln (Eye().Translated (aProjection * ZNear()), aProjection);
712 theFar = gp_Pln (Eye().Translated (aProjection * ZFar()), -aProjection);
714 Standard_Real aHScaleHor = 0.0, aHScaleVer = 0.0;
717 aHScaleHor = Scale() * 0.5 * Aspect();
718 aHScaleVer = Scale() * 0.5;
722 aHScaleHor = Scale() * 0.5;
723 aHScaleVer = Scale() * 0.5 / Aspect();
726 gp_Pnt aPntLeft = Center().Translated (aHScaleHor * -aSide);
727 gp_Pnt aPntRight = Center().Translated (aHScaleHor * aSide);
728 gp_Pnt aPntBottom = Center().Translated (aHScaleVer * -anUp);
729 gp_Pnt aPntTop = Center().Translated (aHScaleVer * anUp);
731 gp_Vec aDirLeft = aSide;
732 gp_Vec aDirRight = -aSide;
733 gp_Vec aDirBottom = anUp;
734 gp_Vec aDirTop = -anUp;
735 if (!IsOrthographic())
737 Standard_Real aHFOVHor = ATan (Tan (DTR_HALF * FOVy()) * Aspect());
738 Standard_Real aHFOVVer = DTR_HALF * FOVy();
739 aDirLeft.Rotate (gp_Ax1 (gp::Origin(), anUp), aHFOVHor);
740 aDirRight.Rotate (gp_Ax1 (gp::Origin(), anUp), -aHFOVHor);
741 aDirBottom.Rotate (gp_Ax1 (gp::Origin(), aSide), -aHFOVVer);
742 aDirTop.Rotate (gp_Ax1 (gp::Origin(), aSide), aHFOVVer);
745 theLeft = gp_Pln (aPntLeft, aDirLeft);
746 theRight = gp_Pln (aPntRight, aDirRight);
747 theBottom = gp_Pln (aPntBottom, aDirBottom);
748 theTop = gp_Pln (aPntTop, aDirTop);
751 // =======================================================================
752 // function : OrientationMatrix
754 // =======================================================================
755 const Graphic3d_Mat4d& Graphic3d_Camera::OrientationMatrix() const
757 return UpdateOrientation (myMatricesD).Orientation;
760 // =======================================================================
761 // function : OrientationMatrixF
763 // =======================================================================
764 const Graphic3d_Mat4& Graphic3d_Camera::OrientationMatrixF() const
766 return UpdateOrientation (myMatricesF).Orientation;
769 // =======================================================================
770 // function : ProjectionMatrix
772 // =======================================================================
773 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionMatrix() const
775 return UpdateProjection (myMatricesD).MProjection;
778 // =======================================================================
779 // function : ProjectionMatrixF
781 // =======================================================================
782 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionMatrixF() const
784 return UpdateProjection (myMatricesF).MProjection;
787 // =======================================================================
788 // function : ProjectionStereoLeft
790 // =======================================================================
791 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoLeft() const
793 return UpdateProjection (myMatricesD).LProjection;
796 // =======================================================================
797 // function : ProjectionStereoLeftF
799 // =======================================================================
800 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoLeftF() const
802 return UpdateProjection (myMatricesF).LProjection;
805 // =======================================================================
806 // function : ProjectionStereoRight
808 // =======================================================================
809 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoRight() const
811 return UpdateProjection (myMatricesD).RProjection;
814 // =======================================================================
815 // function : ProjectionStereoRightF
817 // =======================================================================
818 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoRightF() const
820 return UpdateProjection (myMatricesF).RProjection;
823 // =======================================================================
824 // function : UpdateProjection
826 // =======================================================================
827 template <typename Elem_t>
828 Graphic3d_Camera::TransformMatrices<Elem_t>&
829 Graphic3d_Camera::UpdateProjection (TransformMatrices<Elem_t>& theMatrices) const
831 if (theMatrices.IsProjectionValid())
833 return theMatrices; // for inline accessors
836 theMatrices.InitProjection();
838 // sets top of frustum based on FOVy and near clipping plane
839 Elem_t aScale = static_cast<Elem_t> (myScale);
840 Elem_t aZNear = static_cast<Elem_t> (myZNear);
841 Elem_t aZFar = static_cast<Elem_t> (myZFar);
842 Elem_t anAspect = static_cast<Elem_t> (myAspect);
843 Elem_t aDXHalf = 0.0, aDYHalf = 0.0;
844 if (IsOrthographic())
846 aDXHalf = aScale * Elem_t (0.5);
847 aDYHalf = aScale * Elem_t (0.5);
851 aDXHalf = aZNear * Elem_t (myFOVyTan);
852 aDYHalf = aZNear * Elem_t (myFOVyTan);
864 // sets right of frustum based on aspect ratio
865 Elem_t aLeft = -aDXHalf;
866 Elem_t aRight = aDXHalf;
867 Elem_t aBot = -aDYHalf;
868 Elem_t aTop = aDYHalf;
870 Elem_t aIOD = myIODType == IODType_Relative
871 ? static_cast<Elem_t> (myIOD * Distance())
872 : static_cast<Elem_t> (myIOD);
874 Elem_t aFocus = myZFocusType == FocusType_Relative
875 ? static_cast<Elem_t> (myZFocus * Distance())
876 : static_cast<Elem_t> (myZFocus);
878 if (myTile.IsValid())
880 const Elem_t aDXFull = Elem_t(2) * aDXHalf;
881 const Elem_t aDYFull = Elem_t(2) * aDYHalf;
882 const Graphic3d_Vec2i anOffset = myTile.OffsetLowerLeft();
883 aLeft = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x()) / static_cast<Elem_t> (myTile.TotalSize.x());
884 aRight = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x() + myTile.TileSize.x()) / static_cast<Elem_t> (myTile.TotalSize.x());
885 aBot = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y()) / static_cast<Elem_t> (myTile.TotalSize.y());
886 aTop = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y() + myTile.TileSize.y()) / static_cast<Elem_t> (myTile.TotalSize.y());
891 case Projection_Orthographic :
892 OrthoProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, theMatrices.MProjection);
895 case Projection_Perspective :
896 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, theMatrices.MProjection);
899 case Projection_MonoLeftEye :
901 StereoEyeProj (aLeft, aRight, aBot, aTop,
902 aZNear, aZFar, aIOD, aFocus,
903 Standard_True, theMatrices.MProjection);
904 theMatrices.LProjection = theMatrices.MProjection;
908 case Projection_MonoRightEye :
910 StereoEyeProj (aLeft, aRight, aBot, aTop,
911 aZNear, aZFar, aIOD, aFocus,
912 Standard_False, theMatrices.MProjection);
913 theMatrices.RProjection = theMatrices.MProjection;
917 case Projection_Stereo :
919 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, theMatrices.MProjection);
921 StereoEyeProj (aLeft, aRight, aBot, aTop,
922 aZNear, aZFar, aIOD, aFocus,
924 theMatrices.LProjection);
926 StereoEyeProj (aLeft, aRight, aBot, aTop,
927 aZNear, aZFar, aIOD, aFocus,
929 theMatrices.RProjection);
934 return theMatrices; // for inline accessors
937 // =======================================================================
938 // function : UpdateOrientation
940 // =======================================================================
941 template <typename Elem_t>
942 Graphic3d_Camera::TransformMatrices<Elem_t>&
943 Graphic3d_Camera::UpdateOrientation (TransformMatrices<Elem_t>& theMatrices) const
945 if (theMatrices.IsOrientationValid())
947 return theMatrices; // for inline accessors
950 theMatrices.InitOrientation();
952 NCollection_Vec3<Elem_t> anEye (static_cast<Elem_t> (myEye.X()),
953 static_cast<Elem_t> (myEye.Y()),
954 static_cast<Elem_t> (myEye.Z()));
956 NCollection_Vec3<Elem_t> aCenter (static_cast<Elem_t> (myCenter.X()),
957 static_cast<Elem_t> (myCenter.Y()),
958 static_cast<Elem_t> (myCenter.Z()));
960 NCollection_Vec3<Elem_t> anUp (static_cast<Elem_t> (myUp.X()),
961 static_cast<Elem_t> (myUp.Y()),
962 static_cast<Elem_t> (myUp.Z()));
964 NCollection_Vec3<Elem_t> anAxialScale (static_cast<Elem_t> (myAxialScale.X()),
965 static_cast<Elem_t> (myAxialScale.Y()),
966 static_cast<Elem_t> (myAxialScale.Z()));
968 LookOrientation (anEye, aCenter, anUp, anAxialScale, theMatrices.Orientation);
970 return theMatrices; // for inline accessors
973 // =======================================================================
974 // function : InvalidateProjection
976 // =======================================================================
977 void Graphic3d_Camera::InvalidateProjection()
979 myMatricesD.ResetProjection();
980 myMatricesF.ResetProjection();
981 myWorldViewProjState.ProjectionState() = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
984 // =======================================================================
985 // function : InvalidateOrientation
987 // =======================================================================
988 void Graphic3d_Camera::InvalidateOrientation()
990 myMatricesD.ResetOrientation();
991 myMatricesF.ResetOrientation();
992 myWorldViewProjState.WorldViewState() = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
995 // =======================================================================
996 // function : OrthoProj
998 // =======================================================================
999 template <typename Elem_t>
1000 void Graphic3d_Camera::OrthoProj (const Elem_t theLeft,
1001 const Elem_t theRight,
1002 const Elem_t theBottom,
1003 const Elem_t theTop,
1004 const Elem_t theNear,
1005 const Elem_t theFar,
1006 NCollection_Mat4<Elem_t>& theOutMx)
1009 theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theRight - theLeft);
1010 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
1011 theOutMx.ChangeValue (0, 2) = Elem_t (0.0);
1012 theOutMx.ChangeValue (0, 3) = - (theRight + theLeft) / (theRight - theLeft);
1015 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
1016 theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theTop - theBottom);
1017 theOutMx.ChangeValue (1, 2) = Elem_t (0.0);
1018 theOutMx.ChangeValue (1, 3) = - (theTop + theBottom) / (theTop - theBottom);
1021 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
1022 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
1023 theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear);
1024 theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear);
1027 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
1028 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
1029 theOutMx.ChangeValue (3, 2) = Elem_t (0.0);
1030 theOutMx.ChangeValue (3, 3) = Elem_t (1.0);
1033 // =======================================================================
1034 // function : PerspectiveProj
1036 // =======================================================================
1037 template <typename Elem_t>
1038 void Graphic3d_Camera::PerspectiveProj (const Elem_t theLeft,
1039 const Elem_t theRight,
1040 const Elem_t theBottom,
1041 const Elem_t theTop,
1042 const Elem_t theNear,
1043 const Elem_t theFar,
1044 NCollection_Mat4<Elem_t>& theOutMx)
1047 theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theRight - theLeft);
1048 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
1049 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
1050 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
1053 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
1054 theOutMx.ChangeValue (1, 1) = (Elem_t (2.0) * theNear) / (theTop - theBottom);
1055 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
1056 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
1059 theOutMx.ChangeValue (0, 2) = (theRight + theLeft) / (theRight - theLeft);
1060 theOutMx.ChangeValue (1, 2) = (theTop + theBottom) / (theTop - theBottom);
1061 theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear);
1062 theOutMx.ChangeValue (3, 2) = Elem_t (-1.0);
1065 theOutMx.ChangeValue (0, 3) = Elem_t (0.0);
1066 theOutMx.ChangeValue (1, 3) = Elem_t (0.0);
1067 theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear);
1068 theOutMx.ChangeValue (3, 3) = Elem_t (0.0);
1071 // =======================================================================
1072 // function : StereoEyeProj
1074 // =======================================================================
1075 template <typename Elem_t>
1076 void Graphic3d_Camera::StereoEyeProj (const Elem_t theLeft,
1077 const Elem_t theRight,
1078 const Elem_t theBottom,
1079 const Elem_t theTop,
1080 const Elem_t theNear,
1081 const Elem_t theFar,
1082 const Elem_t theIOD,
1083 const Elem_t theZFocus,
1084 const Standard_Boolean theIsLeft,
1085 NCollection_Mat4<Elem_t>& theOutMx)
1087 Elem_t aDx = theIsLeft ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD;
1088 Elem_t aDXStereoShift = aDx * theNear / theZFocus;
1090 // construct eye projection matrix
1091 PerspectiveProj (theLeft + aDXStereoShift,
1092 theRight + aDXStereoShift,
1093 theBottom, theTop, theNear, theFar,
1096 if (theIOD != Elem_t (0.0))
1098 // X translation to cancel parallax
1099 theOutMx.Translate (NCollection_Vec3<Elem_t> (aDx, Elem_t (0.0), Elem_t (0.0)));
1103 // =======================================================================
1104 // function : LookOrientation
1106 // =======================================================================
1107 template <typename Elem_t>
1108 void Graphic3d_Camera::LookOrientation (const NCollection_Vec3<Elem_t>& theEye,
1109 const NCollection_Vec3<Elem_t>& theLookAt,
1110 const NCollection_Vec3<Elem_t>& theUpDir,
1111 const NCollection_Vec3<Elem_t>& theAxialScale,
1112 NCollection_Mat4<Elem_t>& theOutMx)
1114 NCollection_Vec3<Elem_t> aForward = theLookAt - theEye;
1115 aForward.Normalize();
1117 // side = forward x up
1118 NCollection_Vec3<Elem_t> aSide = NCollection_Vec3<Elem_t>::Cross (aForward, theUpDir);
1121 // recompute up as: up = side x forward
1122 NCollection_Vec3<Elem_t> anUp = NCollection_Vec3<Elem_t>::Cross (aSide, aForward);
1124 NCollection_Mat4<Elem_t> aLookMx;
1125 aLookMx.SetRow (0, aSide);
1126 aLookMx.SetRow (1, anUp);
1127 aLookMx.SetRow (2, -aForward);
1129 theOutMx.InitIdentity();
1130 theOutMx.Multiply (aLookMx);
1131 theOutMx.Translate (-theEye);
1133 NCollection_Mat4<Elem_t> anAxialScaleMx;
1134 anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x();
1135 anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y();
1136 anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z();
1138 theOutMx.Multiply (anAxialScaleMx);
1141 //=============================================================================
1142 //function : ZFitAll
1144 //=============================================================================
1145 bool Graphic3d_Camera::ZFitAll (const Standard_Real theScaleFactor,
1146 const Bnd_Box& theMinMax,
1147 const Bnd_Box& theGraphicBB,
1148 Standard_Real& theZNear,
1149 Standard_Real& theZFar) const
1151 Standard_ASSERT_RAISE (theScaleFactor > 0.0, "Zero or negative scale factor is not allowed.");
1153 // Method changes zNear and zFar parameters of camera so as to fit graphical structures
1154 // by their graphical boundaries. It precisely fits min max boundaries of primary application
1155 // objects (second argument), while it can sacrifice the real graphical boundaries of the
1156 // scene with infinite or helper objects (third argument) for the sake of perspective projection.
1157 if (theGraphicBB.IsVoid())
1159 theZNear = DEFAULT_ZNEAR;
1160 theZFar = DEFAULT_ZFAR;
1164 // Measure depth of boundary points from camera eye.
1165 NCollection_Sequence<gp_Pnt> aPntsToMeasure;
1167 Standard_Real aGraphicBB[6];
1168 theGraphicBB.Get (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2], aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]);
1170 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2]));
1171 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[5]));
1172 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[2]));
1173 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[5]));
1174 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[2]));
1175 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[5]));
1176 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[2]));
1177 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]));
1179 Standard_Boolean isFiniteMinMax = !theMinMax.IsVoid() && !theMinMax.IsWhole();
1183 Standard_Real aMinMax[6];
1184 theMinMax.Get (aMinMax[0], aMinMax[1], aMinMax[2], aMinMax[3], aMinMax[4], aMinMax[5]);
1186 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[2]));
1187 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[5]));
1188 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[2]));
1189 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[5]));
1190 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[2]));
1191 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[5]));
1192 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[2]));
1193 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[5]));
1196 // Camera eye plane.
1197 gp_Dir aCamDir = Direction();
1198 gp_Pnt aCamEye = myEye;
1199 gp_Pln aCamPln (aCamEye, aCamDir);
1201 Standard_Real aModelMinDist = RealLast();
1202 Standard_Real aModelMaxDist = RealFirst();
1203 Standard_Real aGraphMinDist = RealLast();
1204 Standard_Real aGraphMaxDist = RealFirst();
1206 const gp_XYZ& anAxialScale = myAxialScale;
1208 // Get minimum and maximum distances to the eye plane.
1209 Standard_Integer aCounter = 0;
1210 NCollection_Sequence<gp_Pnt>::Iterator aPntIt(aPntsToMeasure);
1211 for (; aPntIt.More(); aPntIt.Next())
1213 gp_Pnt aMeasurePnt = aPntIt.Value();
1215 aMeasurePnt = gp_Pnt (aMeasurePnt.X() * anAxialScale.X(),
1216 aMeasurePnt.Y() * anAxialScale.Y(),
1217 aMeasurePnt.Z() * anAxialScale.Z());
1219 Standard_Real aDistance = aCamPln.Distance (aMeasurePnt);
1221 // Check if the camera is intruded into the scene.
1222 if (aCamDir.IsOpposite (gp_Vec (aCamEye, aMeasurePnt), M_PI * 0.5))
1227 // The first eight points are from theGraphicBB, the last eight points are from theMinMax (can be absent).
1228 Standard_Real& aChangeMinDist = aCounter >= 8 ? aModelMinDist : aGraphMinDist;
1229 Standard_Real& aChangeMaxDist = aCounter >= 8 ? aModelMaxDist : aGraphMaxDist;
1230 aChangeMinDist = Min (aDistance, aChangeMinDist);
1231 aChangeMaxDist = Max (aDistance, aChangeMaxDist);
1235 // Compute depth of bounding box center.
1236 Standard_Real aMidDepth = (aGraphMinDist + aGraphMaxDist) * 0.5;
1237 Standard_Real aHalfDepth = (aGraphMaxDist - aGraphMinDist) * 0.5;
1239 // Compute enlarged or shrank near and far z ranges.
1240 Standard_Real aZNear = aMidDepth - aHalfDepth * theScaleFactor;
1241 Standard_Real aZFar = aMidDepth + aHalfDepth * theScaleFactor;
1243 if (!IsOrthographic())
1245 // Everything is behind the perspective camera.
1246 if (aZFar < zEpsilon())
1248 theZNear = DEFAULT_ZNEAR;
1249 theZFar = DEFAULT_ZFAR;
1255 // Consider clipping errors due to double to single precision floating-point conversion.
1258 // Model to view transformation performs translation of points against eye position
1259 // in three dimensions. Both point coordinate and eye position values are converted from
1260 // double to single precision floating point numbers producing conversion errors.
1261 // Epsilon (Mod) * 3.0 should safely compensate precision error for z coordinate after
1262 // translation assuming that the:
1263 // Epsilon (Eye.Mod()) * 3.0 > Epsilon (Eye.X()) + Epsilon (Eye.Y()) + Epsilon (Eye.Z()).
1264 Standard_Real aEyeConf = 3.0 * zEpsilon (myEye.XYZ().Modulus());
1266 // Model to view transformation performs rotation of points according to view direction.
1267 // New z coordinate is computed as a multiplication of point's x, y, z coordinates by the
1268 // "forward" direction vector's x, y, z coordinates. Both point's and "z" direction vector's
1269 // values are converted from double to single precision floating point numbers producing
1270 // conversion errors.
1271 // Epsilon (Mod) * 6.0 should safely compensate the precision errors for the multiplication
1272 // of point coordinates by direction vector.
1273 gp_Pnt aGraphicMin = theGraphicBB.CornerMin();
1274 gp_Pnt aGraphicMax = theGraphicBB.CornerMax();
1276 Standard_Real aModelConf = 6.0 * zEpsilon (aGraphicMin.XYZ().Modulus()) +
1277 6.0 * zEpsilon (aGraphicMax.XYZ().Modulus());
1279 // Compensate floating point conversion errors by increasing zNear, zFar to avoid clipping.
1280 aZNear -= zEpsilon (aZNear) + aEyeConf + aModelConf;
1281 aZFar += zEpsilon (aZFar) + aEyeConf + aModelConf;
1283 if (!IsOrthographic())
1285 // For perspective projection, the value of z in normalized device coordinates is non-linear
1286 // function of eye z coordinate. For fixed-point depth representation resolution of z in
1287 // model-view space will grow towards zFar plane and its scale depends mostly on how far is zNear
1288 // against camera's eye. The purpose of the code below is to select most appropriate zNear distance
1289 // to balance between clipping (less zNear, more chances to observe closely small models without clipping)
1290 // and resolution of depth. A well applicable criteria to this is a ratio between resolution of z at center
1291 // of model boundaries and the distance to that center point. The ratio is chosen empirically and validated
1292 // by tests database. It is considered to be ~0.001 (0.1%) for 24 bit depth buffer, for less depth bitness
1293 // the zNear will be placed similarly giving lower resolution.
1294 // Approximation of the formula for respectively large z range is:
1295 // zNear = [z * (1 + k) / (k * c)],
1297 // z - distance to center of model boundaries;
1298 // k - chosen ratio, c - capacity of depth buffer;
1299 // k = 0.001, k * c = 1677.216, (1 + k) / (k * c) ~ 5.97E-4
1301 // The function uses center of model boundaries computed from "theMinMax" boundaries (instead of using real
1302 // graphical boundaries of all displayed objects). That means that it can sacrifice resolution of presentation
1303 // of non primary ("infinite") application graphical objects in favor of better perspective projection of the
1304 // small applicative objects measured with "theMinMax" values.
1305 Standard_Real aZRange = isFiniteMinMax ? aModelMaxDist - aModelMinDist : aGraphMaxDist - aGraphMinDist;
1306 Standard_Real aZMin = isFiniteMinMax ? aModelMinDist : aGraphMinDist;
1307 Standard_Real aZ = aZMin < 0 ? aZRange / 2.0 : aZRange / 2.0 + aZMin;
1308 Standard_Real aZNearMin = aZ * 5.97E-4;
1309 if (aZNear < aZNearMin)
1311 // Clip zNear according to the minimum value matching the quality.
1316 // Compensate zNear conversion errors for perspective projection.
1317 aZNear -= aZFar * zEpsilon (aZNear) / (aZFar - zEpsilon (aZNear));
1320 // Compensate zFar conversion errors for perspective projection.
1321 aZFar += zEpsilon (aZFar);
1323 // Ensure that after all the zNear is not a negative value.
1324 if (aZNear < zEpsilon())
1326 aZNear = zEpsilon();
1335 //=============================================================================
1336 //function : Interpolate
1338 //=============================================================================
1340 Standard_EXPORT void NCollection_Lerp<Handle(Graphic3d_Camera)>::Interpolate (const double theT,
1341 Handle(Graphic3d_Camera)& theCamera) const
1343 if (Abs (theT - 1.0) < Precision::Confusion())
1345 // just copy end-point transformation
1346 theCamera->Copy (myEnd);
1350 theCamera->Copy (myStart);
1351 if (Abs (theT - 0.0) < Precision::Confusion())
1358 gp_Ax3 aCamStart = cameraToAx3 (*myStart);
1359 gp_Ax3 aCamEnd = cameraToAx3 (*myEnd);
1360 gp_Trsf aTrsfStart, aTrsfEnd;
1361 aTrsfStart.SetTransformation (aCamStart, gp::XOY());
1362 aTrsfEnd .SetTransformation (aCamEnd, gp::XOY());
1364 gp_Quaternion aRotStart = aTrsfStart.GetRotation();
1365 gp_Quaternion aRotEnd = aTrsfEnd .GetRotation();
1366 gp_Quaternion aRotDelta = aRotEnd * aRotStart.Inverted();
1367 gp_Quaternion aRot = gp_QuaternionNLerp::Interpolate (gp_Quaternion(), aRotDelta, theT);
1369 aTrsfRot.SetRotation (aRot);
1370 theCamera->Transform (aTrsfRot);
1373 // apply translation
1375 gp_XYZ aCenter = NCollection_Lerp<gp_XYZ>::Interpolate (myStart->Center().XYZ(), myEnd->Center().XYZ(), theT);
1376 gp_XYZ anEye = NCollection_Lerp<gp_XYZ>::Interpolate (myStart->Eye().XYZ(), myEnd->Eye().XYZ(), theT);
1377 gp_XYZ anAnchor = aCenter;
1378 Standard_Real aKc = 0.0;
1380 const Standard_Real aDeltaCenter = myStart->Center().Distance (myEnd->Center());
1381 const Standard_Real aDeltaEye = myStart->Eye() .Distance (myEnd->Eye());
1382 if (aDeltaEye <= gp::Resolution())
1387 else if (aDeltaCenter > gp::Resolution())
1389 aKc = aDeltaCenter / (aDeltaCenter + aDeltaEye);
1391 const gp_XYZ anAnchorStart = NCollection_Lerp<gp_XYZ>::Interpolate (myStart->Center().XYZ(), myStart->Eye().XYZ(), aKc);
1392 const gp_XYZ anAnchorEnd = NCollection_Lerp<gp_XYZ>::Interpolate (myEnd ->Center().XYZ(), myEnd ->Eye().XYZ(), aKc);
1393 anAnchor = NCollection_Lerp<gp_XYZ>::Interpolate (anAnchorStart, anAnchorEnd, theT);
1396 const gp_Vec aDirEyeToCenter = theCamera->Direction();
1397 const Standard_Real aDistEyeCenterStart = myStart->Eye().Distance (myStart->Center());
1398 const Standard_Real aDistEyeCenterEnd = myEnd ->Eye().Distance (myEnd ->Center());
1399 const Standard_Real aDistEyeCenter = NCollection_Lerp<Standard_Real>::Interpolate (aDistEyeCenterStart, aDistEyeCenterEnd, theT);
1400 aCenter = anAnchor + aDirEyeToCenter.XYZ() * aDistEyeCenter * aKc;
1401 anEye = anAnchor - aDirEyeToCenter.XYZ() * aDistEyeCenter * (1.0 - aKc);
1403 theCamera->SetCenter (aCenter);
1404 theCamera->SetEye (anEye);
1408 if (Abs(myStart->Scale() - myEnd->Scale()) > Precision::Confusion()
1409 && myStart->IsOrthographic())
1411 const Standard_Real aScale = NCollection_Lerp<Standard_Real>::Interpolate (myStart->Scale(), myEnd->Scale(), theT);
1412 theCamera->SetScale (aScale);
1416 //=======================================================================
1417 //function : FrustumPoints
1419 //=======================================================================
1420 void Graphic3d_Camera::FrustumPoints (NCollection_Array1<Graphic3d_Vec3d>& thePoints) const
1422 if (thePoints.Length() != FrustumVerticesNB)
1424 thePoints.Resize (0, FrustumVerticesNB, Standard_False);
1427 const Graphic3d_Mat4d& aProjectionMat = ProjectionMatrix();
1428 const Graphic3d_Mat4d& aWorldViewMat = OrientationMatrix();
1430 Standard_Real nLeft = 0.0, nRight = 0.0, nTop = 0.0, nBottom = 0.0;
1431 Standard_Real fLeft = 0.0, fRight = 0.0, fTop = 0.0, fBottom = 0.0;
1432 Standard_Real aNear = 0.0, aFar = 0.0;
1433 if (!IsOrthographic())
1435 // handle perspective projection
1436 aNear = aProjectionMat.GetValue (2, 3) / (-1.0 + aProjectionMat.GetValue (2, 2));
1437 aFar = aProjectionMat.GetValue (2, 3) / ( 1.0 + aProjectionMat.GetValue (2, 2));
1439 nLeft = aNear * (aProjectionMat.GetValue (0, 2) - 1.0) / aProjectionMat.GetValue (0, 0);
1440 nRight = aNear * (aProjectionMat.GetValue (0, 2) + 1.0) / aProjectionMat.GetValue (0, 0);
1441 nTop = aNear * (aProjectionMat.GetValue (1, 2) + 1.0) / aProjectionMat.GetValue (1, 1);
1442 nBottom = aNear * (aProjectionMat.GetValue (1, 2) - 1.0) / aProjectionMat.GetValue (1, 1);
1444 fLeft = aFar * (aProjectionMat.GetValue (0, 2) - 1.0) / aProjectionMat.GetValue (0, 0);
1445 fRight = aFar * (aProjectionMat.GetValue (0, 2) + 1.0) / aProjectionMat.GetValue (0, 0);
1446 fTop = aFar * (aProjectionMat.GetValue (1, 2) + 1.0) / aProjectionMat.GetValue (1, 1);
1447 fBottom = aFar * (aProjectionMat.GetValue (1, 2) - 1.0) / aProjectionMat.GetValue (1, 1);
1451 // handle orthographic projection
1452 aNear = (1.0 / aProjectionMat.GetValue (2, 2)) * (aProjectionMat.GetValue (2, 3) + 1.0);
1453 aFar = (1.0 / aProjectionMat.GetValue (2, 2)) * (aProjectionMat.GetValue (2, 3) - 1.0);
1455 nLeft = ( 1.0 + aProjectionMat.GetValue (0, 3)) / (-aProjectionMat.GetValue (0, 0));
1457 nRight = ( 1.0 - aProjectionMat.GetValue (0, 3)) / aProjectionMat.GetValue (0, 0);
1459 nTop = ( 1.0 - aProjectionMat.GetValue (1, 3)) / aProjectionMat.GetValue (1, 1);
1461 nBottom = (-1.0 - aProjectionMat.GetValue (1, 3)) / aProjectionMat.GetValue (1, 1);
1465 Graphic3d_Vec4d aLeftTopNear (nLeft, nTop, -aNear, 1.0), aRightBottomFar (fRight, fBottom, -aFar, 1.0);
1466 Graphic3d_Vec4d aLeftBottomNear (nLeft, nBottom, -aNear, 1.0), aRightTopFar (fRight, fTop, -aFar, 1.0);
1467 Graphic3d_Vec4d aRightBottomNear (nRight, nBottom, -aNear, 1.0), aLeftTopFar (fLeft, fTop, -aFar, 1.0);
1468 Graphic3d_Vec4d aRightTopNear (nRight, nTop, -aNear, 1.0), aLeftBottomFar (fLeft, fBottom, -aFar, 1.0);
1470 Graphic3d_Mat4d anInvWorldView;
1471 aWorldViewMat.Inverted (anInvWorldView);
1473 Graphic3d_Vec4d aTmpPnt;
1474 aTmpPnt = anInvWorldView * aLeftTopNear;
1475 thePoints.SetValue (FrustumVert_LeftTopNear, aTmpPnt.xyz() / aTmpPnt.w());
1476 aTmpPnt = anInvWorldView * aRightBottomFar;
1477 thePoints.SetValue (FrustumVert_RightBottomFar, aTmpPnt.xyz() / aTmpPnt.w());
1478 aTmpPnt = anInvWorldView * aLeftBottomNear;
1479 thePoints.SetValue (FrustumVert_LeftBottomNear, aTmpPnt.xyz() / aTmpPnt.w());
1480 aTmpPnt = anInvWorldView * aRightTopFar;
1481 thePoints.SetValue (FrustumVert_RightTopFar, aTmpPnt.xyz() / aTmpPnt.w());
1482 aTmpPnt = anInvWorldView * aRightBottomNear;
1483 thePoints.SetValue (FrustumVert_RightBottomNear, aTmpPnt.xyz() / aTmpPnt.w());
1484 aTmpPnt = anInvWorldView * aLeftTopFar;
1485 thePoints.SetValue (FrustumVert_LeftTopFar, aTmpPnt.xyz() / aTmpPnt.w());
1486 aTmpPnt = anInvWorldView * aRightTopNear;
1487 thePoints.SetValue (FrustumVert_RightTopNear, aTmpPnt.xyz() / aTmpPnt.w());
1488 aTmpPnt = anInvWorldView * aLeftBottomFar;
1489 thePoints.SetValue (FrustumVert_LeftBottomFar, aTmpPnt.xyz() / aTmpPnt.w());