// Created on: 2013-05-29 // Created by: Anton POLETAEV // Copyright (c) 1999-2014 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. #include #include #include #include #include #include IMPLEMENT_STANDARD_HANDLE(Graphic3d_Camera, Standard_Transient) IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_Camera, Standard_Transient) namespace { // (degrees -> radians) * 0.5 static const Standard_Real DTR_HALF = 0.5 * 0.0174532925; // default property values static const Standard_Real DEFAULT_ZNEAR = 0.001; static const Standard_Real DEFAULT_ZFAR = 3000.0; // atomic state counter static volatile Standard_Integer THE_STATE_COUNTER = 0; }; // ======================================================================= // function : Graphic3d_Camera // purpose : // ======================================================================= Graphic3d_Camera::Graphic3d_Camera() : myUp (0.0, 1.0, 0.0), myEye (0.0, 0.0, -1500.0), myCenter (0.0, 0.0, 0.0), myAxialScale (1.0, 1.0, 1.0), myProjType (Projection_Orthographic), myFOVy (45.0), myZNear (DEFAULT_ZNEAR), myZFar (DEFAULT_ZFAR), myAspect (1.0), myScale (1000.0), myZFocus (1.0), myZFocusType (FocusType_Relative), myIOD (0.05), myIODType (IODType_Relative) { myProjectionState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER); myOrientationState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER); } // ======================================================================= // function : Graphic3d_Camera // purpose : // ======================================================================= Graphic3d_Camera::Graphic3d_Camera (const Handle(Graphic3d_Camera)& theOther) { Copy (theOther); } // ======================================================================= // function : CopyMappingData // purpose : // ======================================================================= void Graphic3d_Camera::CopyMappingData (const Handle(Graphic3d_Camera)& theOtherCamera) { myFOVy = theOtherCamera->myFOVy; myZNear = theOtherCamera->myZNear; myZFar = theOtherCamera->myZFar; myAspect = theOtherCamera->myAspect; myScale = theOtherCamera->myScale; myZFocus = theOtherCamera->myZFocus; myZFocusType = theOtherCamera->myZFocusType; myIOD = theOtherCamera->myIOD; myIODType = theOtherCamera->myIODType; myProjType = theOtherCamera->myProjType; myProjectionState = theOtherCamera->myProjectionState; InvalidateProjection(); } // ======================================================================= // function : CopyOrientationData // purpose : // ======================================================================= void Graphic3d_Camera::CopyOrientationData (const Handle(Graphic3d_Camera)& theOtherCamera) { myUp = theOtherCamera->myUp; myEye = theOtherCamera->myEye; myCenter = theOtherCamera->myCenter; myAxialScale = theOtherCamera->myAxialScale; myOrientationState = theOtherCamera->myOrientationState; InvalidateOrientation(); } // ======================================================================= // function : Copy // purpose : // ======================================================================= void Graphic3d_Camera::Copy (const Handle(Graphic3d_Camera)& theOther) { CopyMappingData (theOther); CopyOrientationData (theOther); } // ======================================================================= // function : SetEye // purpose : // ======================================================================= void Graphic3d_Camera::SetEye (const gp_Pnt& theEye) { myEye = theEye; InvalidateOrientation(); } // ======================================================================= // function : SetCenter // purpose : // ======================================================================= void Graphic3d_Camera::SetCenter (const gp_Pnt& theCenter) { myCenter = theCenter; InvalidateOrientation(); } // ======================================================================= // function : SetUp // purpose : // ======================================================================= void Graphic3d_Camera::SetUp (const gp_Dir& theUp) { myUp = theUp; InvalidateOrientation(); } // ======================================================================= // function : SetAxialScale // purpose : // ======================================================================= void Graphic3d_Camera::SetAxialScale (const gp_XYZ& theAxialScale) { myAxialScale = theAxialScale; InvalidateOrientation(); } // ======================================================================= // function : SetDistance // purpose : // ======================================================================= void Graphic3d_Camera::SetDistance (const Standard_Real theDistance) { gp_Vec aCenter2Eye (Direction()); aCenter2Eye.Reverse(); aCenter2Eye.Scale (theDistance); SetEye (Center().Translated (aCenter2Eye)); } // ======================================================================= // function : Distance // purpose : // ======================================================================= Standard_Real Graphic3d_Camera::Distance() const { return myEye.Distance (myCenter); } // ======================================================================= // function : SetDirection // purpose : // ======================================================================= void Graphic3d_Camera::SetDirection (const gp_Dir& theDir) { gp_Vec aScaledDir (theDir); aScaledDir.Scale (Distance()); aScaledDir.Reverse(); SetEye (Center().Translated (aScaledDir)); } // ======================================================================= // function : Direction // purpose : // ======================================================================= gp_Dir Graphic3d_Camera::Direction() const { return gp_Dir (gp_Vec (myEye, myCenter)); } // ======================================================================= // function : SetScale // purpose : // ======================================================================= void Graphic3d_Camera::SetScale (const Standard_Real theScale) { myScale = theScale; switch (myProjType) { case Projection_Perspective : case Projection_Stereo : case Projection_MonoLeftEye : case Projection_MonoRightEye : { Standard_Real aDistance = theScale * 0.5 / Tan(myFOVy * M_PI / 360.0); SetDistance (aDistance); } default : break; } InvalidateProjection(); } // ======================================================================= // function : Scale // purpose : // ======================================================================= Standard_Real Graphic3d_Camera::Scale() const { switch (myProjType) { case Projection_Orthographic : return myScale; // case Projection_Perspective : // case Projection_Stereo : // case Projection_MonoLeftEye : // case Projection_MonoRightEye : default : return Distance() * 2.0 * Tan (myFOVy * M_PI / 360.0); } } // ======================================================================= // function : SetProjectionType // purpose : // ======================================================================= void Graphic3d_Camera::SetProjectionType (const Projection theProjectionType) { Projection anOldType = myProjType; if (anOldType == theProjectionType) { return; } if (anOldType == Projection_Orthographic) { if (myZNear <= RealEpsilon()) { myZNear = DEFAULT_ZNEAR; } if (myZFar <= RealEpsilon()) { myZFar = DEFAULT_ZFAR; } } myProjType = theProjectionType; InvalidateProjection(); } // ======================================================================= // function : SetFOVy // purpose : // ======================================================================= void Graphic3d_Camera::SetFOVy (const Standard_Real theFOVy) { myFOVy = theFOVy; InvalidateProjection(); } // ======================================================================= // function : SetZRange // purpose : // ======================================================================= void Graphic3d_Camera::SetZRange (const Standard_Real theZNear, const Standard_Real theZFar) { Standard_ASSERT_RAISE (theZFar > theZNear, "ZFar should be greater than ZNear"); if (!IsOrthographic()) { Standard_ASSERT_RAISE (theZNear > 0.0, "Only positive Z-Near is allowed for perspective camera"); Standard_ASSERT_RAISE (theZFar > 0.0, "Only positive Z-Far is allowed for perspective camera"); } myZNear = theZNear; myZFar = theZFar; InvalidateProjection(); } // ======================================================================= // function : SetAspect // purpose : // ======================================================================= void Graphic3d_Camera::SetAspect (const Standard_Real theAspect) { myAspect = theAspect; InvalidateProjection(); } // ======================================================================= // function : SetZFocus // purpose : // ======================================================================= void Graphic3d_Camera::SetZFocus(const FocusType theType, const Standard_Real theZFocus) { myZFocusType = theType; myZFocus = theZFocus; InvalidateProjection(); } // ======================================================================= // function : SetIOD // purpose : // ======================================================================= void Graphic3d_Camera::SetIOD (const IODType theType, const Standard_Real theIOD) { myIODType = theType; myIOD = theIOD; InvalidateProjection(); } // ======================================================================= // function : OrthogonalizeUp // purpose : // ======================================================================= void Graphic3d_Camera::OrthogonalizeUp() { SetUp (OrthogonalizedUp()); } // ======================================================================= // function : OrthogonalizedUp // purpose : // ======================================================================= gp_Dir Graphic3d_Camera::OrthogonalizedUp() const { gp_Dir aDir = Direction(); gp_Dir aLeft = aDir.Crossed (Up()); // recompute up as: up = left x direction return aLeft.Crossed (aDir); } // ======================================================================= // function : Transform // purpose : // ======================================================================= void Graphic3d_Camera::Transform (const gp_Trsf& theTrsf) { myUp.Transform (theTrsf); myEye.Transform (theTrsf); myCenter.Transform (theTrsf); InvalidateOrientation(); } // ======================================================================= // function : safePointCast // purpose : // ======================================================================= static Graphic3d_Vec4d safePointCast (const gp_Pnt& thePnt) { Standard_Real aLim = 1e15f; // have to deal with values greater then max float gp_Pnt aSafePoint = thePnt; const Standard_Real aBigFloat = aLim * 0.1f; if (Abs (aSafePoint.X()) > aLim) aSafePoint.SetX (aSafePoint.X() >= 0 ? aBigFloat : -aBigFloat); if (Abs (aSafePoint.Y()) > aLim) aSafePoint.SetY (aSafePoint.Y() >= 0 ? aBigFloat : -aBigFloat); if (Abs (aSafePoint.Z()) > aLim) aSafePoint.SetZ (aSafePoint.Z() >= 0 ? aBigFloat : -aBigFloat); // convert point Graphic3d_Vec4d aPnt (aSafePoint.X(), aSafePoint.Y(), aSafePoint.Z(), 1.0); return aPnt; } // ======================================================================= // function : Project // purpose : // ======================================================================= gp_Pnt Graphic3d_Camera::Project (const gp_Pnt& thePnt) const { const Graphic3d_Mat4d& aViewMx = OrientationMatrix(); const Graphic3d_Mat4d& aProjMx = ProjectionMatrix(); // use compatible type of point Graphic3d_Vec4d aPnt = safePointCast (thePnt); aPnt = aViewMx * aPnt; // convert to view coordinate space aPnt = aProjMx * aPnt; // convert to projection coordinate space const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w()); return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW); } // ======================================================================= // function : UnProject // purpose : // ======================================================================= gp_Pnt Graphic3d_Camera::UnProject (const gp_Pnt& thePnt) const { const Graphic3d_Mat4d& aViewMx = OrientationMatrix(); const Graphic3d_Mat4d& aProjMx = ProjectionMatrix(); Graphic3d_Mat4d aInvView; Graphic3d_Mat4d aInvProj; // this case should never happen if (!aViewMx.Inverted (aInvView) || !aProjMx.Inverted (aInvProj)) { return gp_Pnt (0.0, 0.0, 0.0); } // use compatible type of point Graphic3d_Vec4d aPnt = safePointCast (thePnt); aPnt = aInvProj * aPnt; // convert to view coordinate space aPnt = aInvView * aPnt; // convert to world coordinate space const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w()); return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW); } // ======================================================================= // function : ConvertView2Proj // purpose : // ======================================================================= gp_Pnt Graphic3d_Camera::ConvertView2Proj (const gp_Pnt& thePnt) const { const Graphic3d_Mat4d& aProjMx = ProjectionMatrix(); // use compatible type of point Graphic3d_Vec4d aPnt = safePointCast (thePnt); aPnt = aProjMx * aPnt; // convert to projection coordinate space const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w()); return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW); } // ======================================================================= // function : ConvertProj2View // purpose : // ======================================================================= gp_Pnt Graphic3d_Camera::ConvertProj2View (const gp_Pnt& thePnt) const { const Graphic3d_Mat4d& aProjMx = ProjectionMatrix(); Graphic3d_Mat4d aInvProj; // this case should never happen, but... if (!aProjMx.Inverted (aInvProj)) { return gp_Pnt (0, 0, 0); } // use compatible type of point Graphic3d_Vec4d aPnt = safePointCast (thePnt); aPnt = aInvProj * aPnt; // convert to view coordinate space const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w()); return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW); } // ======================================================================= // function : ConvertWorld2View // purpose : // ======================================================================= gp_Pnt Graphic3d_Camera::ConvertWorld2View (const gp_Pnt& thePnt) const { const Graphic3d_Mat4d& aViewMx = OrientationMatrix(); // use compatible type of point Graphic3d_Vec4d aPnt = safePointCast (thePnt); aPnt = aViewMx * aPnt; // convert to view coordinate space const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w()); return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW); } // ======================================================================= // function : ConvertView2World // purpose : // ======================================================================= gp_Pnt Graphic3d_Camera::ConvertView2World (const gp_Pnt& thePnt) const { const Graphic3d_Mat4d& aViewMx = OrientationMatrix(); Graphic3d_Mat4d aInvView; if (!aViewMx.Inverted (aInvView)) { return gp_Pnt(0, 0, 0); } // use compatible type of point Graphic3d_Vec4d aPnt = safePointCast (thePnt); aPnt = aInvView * aPnt; // convert to world coordinate space const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w()); return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW); } // ======================================================================= // function : ViewDimensions // purpose : // ======================================================================= gp_XYZ Graphic3d_Camera::ViewDimensions() const { // view plane dimensions Standard_Real aSizeY = IsOrthographic() ? myScale : (2.0 * Distance() * Tan (DTR_HALF * myFOVy)); Standard_Real aSizeX = myAspect * aSizeY; // and frustum depth return gp_XYZ (aSizeX, aSizeY, myZFar - myZNear); } // ======================================================================= // function : Frustum // purpose : // ======================================================================= void Graphic3d_Camera::Frustum (gp_Pln& theLeft, gp_Pln& theRight, gp_Pln& theBottom, gp_Pln& theTop, gp_Pln& theNear, gp_Pln& theFar) const { gp_Vec aProjection = gp_Vec (Direction()); gp_Vec anUp = OrthogonalizedUp(); gp_Vec aSide = aProjection ^ anUp; Standard_ASSERT_RAISE ( !aProjection.IsParallel (anUp, Precision::Angular()), "Can not derive SIDE = PROJ x UP - directions are parallel"); theNear = gp_Pln (Eye().Translated (aProjection * ZNear()), aProjection); theFar = gp_Pln (Eye().Translated (aProjection * ZFar()), -aProjection); Standard_Real aHScaleHor = Scale() * 0.5 * Aspect(); Standard_Real aHScaleVer = Scale() * 0.5; gp_Pnt aPntLeft = Center().Translated (aHScaleHor * -aSide); gp_Pnt aPntRight = Center().Translated (aHScaleHor * aSide); gp_Pnt aPntBottom = Center().Translated (aHScaleVer * -anUp); gp_Pnt aPntTop = Center().Translated (aHScaleVer * anUp); gp_Vec aDirLeft = aSide; gp_Vec aDirRight = -aSide; gp_Vec aDirBottom = anUp; gp_Vec aDirTop = -anUp; if (!IsOrthographic()) { Standard_Real aHFOVHor = ATan (Tan (DTR_HALF * FOVy()) * Aspect()); Standard_Real aHFOVVer = DTR_HALF * FOVy(); aDirLeft.Rotate (gp_Ax1 (gp::Origin(), anUp), aHFOVHor); aDirRight.Rotate (gp_Ax1 (gp::Origin(), anUp), -aHFOVHor); aDirBottom.Rotate (gp_Ax1 (gp::Origin(), aSide), -aHFOVVer); aDirTop.Rotate (gp_Ax1 (gp::Origin(), aSide), aHFOVVer); } theLeft = gp_Pln (aPntLeft, aDirLeft); theRight = gp_Pln (aPntRight, aDirRight); theBottom = gp_Pln (aPntBottom, aDirBottom); theTop = gp_Pln (aPntTop, aDirTop); } // ======================================================================= // function : OrientationMatrix // purpose : // ======================================================================= const Graphic3d_Mat4d& Graphic3d_Camera::OrientationMatrix() const { return *UpdateOrientation (myMatricesD).Orientation; } // ======================================================================= // function : OrientationMatrixF // purpose : // ======================================================================= const Graphic3d_Mat4& Graphic3d_Camera::OrientationMatrixF() const { return *UpdateOrientation (myMatricesF).Orientation; } // ======================================================================= // function : ProjectionMatrix // purpose : // ======================================================================= const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionMatrix() const { return *UpdateProjection (myMatricesD).MProjection; } // ======================================================================= // function : ProjectionMatrixF // purpose : // ======================================================================= const Graphic3d_Mat4& Graphic3d_Camera::ProjectionMatrixF() const { return *UpdateProjection (myMatricesF).MProjection; } // ======================================================================= // function : ProjectionStereoLeft // purpose : // ======================================================================= const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoLeft() const { return *UpdateProjection (myMatricesD).LProjection; } // ======================================================================= // function : ProjectionStereoLeftF // purpose : // ======================================================================= const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoLeftF() const { return *UpdateProjection (myMatricesF).LProjection; } // ======================================================================= // function : ProjectionStereoRight // purpose : // ======================================================================= const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoRight() const { return *UpdateProjection (myMatricesD).RProjection; } // ======================================================================= // function : ProjectionStereoRightF // purpose : // ======================================================================= const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoRightF() const { return *UpdateProjection (myMatricesF).RProjection; } // ======================================================================= // function : UpdateProjection // purpose : // ======================================================================= template Graphic3d_Camera::TransformMatrices& Graphic3d_Camera::UpdateProjection (TransformMatrices& theMatrices) const { if (theMatrices.IsProjectionValid()) { return theMatrices; // for inline accessors } theMatrices.InitProjection(); // sets top of frustum based on FOVy and near clipping plane Elem_t aScale = static_cast (myScale); Elem_t aZNear = static_cast (myZNear); Elem_t aZFar = static_cast (myZFar); Elem_t anAspect = static_cast (myAspect); Elem_t aDYHalf = 0.0; if (IsOrthographic()) { aDYHalf = aScale * Elem_t (0.5); } else { aDYHalf = aZNear * Elem_t (Tan (DTR_HALF * myFOVy)); } // sets right of frustum based on aspect ratio Elem_t aDXHalf = anAspect * aDYHalf; Elem_t aLeft = -aDXHalf; Elem_t aRight = aDXHalf; Elem_t aBot = -aDYHalf; Elem_t aTop = aDYHalf; Elem_t aIOD = myIODType == IODType_Relative ? static_cast (myIOD * Distance()) : static_cast (myIOD); Elem_t aFocus = myZFocusType == FocusType_Relative ? static_cast (myZFocus * Distance()) : static_cast (myZFocus); switch (myProjType) { case Projection_Orthographic : OrthoProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection); break; case Projection_Perspective : PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection); break; case Projection_MonoLeftEye : { StereoEyeProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, aIOD, aFocus, Standard_True, *theMatrices.MProjection); break; } case Projection_MonoRightEye : { StereoEyeProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, aIOD, aFocus, Standard_False, *theMatrices.MProjection); break; } case Projection_Stereo : { PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection); StereoEyeProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, aIOD, aFocus, Standard_True, *theMatrices.LProjection); StereoEyeProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, aIOD, aFocus, Standard_False, *theMatrices.RProjection); break; } } return theMatrices; // for inline accessors } // ======================================================================= // function : UpdateOrientation // purpose : // ======================================================================= template Graphic3d_Camera::TransformMatrices& Graphic3d_Camera::UpdateOrientation (TransformMatrices& theMatrices) const { if (theMatrices.IsOrientationValid()) { return theMatrices; // for inline accessors } theMatrices.InitOrientation(); NCollection_Vec3 anEye (static_cast (myEye.X()), static_cast (myEye.Y()), static_cast (myEye.Z())); NCollection_Vec3 aCenter (static_cast (myCenter.X()), static_cast (myCenter.Y()), static_cast (myCenter.Z())); NCollection_Vec3 anUp (static_cast (myUp.X()), static_cast (myUp.Y()), static_cast (myUp.Z())); NCollection_Vec3 anAxialScale (static_cast (myAxialScale.X()), static_cast (myAxialScale.Y()), static_cast (myAxialScale.Z())); LookOrientation (anEye, aCenter, anUp, anAxialScale, *theMatrices.Orientation); return theMatrices; // for inline accessors } // ======================================================================= // function : InvalidateProjection // purpose : // ======================================================================= void Graphic3d_Camera::InvalidateProjection() { myMatricesD.ResetProjection(); myMatricesF.ResetProjection(); myProjectionState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER); } // ======================================================================= // function : InvalidateOrientation // purpose : // ======================================================================= void Graphic3d_Camera::InvalidateOrientation() { myMatricesD.ResetOrientation(); myMatricesF.ResetOrientation(); myOrientationState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER); } // ======================================================================= // function : OrthoProj // purpose : // ======================================================================= template void Graphic3d_Camera::OrthoProj (const Elem_t theLeft, const Elem_t theRight, const Elem_t theBottom, const Elem_t theTop, const Elem_t theNear, const Elem_t theFar, NCollection_Mat4& theOutMx) { // row 0 theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theRight - theLeft); theOutMx.ChangeValue (0, 1) = Elem_t (0.0); theOutMx.ChangeValue (0, 2) = Elem_t (0.0); theOutMx.ChangeValue (0, 3) = - (theRight + theLeft) / (theRight - theLeft); // row 1 theOutMx.ChangeValue (1, 0) = Elem_t (0.0); theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theTop - theBottom); theOutMx.ChangeValue (1, 2) = Elem_t (0.0); theOutMx.ChangeValue (1, 3) = - (theTop + theBottom) / (theTop - theBottom); // row 2 theOutMx.ChangeValue (2, 0) = Elem_t (0.0); theOutMx.ChangeValue (2, 1) = Elem_t (0.0); theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear); theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear); // row 3 theOutMx.ChangeValue (3, 0) = Elem_t (0.0); theOutMx.ChangeValue (3, 1) = Elem_t (0.0); theOutMx.ChangeValue (3, 2) = Elem_t (0.0); theOutMx.ChangeValue (3, 3) = Elem_t (1.0); } // ======================================================================= // function : PerspectiveProj // purpose : // ======================================================================= template void Graphic3d_Camera::PerspectiveProj (const Elem_t theLeft, const Elem_t theRight, const Elem_t theBottom, const Elem_t theTop, const Elem_t theNear, const Elem_t theFar, NCollection_Mat4& theOutMx) { // column 0 theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theRight - theLeft); theOutMx.ChangeValue (1, 0) = Elem_t (0.0); theOutMx.ChangeValue (2, 0) = Elem_t (0.0); theOutMx.ChangeValue (3, 0) = Elem_t (0.0); // column 1 theOutMx.ChangeValue (0, 1) = Elem_t (0.0); theOutMx.ChangeValue (1, 1) = (Elem_t (2.0) * theNear) / (theTop - theBottom); theOutMx.ChangeValue (2, 1) = Elem_t (0.0); theOutMx.ChangeValue (3, 1) = Elem_t (0.0); // column 2 theOutMx.ChangeValue (0, 2) = (theRight + theLeft) / (theRight - theLeft); theOutMx.ChangeValue (1, 2) = (theTop + theBottom) / (theTop - theBottom); theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear); theOutMx.ChangeValue (3, 2) = Elem_t (-1.0); // column 3 theOutMx.ChangeValue (0, 3) = Elem_t (0.0); theOutMx.ChangeValue (1, 3) = Elem_t (0.0); theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear); theOutMx.ChangeValue (3, 3) = Elem_t (0.0); } // ======================================================================= // function : StereoEyeProj // purpose : // ======================================================================= template void Graphic3d_Camera::StereoEyeProj (const Elem_t theLeft, const Elem_t theRight, const Elem_t theBottom, const Elem_t theTop, const Elem_t theNear, const Elem_t theFar, const Elem_t theIOD, const Elem_t theZFocus, const Standard_Boolean theIsLeft, NCollection_Mat4& theOutMx) { Elem_t aDx = theIsLeft ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD; Elem_t aDXStereoShift = aDx * theNear / theZFocus; // construct eye projection matrix PerspectiveProj (theLeft + aDXStereoShift, theRight + aDXStereoShift, theBottom, theTop, theNear, theFar, theOutMx); if (theIOD != Elem_t (0.0)) { // X translation to cancel parallax theOutMx.Translate (NCollection_Vec3 (aDx, Elem_t (0.0), Elem_t (0.0))); } } // ======================================================================= // function : LookOrientation // purpose : // ======================================================================= template void Graphic3d_Camera::LookOrientation (const NCollection_Vec3& theEye, const NCollection_Vec3& theLookAt, const NCollection_Vec3& theUpDir, const NCollection_Vec3& theAxialScale, NCollection_Mat4& theOutMx) { NCollection_Vec3 aForward = theLookAt - theEye; aForward.Normalize(); // side = forward x up NCollection_Vec3 aSide = NCollection_Vec3::Cross (aForward, theUpDir); aSide.Normalize(); // recompute up as: up = side x forward NCollection_Vec3 anUp = NCollection_Vec3::Cross (aSide, aForward); NCollection_Mat4 aLookMx; aLookMx.SetRow (0, aSide); aLookMx.SetRow (1, anUp); aLookMx.SetRow (2, -aForward); theOutMx.InitIdentity(); theOutMx.Multiply (aLookMx); theOutMx.Translate (-theEye); NCollection_Mat4 anAxialScaleMx; anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x(); anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y(); anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z(); theOutMx.Multiply (anAxialScaleMx); }