1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-14 13:30:48 +03:00
Files
occt/src/Graphic3d/Graphic3d_Camera.cxx
apl 197ac94e72 0024413: Visualization - get rid of projection shift from orthographic camera definition
From now on, the panning behavior of V3d_View completely corresponds to equal operations with camera. There is no more confusing "Center" property and "ProjectionShift" which were used to introduce composite panning, while respecting view referential points: At, Eye unchanged. The V3d_View::FitAll approach has been rewritten to do "fit all" geometrically, operating with frustum, to make it working for both orthographic and perspective projections.

1) Getting rid of ProjectionShift and Center property:
- Removed ProjectionShift property of Graphic3d_Camera.
- Removed confusing Center property of V3d_View (related to projection shift).
- Removed redundant code related to the Center property of V3d_View.
- Removed WindowLimit method of Graphic3d_Camera - no more used.

2) Improvements of fit all and selector:
- Improved FitAll operation of V3d_View and reused it in NIS_View - the perspective projection is now handled correctly.
- Revised code of Select3D_Projector class - can be defined with any given projection and model-view matrices.
- Modified StdSelect_ViewerSelector3d and ensured that panning, zooming and going into the view do not lead to unwanted re-projection of sensitives. The handling of perspective selection is revised.
- Take into account graphical boundaries of infinite structure on ZFitAll.

3) Improvements of camera:
- Introduced new z range scale parameter for V3d_View::AutoZFit. See, V3d_View::AutoZFitMode.
- Allow negative ZNear, ZFar for orthographic camera to avoid clipping of viewed model.
- Moved camera ZNear, ZFar validity checks to V3d_View level.
- Use more meaningful Standard_ShortReal relative precision for ZNear, ZFar ranges computed by ZFitAll.
- Use Standard_Real type for camera projection and orientation matrices.
- Extended camera to generate both Standard_Real and Standard_ShortReal transformation matrices using the same matrix evaluation methods and converted input parameters.

Correcting picking tests for perspective view

Modify v3d face test cases for 1px changes in face picking

Modified test cases for new arguments of vviewparams DRAWEXE command
2014-03-06 15:50:33 +04:00

964 lines
32 KiB
C++

// 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 <gp_Pln.hxx>
#include <Standard_ShortReal.hxx>
#include <Graphic3d_Vec4.hxx>
#include <Graphic3d_Camera.hxx>
#include <Standard_Atomic.hxx>
#include <Standard_Assert.hxx>
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 <typename Elem_t>
Graphic3d_Camera::TransformMatrices<Elem_t>&
Graphic3d_Camera::UpdateProjection (TransformMatrices<Elem_t>& 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<Elem_t> (myScale);
Elem_t aZNear = static_cast<Elem_t> (myZNear);
Elem_t aZFar = static_cast<Elem_t> (myZFar);
Elem_t anAspect = static_cast<Elem_t> (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<Elem_t> (myIOD * Distance())
: static_cast<Elem_t> (myIOD);
Elem_t aFocus = myZFocusType == FocusType_Relative
? static_cast<Elem_t> (myZFocus * Distance())
: static_cast<Elem_t> (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 <typename Elem_t>
Graphic3d_Camera::TransformMatrices<Elem_t>&
Graphic3d_Camera::UpdateOrientation (TransformMatrices<Elem_t>& theMatrices) const
{
if (theMatrices.IsOrientationValid())
{
return theMatrices; // for inline accessors
}
theMatrices.InitOrientation();
NCollection_Vec3<Elem_t> anEye (static_cast<Elem_t> (myEye.X()),
static_cast<Elem_t> (myEye.Y()),
static_cast<Elem_t> (myEye.Z()));
NCollection_Vec3<Elem_t> aCenter (static_cast<Elem_t> (myCenter.X()),
static_cast<Elem_t> (myCenter.Y()),
static_cast<Elem_t> (myCenter.Z()));
NCollection_Vec3<Elem_t> anUp (static_cast<Elem_t> (myUp.X()),
static_cast<Elem_t> (myUp.Y()),
static_cast<Elem_t> (myUp.Z()));
NCollection_Vec3<Elem_t> anAxialScale (static_cast<Elem_t> (myAxialScale.X()),
static_cast<Elem_t> (myAxialScale.Y()),
static_cast<Elem_t> (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 <typename Elem_t>
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<Elem_t>& 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 <typename Elem_t>
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<Elem_t>& 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 <typename Elem_t>
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<Elem_t>& 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<Elem_t> (aDx, Elem_t (0.0), Elem_t (0.0)));
}
}
// =======================================================================
// function : LookOrientation
// purpose :
// =======================================================================
template <typename Elem_t>
void Graphic3d_Camera::LookOrientation (const NCollection_Vec3<Elem_t>& theEye,
const NCollection_Vec3<Elem_t>& theLookAt,
const NCollection_Vec3<Elem_t>& theUpDir,
const NCollection_Vec3<Elem_t>& theAxialScale,
NCollection_Mat4<Elem_t>& theOutMx)
{
NCollection_Vec3<Elem_t> aForward = theLookAt - theEye;
aForward.Normalize();
// side = forward x up
NCollection_Vec3<Elem_t> aSide = NCollection_Vec3<Elem_t>::Cross (aForward, theUpDir);
aSide.Normalize();
// recompute up as: up = side x forward
NCollection_Vec3<Elem_t> anUp = NCollection_Vec3<Elem_t>::Cross (aSide, aForward);
NCollection_Mat4<Elem_t> aLookMx;
aLookMx.SetRow (0, aSide);
aLookMx.SetRow (1, anUp);
aLookMx.SetRow (2, -aForward);
theOutMx.InitIdentity();
theOutMx.Multiply (aLookMx);
theOutMx.Translate (-theEye);
NCollection_Mat4<Elem_t> anAxialScaleMx;
anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x();
anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y();
anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z();
theOutMx.Multiply (anAxialScaleMx);
}