1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-02 17:46:22 +03:00

0029384: Visualization, TKOpenGl - basic integration with OpenVR

V3d_View::AutoZFit() is now called only before redraw
within methods V3d_View::Redraw() and V3d_View::Update().

Graphic3d_CView now holds Aspect_ExtendedRealitySession object.
Aspect_OpenVRSession implements new interface via optional OpenVR library.
Graphic3d_CView::ProcessInput() - added new interface method
which should be called for processing positional input (head tracking).

Graphic3d_Camera now allows setting custom stereoscopic Projection matrices.

OpenGl_Context::Camera() - context now holds Camera object
in addition to active camera matrices.

genproj.tcl has been extended to handle optional CSF_OpenVR dependency.
This commit is contained in:
kgv 2020-04-16 18:44:50 +03:00
parent 2615c2d705
commit b40cdc2b55
69 changed files with 4819 additions and 267 deletions

View File

@ -3,6 +3,7 @@ StdResource
SHMessage
Textures
Shaders
XRResources
XSMessage
XSTEPResource
XmlOcafResource

View File

@ -222,6 +222,7 @@ n Xw
n Cocoa
r Textures
r Shaders
r XRResources
t TKMeshVS
t TKOpenGl
t TKD3DHost

View File

@ -187,6 +187,9 @@ proc wokdep:gui:UpdateList {} {
if { "$::HAVE_FFMPEG" == "true" } {
wokdep:SearchFFmpeg anIncErrs anLib32Errs anLib64Errs anBin32Errs anBin64Errs
}
if { "$::HAVE_OPENVR" == "true" } {
wokdep:SearchOpenVR anIncErrs anLib32Errs anLib64Errs anBin32Errs anBin64Errs
}
if { "$::HAVE_TBB" == "true" } {
wokdep:SearchTBB anIncErrs anLib32Errs anLib64Errs anBin32Errs anBin64Errs
}
@ -472,6 +475,8 @@ checkbutton .myFrame.myChecks.myFImageCheck -offvalue "false" -onvalue "true
ttk::label .myFrame.myChecks.myFImageLbl -text "Use FreeImage"
checkbutton .myFrame.myChecks.myTbbCheck -offvalue "false" -onvalue "true" -variable HAVE_TBB -command wokdep:gui:UpdateList
ttk::label .myFrame.myChecks.myTbbLbl -text "Use Intel TBB"
checkbutton .myFrame.myChecks.myOpenVrCheck -offvalue "false" -onvalue "true" -variable HAVE_OPENVR -command wokdep:gui:UpdateList
ttk::label .myFrame.myChecks.myOpenVrLbl -text "Use OpenVR"
if { "$::tcl_platform(os)" != "Darwin" } {
checkbutton .myFrame.myChecks.myGlesCheck -offvalue "false" -onvalue "true" -variable HAVE_GLES2 -command wokdep:gui:UpdateList
ttk::label .myFrame.myChecks.myGlesLbl -text "Use OpenGL ES"
@ -635,6 +640,8 @@ grid .myFrame.myChecks.myJDKLbl -row $aCheckRowIter -column 13 -sticky w
incr aCheckRowIter
grid .myFrame.myChecks.myRapidJsonCheck -row $aCheckRowIter -column 0 -sticky e
grid .myFrame.myChecks.myRapidJsonLbl -row $aCheckRowIter -column 1 -sticky w
grid .myFrame.myChecks.myOpenVrCheck -row $aCheckRowIter -column 4 -sticky e
grid .myFrame.myChecks.myOpenVrLbl -row $aCheckRowIter -column 5 -sticky w
grid .myFrame.myChecks.myE57Check -row $aCheckRowIter -column 6 -sticky e
grid .myFrame.myChecks.myE57Lbl -row $aCheckRowIter -column 7 -sticky w

View File

@ -68,7 +68,7 @@ if { [info exists ::env(SHORTCUT_HEADERS)] } {
}
# fetch environment variables (e.g. set by custom.sh or custom.bat) and set them as tcl variables with the same name
set THE_ENV_VARIABLES {HAVE_FREEIMAGE HAVE_FFMPEG HAVE_TBB HAVE_GLES2 HAVE_D3D HAVE_VTK HAVE_ZLIB HAVE_LIBLZMA HAVE_E57 HAVE_RAPIDJSON HAVE_OPENCL CHECK_QT4 CHECK_JDK MACOSX_USE_GLX HAVE_RelWithDebInfo BUILD_Inspector}
set THE_ENV_VARIABLES {HAVE_FREEIMAGE HAVE_FFMPEG HAVE_TBB HAVE_GLES2 HAVE_D3D HAVE_VTK HAVE_ZLIB HAVE_LIBLZMA HAVE_E57 HAVE_RAPIDJSON HAVE_OPENVR HAVE_OPENCL CHECK_QT4 CHECK_JDK MACOSX_USE_GLX HAVE_RelWithDebInfo BUILD_Inspector}
foreach anEnvIter $THE_ENV_VARIABLES {
set ${anEnvIter} "false"
if { [info exists ::env(${anEnvIter})] } {
@ -625,6 +625,59 @@ proc wokdep:SearchFFmpeg {theErrInc theErrLib32 theErrLib64 theErrBin32 theErrBi
return "$isFound"
}
# Search OpenVR SDK placement
proc wokdep:SearchOpenVR {theErrInc theErrLib32 theErrLib64 theErrBin32 theErrBin64} {
upvar $theErrInc anErrInc
upvar $theErrLib32 anErrLib32
upvar $theErrLib64 anErrLib64
upvar $theErrBin32 anErrBin32
upvar $theErrBin64 anErrBin64
set isFound "true"
set anOpenVrHPath [wokdep:SearchHeader "openvr.h"]
if { "$anOpenVrHPath" == "" } {
set aPath [wokdep:Preferred [glob -nocomplain -directory "$::PRODUCTS_PATH" -type d *{openvr}*] "$::VCVER" "$::ARCH" ]
if { "$aPath" != "" && [file exists "$aPath/include/openvr.h"] } {
lappend ::CSF_OPT_INC "$aPath/include"
} elseif { "$aPath" != "" && [file exists "$aPath/headers/openvr.h"] } {
lappend ::CSF_OPT_INC "$aPath/headers"
} else {
lappend anErrInc "Error: 'openvr.h' not found (OpenVR)"
set isFound "false"
}
}
set aPlatform "unknown"
if { "$::tcl_platform(platform)" == "windows" } {
set aPlatform "win"
} elseif { "$::tcl_platform(os)" == "Darwin" } {
set aPlatform "osx"
} elseif { "$::tcl_platform(os)" == "Linux" } {
set aPlatform "linux"
}
foreach anArchIter {64 32} {
set anOpenVrLibPath [wokdep:SearchLib "openvr_api" "$anArchIter"]
if { "$anOpenVrLibPath" == "" } {
set aPath [wokdep:Preferred [glob -nocomplain -directory "$::PRODUCTS_PATH" -type d *{openvr}*] "$::VCVER" "$anArchIter" ]
set anOpenVrLibPath [wokdep:SearchLib "openvr_api" "$anArchIter" "$aPath/lib/${aPlatform}${anArchIter}"]
set anOpenVrLibPath2 [wokdep:SearchLib "openvr_api" "$anArchIter" "$aPath/lib"]
if { "$anOpenVrLibPath" != "" } {
lappend ::CSF_OPT_LIB$anArchIter "$aPath/lib/${aPlatform}${anArchIter}"
lappend ::CSF_OPT_BIN$anArchIter "$aPath/bin/${aPlatform}${anArchIter}"
} elseif { "$anOpenVrLibPath2" != "" } {
lappend ::CSF_OPT_LIB$anArchIter "$aPath/lib"
lappend ::CSF_OPT_BIN$anArchIter "$aPath/bin"
} else {
lappend anErrLib$anArchIter "Error: '${::SYS_LIB_PREFIX}openvr_api.${::SYS_LIB_SUFFIX}' not found (OpenVR)"
if { "$::ARCH" == "$anArchIter"} { set isFound "false" }
}
}
}
return "$isFound"
}
# Search TBB library placement
proc wokdep:SearchTBB {theErrInc theErrLib32 theErrLib64 theErrBin32 theErrBin64} {
upvar $theErrInc anErrInc

View File

@ -1440,6 +1440,9 @@ proc osutils:csfList { theOS theCsfLibsMap theCsfFrmsMap theRelease} {
if { "$::HAVE_LIBLZMA" == "true" } {
set aLibsMap(CSF_LIBLZMA) "liblzma"
}
if { "$::HAVE_OPENVR" == "true" } {
set aLibsMap(CSF_OpenVR) "openvr_api"
}
if { "$::HAVE_E57" == "true" && "$theOS" != "wnt" } {
# exclude wnt, as there are different pragma lib depending on debug/release
set aLibsMap(CSF_E57) "E57RefImpl"

View File

@ -25,6 +25,7 @@ set "HAVE_D3D=false"
set "HAVE_ZLIB=false"
set "HAVE_LIBLZMA=false"
set "HAVE_RAPIDJSON=false"
set "HAVE_OPENVR=false"
set "HAVE_E57=false"
set "CSF_OPT_INC="
set "CSF_OPT_LIB32="
@ -189,6 +190,7 @@ if ["%HAVE_D3D%"] == ["true"] set "PRODUCTS_DEFINES=%PRODUCTS_DEFINES% -DH
if ["%HAVE_ZLIB%"] == ["true"] set "PRODUCTS_DEFINES=%PRODUCTS_DEFINES% -DHAVE_ZLIB" & set "CSF_DEFINES=HAVE_ZLIB;%CSF_DEFINES%"
if ["%HAVE_LIBLZMA%"] == ["true"] set "PRODUCTS_DEFINES=%PRODUCTS_DEFINES% -DHAVE_LIBLZMA" & set "CSF_DEFINES=HAVE_LIBLZMA;%CSF_DEFINES%"
if ["%HAVE_RAPIDJSON%"] == ["true"] set "PRODUCTS_DEFINES=%PRODUCTS_DEFINES% -DHAVE_RAPIDJSON" & set "CSF_DEFINES=HAVE_RAPIDJSON;%CSF_DEFINES%"
if ["%HAVE_OPENVR%"] == ["true"] set "PRODUCTS_DEFINES=%PRODUCTS_DEFINES% -DHAVE_OPENVR" & set "CSF_DEFINES=HAVE_OPENVR;%CSF_DEFINES%"
if ["%HAVE_E57%"] == ["true"] set "PRODUCTS_DEFINES=%PRODUCTS_DEFINES% -DHAVE_E57" & set "CSF_DEFINES=HAVE_E57;%CSF_DEFINES%"
rem Eliminate VS warning

View File

@ -16,6 +16,7 @@ export HAVE_GLES2="false";
export HAVE_ZLIB="false";
export HAVE_LIBLZMA="false";
export HAVE_RAPIDJSON="false";
export HAVE_OPENVR="false";
export HAVE_E57="false";
export MACOSX_USE_GLX="false";
export CSF_OPT_INC=""
@ -106,6 +107,7 @@ if [ "$HAVE_VTK" == "true" ]; then export CSF_OPT_CMPL="${CSF_OPT_CMPL} -D
if [ "$HAVE_ZLIB" == "true" ]; then export CSF_OPT_CMPL="${CSF_OPT_CMPL} -DHAVE_ZLIB"; fi
if [ "$HAVE_LIBLZMA" == "true" ]; then export CSF_OPT_CMPL="${CSF_OPT_CMPL} -DHAVE_LIBLZMA"; fi
if [ "$HAVE_RAPIDJSON" == "true" ]; then export CSF_OPT_CMPL="${CSF_OPT_CMPL} -DHAVE_RAPIDJSON"; fi
if [ "$HAVE_OPENVR" == "true" ]; then export CSF_OPT_CMPL="${CSF_OPT_CMPL} -DHAVE_OPENVR"; fi
if [ "$HAVE_E57" == "true" ]; then export CSF_OPT_CMPL="${CSF_OPT_CMPL} -DHAVE_E57"; fi
# Option to compile OCCT with X11 libs on Mac OS X
if [ "$MACOSX_USE_GLX" == "true" ]; then export CSF_OPT_CMPL="${CSF_OPT_CMPL} -DMACOSX_USE_GLX"; fi

View File

@ -18,8 +18,12 @@
#include <AIS_Manipulator.hxx>
#include <AIS_Point.hxx>
#include <AIS_RubberBand.hxx>
#include <AIS_XRTrackedDevice.hxx>
#include <Aspect_XRSession.hxx>
#include <Aspect_Grid.hxx>
#include <Geom_CartesianPoint.hxx>
#include <Graphic3d_ArrayOfSegments.hxx>
#include <Graphic3d_Texture2Dmanual.hxx>
#include <Message.hxx>
#include <Message_Messenger.hxx>
#include <gp_Quaternion.hxx>
@ -60,6 +64,17 @@ AIS_ViewController::AIS_ViewController()
myPrevMoveTo (-1, -1),
myHasHlrOnBeforeRotation (false),
//
myXRPrsDevices (0, 0),
myXRLaserTeleColor (Quantity_NOC_GREEN),
myXRLaserPickColor (Quantity_NOC_BLUE),
myXRLastTeleportHand(Aspect_XRTrackedDeviceRole_Other),
myXRLastPickingHand (Aspect_XRTrackedDeviceRole_Other),
myXRLastPickDepthLeft (Precision::Infinite()),
myXRLastPickDepthRight(Precision::Infinite()),
myXRTurnAngle (M_PI_4),
myToDisplayXRAuxDevices (false),
myToDisplayXRHands (true),
//
myMouseClickThreshold (3.0),
myMouseDoubleClickInt (0.4),
myScrollZoomRatio (15.0f),
@ -111,6 +126,18 @@ AIS_ViewController::AIS_ViewController()
myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton, AIS_MouseGesture_Pan);
myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_Pan);
myXRTeleportHaptic.Duration = 3600.0f;
myXRTeleportHaptic.Frequency = 0.1f;
myXRTeleportHaptic.Amplitude = 0.2f;
myXRPickingHaptic.Duration = 0.1f;
myXRPickingHaptic.Frequency = 4.0f;
myXRPickingHaptic.Amplitude = 0.1f;
myXRSelectHaptic.Duration = 0.2f;
myXRSelectHaptic.Frequency = 4.0f;
myXRSelectHaptic.Amplitude = 0.5f;
}
// =======================================================================
@ -1287,6 +1314,7 @@ void AIS_ViewController::handlePanning (const Handle(V3d_View)& theView)
{
theView->Pan (myGL.Panning.Delta.x(), myGL.Panning.Delta.y());
theView->Invalidate();
theView->View()->SynchronizeXRPosedToBaseCamera();
return;
}
@ -1307,6 +1335,7 @@ void AIS_ViewController::handlePanning (const Handle(V3d_View)& theView)
aPanTrsf.SetTranslation (aCameraPan);
aCam->Transform (aPanTrsf);
theView->Invalidate();
theView->View()->SynchronizeXRPosedToBaseCamera();
}
// =======================================================================
@ -1331,6 +1360,7 @@ void AIS_ViewController::handleZRotate (const Handle(V3d_View)& theView)
aRotPnt.y() += myGL.ZRotate.Angle * aViewPort.y();
theView->Rotation (int(aRotPnt.x()), int(aRotPnt.y()));
theView->Invalidate();
theView->View()->SynchronizeXRPosedToBaseCamera();
}
// =======================================================================
@ -1361,6 +1391,7 @@ void AIS_ViewController::handleZoom (const Handle(V3d_View)& theView,
aCoeff = theParams.Delta > 0.0 ? aCoeff : 1.0 / aCoeff;
theView->SetZoom (aCoeff, true);
theView->Invalidate();
theView->View()->SynchronizeXRPosedToBaseCamera();
return;
}
@ -1432,6 +1463,7 @@ void AIS_ViewController::handleZoom (const Handle(V3d_View)& theView,
aPanTrsf.SetTranslation (aCameraPan);
aCam->Transform (aPanTrsf);
theView->Invalidate();
theView->View()->SynchronizeXRPosedToBaseCamera();
}
// =======================================================================
@ -1452,7 +1484,7 @@ void AIS_ViewController::handleZFocusScroll (const Handle(V3d_View)& theView,
&& aFocus < 2.0)
{
theView->Camera()->SetZFocus (theView->Camera()->ZFocusType(), aFocus);
theView->Redraw();
theView->Invalidate();
}
}
@ -1469,7 +1501,9 @@ void AIS_ViewController::handleOrbitRotation (const Handle(V3d_View)& theView,
return;
}
const Handle(Graphic3d_Camera)& aCam = theView->Camera();
const Handle(Graphic3d_Camera)& aCam = theView->View()->IsActiveXR()
? theView->View()->BaseXRCamera()
: theView->Camera();
if (myGL.OrbitRotation.ToStart)
{
// default alternatives
@ -1508,9 +1542,13 @@ void AIS_ViewController::handleOrbitRotation (const Handle(V3d_View)& theView,
theView->Window()->Size (aWinXY.x(), aWinXY.y());
double aYawAngleDelta = ((myGL.OrbitRotation.PointStart.x() - myGL.OrbitRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
double aPitchAngleDelta = -((myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
const double aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
const double aYawAngleNew = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
const double aRoll = 0.0;
double aPitchAngleNew = 0.0, aRoll = 0.0;
const double aYawAngleNew = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
if (!theView->View()->IsActiveXR())
{
aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
aRoll = 0.0;
}
gp_Quaternion aRot;
aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, aRoll);
@ -1564,6 +1602,7 @@ void AIS_ViewController::handleOrbitRotation (const Handle(V3d_View)& theView,
}
theView->Invalidate();
theView->View()->SynchronizeXRBaseToPosedCamera();
}
// =======================================================================
@ -1933,6 +1972,251 @@ void AIS_ViewController::handleCameraActions (const Handle(AIS_InteractiveContex
}
}
// =======================================================================
// function : handleXRInput
// purpose :
// =======================================================================
void AIS_ViewController::handleXRInput (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView,
const AIS_WalkDelta& )
{
theView->View()->ProcessXRInput();
if (!theView->View()->IsActiveXR())
{
return;
}
if (myXRCameraTmp.IsNull())
{
myXRCameraTmp = new Graphic3d_Camera();
}
handleXRTurnPad (theCtx, theView);
handleXRTeleport(theCtx, theView);
handleXRPicking (theCtx, theView);
}
// =======================================================================
// function : handleXRTurnPad
// purpose :
// =======================================================================
void AIS_ViewController::handleXRTurnPad (const Handle(AIS_InteractiveContext)& ,
const Handle(V3d_View)& theView)
{
if (myXRTurnAngle <= 0.0
|| !theView->View()->IsActiveXR())
{
return;
}
// turn left/right at 45 degrees on left/right trackpad clicks
for (int aHand = 0; aHand < 2; ++aHand)
{
const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
const Handle(Aspect_XRAction)& aPadClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadClick);
const Handle(Aspect_XRAction)& aPadPosAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadPosition);
if (aPadClickAct.IsNull()
|| aPadPosAct.IsNull())
{
continue;
}
const Aspect_XRDigitalActionData aPadClick = theView->View()->XRSession()->GetDigitalActionData (aPadClickAct);
const Aspect_XRAnalogActionData aPadPos = theView->View()->XRSession()->GetAnalogActionData (aPadPosAct);
if (aPadClick.IsActive
&& aPadClick.IsPressed
&& aPadClick.IsChanged
&& aPadPos.IsActive
&& Abs (aPadPos.VecXYZ.y()) < 0.5f
&& Abs (aPadPos.VecXYZ.x()) > 0.7f)
{
gp_Trsf aTrsfTurn;
aTrsfTurn.SetRotation (gp_Ax1 (gp::Origin(), theView->View()->BaseXRCamera()->Up()), aPadPos.VecXYZ.x() < 0.0f ? myXRTurnAngle : -myXRTurnAngle);
theView->View()->TurnViewXRCamera (aTrsfTurn);
break;
}
}
}
// =======================================================================
// function : handleXRTeleport
// purpose :
// =======================================================================
void AIS_ViewController::handleXRTeleport (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView)
{
if (!theView->View()->IsActiveXR())
{
return;
}
// teleport on forward trackpad unclicks
const Aspect_XRTrackedDeviceRole aTeleOld = myXRLastTeleportHand;
myXRLastTeleportHand = Aspect_XRTrackedDeviceRole_Other;
for (int aHand = 0; aHand < 2; ++aHand)
{
const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
const Standard_Integer aDeviceId = theView->View()->XRSession()->NamedTrackedDevice (aRole);
if (aDeviceId == -1)
{
continue;
}
const Handle(Aspect_XRAction)& aPadClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadClick);
const Handle(Aspect_XRAction)& aPadPosAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadPosition);
if (aPadClickAct.IsNull()
|| aPadPosAct.IsNull())
{
continue;
}
const Aspect_XRDigitalActionData aPadClick = theView->View()->XRSession()->GetDigitalActionData (aPadClickAct);
const Aspect_XRAnalogActionData aPadPos = theView->View()->XRSession()->GetAnalogActionData (aPadPosAct);
const bool isPressed = aPadClick.IsPressed;
const bool isClicked = !aPadClick.IsPressed
&& aPadClick.IsChanged;
if (aPadClick.IsActive
&& (isPressed || isClicked)
&& aPadPos.IsActive
&& aPadPos.VecXYZ.y() > 0.6f
&& Abs (aPadPos.VecXYZ.x()) < 0.5f)
{
const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceId];
if (!aPose.IsValidPose)
{
continue;
}
myXRLastTeleportHand = aRole;
Standard_Real& aPickDepth = aRole == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
aPickDepth = Precision::Infinite();
Graphic3d_Vec3 aPickNorm;
const gp_Trsf aHandBase = theView->View()->PoseXRToWorld (aPose.Orientation);
const Standard_Real aHeadHeight = theView->View()->XRSession()->HeadPose().TranslationPart().Y();
{
const Standard_Integer aPickedId = handleXRMoveTo (theCtx, theView, aPose.Orientation, false);
if (aPickedId >= 1)
{
const SelectMgr_SortCriterion& aPickedData = theCtx->MainSelector()->PickedData (aPickedId);
aPickNorm = aPickedData.Normal;
if (aPickNorm.SquareModulus() > ShortRealEpsilon())
{
aPickDepth = aPickedData.Point.Distance (aHandBase.TranslationPart());
}
}
}
if (isClicked)
{
myXRLastTeleportHand = Aspect_XRTrackedDeviceRole_Other;
if (!Precision::IsInfinite (aPickDepth))
{
const gp_Dir aTeleDir = -gp::DZ().Transformed (aHandBase);
const gp_Dir anUpDir = theView->View()->BaseXRCamera()->Up();
bool isHorizontal = false;
gp_Dir aPickNormDir (aPickNorm.x(), aPickNorm.y(), aPickNorm.z());
if (anUpDir.IsEqual ( aPickNormDir, M_PI_4)
|| anUpDir.IsEqual (-aPickNormDir, M_PI_4))
{
isHorizontal = true;
}
gp_Pnt aNewEye = aHandBase.TranslationPart();
if (isHorizontal)
{
aNewEye = aHandBase.TranslationPart()
+ aTeleDir.XYZ() * aPickDepth
+ anUpDir.XYZ() * aHeadHeight;
}
else
{
if (aPickNormDir.Dot (aTeleDir) < 0.0)
{
aPickNormDir.Reverse();
}
aNewEye = aHandBase.TranslationPart()
+ aTeleDir.XYZ() * aPickDepth
- aPickNormDir.XYZ() * aHeadHeight / 4;
}
theView->View()->PosedXRCamera()->MoveEyeTo (aNewEye);
theView->View()->ComputeXRBaseCameraFromPosed (theView->View()->PosedXRCamera(), theView->View()->XRSession()->HeadPose());
}
}
break;
}
}
if (myXRLastTeleportHand != aTeleOld)
{
if (aTeleOld != Aspect_XRTrackedDeviceRole_Other)
{
if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (aTeleOld, Aspect_XRGenericAction_OutputHaptic))
{
theView->View()->XRSession()->AbortHapticVibrationAction (aHaptic);
}
}
if (myXRLastTeleportHand != Aspect_XRTrackedDeviceRole_Other)
{
if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastTeleportHand, Aspect_XRGenericAction_OutputHaptic))
{
theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRTeleportHaptic);
}
}
}
}
// =======================================================================
// function : handleXRPicking
// purpose :
// =======================================================================
void AIS_ViewController::handleXRPicking (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView)
{
if (!theView->View()->IsActiveXR())
{
return;
}
// handle selection on trigger clicks
Aspect_XRTrackedDeviceRole aPickDevOld = myXRLastPickingHand;
myXRLastPickingHand = Aspect_XRTrackedDeviceRole_Other;
for (int aHand = 0; aHand < 2; ++aHand)
{
const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
const Handle(Aspect_XRAction)& aTrigClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTriggerClick);
const Handle(Aspect_XRAction)& aTrigPullAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTriggerPull);
if (aTrigClickAct.IsNull()
|| aTrigPullAct.IsNull())
{
continue;
}
const Aspect_XRDigitalActionData aTrigClick = theView->View()->XRSession()->GetDigitalActionData (aTrigClickAct);
const Aspect_XRAnalogActionData aTrigPos = theView->View()->XRSession()->GetAnalogActionData (aTrigPullAct);
if (aTrigPos.IsActive
&& Abs (aTrigPos.VecXYZ.x()) > 0.1f)
{
myXRLastPickingHand = aRole;
handleXRHighlight (theCtx, theView);
if (aTrigClick.IsActive
&& aTrigClick.IsPressed
&& aTrigClick.IsChanged)
{
theCtx->Select (false);
OnSelectionChanged (theCtx, theView);
if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastPickingHand, Aspect_XRGenericAction_OutputHaptic))
{
theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRSelectHaptic);
}
}
break;
}
}
if (myXRLastPickingHand != aPickDevOld)
{
theCtx->ClearDetected();
}
}
// =======================================================================
// function : OnSelectionChanged
// purpose :
@ -2041,6 +2325,7 @@ void AIS_ViewController::contextLazyMoveTo (const Handle(AIS_InteractiveContext)
myPrevMoveTo = thePnt;
Handle(SelectMgr_EntityOwner) aLastPicked = theCtx->DetectedOwner();
theView->AutoZFit();
theCtx->MoveTo (thePnt.x(), thePnt.y(), theView, false);
Handle(SelectMgr_EntityOwner) aNewPicked = theCtx->DetectedOwner();
@ -2272,9 +2557,10 @@ void AIS_ViewController::handleDynamicHighlight (const Handle(AIS_InteractiveCon
else if (myToAllowHighlight)
{
if (myPrevMoveTo != aMoveToPnt
|| myGL.OrbitRotation.ToRotate
|| myGL.ViewRotation.ToRotate
|| theView->IsInvalidated())
|| (!theView->View()->IsActiveXR()
&& (myGL.OrbitRotation.ToRotate
|| myGL.ViewRotation.ToRotate
|| theView->IsInvalidated())))
{
ResetPreviousMoveTo();
contextLazyMoveTo (theCtx, theView, aMoveToPnt);
@ -2340,6 +2626,12 @@ void AIS_ViewController::handleViewRedraw (const Handle(AIS_InteractiveContext)&
setAskNextFrame();
}
if (theView->View()->IsActiveXR())
{
// VR requires continuous rendering
myToAskNextFrame = true;
}
for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
{
const Handle(V3d_View)& aView = aViewIter.Value();
@ -2368,6 +2660,266 @@ void AIS_ViewController::handleViewRedraw (const Handle(AIS_InteractiveContext)&
}
}
// =======================================================================
// function : handleXRMoveTo
// purpose :
// =======================================================================
Standard_Integer AIS_ViewController::handleXRMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView,
const gp_Trsf& thePose,
const Standard_Boolean theToHighlight)
{
//ResetPreviousMoveTo();
Standard_Integer aPickResult = 0;
Handle(Graphic3d_Camera) aCamBack = theView->Camera();
myXRCameraTmp->Copy (aCamBack);
theView->View()->ComputeXRPosedCameraFromBase (*myXRCameraTmp, thePose);
theView->SetCamera (myXRCameraTmp);
Graphic3d_Vec2i aPickPixel;
theView->Window()->Size (aPickPixel.x(), aPickPixel.y());
aPickPixel /= 2;
const Standard_Integer aSelTolerBack = theCtx->MainSelector()->CustomPixelTolerance();
theCtx->MainSelector()->SetPixelTolerance (1);
theView->AutoZFit();
if (theToHighlight)
{
theCtx->MoveTo (aPickPixel.x(), aPickPixel.y(), theView, false);
if (!theCtx->DetectedOwner().IsNull())
{
// ignore 2D objects
for (aPickResult = 1; !theCtx->DetectedOwner()->Selectable()->TransformPersistence().IsNull(); ++aPickResult)
{
if (theCtx->HilightNextDetected (theView, false) <= 1)
{
theCtx->ClearDetected();
aPickResult = 0;
break;
}
}
}
}
else
{
theCtx->MainSelector()->Pick (aPickPixel.x(), aPickPixel.y(), theView);
for (Standard_Integer aPickIter = 1; aPickIter <= theCtx->MainSelector()->NbPicked(); ++aPickIter)
{
const SelectMgr_SortCriterion& aPickedData = theCtx->MainSelector()->PickedData (aPickIter);
if (!aPickedData.Entity->OwnerId()->Selectable()->TransformPersistence().IsNull())
{
// skip 2d objects
continue;
}
aPickResult = aPickIter;
break;
}
}
theCtx->MainSelector()->SetPixelTolerance (aSelTolerBack);
theView->SetCamera (aCamBack);
return aPickResult;
}
// =======================================================================
// function : handleXRHighlight
// purpose :
// =======================================================================
void AIS_ViewController::handleXRHighlight (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView)
{
if (myXRLastPickingHand != Aspect_XRTrackedDeviceRole_LeftHand
&& myXRLastPickingHand != Aspect_XRTrackedDeviceRole_RightHand)
{
return;
}
const Standard_Integer aDeviceId = theView->View()->XRSession()->NamedTrackedDevice (myXRLastPickingHand);
if (aDeviceId == -1)
{
return;
}
const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceId];
if (!aPose.IsValidPose)
{
return;
}
Handle(SelectMgr_EntityOwner) aDetOld = theCtx->DetectedOwner();
handleXRMoveTo (theCtx, theView, aPose.Orientation, true);
if (!theCtx->DetectedOwner().IsNull()
&& theCtx->DetectedOwner() != aDetOld)
{
if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastPickingHand, Aspect_XRGenericAction_OutputHaptic))
{
theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRPickingHaptic);
}
}
Standard_Real& aPickDepth = myXRLastPickingHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
aPickDepth = Precision::Infinite();
if (theCtx->MainSelector()->NbPicked() > 0)
{
const gp_Trsf aHandBase = theView->View()->PoseXRToWorld (aPose.Orientation);
const SelectMgr_SortCriterion& aPicked = theCtx->MainSelector()->PickedData (1);
aPickDepth = aPicked.Point.Distance (aHandBase.TranslationPart());
}
}
// =======================================================================
// function : handleXRPresentations
// purpose :
// =======================================================================
void AIS_ViewController::handleXRPresentations (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView)
{
if (!theView->View()->IsActiveXR()
|| (!myToDisplayXRAuxDevices
&& !myToDisplayXRHands))
{
for (NCollection_Array1<Handle(AIS_XRTrackedDevice)>::Iterator aPrsIter (myXRPrsDevices); aPrsIter.More(); aPrsIter.Next())
{
if (!aPrsIter.Value().IsNull()
&& aPrsIter.Value()->HasInteractiveContext())
{
theCtx->Remove (aPrsIter.Value(), false);
}
aPrsIter.ChangeValue().Nullify();
}
return;
}
if (myXRPrsDevices.Length() != theView->View()->XRSession()->TrackedPoses().Length())
{
for (NCollection_Array1<Handle(AIS_XRTrackedDevice)>::Iterator aPrsIter (myXRPrsDevices); aPrsIter.More(); aPrsIter.Next())
{
if (!aPrsIter.Value().IsNull())
{
theCtx->Remove (aPrsIter.Value(), false);
}
}
myXRPrsDevices.Resize (theView->View()->XRSession()->TrackedPoses().Lower(), theView->View()->XRSession()->TrackedPoses().Upper(), false);
}
const Standard_Integer aHeadDevice = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_Head);
const Standard_Integer aLeftDevice = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_LeftHand);
const Standard_Integer aRightDevice = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_RightHand);
for (Standard_Integer aDeviceIter = theView->View()->XRSession()->TrackedPoses().Lower(); aDeviceIter <= theView->View()->XRSession()->TrackedPoses().Upper(); ++aDeviceIter)
{
const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceIter];
Handle(AIS_XRTrackedDevice)& aPosePrs = myXRPrsDevices[aDeviceIter];
if (!aPose.IsValidPose)
{
continue;
}
const bool isHand = aDeviceIter == aLeftDevice
|| aDeviceIter == aRightDevice;
if ((!myToDisplayXRHands && isHand)
|| (!myToDisplayXRAuxDevices && !isHand))
{
if (!aPosePrs.IsNull()
&& aPosePrs->HasInteractiveContext())
{
theCtx->Remove (aPosePrs, false);
}
continue;
}
Aspect_XRTrackedDeviceRole aRole = Aspect_XRTrackedDeviceRole_Other;
if (aDeviceIter == aLeftDevice)
{
aRole = Aspect_XRTrackedDeviceRole_LeftHand;
}
else if (aDeviceIter == aRightDevice)
{
aRole = Aspect_XRTrackedDeviceRole_RightHand;
}
if (!aPosePrs.IsNull()
&& aPosePrs->UnitFactor() != (float )theView->View()->UnitFactor())
{
theCtx->Remove (aPosePrs, false);
aPosePrs.Nullify();
}
if (aPosePrs.IsNull())
{
Handle(Image_Texture) aTexture;
Handle(Graphic3d_ArrayOfTriangles) aTris;
if (aDeviceIter != aHeadDevice)
{
aTris = theView->View()->XRSession()->LoadRenderModel (aDeviceIter, aTexture);
}
if (!aTris.IsNull())
{
aPosePrs = new AIS_XRTrackedDevice (aTris, aTexture);
}
else
{
aPosePrs = new AIS_XRTrackedDevice();
}
aPosePrs->SetUnitFactor ((float )theView->View()->UnitFactor());
aPosePrs->SetMutable (true);
aPosePrs->SetInfiniteState (true);
}
aPosePrs->SetRole (aRole);
if (!aPosePrs->HasInteractiveContext())
{
theCtx->Display (aPosePrs, 0, -1, false);
}
gp_Trsf aPoseLocal = aPose.Orientation;
if (aDeviceIter == aHeadDevice)
{
// show headset position on floor level
aPoseLocal.SetTranslationPart (gp_Vec (aPoseLocal.TranslationPart().X(), 0.0, aPoseLocal.TranslationPart().Z()));
}
const gp_Trsf aPoseWorld = theView->View()->PoseXRToWorld (aPoseLocal);
theCtx->SetLocation (aPosePrs, aPoseWorld);
Standard_Real aLaserLen = 0.0;
if (isHand
&& aPosePrs->Role() == myXRLastPickingHand)
{
aLaserLen = myXRLastPickingHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
if (Precision::IsInfinite (aLaserLen))
{
const Bnd_Box aViewBox = theView->View()->MinMaxValues (true);
if (!aViewBox.IsVoid())
{
aLaserLen = Sqrt (aViewBox.SquareExtent());
}
else
{
aLaserLen = 100.0;
}
}
aPosePrs->SetLaserColor (myXRLaserPickColor);
}
else if (isHand
&& aPosePrs->Role() == myXRLastTeleportHand)
{
aLaserLen = myXRLastTeleportHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
if (Precision::IsInfinite (aLaserLen))
{
const Bnd_Box aViewBox = theView->View()->MinMaxValues (true);
if (!aViewBox.IsVoid())
{
aLaserLen = Sqrt (aViewBox.SquareExtent());
}
else
{
aLaserLen = 100.0;
}
}
aPosePrs->SetLaserColor (myXRLaserTeleColor);
}
aPosePrs->SetLaserLength ((float )aLaserLen);
}
}
// =======================================================================
// function : HandleViewEvents
// purpose :
@ -2375,11 +2927,23 @@ void AIS_ViewController::handleViewRedraw (const Handle(AIS_InteractiveContext)&
void AIS_ViewController::HandleViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView)
{
handleMoveTo (theCtx, theView);
const bool wasImmediateUpdate = theView->SetImmediateUpdate (false);
const AIS_WalkDelta aWalk = FetchNavigationKeys (1.0, 1.0);
handleXRInput (theCtx, theView, aWalk);
if (theView->View()->IsActiveXR())
{
theView->View()->SetupXRPosedCamera();
}
handleCameraActions (theCtx, theView, aWalk);
theView->View()->SynchronizeXRPosedToBaseCamera(); // handleCameraActions() may modify posed camera position - copy this modifications also to the base camera
handleXRPresentations (theCtx, theView);
handleMoveTo (theCtx, theView);
handleViewRedraw (theCtx, theView);
theView->View()->UnsetXRPosedCamera();
theView->SetImmediateUpdate (wasImmediateUpdate);
// make sure to not process the same events twice
myGL.Reset();

View File

@ -16,6 +16,8 @@
#include <Aspect_VKeySet.hxx>
#include <Aspect_TouchMap.hxx>
#include <Aspect_XRHapticActionData.hxx>
#include <Aspect_XRTrackedDeviceRole.hxx>
#include <AIS_DragAction.hxx>
#include <AIS_MouseGesture.hxx>
#include <AIS_NavigationMode.hxx>
@ -28,6 +30,7 @@
#include <NCollection_Array1.hxx>
#include <OSD_Timer.hxx>
#include <Precision.hxx>
#include <Quantity_ColorRGBA.hxx>
#include <Standard_Mutex.hxx>
class AIS_AnimationCamera;
@ -35,6 +38,8 @@ class AIS_InteractiveObject;
class AIS_InteractiveContext;
class AIS_Point;
class AIS_RubberBand;
class AIS_XRTrackedDevice;
class Graphic3d_Camera;
class V3d_View;
//! Auxiliary structure for handling viewer events between GUI and Rendering threads.
@ -200,6 +205,18 @@ public: //! @name global parameters
//! Reset previous position of MoveTo.
void ResetPreviousMoveTo() { myPrevMoveTo = Graphic3d_Vec2i (-1); }
//! Return TRUE to display auxiliary tracked XR devices (like tracking stations).
bool ToDisplayXRAuxDevices() const { return myToDisplayXRAuxDevices; }
//! Set if auxiliary tracked XR devices should be displayed.
void SetDisplayXRAuxDevices (bool theToDisplay) { myToDisplayXRAuxDevices = theToDisplay; }
//! Return TRUE to display XR hand controllers.
bool ToDisplayXRHands() const { return myToDisplayXRHands; }
//! Set if tracked XR hand controllers should be displayed.
void SetDisplayXRHands (bool theToDisplay) { myToDisplayXRHands = theToDisplay; }
public: //! @name keyboard input
//! Return keyboard state.
@ -548,6 +565,40 @@ public:
Standard_EXPORT virtual void handleViewRedraw (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView);
public:
//! Perform XR input.
//! This method is expected to be called from rendering thread.
Standard_EXPORT virtual void handleXRInput (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView,
const AIS_WalkDelta& theWalk);
//! Handle trackpad view turn action.
Standard_EXPORT virtual void handleXRTurnPad (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView);
//! Handle trackpad teleportation action.
Standard_EXPORT virtual void handleXRTeleport (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView);
//! Handle picking on trigger click.
Standard_EXPORT virtual void handleXRPicking (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView);
//! Perform dynamic highlighting for active hand.
Standard_EXPORT virtual void handleXRHighlight (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView);
//! Display auxiliary XR presentations.
Standard_EXPORT virtual void handleXRPresentations (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView);
//! Perform picking with/without dynamic highlighting for XR pose.
Standard_EXPORT virtual Standard_Integer handleXRMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView,
const gp_Trsf& thePose,
const Standard_Boolean theToHighlight);
protected:
//! Flush buffers.
@ -629,6 +680,23 @@ protected:
Graphic3d_Vec2i myPrevMoveTo; //!< previous position of MoveTo event in 3D viewer
Standard_Boolean myHasHlrOnBeforeRotation; //!< flag for restoring Computed mode after rotation
protected: //! @name XR input variables
NCollection_Array1<Handle(AIS_XRTrackedDevice)> myXRPrsDevices; //!< array of XR tracked devices presentations
Handle(Graphic3d_Camera) myXRCameraTmp; //!< temporary camera
Quantity_Color myXRLaserTeleColor; //!< color of teleport laser
Quantity_Color myXRLaserPickColor; //!< color of picking laser
Aspect_XRTrackedDeviceRole myXRLastTeleportHand;//!< active hand for teleport
Aspect_XRTrackedDeviceRole myXRLastPickingHand; //!< active hand for picking objects
Aspect_XRHapticActionData myXRTeleportHaptic; //!< vibration on picking teleport destination
Aspect_XRHapticActionData myXRPickingHaptic; //!< vibration on dynamic highlighting
Aspect_XRHapticActionData myXRSelectHaptic; //!< vibration on selection
Standard_Real myXRLastPickDepthLeft; //!< last picking depth for left hand
Standard_Real myXRLastPickDepthRight; //!< last picking depth for right hand
Standard_Real myXRTurnAngle; //!< discrete turn angle for XR trackpad
Standard_Boolean myToDisplayXRAuxDevices; //!< flag to display auxiliary tracked XR devices
Standard_Boolean myToDisplayXRHands; //!< flag to display XR hands
protected: //! @name keyboard input variables
Aspect_VKeySet myKeys; //!< keyboard state

View File

@ -0,0 +1,202 @@
// Copyright (c) 2020 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 <AIS_XRTrackedDevice.hxx>
#include <Graphic3d_ArrayOfSegments.hxx>
#include <Graphic3d_ArrayOfTriangles.hxx>
#include <Graphic3d_Group.hxx>
#include <Graphic3d_Texture2Dmanual.hxx>
#include <Image_Texture.hxx>
#include <Prs3d_LineAspect.hxx>
#include <Prs3d_ShadingAspect.hxx>
#include <Select3D_SensitivePrimitiveArray.hxx>
#include <SelectMgr_EntityOwner.hxx>
//! Texture holder.
class AIS_XRTrackedDevice::XRTexture : public Graphic3d_Texture2Dmanual
{
public:
//! Constructor.
XRTexture (const Handle(Image_Texture)& theImageSource,
const Graphic3d_TextureUnit theUnit = Graphic3d_TextureUnit_BaseColor)
: Graphic3d_Texture2Dmanual (""), myImageSource (theImageSource)
{
if (!theImageSource->TextureId().IsEmpty())
{
myTexId = theImageSource->TextureId();
}
myParams->SetTextureUnit (theUnit);
myIsColorMap = theUnit == Graphic3d_TextureUnit_BaseColor
|| theUnit == Graphic3d_TextureUnit_Emissive;
}
//! Image reader.
virtual Handle(Image_PixMap) GetImage() const Standard_OVERRIDE { return myImageSource->ReadImage(); }
protected:
Handle(Image_Texture) myImageSource;
};
IMPLEMENT_STANDARD_RTTIEXT(AIS_XRTrackedDevice, AIS_InteractiveObject)
//=======================================================================
//function : AIS_XRTrackedDevice
//purpose :
//=======================================================================
AIS_XRTrackedDevice::AIS_XRTrackedDevice (const Handle(Graphic3d_ArrayOfTriangles)& theTris,
const Handle(Image_Texture)& theTexture)
: myTris (theTris),
myLaserColor (Quantity_NOC_BLUE),
myLaserLength (0.0f),
myUnitFactor (1.0f),
myRole (Aspect_XRTrackedDeviceRole_Other),
myToShowAxes (false)
{
myDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
myDrawer->ShadingAspect()->SetMaterial (Graphic3d_NOM_DEFAULT);
myDrawer->ShadingAspect()->SetColor (Quantity_NOC_WHITE);
if (!theTexture.IsNull())
{
myDrawer->ShadingAspect()->Aspect()->SetTextureMap (new XRTexture (theTexture));
myDrawer->ShadingAspect()->Aspect()->SetTextureMapOn (true);
}
}
//=======================================================================
//function : AIS_XRTrackedDevice
//purpose :
//=======================================================================
AIS_XRTrackedDevice::AIS_XRTrackedDevice()
: myLaserColor (Quantity_NOC_BLUE),
myLaserLength (0.0f),
myUnitFactor (1.0f),
myRole (Aspect_XRTrackedDeviceRole_Other),
myToShowAxes (true)
{
//
}
//=======================================================================
//function : SetLaserColor
//purpose :
//=======================================================================
void AIS_XRTrackedDevice::SetLaserColor (const Quantity_Color& theColor)
{
if (!myLaserColor.IsEqual (theColor))
{
myLaserColor = theColor;
computeLaserRay();
}
}
//=======================================================================
//function : SetLaserLength
//purpose :
//=======================================================================
void AIS_XRTrackedDevice::SetLaserLength (Standard_ShortReal theLength)
{
if (myLaserLength != theLength)
{
myLaserLength = theLength;
computeLaserRay();
}
}
//=======================================================================
//function : computeLaserRay
//purpose :
//=======================================================================
void AIS_XRTrackedDevice::computeLaserRay()
{
if (myRayGroup.IsNull())
{
return;
}
if (!myRayGroup->IsEmpty())
{
myRayGroup->Clear();
}
if (myLaserLength <= 0.0f)
{
return;
}
Handle(Graphic3d_ArrayOfPrimitives) aLines = new Graphic3d_ArrayOfSegments (2, 0, Graphic3d_ArrayFlags_VertexColor);
aLines->AddVertex (gp_Pnt (0.0, 0.0, 0.0), myLaserColor);
aLines->AddVertex (gp_Pnt (0.0, 0.0, -myLaserLength), myLaserColor);
myRayGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
myRayGroup->AddPrimitiveArray (aLines, false); // do not extend camera frustum by ray
}
//=======================================================================
//function : Compute
//purpose :
//=======================================================================
void AIS_XRTrackedDevice::Compute (const Handle(PrsMgr_PresentationManager3d)& ,
const Handle(Prs3d_Presentation)& thePrs,
const Standard_Integer theMode)
{
if (theMode != 0)
{
return;
}
thePrs->SetInfiniteState (myInfiniteState);
Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
if (!myTris.IsNull())
{
aGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
aGroup->AddPrimitiveArray (myTris);
}
if (myToShowAxes || myTris.IsNull())
{
const float aSize = 0.1f * myUnitFactor;
aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
Handle(Graphic3d_ArrayOfPrimitives) aLines = new Graphic3d_ArrayOfSegments (6, 0, Graphic3d_ArrayFlags_VertexColor);
aLines->AddVertex (gp_Pnt (0.0, 0.0, 0.0), Quantity_Color (Quantity_NOC_RED));
aLines->AddVertex (gp_Pnt (aSize, 0.0, 0.0), Quantity_Color (Quantity_NOC_RED));
aLines->AddVertex (gp_Pnt (0.0, 0.0, 0.0), Quantity_Color (Quantity_NOC_GREEN));
aLines->AddVertex (gp_Pnt (0.0, aSize, 0.0), Quantity_Color (Quantity_NOC_GREEN));
aLines->AddVertex (gp_Pnt (0.0, 0.0, 0.0), Quantity_Color (Quantity_NOC_BLUE));
aLines->AddVertex (gp_Pnt (0.0, 0.0, aSize), Quantity_Color (Quantity_NOC_BLUE));
aGroup->AddPrimitiveArray (aLines);
}
myRayGroup = thePrs->NewGroup();
computeLaserRay();
}
//=======================================================================
//function : ComputeSelection
//purpose :
//=======================================================================
void AIS_XRTrackedDevice::ComputeSelection (const Handle(SelectMgr_Selection)& theSel,
const Standard_Integer theMode)
{
if (theMode != 0)
{
return;
}
if (!myTris.IsNull())
{
Handle(SelectMgr_EntityOwner) anOwner = new SelectMgr_EntityOwner (this);
Handle(Select3D_SensitivePrimitiveArray) aSensitive = new Select3D_SensitivePrimitiveArray (anOwner);
aSensitive->InitTriangulation (myTris->Attributes(), myTris->Indices(), TopLoc_Location(), true);
theSel->Add (aSensitive);
}
}

View File

@ -0,0 +1,92 @@
// Copyright (c) 2020 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.
#ifndef _AIS_XRTrackedDevice_HeaderFile
#define _AIS_XRTrackedDevice_HeaderFile
#include <AIS_InteractiveObject.hxx>
#include <Aspect_XRTrackedDeviceRole.hxx>
class Graphic3d_ArrayOfTriangles;
class Image_Texture;
//! Auxiliary textured mesh presentation of tracked XR device.
class AIS_XRTrackedDevice : public AIS_InteractiveObject
{
DEFINE_STANDARD_RTTIEXT(AIS_XRTrackedDevice, AIS_InteractiveObject)
public:
//! Main constructor.
Standard_EXPORT AIS_XRTrackedDevice (const Handle(Graphic3d_ArrayOfTriangles)& theTris,
const Handle(Image_Texture)& theTexture);
//! Empty constructor.
Standard_EXPORT AIS_XRTrackedDevice();
//! Return device role.
Aspect_XRTrackedDeviceRole Role() const { return myRole; }
//! Set device role.
void SetRole (Aspect_XRTrackedDeviceRole theRole) { myRole = theRole; }
//! Return laser color.
const Quantity_Color& LaserColor() const { return myLaserColor; }
//! Set laser color.
Standard_EXPORT void SetLaserColor (const Quantity_Color& theColor);
//! Return laser length.
Standard_ShortReal LaserLength() const { return myLaserLength; }
//! Set laser length.
Standard_EXPORT void SetLaserLength (Standard_ShortReal theLength);
//! Return unit scale factor.
Standard_ShortReal UnitFactor() const { return myUnitFactor; }
//! Set unit scale factor.
void SetUnitFactor (Standard_ShortReal theFactor) { myUnitFactor = theFactor; }
protected:
//! Returns true for 0 mode.
virtual Standard_Boolean AcceptDisplayMode (const Standard_Integer theMode) const Standard_OVERRIDE { return theMode == 0; }
//! Compute presentation.
Standard_EXPORT virtual void Compute (const Handle(PrsMgr_PresentationManager3d)& thePrsMgr,
const Handle(Prs3d_Presentation)& thePrs,
const Standard_Integer theMode) Standard_OVERRIDE;
//! Compute selection.
Standard_EXPORT virtual void ComputeSelection (const Handle(SelectMgr_Selection)& theSel,
const Standard_Integer theMode) Standard_OVERRIDE;
//! Compute laser ray presentation.
Standard_EXPORT void computeLaserRay();
private:
//! Texture holder.
class XRTexture;
private:
Handle(Graphic3d_Group) myRayGroup;
Handle(Graphic3d_ArrayOfTriangles) myTris;
Quantity_Color myLaserColor;
Standard_ShortReal myLaserLength;
Standard_ShortReal myUnitFactor;
Aspect_XRTrackedDeviceRole myRole;
Standard_Boolean myToShowAxes;
};
#endif // _AIS_XRTrackedDevice_HeaderFile

View File

@ -141,3 +141,5 @@ AIS_RadiusDimension.hxx
AIS_Relation.hxx
AIS_SymmetricRelation.hxx
AIS_TangentRelation.hxx
AIS_XRTrackedDevice.cxx
AIS_XRTrackedDevice.hxx

View File

@ -0,0 +1,26 @@
// Copyright (c) 2020 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.
#ifndef _Aspect_ColorSpace_HeaderFile
#define _Aspect_ColorSpace_HeaderFile
#include <Aspect_GraphicsLibrary.hxx>
//! Texture color spaces accepted by XR composer.
enum Aspect_ColorSpace
{
Aspect_ColorSpace_sRGB = 0, //!< non-linear sRGB color space
Aspect_ColorSpace_Linear = 1, //!< linear RGB color space
};
#endif // _Aspect_ColorSpace_HeaderFile

24
src/Aspect/Aspect_Eye.hxx Normal file
View File

@ -0,0 +1,24 @@
// Copyright (c) 2020 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.
#ifndef _Aspect_Eye_HeaderFile
#define _Aspect_Eye_HeaderFile
//! Camera eye index within stereoscopic pair.
enum Aspect_Eye
{
Aspect_Eye_Left,
Aspect_Eye_Right
};
#endif // _Aspect_Eye_HeaderFile

View File

@ -0,0 +1,55 @@
// Copyright (c) 2020 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.
#ifndef _Aspect_FrustumLRBT_HeaderFile
#define _Aspect_FrustumLRBT_HeaderFile
//! Structure defining frustum boundaries.
template<typename Elem_t>
struct Aspect_FrustumLRBT
{
Elem_t Left;
Elem_t Right;
Elem_t Bottom;
Elem_t Top;
//! Empty constructor.
Aspect_FrustumLRBT() : Left (0), Right (0), Bottom (0), Top (0) {}
//! Copy/cast constructor.
template<typename Other_t>
explicit Aspect_FrustumLRBT (const Aspect_FrustumLRBT<Other_t>& theOther)
: Left (static_cast<Elem_t> (theOther.Left)),
Right (static_cast<Elem_t> (theOther.Right)),
Bottom(static_cast<Elem_t> (theOther.Bottom)),
Top (static_cast<Elem_t> (theOther.Top)) {}
//! Apply multiply factor.
void Multiply (Elem_t theScale)
{
Left *= theScale;
Right *= theScale;
Bottom *= theScale;
Top *= theScale;
}
//! Return multiplied frustum.
Aspect_FrustumLRBT<Elem_t> Multiplied (Elem_t theScale)
{
Aspect_FrustumLRBT<Elem_t> aCopy (*this);
aCopy.Multiply (theScale);
return aCopy;
}
};
#endif // _Aspect_FrustumLRBT_HeaderFile

View File

@ -0,0 +1,24 @@
// Copyright (c) 2020 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.
#ifndef _Aspect_GraphicsLibrary_HeaderFile
#define _Aspect_GraphicsLibrary_HeaderFile
//! Graphics API enumeration.
enum Aspect_GraphicsLibrary
{
Aspect_GraphicsLibrary_OpenGL,
Aspect_GraphicsLibrary_OpenGLES,
};
#endif // _Aspect_GraphicsLibrary_HeaderFile

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,149 @@
// Copyright (c) 2020 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.
#ifndef _Aspect_OpenVRSession_HeaderFile
#define _Aspect_OpenVRSession_HeaderFile
#include <Aspect_XRSession.hxx>
//! OpenVR wrapper implementing Aspect_XRSession interface.
class Aspect_OpenVRSession : public Aspect_XRSession
{
DEFINE_STANDARD_RTTIEXT(Aspect_OpenVRSession, Aspect_XRSession)
public:
//! Return TRUE if an HMD may be presented on the system (e.g. to show VR checkbox in application GUI).
//! This is fast check, and even if it returns TRUE, opening session may fail.
Standard_EXPORT static bool IsHmdPresent();
public:
//! Empty constructor.
Standard_EXPORT Aspect_OpenVRSession();
//! Destructor.
Standard_EXPORT virtual ~Aspect_OpenVRSession();
//! Return TRUE if session is opened.
Standard_EXPORT virtual bool IsOpen() const Standard_OVERRIDE;
//! Initialize session.
Standard_EXPORT virtual bool Open() Standard_OVERRIDE;
//! Release session.
Standard_EXPORT virtual void Close() Standard_OVERRIDE;
//! Fetch actual poses of tracked devices.
Standard_EXPORT virtual bool WaitPoses() Standard_OVERRIDE;
//! Return recommended viewport Width x Height for rendering into VR.
virtual NCollection_Vec2<int> RecommendedViewport() const Standard_OVERRIDE { return myRendSize; }
//! Return transformation from eye to head.
//! vr::GetEyeToHeadTransform() wrapper.
Standard_EXPORT virtual NCollection_Mat4<double> EyeToHeadTransform (Aspect_Eye theEye) const Standard_OVERRIDE;
//! Return projection matrix.
Standard_EXPORT virtual NCollection_Mat4<double> ProjectionMatrix (Aspect_Eye theEye,
double theZNear,
double theZFar) const Standard_OVERRIDE;
//! Return TRUE.
virtual bool HasProjectionFrustums() const Standard_OVERRIDE { return true; }
//! Receive XR events.
Standard_EXPORT virtual void ProcessEvents() Standard_OVERRIDE;
//! Submit texture eye to XR Composer.
//! @param theTexture [in] texture handle
//! @param theGraphicsLib [in] graphics library in which texture handle is defined
//! @param theColorSpace [in] texture color space;
//! sRGB means no color conversion by composer;
//! Linear means to sRGB color conversion by composer
//! @param theEye [in] eye to display
//! @return FALSE on error
Standard_EXPORT virtual bool SubmitEye (void* theTexture,
Aspect_GraphicsLibrary theGraphicsLib,
Aspect_ColorSpace theColorSpace,
Aspect_Eye theEye) Standard_OVERRIDE;
//! Query information.
Standard_EXPORT virtual TCollection_AsciiString GetString (InfoString theInfo) const Standard_OVERRIDE;
//! Return index of tracked device of known role.
Standard_EXPORT virtual Standard_Integer NamedTrackedDevice (Aspect_XRTrackedDeviceRole theDevice) const Standard_OVERRIDE;
//! Fetch data for digital input action (like button).
Standard_EXPORT virtual Aspect_XRDigitalActionData GetDigitalActionData (const Handle(Aspect_XRAction)& theAction) const Standard_OVERRIDE;
//! Fetch data for analog input action (like axis).
Standard_EXPORT virtual Aspect_XRAnalogActionData GetAnalogActionData (const Handle(Aspect_XRAction)& theAction) const Standard_OVERRIDE;
//! Fetch data for pose input action (like fingertip position).
Standard_EXPORT virtual Aspect_XRPoseActionData GetPoseActionDataForNextFrame (const Handle(Aspect_XRAction)& theAction) const Standard_OVERRIDE;
//! Set tracking origin.
Standard_EXPORT virtual void SetTrackingOrigin (TrackingUniverseOrigin theOrigin) Standard_OVERRIDE;
protected:
//! Find location of default actions manifest file (based on CSF_OCCTResourcePath or CASROOT variables).
Standard_EXPORT TCollection_AsciiString defaultActionsManifest();
//! Release OpenVR device.
Standard_EXPORT void closeVR();
//! Update projection frustums.
Standard_EXPORT virtual void updateProjectionFrustums();
//! Init VR input.
Standard_EXPORT virtual bool initInput();
//! Handle tracked device activation.
Standard_EXPORT virtual void onTrackedDeviceActivated (Standard_Integer theDeviceIndex);
//! Handle tracked device deactivation.
Standard_EXPORT virtual void onTrackedDeviceDeactivated (Standard_Integer theDeviceIndex);
//! Handle tracked device update.
Standard_EXPORT virtual void onTrackedDeviceUpdated (Standard_Integer theDeviceIndex);
//! Trigger vibration.
Standard_EXPORT virtual void triggerHapticVibrationAction (const Handle(Aspect_XRAction)& theAction,
const Aspect_XRHapticActionData& theParams) Standard_OVERRIDE;
//! Return model for displaying device.
Standard_EXPORT virtual Handle(Graphic3d_ArrayOfTriangles) loadRenderModel (Standard_Integer theDevice,
Standard_Boolean theToApplyUnitFactor,
Handle(Image_Texture)& theTexture) Standard_OVERRIDE;
protected:
//! Access vr::IVRSystem* - OpenVR session object.
Standard_EXPORT void* getVRSystem() const;
private:
//! Internal fields
struct VRContext;
class VRImagePixmap;
class VRTextureSource;
protected:
VRContext* myContext;
TCollection_AsciiString myActionsManifest;
};
#endif // _Aspect_OpenVRSession_HeaderFile

View File

@ -0,0 +1,36 @@
// Copyright (c) 2020 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.
#ifndef _Aspect_TrackedDevicePose_HeaderFile
#define _Aspect_TrackedDevicePose_HeaderFile
#include <gp_Trsf.hxx>
#include <NCollection_Array1.hxx>
//! Describes a single pose for a tracked object (for XR).
struct Aspect_TrackedDevicePose
{
gp_Trsf Orientation; //!< device to absolute transformation
gp_Vec Velocity; //!< velocity in tracker space in m/s
gp_Vec AngularVelocity; //!< angular velocity in radians/s
bool IsValidPose; //!< indicates valid pose
bool IsConnectedDevice; //!< indicates connected state
//! Empty constructor.
Aspect_TrackedDevicePose() : IsValidPose (false), IsConnectedDevice (false) {}
};
//! Array of tracked poses.
typedef NCollection_Array1<Aspect_TrackedDevicePose> Aspect_TrackedDevicePoseArray;
#endif // _Aspect_TrackedDevicePose_HeaderFile

View File

@ -0,0 +1,58 @@
// Copyright (c) 2020 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.
#ifndef _Aspect_XRAction_HeaderFile
#define _Aspect_XRAction_HeaderFile
#include <Aspect_XRActionType.hxx>
#include <NCollection_IndexedDataMap.hxx>
#include <Standard_Transient.hxx>
#include <Standard_Type.hxx>
#include <TCollection_AsciiString.hxx>
//! XR action definition.
class Aspect_XRAction : public Standard_Transient
{
DEFINE_STANDARD_RTTIEXT(Aspect_XRAction, Standard_Transient)
public:
//! Return action id.
const TCollection_AsciiString& Id() const { return myId; }
//! Return action type.
Aspect_XRActionType Type() const { return myType; }
//! Return TRUE if action is defined.
bool IsValid() const { return myRawHandle != 0; }
//! Return action handle.
uint64_t RawHandle() const { return myRawHandle; }
//! Set action handle.
void SetRawHandle (uint64_t theHande) { myRawHandle = theHande; }
//! Main constructor.
Aspect_XRAction (const TCollection_AsciiString& theId,
const Aspect_XRActionType theType)
: myId (theId), myRawHandle (0), myType (theType) {}
protected:
TCollection_AsciiString myId; //!< action id
uint64_t myRawHandle; //!< action handle
Aspect_XRActionType myType; //!< action type
};
//! Map of actions with action Id as a key.
typedef NCollection_IndexedDataMap<TCollection_AsciiString, Handle(Aspect_XRAction), TCollection_AsciiString> Aspect_XRActionMap;
#endif // _Aspect_XRAction_HeaderFile

View File

@ -0,0 +1,55 @@
// Copyright (c) 2020 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.
#ifndef _Aspect_XRActionSet_HeaderFile
#define _Aspect_XRActionSet_HeaderFile
#include <Aspect_XRAction.hxx>
//! XR action set.
class Aspect_XRActionSet : public Standard_Transient
{
DEFINE_STANDARD_RTTIEXT(Aspect_XRActionSet, Standard_Transient)
public:
//! Return action id.
const TCollection_AsciiString& Id() const { return myId; }
//! Return action handle.
uint64_t RawHandle() const { return myRawHandle; }
//! Set action handle.
void SetRawHandle (uint64_t theHande) { myRawHandle = theHande; }
//! Add action.
void AddAction (const Handle(Aspect_XRAction)& theAction)
{
myActions.Add (theAction->Id(), theAction);
}
//! Return map of actions.
const Aspect_XRActionMap& Actions() const { return myActions; }
//! Main constructor.
Aspect_XRActionSet (const TCollection_AsciiString& theId)
: myId (theId), myRawHandle (0) {}
protected:
TCollection_AsciiString myId; //!< action set id
uint64_t myRawHandle; //!< action set handle
Aspect_XRActionMap myActions; //!< map of actions
};
typedef NCollection_IndexedDataMap<TCollection_AsciiString, Handle(Aspect_XRActionSet), TCollection_AsciiString> Aspect_XRActionSetMap;
#endif // _Aspect_XRActionSet_HeaderFile

View File

@ -0,0 +1,27 @@
// Copyright (c) 2020 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.
#ifndef _Aspect_XRActionType_HeaderFile
#define _Aspect_XRActionType_HeaderFile
//! XR action type.
enum Aspect_XRActionType
{
Aspect_XRActionType_InputDigital, //!< boolean input (like button)
Aspect_XRActionType_InputAnalog, //!< analog input (1/2/3 axes)
Aspect_XRActionType_InputPose, //!< positional input
Aspect_XRActionType_InputSkeletal, //!< skeletal input
Aspect_XRActionType_OutputHaptic //!< haptic output (vibration)
};
#endif // _Aspect_XRActionType_HeaderFile

View File

@ -0,0 +1,35 @@
// Copyright (c) 2020 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.
#ifndef _Aspect_XRAnalogActionData_HeaderFile
#define _Aspect_XRAnalogActionData_HeaderFile
#include <NCollection_Vec3.hxx>
//! Analog input XR action data.
struct Aspect_XRAnalogActionData
{
uint64_t ActiveOrigin; //!< The origin that caused this action's current state
float UpdateTime; //!< Time relative to now when this event happened. Will be negative to indicate a past time
NCollection_Vec3<float> VecXYZ; //!< the current state of this action
NCollection_Vec3<float> DeltaXYZ; //!< deltas since the previous update
bool IsActive; //!< whether or not this action is currently available to be bound in the active action set
//! Return TRUE if delta is non-zero.
bool IsChanged() { return !DeltaXYZ.IsEqual (NCollection_Vec3<float> (0.0f, 0.0f, 0.0f)); }
//! Empty constructor.
Aspect_XRAnalogActionData() : ActiveOrigin (0), UpdateTime (0.0f), IsActive (false) {}
};
#endif // _Aspect_XRAnalogActionData_HeaderFile

View File

@ -0,0 +1,32 @@
// Copyright (c) 2020 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.
#ifndef _Aspect_XRDigitalActionData_HeaderFile
#define _Aspect_XRDigitalActionData_HeaderFile
#include <Standard_TypeDef.hxx>
//! Digital input XR action data.
struct Aspect_XRDigitalActionData
{
uint64_t ActiveOrigin; //!< The origin that caused this action's current state
float UpdateTime; //!< Time relative to now when this event happened. Will be negative to indicate a past time
bool IsActive; //!< whether or not this action is currently available to be bound in the active action set
bool IsPressed; //!< Aspect_InputActionType_Digital state - The current state of this action; will be true if currently pressed
bool IsChanged; //!< Aspect_InputActionType_Digital state - this is true if the state has changed since the last frame
//! Empty constructor.
Aspect_XRDigitalActionData() : ActiveOrigin (0), UpdateTime (0.0f), IsActive (false), IsPressed (false), IsChanged (false) {}
};
#endif // _Aspect_XRDigitalActionData_HeaderFile

View File

@ -0,0 +1,40 @@
// Copyright (c) 2020 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.
#ifndef _Aspect_XRGenericAction_HeaderFile
#define _Aspect_XRGenericAction_HeaderFile
//! Generic XR action.
enum Aspect_XRGenericAction
{
Aspect_XRGenericAction_IsHeadsetOn, //!< headset is on/off head
Aspect_XRGenericAction_InputAppMenu, //!< application menu button pressed/released
Aspect_XRGenericAction_InputSysMenu, //!< system menu button pressed/released
Aspect_XRGenericAction_InputTriggerPull, //!< trigger squeezing [0..1], 1 to click
Aspect_XRGenericAction_InputTriggerClick, //!< trigger clicked/released
Aspect_XRGenericAction_InputGripClick, //!< grip state on/off
Aspect_XRGenericAction_InputTrackPadPosition, //!< trackpad 2D position [-1,+1] with X and Y axes
Aspect_XRGenericAction_InputTrackPadTouch, //!< trackpad touched/untouched
Aspect_XRGenericAction_InputTrackPadClick, //!< trackpad clicked/released
Aspect_XRGenericAction_InputThumbstickPosition, //!< thumbstick 2D position [-1,+1] with X and Y axes
Aspect_XRGenericAction_InputThumbstickTouch, //!< thumbstick touched/untouched
Aspect_XRGenericAction_InputThumbstickClick, //!< thumbstick clicked/released
Aspect_XRGenericAction_InputPoseBase, //!< base position of hand
Aspect_XRGenericAction_InputPoseFront, //!< front position of hand
Aspect_XRGenericAction_InputPoseHandGrip, //!< position of main handgrip
Aspect_XRGenericAction_InputPoseFingerTip, //!< position of main fingertip
Aspect_XRGenericAction_OutputHaptic //!< haptic output (vibration)
};
enum { Aspect_XRGenericAction_NB = Aspect_XRGenericAction_OutputHaptic + 1 };
#endif // _Aspect_XRGenericAction_HeaderFile

View File

@ -0,0 +1,38 @@
// Copyright (c) 2020 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.
#ifndef _Aspect_XRHapticActionData_HeaderFile
#define _Aspect_XRHapticActionData_HeaderFile
//! Haptic output XR action data.
struct Aspect_XRHapticActionData
{
float Delay; //!< delay in seconds before start
float Duration; //!< duration in seconds
float Frequency; //!< vibration frequency
float Amplitude; //!< vibration amplitude
//! Return TRUE if data is not empty.
bool IsValid() const
{
return Duration > 0.0f
&& Amplitude > 0.0f
&& Frequency > 0.0f
&& Delay >= 0.0f;
}
//! Empty constructor.
Aspect_XRHapticActionData() : Delay (0.0f), Duration (0.0f), Frequency (0.0f), Amplitude (0.0f) {}
};
#endif // _Aspect_XRHapticActionData_HeaderFile

View File

@ -0,0 +1,31 @@
// Copyright (c) 2020 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.
#ifndef _Aspect_XRPoseActionData_HeaderFile
#define _Aspect_XRPoseActionData_HeaderFile
#include <Aspect_TrackedDevicePose.hxx>
#include <Standard_TypeDef.hxx>
//! Pose input XR action data.
struct Aspect_XRPoseActionData
{
Aspect_TrackedDevicePose Pose; //!< pose state
uint64_t ActiveOrigin; //!< The origin that caused this action's current state
bool IsActive; //!< whether or not this action is currently available to be bound in the active action set
//! Empty constructor.
Aspect_XRPoseActionData() : ActiveOrigin (0), IsActive (false) {}
};
#endif // _Aspect_XRPoseActionData_HeaderFile

View File

@ -0,0 +1,60 @@
// Copyright (c) 2020 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 <Aspect_XRSession.hxx>
IMPLEMENT_STANDARD_RTTIEXT(Aspect_XRSession, Standard_Transient)
IMPLEMENT_STANDARD_RTTIEXT(Aspect_XRAction, Standard_Transient)
IMPLEMENT_STANDARD_RTTIEXT(Aspect_XRActionSet, Standard_Transient)
// =======================================================================
// function : Aspect_XRSession
// purpose :
// =======================================================================
Aspect_XRSession::Aspect_XRSession()
: myTrackOrigin (TrackingUniverseOrigin_Standing),
myTrackedPoses (0, 0),
myUnitFactor (1.0),
myAspect (1.0),
myFieldOfView (90.0),
myIod (0.0),
myDispFreq (0.0f)
{
for (Standard_Integer aRoleIter = 0; aRoleIter < Aspect_XRTrackedDeviceRole_NB; ++aRoleIter)
{
myRoleActions[aRoleIter].Resize (0, Aspect_XRGenericAction_NB - 1, false);
}
}
// =======================================================================
// function : AbortHapticVibrationAction
// purpose :
// =======================================================================
void Aspect_XRSession::AbortHapticVibrationAction (const Handle(Aspect_XRAction)& theAction)
{
triggerHapticVibrationAction (theAction, Aspect_XRHapticActionData());
}
// =======================================================================
// function : TriggerHapticVibrationAction
// purpose :
// =======================================================================
void Aspect_XRSession::TriggerHapticVibrationAction (const Handle(Aspect_XRAction)& theAction,
const Aspect_XRHapticActionData& theParams)
{
if (!theParams.IsValid())
{
throw Standard_ProgramError("Aspect_OpenVRSession::TriggerHapticVibrationAction() called for wrong action");
}
triggerHapticVibrationAction (theAction, theParams);
}

View File

@ -0,0 +1,262 @@
// Copyright (c) 2020 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.
#ifndef _Aspect_XRSession_HeaderFile
#define _Aspect_XRSession_HeaderFile
#include <Aspect_ColorSpace.hxx>
#include <Aspect_Eye.hxx>
#include <Aspect_FrustumLRBT.hxx>
#include <Aspect_GraphicsLibrary.hxx>
#include <Aspect_XRActionSet.hxx>
#include <Aspect_XRAnalogActionData.hxx>
#include <Aspect_XRDigitalActionData.hxx>
#include <Aspect_XRGenericAction.hxx>
#include <Aspect_XRHapticActionData.hxx>
#include <Aspect_XRPoseActionData.hxx>
#include <Aspect_XRTrackedDeviceRole.hxx>
#include <gp_Trsf.hxx>
#include <NCollection_Array1.hxx>
class Graphic3d_ArrayOfTriangles;
class Image_Texture;
//! Extended Reality (XR) Session interface.
class Aspect_XRSession : public Standard_Transient
{
DEFINE_STANDARD_RTTIEXT(Aspect_XRSession, Standard_Transient)
public:
//! Identifies which style of tracking origin the application wants to use for the poses it is requesting.
enum TrackingUniverseOrigin
{
TrackingUniverseOrigin_Seated, //! poses are provided relative to the seated zero pose
TrackingUniverseOrigin_Standing, //! poses are provided relative to the safe bounds configured by the user
};
public:
//! Return TRUE if session is opened.
virtual bool IsOpen() const = 0;
//! Initialize session.
virtual bool Open() = 0;
//! Release session.
virtual void Close() = 0;
//! Fetch actual poses of tracked devices.
virtual bool WaitPoses() = 0;
//! Return recommended viewport Width x Height for rendering into VR.
virtual NCollection_Vec2<int> RecommendedViewport() const = 0;
//! Return transformation from eye to head.
virtual NCollection_Mat4<double> EyeToHeadTransform (Aspect_Eye theEye) const = 0;
//! Return transformation from head to eye.
NCollection_Mat4<double> HeadToEyeTransform (Aspect_Eye theEye) const
{
NCollection_Mat4<double> aMat;
EyeToHeadTransform (theEye).Inverted (aMat);
return aMat;
}
//! Return projection matrix.
virtual NCollection_Mat4<double> ProjectionMatrix (Aspect_Eye theEye,
double theZNear,
double theZFar) const = 0;
//! Return FALSE if projection frustums are unsupported and general 4x4 projection matrix should be fetched instead
virtual bool HasProjectionFrustums() const = 0;
//! Receive XR events.
virtual void ProcessEvents() = 0;
//! Submit texture eye to XR Composer.
//! @param theTexture [in] texture handle
//! @param theGraphicsLib [in] graphics library in which texture handle is defined
//! @param theColorSpace [in] texture color space;
//! sRGB means no color conversion by composer;
//! Linear means to sRGB color conversion by composer
//! @param theEye [in] eye to display
//! @return FALSE on error
virtual bool SubmitEye (void* theTexture,
Aspect_GraphicsLibrary theGraphicsLib,
Aspect_ColorSpace theColorSpace,
Aspect_Eye theEye) = 0;
//! Return unit scale factor defined as scale factor for m (meters); 1.0 by default.
Standard_Real UnitFactor() const { return myUnitFactor; }
//! Set unit scale factor.
void SetUnitFactor (Standard_Real theFactor) { myUnitFactor = theFactor; }
//! Return aspect ratio.
Standard_Real Aspect() const { return myAspect; }
//! Return field of view.
Standard_Real FieldOfView() const { return myFieldOfView; }
//! Return Intra-ocular Distance (IOD); also known as Interpupillary Distance (IPD).
//! Defined in meters by default (@sa UnitFactor()).
Standard_Real IOD() const { return myIod; }
//! Return display frequency or 0 if unknown.
Standard_ShortReal DisplayFrequency() const { return myDispFreq; }
//! Return projection frustum.
//! @sa HasProjectionFrustums().
const Aspect_FrustumLRBT<double>& ProjectionFrustum (Aspect_Eye theEye) const
{
return theEye == Aspect_Eye_Right ? myFrustumR : myFrustumL;
}
//! Return head orientation in right-handed system:
//! +y is up
//! +x is to the right
//! -z is forward
//! Distance unit is meters by default (@sa UnitFactor()).
const gp_Trsf& HeadPose() const { return myHeadPose; }
//! Return left hand orientation.
gp_Trsf LeftHandPose() const
{
const Standard_Integer aDevice = NamedTrackedDevice (Aspect_XRTrackedDeviceRole_LeftHand);
return aDevice != -1 ? myTrackedPoses[aDevice].Orientation : gp_Trsf();
}
//! Return right hand orientation.
gp_Trsf RightHandPose() const
{
const Standard_Integer aDevice = NamedTrackedDevice (Aspect_XRTrackedDeviceRole_RightHand);
return aDevice != -1 ? myTrackedPoses[aDevice].Orientation : gp_Trsf();
}
//! Return number of tracked poses array.
const Aspect_TrackedDevicePoseArray& TrackedPoses() const { return myTrackedPoses; }
//! Return TRUE if device orientation is defined.
bool HasTrackedPose (Standard_Integer theDevice) const { return myTrackedPoses[theDevice].IsValidPose; }
//! Return index of tracked device of known role, or -1 if undefined.
virtual Standard_Integer NamedTrackedDevice (Aspect_XRTrackedDeviceRole theDevice) const = 0;
//! Load model for displaying device.
//! @param theDevice [in] device index
//! @param theTexture [out] texture source
//! @return model triangulation or NULL if not found
Handle(Graphic3d_ArrayOfTriangles) LoadRenderModel (Standard_Integer theDevice,
Handle(Image_Texture)& theTexture)
{
return loadRenderModel (theDevice, true, theTexture);
}
//! Load model for displaying device.
//! @param theDevice [in] device index
//! @param theToApplyUnitFactor [in] flag to apply unit scale factor
//! @param theTexture [out] texture source
//! @return model triangulation or NULL if not found
Handle(Graphic3d_ArrayOfTriangles) LoadRenderModel (Standard_Integer theDevice,
Standard_Boolean theToApplyUnitFactor,
Handle(Image_Texture)& theTexture)
{
return loadRenderModel (theDevice, theToApplyUnitFactor, theTexture);
}
//! Fetch data for digital input action (like button).
//! @param theAction [in] action of Aspect_XRActionType_InputDigital type
virtual Aspect_XRDigitalActionData GetDigitalActionData (const Handle(Aspect_XRAction)& theAction) const = 0;
//! Fetch data for digital input action (like axis).
//! @param theAction [in] action of Aspect_XRActionType_InputAnalog type
virtual Aspect_XRAnalogActionData GetAnalogActionData (const Handle(Aspect_XRAction)& theAction) const = 0;
//! Fetch data for pose input action (like fingertip position).
//! The returned values will match the values returned by the last call to WaitPoses().
//! @param theAction [in] action of Aspect_XRActionType_InputPose type
virtual Aspect_XRPoseActionData GetPoseActionDataForNextFrame (const Handle(Aspect_XRAction)& theAction) const = 0;
//! Trigger vibration.
Standard_EXPORT void TriggerHapticVibrationAction (const Handle(Aspect_XRAction)& theAction,
const Aspect_XRHapticActionData& theParams);
//! Abort vibration.
Standard_EXPORT void AbortHapticVibrationAction (const Handle(Aspect_XRAction)& theAction);
//! Return tracking origin.
TrackingUniverseOrigin TrackingOrigin() const { return myTrackOrigin; }
//! Set tracking origin.
virtual void SetTrackingOrigin (TrackingUniverseOrigin theOrigin) { myTrackOrigin = theOrigin; }
//! Return generic action for specific hand or NULL if undefined.
const Handle(Aspect_XRAction)& GenericAction (Aspect_XRTrackedDeviceRole theDevice,
Aspect_XRGenericAction theAction) const
{
const NCollection_Array1<Handle(Aspect_XRAction)>& anActions = myRoleActions[theDevice];
return anActions[theAction];
}
public:
//! Info string enumeration.
enum InfoString
{
InfoString_Vendor,
InfoString_Device,
InfoString_Tracker,
InfoString_SerialNumber,
};
//! Query information.
virtual TCollection_AsciiString GetString (InfoString theInfo) const = 0;
protected:
//! Empty constructor.
Standard_EXPORT Aspect_XRSession();
//! Load model for displaying device.
//! @param theDevice [in] device index
//! @param theToApplyUnitFactor [in] flag to apply unit scale factor
//! @param theTexture [out] texture source
//! @return model triangulation or NULL if not found
virtual Handle(Graphic3d_ArrayOfTriangles) loadRenderModel (Standard_Integer theDevice,
Standard_Boolean theToApplyUnitFactor,
Handle(Image_Texture)& theTexture) = 0;
//! Trigger vibration.
virtual void triggerHapticVibrationAction (const Handle(Aspect_XRAction)& theAction,
const Aspect_XRHapticActionData& theParams) = 0;
protected:
NCollection_Array1<Handle(Aspect_XRAction)>
myRoleActions[Aspect_XRTrackedDeviceRole_NB]; //!< generic actions
Aspect_XRActionSetMap myActionSets; //!< actions sets
TrackingUniverseOrigin myTrackOrigin; //!< tracking origin
Aspect_TrackedDevicePoseArray myTrackedPoses; //!< array of tracked poses
gp_Trsf myHeadPose; //!< head orientation
NCollection_Vec2<int> myRendSize; //!< viewport Width x Height for rendering into VR
Aspect_FrustumLRBT<double> myFrustumL; //!< left eye projection frustum
Aspect_FrustumLRBT<double> myFrustumR; //!< right eye projection frustum
Standard_Real myUnitFactor; //!< unit scale factor defined as scale factor for m (meters)
Standard_Real myAspect; //!< aspect ratio
Standard_Real myFieldOfView; //!< field of view
Standard_Real myIod; //!< intra-ocular distance in meters
Standard_ShortReal myDispFreq; //!< display frequency
};
#endif // _Aspect_XRSession_HeaderFile

View File

@ -0,0 +1,27 @@
// Copyright (c) 2020 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.
#ifndef _Aspect_XRTrackedDeviceRole_HeaderFile
#define _Aspect_XRTrackedDeviceRole_HeaderFile
//! Predefined tracked devices.
enum Aspect_XRTrackedDeviceRole
{
Aspect_XRTrackedDeviceRole_Head, //!< head
Aspect_XRTrackedDeviceRole_LeftHand, //!< left hand
Aspect_XRTrackedDeviceRole_RightHand, //!< right hand
Aspect_XRTrackedDeviceRole_Other, //!< other devices
};
enum { Aspect_XRTrackedDeviceRole_NB = Aspect_XRTrackedDeviceRole_Other + 1 };
#endif // _Aspect_XRTrackedDeviceRole_HeaderFile

View File

@ -5,26 +5,32 @@ Aspect_Background.cxx
Aspect_Background.hxx
Aspect_CircularGrid.cxx
Aspect_CircularGrid.hxx
Aspect_ColorSpace.hxx
Aspect_Convert.hxx
Aspect_Display.hxx
Aspect_DisplayConnection.cxx
Aspect_DisplayConnection.hxx
Aspect_DisplayConnectionDefinitionError.hxx
Aspect_Drawable.hxx
Aspect_Eye.hxx
Aspect_FBConfig.hxx
Aspect_FillMethod.hxx
Aspect_FrustumLRBT.hxx
Aspect_GenId.cxx
Aspect_GenId.hxx
Aspect_GradientBackground.cxx
Aspect_GradientBackground.hxx
Aspect_GradientFillMethod.hxx
Aspect_GraphicDeviceDefinitionError.hxx
Aspect_GraphicsLibrary.hxx
Aspect_Grid.cxx
Aspect_Grid.hxx
Aspect_GridDrawMode.hxx
Aspect_GridType.hxx
Aspect_NeutralWindow.cxx
Aspect_NeutralWindow.hxx
Aspect_OpenVRSession.cxx
Aspect_OpenVRSession.hxx
Aspect_Handle.hxx
Aspect_HatchStyle.hxx
Aspect_IdentDefinitionError.hxx
@ -37,6 +43,7 @@ Aspect_SequenceOfColor.hxx
Aspect_ScrollDelta.hxx
Aspect_Touch.hxx
Aspect_TouchMap.hxx
Aspect_TrackedDevicePose.hxx
Aspect_TypeOfColorScaleData.hxx
Aspect_TypeOfColorScaleOrientation.hxx
Aspect_TypeOfColorScalePosition.hxx
@ -60,4 +67,15 @@ Aspect_Window.hxx
Aspect_WindowDefinitionError.hxx
Aspect_WindowError.hxx
Aspect_XAtom.hxx
Aspect_XRAction.hxx
Aspect_XRActionSet.hxx
Aspect_XRActionType.hxx
Aspect_XRAnalogActionData.hxx
Aspect_XRDigitalActionData.hxx
Aspect_XRGenericAction.hxx
Aspect_XRHapticActionData.hxx
Aspect_XRPoseActionData.hxx
Aspect_XRSession.cxx
Aspect_XRSession.hxx
Aspect_XRTrackedDeviceRole.hxx
Aspect_XWD.hxx

View File

@ -362,6 +362,11 @@ static Standard_Integer dversion(Draw_Interpretor& di, Standard_Integer, const c
#else
di << "OpenGL: desktop\n";
#endif
#ifdef HAVE_OPENVR
di << "OpenVR enabled (HAVE_OPENVR)\n";
#else
di << "OpenVR disabled\n";
#endif
#ifdef HAVE_RAPIDJSON
di << "RapidJSON enabled (HAVE_RAPIDJSON)\n";
#else

View File

@ -13,6 +13,7 @@
#include <Graphic3d_CView.hxx>
#include <Aspect_OpenVRSession.hxx>
#include <Graphic3d_Layer.hxx>
#include <Graphic3d_MapIteratorOfMapOfStructure.hxx>
#include <Graphic3d_StructureManager.hxx>
@ -32,7 +33,8 @@ Graphic3d_CView::Graphic3d_CView (const Handle(Graphic3d_StructureManager)& theM
myIsActive (Standard_False),
myIsRemoved (Standard_False),
myShadingModel (Graphic3d_TOSM_FRAGMENT),
myVisualization (Graphic3d_TOV_WIREFRAME)
myVisualization (Graphic3d_TOV_WIREFRAME),
myUnitFactor (1.0)
{
myId = myStructureManager->Identification (this);
}
@ -43,6 +45,7 @@ Graphic3d_CView::Graphic3d_CView (const Handle(Graphic3d_StructureManager)& theM
//=======================================================================
Graphic3d_CView::~Graphic3d_CView()
{
myXRSession.Nullify();
if (!IsRemoved())
{
myStructureManager->UnIdentification (this);
@ -1083,3 +1086,311 @@ void Graphic3d_CView::SetShadingModel (Graphic3d_TypeOfShadingModel theModel)
myShadingModel = theModel;
}
// =======================================================================
// function : SetUnitFactor
// purpose :
// =======================================================================
void Graphic3d_CView::SetUnitFactor (Standard_Real theFactor)
{
if (theFactor <= 0.0)
{
throw Standard_ProgramError ("Graphic3d_CView::SetUnitFactor() - invalid unit factor");
}
myUnitFactor = theFactor;
if (!myXRSession.IsNull())
{
myXRSession->SetUnitFactor (theFactor);
}
}
// =======================================================================
// function : IsActiveXR
// purpose :
// =======================================================================
bool Graphic3d_CView::IsActiveXR() const
{
return !myXRSession.IsNull()
&& myXRSession->IsOpen();
}
// =======================================================================
// function : InitXR
// purpose :
// =======================================================================
bool Graphic3d_CView::InitXR()
{
if (myXRSession.IsNull())
{
myXRSession = new Aspect_OpenVRSession();
myXRSession->SetUnitFactor (myUnitFactor);
}
if (!myXRSession->IsOpen())
{
myXRSession->Open();
if (myBackXRCamera.IsNull())
{
// backup camera properties
myBackXRCamera = new Graphic3d_Camera (myCamera);
}
}
return myXRSession->IsOpen();
}
// =======================================================================
// function : ReleaseXR
// purpose :
// =======================================================================
void Graphic3d_CView::ReleaseXR()
{
if (!myXRSession.IsNull())
{
if (myXRSession->IsOpen()
&& !myBackXRCamera.IsNull())
{
// restore projection properties overridden by HMD
myCamera->SetFOV2d (myBackXRCamera->FOV2d());
myCamera->SetFOVy (myBackXRCamera->FOVy());
myCamera->SetAspect(myBackXRCamera->Aspect());
myCamera->SetIOD (myBackXRCamera->GetIODType(), myBackXRCamera->IOD());
myCamera->SetZFocus(myBackXRCamera->ZFocusType(), myBackXRCamera->ZFocus());
myCamera->ResetCustomProjection();
myBackXRCamera.Nullify();
}
myXRSession->Close();
}
}
//=======================================================================
//function : ProcessXRInput
//purpose :
//=======================================================================
void Graphic3d_CView::ProcessXRInput()
{
if (myRenderParams.StereoMode == Graphic3d_StereoMode_OpenVR
&& myCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
{
InitXR();
}
else
{
ReleaseXR();
}
if (!IsActiveXR())
{
myBaseXRCamera.Nullify();
myPosedXRCamera.Nullify();
return;
}
myXRSession->ProcessEvents();
Invalidate();
myCamera->SetFOV2d (myRenderParams.HmdFov2d);
myCamera->SetAspect(myXRSession->Aspect());
myCamera->SetFOVy (myXRSession->FieldOfView());
myCamera->SetIOD (Graphic3d_Camera::IODType_Absolute, myXRSession->IOD());
myCamera->SetZFocus(Graphic3d_Camera::FocusType_Absolute, 1.0 * myUnitFactor);
// VR APIs tend to decompose camera orientation-projection matrices into the following components:
// @begincode
// Model * [View * Eye^-1] * [Projection]
// @endcode
// so that Eye position is encoded into Orientation matrix, and there should be 2 Orientation matrices and 2 Projection matrices to make the stereo.
// Graphic3d_Camera historically follows different decomposition, with Eye position encoded into Projection matrix,
// so that there is only 1 Orientation matrix (matching mono view) and 2 Projection matrices.
if (myXRSession->HasProjectionFrustums())
{
// note that this definition does not include a small forward/backward offset from head to eye
myCamera->SetCustomStereoFrustums (myXRSession->ProjectionFrustum (Aspect_Eye_Left),
myXRSession->ProjectionFrustum (Aspect_Eye_Right));
}
else
{
const Graphic3d_Mat4d aPoseL = myXRSession->HeadToEyeTransform (Aspect_Eye_Left);
const Graphic3d_Mat4d aPoseR = myXRSession->HeadToEyeTransform (Aspect_Eye_Right);
const Graphic3d_Mat4d aProjL = myXRSession->ProjectionMatrix (Aspect_Eye_Left, myCamera->ZNear(), myCamera->ZFar());
const Graphic3d_Mat4d aProjR = myXRSession->ProjectionMatrix (Aspect_Eye_Right, myCamera->ZNear(), myCamera->ZFar());
myCamera->SetCustomStereoProjection (aProjL * aPoseL, aProjR * aPoseR);
}
myBaseXRCamera = myCamera;
if (myPosedXRCamera.IsNull())
{
myPosedXRCamera = new Graphic3d_Camera();
}
SynchronizeXRBaseToPosedCamera();
}
//=======================================================================
//function : SynchronizeXRBaseToPosedCamera
//purpose :
//=======================================================================
void Graphic3d_CView::SynchronizeXRBaseToPosedCamera()
{
if (!myPosedXRCamera.IsNull())
{
ComputeXRPosedCameraFromBase (*myPosedXRCamera, myXRSession->HeadPose());
}
}
//=======================================================================
//function : ComputeXRPosedCameraFromBase
//purpose :
//=======================================================================
void Graphic3d_CView::ComputeXRPosedCameraFromBase (Graphic3d_Camera& theCam,
const gp_Trsf& theXRTrsf) const
{
theCam.Copy (myBaseXRCamera);
// convert head pose into camera transformation
const gp_Ax3 anAxVr (gp::Origin(), gp::DZ(), gp::DX());
const gp_Ax3 aCameraCS (gp::Origin(), -myBaseXRCamera->Direction(), -myBaseXRCamera->SideRight());
gp_Trsf aTrsfCS;
aTrsfCS.SetTransformation (aCameraCS, anAxVr);
const gp_Trsf aTrsfToCamera = aTrsfCS * theXRTrsf * aTrsfCS.Inverted();
gp_Trsf aTrsfToEye;
aTrsfToEye.SetTranslation (myBaseXRCamera->Eye().XYZ());
const gp_Trsf aTrsf = aTrsfToEye * aTrsfToCamera;
const gp_Dir anUpNew = myBaseXRCamera->Up().Transformed (aTrsf);
const gp_Dir aDirNew = myBaseXRCamera->Direction().Transformed (aTrsf);
const gp_Pnt anEyeNew = gp::Origin().Translated (aTrsf.TranslationPart());
theCam.SetUp (anUpNew);
theCam.SetDirectionFromEye (aDirNew);
theCam.MoveEyeTo (anEyeNew);
}
//=======================================================================
//function : SynchronizeXRPosedToBaseCamera
//purpose :
//=======================================================================
void Graphic3d_CView::SynchronizeXRPosedToBaseCamera()
{
if (myPosedXRCameraCopy.IsNull()
|| myPosedXRCamera.IsNull()
|| myBaseXRCamera.IsNull()
|| myCamera != myPosedXRCamera)
{
return;
}
if (myPosedXRCameraCopy->Eye().IsEqual (myPosedXRCamera->Eye(), gp::Resolution())
&& (myPosedXRCameraCopy->Distance() - myPosedXRCamera->Distance()) <= gp::Resolution()
&& myPosedXRCameraCopy->Direction().IsEqual (myPosedXRCamera->Direction(), gp::Resolution())
&& myPosedXRCameraCopy->Up().IsEqual (myPosedXRCamera->Up(), gp::Resolution()))
{
// avoid floating point math in case of no changes
return;
}
// re-compute myBaseXRCamera from myPosedXRCamera by applying reversed head pose transformation
ComputeXRBaseCameraFromPosed (myPosedXRCamera, myXRSession->HeadPose());
myPosedXRCameraCopy->Copy (myPosedXRCamera);
}
//=======================================================================
//function : ComputeXRBaseCameraFromPosed
//purpose :
//=======================================================================
void Graphic3d_CView::ComputeXRBaseCameraFromPosed (const Graphic3d_Camera& theCamPosed,
const gp_Trsf& thePoseTrsf)
{
const gp_Ax3 anAxVr (gp::Origin(), gp::DZ(), gp::DX());
const gp_Ax3 aCameraCS (gp::Origin(), -myBaseXRCamera->Direction(), -myBaseXRCamera->SideRight());
gp_Trsf aTrsfCS;
aTrsfCS.SetTransformation (aCameraCS, anAxVr);
const gp_Trsf aTrsfToCamera = aTrsfCS * thePoseTrsf * aTrsfCS.Inverted();
const gp_Trsf aTrsfCamToHead = aTrsfToCamera.Inverted();
const gp_Dir anUpNew = theCamPosed.Up().Transformed (aTrsfCamToHead);
const gp_Dir aDirNew = theCamPosed.Direction().Transformed (aTrsfCamToHead);
const gp_Pnt anEyeNew = theCamPosed.Eye().Translated (aTrsfToCamera.TranslationPart().Reversed());
myBaseXRCamera->SetUp (anUpNew);
myBaseXRCamera->SetDirectionFromEye (aDirNew);
myBaseXRCamera->MoveEyeTo (anEyeNew);
}
//=======================================================================
//function : TurnViewXRCamera
//purpose :
//=======================================================================
void Graphic3d_CView::TurnViewXRCamera (const gp_Trsf& theTrsfTurn)
{
// use current eye position as an anchor
const Handle(Graphic3d_Camera)& aCamBase = myBaseXRCamera;
gp_Trsf aHeadTrsfLocal;
aHeadTrsfLocal.SetTranslationPart (myXRSession->HeadPose().TranslationPart());
const gp_Pnt anEyeAnchor = PoseXRToWorld (aHeadTrsfLocal).TranslationPart();
// turn the view
aCamBase->SetDirectionFromEye (aCamBase->Direction().Transformed (theTrsfTurn));
// recompute new eye
const gp_Ax3 anAxVr (gp::Origin(), gp::DZ(), gp::DX());
const gp_Ax3 aCameraCS (gp::Origin(), -aCamBase->Direction(), -aCamBase->SideRight());
gp_Trsf aTrsfCS;
aTrsfCS.SetTransformation (aCameraCS, anAxVr);
const gp_Trsf aTrsfToCamera = aTrsfCS * aHeadTrsfLocal * aTrsfCS.Inverted();
const gp_Pnt anEyeNew = anEyeAnchor.Translated (aTrsfToCamera.TranslationPart().Reversed());
aCamBase->MoveEyeTo (anEyeNew);
SynchronizeXRBaseToPosedCamera();
}
//=======================================================================
//function : SetupXRPosedCamera
//purpose :
//=======================================================================
void Graphic3d_CView::SetupXRPosedCamera()
{
if (!myPosedXRCamera.IsNull())
{
myCamera = myPosedXRCamera;
if (myPosedXRCameraCopy.IsNull())
{
myPosedXRCameraCopy = new Graphic3d_Camera();
}
myPosedXRCameraCopy->Copy (myPosedXRCamera);
}
}
//=======================================================================
//function : UnsetXRPosedCamera
//purpose :
//=======================================================================
void Graphic3d_CView::UnsetXRPosedCamera()
{
if (myCamera == myPosedXRCamera
&& !myBaseXRCamera.IsNull())
{
SynchronizeXRPosedToBaseCamera();
myCamera = myBaseXRCamera;
}
}
//=======================================================================
//function : DiagnosticInformation
//purpose :
//=======================================================================
void Graphic3d_CView::DiagnosticInformation (TColStd_IndexedDataMapOfStringString& theDict,
Graphic3d_DiagnosticInfo theFlags) const
{
if ((theFlags & Graphic3d_DiagnosticInfo_Device) != 0
&& !myXRSession.IsNull())
{
TCollection_AsciiString aVendor = myXRSession->GetString (Aspect_XRSession::InfoString_Vendor);
TCollection_AsciiString aDevice = myXRSession->GetString (Aspect_XRSession::InfoString_Device);
TCollection_AsciiString aTracker = myXRSession->GetString (Aspect_XRSession::InfoString_Tracker);
TCollection_AsciiString aSerial = myXRSession->GetString (Aspect_XRSession::InfoString_SerialNumber);
TCollection_AsciiString aDisplay = TCollection_AsciiString()
+ myXRSession->RecommendedViewport().x() + "x" + myXRSession->RecommendedViewport().y()
+ "@" + (int )Round (myXRSession->DisplayFrequency())
+ " [FOVy: " + (int )Round (myXRSession->FieldOfView()) + "]";
theDict.ChangeFromIndex (theDict.Add ("VRvendor", aVendor)) = aVendor;
theDict.ChangeFromIndex (theDict.Add ("VRdevice", aDevice)) = aDevice;
theDict.ChangeFromIndex (theDict.Add ("VRtracker", aTracker)) = aTracker;
theDict.ChangeFromIndex (theDict.Add ("VRdisplay", aDisplay)) = aDisplay;
theDict.ChangeFromIndex (theDict.Add ("VRserial", aSerial)) = aSerial;
}
}

View File

@ -45,6 +45,7 @@
#include <Standard_Transient.hxx>
#include <TColStd_IndexedDataMapOfStringString.hxx>
class Aspect_XRSession;
class Graphic3d_CView;
class Graphic3d_GraphicDriver;
class Graphic3d_Layer;
@ -427,8 +428,8 @@ public:
//! The format of returned information (e.g. key-value layout)
//! is NOT part of this API and can be changed at any time.
//! Thus application should not parse returned information to weed out specific parameters.
virtual void DiagnosticInformation (TColStd_IndexedDataMapOfStringString& theDict,
Graphic3d_DiagnosticInfo theFlags) const = 0;
Standard_EXPORT virtual void DiagnosticInformation (TColStd_IndexedDataMapOfStringString& theDict,
Graphic3d_DiagnosticInfo theFlags) const = 0;
//! Returns string with statistic performance info.
virtual TCollection_AsciiString StatisticInformation() const = 0;
@ -436,6 +437,84 @@ public:
//! Fills in the dictionary with statistic performance info.
virtual void StatisticInformation (TColStd_IndexedDataMapOfStringString& theDict) const = 0;
public:
//! Return unit scale factor defined as scale factor for m (meters); 1.0 by default.
//! Normally, view definition is unitless, however some operations like VR input requires proper units mapping.
Standard_Real UnitFactor() const { return myUnitFactor; }
//! Set unit scale factor.
Standard_EXPORT void SetUnitFactor (Standard_Real theFactor);
//! Return XR session.
const Handle(Aspect_XRSession)& XRSession() const { return myXRSession; }
//! Set XR session.
void SetXRSession (const Handle(Aspect_XRSession)& theSession) { myXRSession = theSession; }
//! Return TRUE if there is active XR session.
Standard_EXPORT bool IsActiveXR() const;
//! Initialize XR session.
Standard_EXPORT virtual bool InitXR();
//! Release XR session.
Standard_EXPORT virtual void ReleaseXR();
//! Process input.
Standard_EXPORT virtual void ProcessXRInput();
//! Compute PosedXRCamera() based on current XR head pose and make it active.
Standard_EXPORT void SetupXRPosedCamera();
//! Set current camera back to BaseXRCamera() and copy temporary modifications of PosedXRCamera().
//! Calls SynchronizeXRPosedToBaseCamera() beforehand.
Standard_EXPORT void UnsetXRPosedCamera();
//! Returns transient XR camera position with tracked head orientation applied.
const Handle(Graphic3d_Camera)& PosedXRCamera() const { return myPosedXRCamera; }
//! Sets transient XR camera position with tracked head orientation applied.
void SetPosedXRCamera (const Handle(Graphic3d_Camera)& theCamera) { myPosedXRCamera = theCamera; }
//! Returns anchor camera definition (without tracked head orientation).
const Handle(Graphic3d_Camera)& BaseXRCamera() const { return myBaseXRCamera; }
//! Sets anchor camera definition.
void SetBaseXRCamera (const Handle(Graphic3d_Camera)& theCamera) { myBaseXRCamera = theCamera; }
//! Convert XR pose to world space.
//! @param theTrsfXR [in] transformation defined in VR local coordinate system,
//! oriented as Y-up, X-right and -Z-forward
//! @return transformation defining orientation of XR pose in world space
gp_Trsf PoseXRToWorld (const gp_Trsf& thePoseXR) const
{
const Handle(Graphic3d_Camera)& anOrigin = myBaseXRCamera;
const gp_Ax3 anAxVr (gp::Origin(), gp::DZ(), gp::DX());
const gp_Ax3 aCameraCS (anOrigin->Eye().XYZ(), -anOrigin->Direction(), -anOrigin->SideRight());
gp_Trsf aTrsfCS;
aTrsfCS.SetTransformation (aCameraCS, anAxVr);
return aTrsfCS * thePoseXR;
}
//! Recomputes PosedXRCamera() based on BaseXRCamera() and head orientation.
Standard_EXPORT void SynchronizeXRBaseToPosedCamera();
//! Checks if PosedXRCamera() has been modified since SetupXRPosedCamera()
//! and copies these modifications to BaseXRCamera().
Standard_EXPORT void SynchronizeXRPosedToBaseCamera();
//! Compute camera position based on XR pose.
Standard_EXPORT void ComputeXRPosedCameraFromBase (Graphic3d_Camera& theCam,
const gp_Trsf& theXRTrsf) const;
//! Update based camera from posed camera by applying reversed transformation.
Standard_EXPORT void ComputeXRBaseCameraFromPosed (const Graphic3d_Camera& theCamPosed,
const gp_Trsf& thePoseTrsf);
//! Turn XR camera direction using current (head) eye position as anchor.
Standard_EXPORT void TurnViewXRCamera (const gp_Trsf& theTrsfTurn);
public: //! @name obsolete Graduated Trihedron functionality
//! Returns data of a graduated trihedron
@ -490,6 +569,13 @@ protected:
Graphic3d_TypeOfShadingModel myShadingModel;
Graphic3d_TypeOfVisualization myVisualization;
Handle(Aspect_XRSession) myXRSession;
Handle(Graphic3d_Camera) myBackXRCamera; //!< camera projection parameters to restore after closing XR session (FOV, aspect and similar)
Handle(Graphic3d_Camera) myBaseXRCamera; //!< neutral camera orientation defining coordinate system in which head tracking is defined
Handle(Graphic3d_Camera) myPosedXRCamera; //!< transient XR camera orientation with tracked head orientation applied (based on myBaseXRCamera)
Handle(Graphic3d_Camera) myPosedXRCameraCopy; //!< neutral camera orientation copy at the beginning of processing input
Standard_Real myUnitFactor; //!< unit scale factor defined as scale factor for m (meters)
protected:
Graphic3d_GraduatedTrihedron myGTrihedronData;

View File

@ -81,6 +81,8 @@ Graphic3d_Camera::Graphic3d_Camera()
myAxialScale (1.0, 1.0, 1.0),
myProjType (Projection_Orthographic),
myFOVy (45.0),
myFOVx (45.0),
myFOV2d (180.0),
myFOVyTan (Tan (DTR_HALF * 45.0)),
myZNear (DEFAULT_ZNEAR),
myZFar (DEFAULT_ZFAR),
@ -89,7 +91,10 @@ Graphic3d_Camera::Graphic3d_Camera()
myZFocus (1.0),
myZFocusType (FocusType_Relative),
myIOD (0.05),
myIODType (IODType_Relative)
myIODType (IODType_Relative),
myIsCustomProjMatM (false),
myIsCustomProjMatLR(false),
myIsCustomFrustomLR(false)
{
myWorldViewProjState.Initialize ((Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER),
(Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER),
@ -108,6 +113,8 @@ Graphic3d_Camera::Graphic3d_Camera (const Handle(Graphic3d_Camera)& theOther)
myAxialScale (1.0, 1.0, 1.0),
myProjType (Projection_Orthographic),
myFOVy (45.0),
myFOVx (45.0),
myFOV2d (180.0),
myFOVyTan (Tan (DTR_HALF * 45.0)),
myZNear (DEFAULT_ZNEAR),
myZFar (DEFAULT_ZFAR),
@ -116,7 +123,10 @@ Graphic3d_Camera::Graphic3d_Camera (const Handle(Graphic3d_Camera)& theOther)
myZFocus (1.0),
myZFocusType (FocusType_Relative),
myIOD (0.05),
myIODType (IODType_Relative)
myIODType (IODType_Relative),
myIsCustomProjMatM (false),
myIsCustomProjMatLR(false),
myIsCustomFrustomLR(false)
{
myWorldViewProjState.Initialize (this);
@ -130,6 +140,7 @@ Graphic3d_Camera::Graphic3d_Camera (const Handle(Graphic3d_Camera)& theOther)
void Graphic3d_Camera::CopyMappingData (const Handle(Graphic3d_Camera)& theOtherCamera)
{
SetFOVy (theOtherCamera->FOVy());
SetFOV2d (theOtherCamera->FOV2d());
SetZRange (theOtherCamera->ZNear(), theOtherCamera->ZFar());
SetAspect (theOtherCamera->Aspect());
SetScale (theOtherCamera->Scale());
@ -137,6 +148,20 @@ void Graphic3d_Camera::CopyMappingData (const Handle(Graphic3d_Camera)& theOther
SetIOD (theOtherCamera->GetIODType(), theOtherCamera->IOD());
SetProjectionType (theOtherCamera->ProjectionType());
SetTile (theOtherCamera->myTile);
ResetCustomProjection();
if (theOtherCamera->IsCustomStereoProjection())
{
SetCustomStereoProjection (theOtherCamera->myCustomProjMatL, theOtherCamera->myCustomProjMatR);
}
else if (theOtherCamera->IsCustomStereoFrustum())
{
SetCustomStereoFrustums (theOtherCamera->myCustomFrustumL, theOtherCamera->myCustomFrustumR);
}
if (theOtherCamera->IsCustomMonoProjection())
{
SetCustomMonoProjection (theOtherCamera->myCustomProjMatM);
}
}
// =======================================================================
@ -419,11 +444,27 @@ void Graphic3d_Camera::SetFOVy (const Standard_Real theFOVy)
}
myFOVy = theFOVy;
myFOVx = theFOVy * myAspect;
myFOVyTan = Tan(DTR_HALF * myFOVy);
InvalidateProjection();
}
// =======================================================================
// function : SetFOV2d
// purpose :
// =======================================================================
void Graphic3d_Camera::SetFOV2d (const Standard_Real theFOV)
{
if (FOV2d() == theFOV)
{
return;
}
myFOV2d = theFOV;
InvalidateProjection();
}
// =======================================================================
// function : SetZRange
// purpose :
@ -462,6 +503,7 @@ void Graphic3d_Camera::SetAspect (const Standard_Real theAspect)
}
myAspect = theAspect;
myFOVx = myFOVy * theAspect;
InvalidateProjection();
}
@ -871,6 +913,62 @@ const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoRightF() const
return UpdateProjection (myMatricesF).RProjection;
}
// =======================================================================
// function : ResetCustomProjection
// purpose :
// =======================================================================
void Graphic3d_Camera::ResetCustomProjection()
{
if (myIsCustomFrustomLR
|| myIsCustomProjMatLR
|| myIsCustomProjMatM)
{
myIsCustomFrustomLR = false;
myIsCustomProjMatLR = false;
myIsCustomProjMatM = false;
InvalidateProjection();
}
}
// =======================================================================
// function : SetCustomStereoFrustums
// purpose :
// =======================================================================
void Graphic3d_Camera::SetCustomStereoFrustums (const Aspect_FrustumLRBT<Standard_Real>& theFrustumL,
const Aspect_FrustumLRBT<Standard_Real>& theFrustumR)
{
myCustomFrustumL = theFrustumL;
myCustomFrustumR = theFrustumR;
myIsCustomFrustomLR = true;
myIsCustomProjMatLR = false;
InvalidateProjection();
}
// =======================================================================
// function : SetCustomStereoProjection
// purpose :
// =======================================================================
void Graphic3d_Camera::SetCustomStereoProjection (const Graphic3d_Mat4d& theProjL,
const Graphic3d_Mat4d& theProjR)
{
myCustomProjMatL = theProjL;
myCustomProjMatR = theProjR;
myIsCustomProjMatLR = true;
myIsCustomFrustomLR = false;
InvalidateProjection();
}
// =======================================================================
// function : SetCustomMonoProjection
// purpose :
// =======================================================================
void Graphic3d_Camera::SetCustomMonoProjection (const Graphic3d_Mat4d& theProj)
{
myCustomProjMatM = theProj;
myIsCustomProjMatM = true;
InvalidateProjection();
}
// =======================================================================
// function : UpdateProjection
// purpose :
@ -894,13 +992,11 @@ Graphic3d_Camera::TransformMatrices<Elem_t>&
Elem_t aDXHalf = 0.0, aDYHalf = 0.0;
if (IsOrthographic())
{
aDXHalf = aScale * Elem_t (0.5);
aDYHalf = aScale * Elem_t (0.5);
aDXHalf = aDYHalf = aScale * Elem_t (0.5);
}
else
{
aDXHalf = aZNear * Elem_t (myFOVyTan);
aDYHalf = aZNear * Elem_t (myFOVyTan);
aDXHalf = aDYHalf = aZNear * Elem_t (myFOVyTan);
}
if (anAspect > 1.0)
@ -913,10 +1009,11 @@ Graphic3d_Camera::TransformMatrices<Elem_t>&
}
// sets right of frustum based on aspect ratio
Elem_t aLeft = -aDXHalf;
Elem_t aRight = aDXHalf;
Elem_t aBot = -aDYHalf;
Elem_t aTop = aDYHalf;
Aspect_FrustumLRBT<Elem_t> anLRBT;
anLRBT.Left = -aDXHalf;
anLRBT.Right = aDXHalf;
anLRBT.Bottom = -aDYHalf;
anLRBT.Top = aDYHalf;
Elem_t aIOD = myIODType == IODType_Relative
? static_cast<Elem_t> (myIOD * Distance())
@ -931,56 +1028,83 @@ Graphic3d_Camera::TransformMatrices<Elem_t>&
const Elem_t aDXFull = Elem_t(2) * aDXHalf;
const Elem_t aDYFull = Elem_t(2) * aDYHalf;
const Graphic3d_Vec2i anOffset = myTile.OffsetLowerLeft();
aLeft = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x()) / static_cast<Elem_t> (myTile.TotalSize.x());
aRight = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x() + myTile.TileSize.x()) / static_cast<Elem_t> (myTile.TotalSize.x());
aBot = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y()) / static_cast<Elem_t> (myTile.TotalSize.y());
aTop = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y() + myTile.TileSize.y()) / static_cast<Elem_t> (myTile.TotalSize.y());
anLRBT.Left = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x()) / static_cast<Elem_t> (myTile.TotalSize.x());
anLRBT.Right = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x() + myTile.TileSize.x()) / static_cast<Elem_t> (myTile.TotalSize.x());
anLRBT.Bottom = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y()) / static_cast<Elem_t> (myTile.TotalSize.y());
anLRBT.Top = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y() + myTile.TileSize.y()) / static_cast<Elem_t> (myTile.TotalSize.y());
}
if (myIsCustomProjMatM)
{
theMatrices.MProjection.ConvertFrom (myCustomProjMatM);
}
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 :
case Projection_Orthographic:
{
StereoEyeProj (aLeft, aRight, aBot, aTop,
aZNear, aZFar, aIOD, aFocus,
Standard_True, theMatrices.MProjection);
theMatrices.LProjection = theMatrices.MProjection;
if (!myIsCustomProjMatM)
{
orthoProj (theMatrices.MProjection, anLRBT, aZNear, aZFar);
}
break;
}
case Projection_MonoRightEye :
case Projection_Perspective:
{
StereoEyeProj (aLeft, aRight, aBot, aTop,
aZNear, aZFar, aIOD, aFocus,
Standard_False, theMatrices.MProjection);
theMatrices.RProjection = theMatrices.MProjection;
if (!myIsCustomProjMatM)
{
perspectiveProj (theMatrices.MProjection, anLRBT, aZNear, aZFar);
}
break;
}
case Projection_Stereo :
case Projection_MonoLeftEye:
case Projection_MonoRightEye:
case Projection_Stereo:
{
PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, theMatrices.MProjection);
if (!myIsCustomProjMatM)
{
perspectiveProj (theMatrices.MProjection, anLRBT, aZNear, aZFar);
}
if (myIsCustomProjMatLR)
{
theMatrices.LProjection.ConvertFrom (myCustomProjMatL);
theMatrices.RProjection.ConvertFrom (myCustomProjMatR);
}
else if (myIsCustomFrustomLR)
{
anLRBT = Aspect_FrustumLRBT<Elem_t> (myCustomFrustumL).Multiplied (aZNear);
perspectiveProj (theMatrices.LProjection, anLRBT, aZNear, aZFar);
if (aIOD != Elem_t (0.0))
{
theMatrices.LProjection.Translate (NCollection_Vec3<Elem_t> (Elem_t (0.5) * aIOD, Elem_t (0.0), Elem_t (0.0)));
}
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);
anLRBT = Aspect_FrustumLRBT<Elem_t> (myCustomFrustumR).Multiplied (aZNear);
perspectiveProj (theMatrices.RProjection, anLRBT, aZNear, aZFar);
if (aIOD != Elem_t (0.0))
{
theMatrices.RProjection.Translate (NCollection_Vec3<Elem_t> (Elem_t (-0.5) * aIOD, Elem_t (0.0), Elem_t (0.0)));
}
}
else
{
stereoEyeProj (theMatrices.LProjection,
anLRBT, aZNear, aZFar, aIOD, aFocus,
Aspect_Eye_Left);
stereoEyeProj (theMatrices.RProjection,
anLRBT, aZNear, aZFar, aIOD, aFocus,
Aspect_Eye_Right);
}
break;
}
}
if (myProjType == Projection_MonoLeftEye)
{
theMatrices.MProjection = theMatrices.LProjection;
}
else if (myProjType == Projection_MonoRightEye)
{
theMatrices.MProjection = theMatrices.RProjection;
}
return theMatrices; // for inline accessors
}
@ -1044,29 +1168,26 @@ void Graphic3d_Camera::InvalidateOrientation()
}
// =======================================================================
// function : OrthoProj
// 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,
void Graphic3d_Camera::orthoProj (NCollection_Mat4<Elem_t>& theOutMx,
const Aspect_FrustumLRBT<Elem_t>& theLRBT,
const Elem_t theNear,
const Elem_t theFar,
NCollection_Mat4<Elem_t>& theOutMx)
const Elem_t theFar)
{
// row 0
theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theRight - theLeft);
theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theLRBT.Right - theLRBT.Left);
theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
theOutMx.ChangeValue (0, 2) = Elem_t (0.0);
theOutMx.ChangeValue (0, 3) = - (theRight + theLeft) / (theRight - theLeft);
theOutMx.ChangeValue (0, 3) = - (theLRBT.Right + theLRBT.Left) / (theLRBT.Right - theLRBT.Left);
// row 1
theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theTop - theBottom);
theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theLRBT.Top - theLRBT.Bottom);
theOutMx.ChangeValue (1, 2) = Elem_t (0.0);
theOutMx.ChangeValue (1, 3) = - (theTop + theBottom) / (theTop - theBottom);
theOutMx.ChangeValue (1, 3) = - (theLRBT.Top + theLRBT.Bottom) / (theLRBT.Top - theLRBT.Bottom);
// row 2
theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
@ -1086,29 +1207,26 @@ void Graphic3d_Camera::OrthoProj (const Elem_t theLeft,
// 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,
void Graphic3d_Camera::perspectiveProj (NCollection_Mat4<Elem_t>& theOutMx,
const Aspect_FrustumLRBT<Elem_t>& theLRBT,
const Elem_t theNear,
const Elem_t theFar,
NCollection_Mat4<Elem_t>& theOutMx)
const Elem_t theFar)
{
// column 0
theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theRight - theLeft);
theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theLRBT.Right - theLRBT.Left);
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 (1, 1) = (Elem_t (2.0) * theNear) / (theLRBT.Top - theLRBT.Bottom);
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 (0, 2) = (theLRBT.Right + theLRBT.Left) / (theLRBT.Right - theLRBT.Left);
theOutMx.ChangeValue (1, 2) = (theLRBT.Top + theLRBT.Bottom) / (theLRBT.Top - theLRBT.Bottom);
theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear);
theOutMx.ChangeValue (3, 2) = Elem_t (-1.0);
@ -1124,25 +1242,22 @@ void Graphic3d_Camera::PerspectiveProj (const Elem_t theLeft,
// 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,
void Graphic3d_Camera::stereoEyeProj (NCollection_Mat4<Elem_t>& theOutMx,
const Aspect_FrustumLRBT<Elem_t>& theLRBT,
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)
const Aspect_Eye theEyeIndex)
{
Elem_t aDx = theIsLeft ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD;
Elem_t aDx = theEyeIndex == Aspect_Eye_Left ? 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);
Aspect_FrustumLRBT<Elem_t> aLRBT = theLRBT;
aLRBT.Left = theLRBT.Left + aDXStereoShift;
aLRBT.Right = theLRBT.Right + aDXStereoShift;
perspectiveProj (theOutMx, aLRBT, theNear, theFar);
if (theIOD != Elem_t (0.0))
{

View File

@ -16,6 +16,8 @@
#ifndef _Graphic3d_Camera_HeaderFile
#define _Graphic3d_Camera_HeaderFile
#include <Aspect_Eye.hxx>
#include <Aspect_FrustumLRBT.hxx>
#include <Graphic3d_CameraTile.hxx>
#include <Graphic3d_Mat4d.hxx>
#include <Graphic3d_Mat4.hxx>
@ -185,6 +187,12 @@ public:
//! Return a copy of orthogonalized up direction vector.
Standard_EXPORT gp_Dir OrthogonalizedUp() const;
//! Right side direction.
gp_Dir SideRight() const
{
return -(gp_Vec (Direction()) ^ gp_Vec (OrthogonalizedUp()));
}
//! Get camera Eye position.
//! @return camera eye location.
const gp_Pnt& Eye() const { return myEye; }
@ -284,15 +292,26 @@ public:
}
//! Set Field Of View (FOV) in y axis for perspective projection.
//! Field of View in x axis is automatically scaled from view aspect ratio.
//! @param theFOVy [in] the FOV in degrees.
Standard_EXPORT void SetFOVy (const Standard_Real theFOVy);
//! Get Field Of View (FOV) in y axis.
//! @return the FOV value in degrees.
Standard_Real FOVy() const
{
return myFOVy;
}
Standard_Real FOVy() const { return myFOVy; }
//! Get Field Of View (FOV) in x axis.
//! @return the FOV value in degrees.
Standard_Real FOVx() const { return myFOVx; }
//! Get Field Of View (FOV) restriction for 2D on-screen elements; 180 degrees by default.
//! When 2D FOV is smaller than FOVy or FOVx, 2D elements defined within offset from view corner
//! will be extended to fit into specified 2D FOV.
//! This can be useful to make 2D elements sharply visible, like in case of HMD normally having extra large FOVy.
Standard_Real FOV2d() const { return myFOV2d; }
//! Set Field Of View (FOV) restriction for 2D on-screen elements.
Standard_EXPORT void SetFOV2d (Standard_Real theFOV);
//! Estimate Z-min and Z-max planes of projection volume to match the
//! displayed objects. The methods ensures that view volume will
@ -427,6 +446,24 @@ public:
//! @return values in form of gp_Pnt (Width, Height, Depth).
Standard_EXPORT gp_XYZ ViewDimensions (const Standard_Real theZValue) const;
//! Return offset to the view corner in NDC space within dimension X for 2d on-screen elements, which is normally 0.5.
//! Can be clamped when FOVx exceeds FOV2d.
Standard_Real NDC2dOffsetX() const
{
return myFOV2d >= myFOVx
? 0.5
: 0.5 * myFOV2d / myFOVx;
}
//! Return offset to the view corner in NDC space within dimension X for 2d on-screen elements, which is normally 0.5.
//! Can be clamped when FOVy exceeds FOV2d.
Standard_Real NDC2dOffsetY() const
{
return myFOV2d >= myFOVy
? 0.5
: 0.5 * myFOV2d / myFOVy;
}
//! Calculate WCS frustum planes for the camera projection volume.
//! Frustum is a convex volume determined by six planes directing
//! inwards.
@ -552,6 +589,32 @@ public:
//! The matrix will be updated on request.
Standard_EXPORT void InvalidateOrientation();
public:
//! Unset all custom frustums and projection matrices.
Standard_EXPORT void ResetCustomProjection();
//! Return TRUE if custom stereo frustums are set.
bool IsCustomStereoFrustum() const { return myIsCustomFrustomLR; }
//! Set custom stereo frustums.
//! These can be retrieved from APIs like OpenVR.
Standard_EXPORT void SetCustomStereoFrustums (const Aspect_FrustumLRBT<Standard_Real>& theFrustumL,
const Aspect_FrustumLRBT<Standard_Real>& theFrustumR);
//! Return TRUE if custom stereo projection matrices are set.
bool IsCustomStereoProjection() const { return myIsCustomProjMatLR; }
//! Set custom stereo projection matrices.
Standard_EXPORT void SetCustomStereoProjection (const Graphic3d_Mat4d& theProjL,
const Graphic3d_Mat4d& theProjR);
//! Return TRUE if custom projection matrix is set.
bool IsCustomMonoProjection() const { return myIsCustomProjMatM; }
//! Set custom projection matrix.
Standard_EXPORT void SetCustomMonoProjection (const Graphic3d_Mat4d& theProj);
//! Dumps the content of me into the stream
Standard_EXPORT void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const;
@ -572,68 +635,44 @@ private:
private:
//! Compose orthographic projection matrix for
//! the passed camera volume mapping.
//! @param theLeft [in] the left mapping (clipping) coordinate.
//! @param theRight [in] the right mapping (clipping) coordinate.
//! @param theBottom [in] the bottom mapping (clipping) coordinate.
//! @param theTop [in] the top mapping (clipping) coordinate.
//! @param theNear [in] the near mapping (clipping) coordinate.
//! @param theFar [in] the far mapping (clipping) coordinate.
//! @param theOutMx [out] the projection matrix.
//! Compose orthographic projection matrix for the passed camera volume mapping.
//! @param theOutMx [out] the projection matrix
//! @param theLRBT [in] the left/right/bottom/top mapping (clipping) coordinates
//! @param theNear [in] the near mapping (clipping) coordinate
//! @param theFar [in] the far mapping (clipping) coordinate
template <typename Elem_t>
static void
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);
static void orthoProj (NCollection_Mat4<Elem_t>& theOutMx,
const Aspect_FrustumLRBT<Elem_t>& theLRBT,
const Elem_t theNear,
const Elem_t theFar);
//! Compose perspective projection matrix for
//! the passed camera volume mapping.
//! @param theLeft [in] the left mapping (clipping) coordinate.
//! @param theRight [in] the right mapping (clipping) coordinate.
//! @param theBottom [in] the bottom mapping (clipping) coordinate.
//! @param theTop [in] the top mapping (clipping) coordinate.
//! @param theNear [in] the near mapping (clipping) coordinate.
//! @param theFar [in] the far mapping (clipping) coordinate.
//! @param theOutMx [out] the projection matrix.
//! Compose perspective projection matrix for the passed camera volume mapping.
//! @param theOutMx [out] the projection matrix
//! @param theLRBT [in] the left/right/bottom/top mapping (clipping) coordinates
//! @param theNear [in] the near mapping (clipping) coordinate
//! @param theFar [in] the far mapping (clipping) coordinate
template <typename Elem_t>
static void
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);
static void perspectiveProj (NCollection_Mat4<Elem_t>& theOutMx,
const Aspect_FrustumLRBT<Elem_t>& theLRBT,
const Elem_t theNear,
const Elem_t theFar);
//! Compose projection matrix for L/R stereo eyes.
//! @param theLeft [in] the left mapping (clipping) coordinate.
//! @param theRight [in] the right mapping (clipping) coordinate.
//! @param theBottom [in] the bottom mapping (clipping) coordinate.
//! @param theTop [in] the top mapping (clipping) coordinate.
//! @param theNear [in] the near mapping (clipping) coordinate.
//! @param theFar [in] the far mapping (clipping) coordinate.
//! @param theIOD [in] the Intraocular distance.
//! @param theZFocus [in] the z coordinate of off-axis
//! projection plane with zero parallax.
//! @param theIsLeft [in] boolean flag to choose between L/R eyes.
//! @param theOutMx [out] the projection matrix.
//! @param theOutMx [out] the projection matrix
//! @param theLRBT [in] the left/right/bottom/top mapping (clipping) coordinates
//! @param theNear [in] the near mapping (clipping) coordinate
//! @param theFar [in] the far mapping (clipping) coordinate
//! @param theIOD [in] the Intraocular distance
//! @param theZFocus [in] the z coordinate of off-axis projection plane with zero parallax
//! @param theEyeIndex [in] choose between L/R eyes
template <typename Elem_t>
static void
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);
static void stereoEyeProj (NCollection_Mat4<Elem_t>& theOutMx,
const Aspect_FrustumLRBT<Elem_t>& theLRBT,
const Elem_t theNear,
const Elem_t theFar,
const Elem_t theIOD,
const Elem_t theZFocus,
const Aspect_Eye theEyeIndex);
//! Construct "look at" orientation transformation.
//! Reference point differs for perspective and ortho modes
@ -684,6 +723,8 @@ private:
Projection myProjType; //!< Projection type used for rendering.
Standard_Real myFOVy; //!< Field Of View in y axis.
Standard_Real myFOVx; //!< Field Of View in x axis.
Standard_Real myFOV2d; //!< Field Of View limit for 2d on-screen elements
Standard_Real myFOVyTan; //!< Field Of View as Tan(DTR_HALF * myFOVy)
Standard_Real myZNear; //!< Distance to near clipping plane.
Standard_Real myZFar; //!< Distance to far clipping plane.
@ -698,6 +739,15 @@ private:
Graphic3d_CameraTile myTile;//!< Tile defining sub-area for drawing
Graphic3d_Mat4d myCustomProjMatM;
Graphic3d_Mat4d myCustomProjMatL;
Graphic3d_Mat4d myCustomProjMatR;
Aspect_FrustumLRBT<Standard_Real> myCustomFrustumL; //!< left custom frustum
Aspect_FrustumLRBT<Standard_Real> myCustomFrustumR; //!< right custom frustum
Standard_Boolean myIsCustomProjMatM; //!< flag indicating usage of custom projection matrix
Standard_Boolean myIsCustomProjMatLR; //!< flag indicating usage of custom stereo projection matrices
Standard_Boolean myIsCustomFrustomLR; //!< flag indicating usage of custom stereo frustums
mutable TransformMatrices<Standard_Real> myMatricesD;
mutable TransformMatrices<Standard_ShortReal> myMatricesF;

View File

@ -134,8 +134,10 @@ public:
WhitePoint (1.f),
// stereoscopic parameters
StereoMode (Graphic3d_StereoMode_QuadBuffer),
HmdFov2d (30.0f),
AnaglyphFilter (Anaglyph_RedCyan_Optimized),
ToReverseStereo (Standard_False),
ToMirrorComposer (Standard_True),
//
StatsPosition (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_UPPER, Graphic3d_Vec2i (20, 20))),
ChartPosition (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_RIGHT_UPPER, Graphic3d_Vec2i (20, 20))),
@ -225,10 +227,12 @@ public:
Standard_ShortReal WhitePoint; //!< white point value used in filmic tone mapping (path tracing), 1.0 by default
Graphic3d_StereoMode StereoMode; //!< stereoscopic output mode, Graphic3d_StereoMode_QuadBuffer by default
Standard_ShortReal HmdFov2d; //!< sharp field of view range in degrees for displaying on-screen 2D elements, 30.0 by default;
Anaglyph AnaglyphFilter; //!< filter for anaglyph output, Anaglyph_RedCyan_Optimized by default
Graphic3d_Mat4 AnaglyphLeft; //!< left anaglyph filter (in normalized colorspace), Color = AnaglyphRight * theColorRight + AnaglyphLeft * theColorLeft;
Graphic3d_Mat4 AnaglyphRight; //!< right anaglyph filter (in normalized colorspace), Color = AnaglyphRight * theColorRight + AnaglyphLeft * theColorLeft;
Standard_Boolean ToReverseStereo; //!< flag to reverse stereo pair, FALSE by default
Standard_Boolean ToMirrorComposer; //!< if output device is an external composer - mirror rendering results in window in addition to sending frame to composer, TRUE by default
Handle(Graphic3d_TransformPers) StatsPosition; //!< location of stats, upper-left position by default
Handle(Graphic3d_TransformPers) ChartPosition; //!< location of stats chart, upper-right position by default

View File

@ -27,6 +27,7 @@ enum Graphic3d_StereoMode
Graphic3d_StereoMode_SideBySide, //!< horizontal pair
Graphic3d_StereoMode_OverUnder, //!< vertical pair
Graphic3d_StereoMode_SoftPageFlip, //!< software PageFlip for shutter glasses, should NOT be used!
Graphic3d_StereoMode_OpenVR, //!< OpenVR (HMD)
Graphic3d_StereoMode_NB //!< the number of modes
};

View File

@ -364,7 +364,7 @@ void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera,
{
const Standard_Real anOffsetX = (Standard_Real(myParams.Params2d.OffsetX) + aJitterComp) * aScale;
const gp_Dir aSide = aForward.Crossed (theCamera->Up());
const gp_XYZ aDeltaX = aSide.XYZ() * (Abs(aViewDim.X()) * 0.5 - anOffsetX);
const gp_XYZ aDeltaX = aSide.XYZ() * (Abs(aViewDim.X()) * theCamera->NDC2dOffsetX() - anOffsetX);
if ((myParams.Params2d.Corner & Aspect_TOTP_RIGHT) != 0)
{
aCenter += aDeltaX;
@ -377,7 +377,7 @@ void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera,
if ((myParams.Params2d.Corner & (Aspect_TOTP_TOP | Aspect_TOTP_BOTTOM)) != 0)
{
const Standard_Real anOffsetY = (Standard_Real(myParams.Params2d.OffsetY) + aJitterComp) * aScale;
const gp_XYZ aDeltaY = theCamera->Up().XYZ() * (Abs(aViewDim.Y()) * 0.5 - anOffsetY);
const gp_XYZ aDeltaY = theCamera->Up().XYZ() * (Abs(aViewDim.Y()) * theCamera->NDC2dOffsetY() - anOffsetY);
if ((myParams.Params2d.Corner & Aspect_TOTP_TOP) != 0)
{
aCenter += aDeltaY;
@ -408,7 +408,7 @@ void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera,
gp_XYZ aCenter (0.0, 0.0, -aFocus);
if ((myParams.Params2d.Corner & (Aspect_TOTP_LEFT | Aspect_TOTP_RIGHT)) != 0)
{
aCenter.SetX (-aViewDim.X() * 0.5 + (Standard_Real(myParams.Params2d.OffsetX) + aJitterComp) * aScale);
aCenter.SetX (-aViewDim.X() * theCamera->NDC2dOffsetX() + (Standard_Real(myParams.Params2d.OffsetX) + aJitterComp) * aScale);
if ((myParams.Params2d.Corner & Aspect_TOTP_RIGHT) != 0)
{
aCenter.SetX (-aCenter.X());
@ -416,7 +416,7 @@ void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera,
}
if ((myParams.Params2d.Corner & (Aspect_TOTP_TOP | Aspect_TOTP_BOTTOM)) != 0)
{
aCenter.SetY (-aViewDim.Y() * 0.5 + (Standard_Real(myParams.Params2d.OffsetY) + aJitterComp) * aScale);
aCenter.SetY (-aViewDim.Y() * theCamera->NDC2dOffsetY() + (Standard_Real(myParams.Params2d.OffsetY) + aJitterComp) * aScale);
if ((myParams.Params2d.Corner & Aspect_TOTP_TOP) != 0)
{
aCenter.SetY (-aCenter.Y());

View File

@ -40,10 +40,11 @@ proc Visualization:toolkits { } {
;# Autres UDs a prendre.
;#
proc Visualization:ressources { } {
return [list \
[list both r Textures {}] \
[list both r Shaders {}] \
]
return [list \
[list both r Textures {}] \
[list both r Shaders {}] \
[list both r XRResources {}] \
]
}
;#
;# Nom du module

View File

@ -4067,6 +4067,22 @@ void OpenGl_Context::SetPolygonOffset (const Graphic3d_PolygonOffset& theOffset)
myPolygonOffset = theOffset;
}
// =======================================================================
// function : SetCamera
// purpose :
// =======================================================================
void OpenGl_Context::SetCamera (const Handle(Graphic3d_Camera)& theCamera)
{
myCamera = theCamera;
if (!theCamera.IsNull())
{
ProjectionState.SetCurrent (theCamera->ProjectionMatrixF());
WorldViewState .SetCurrent (theCamera->OrientationMatrixF());
ApplyProjectionMatrix();
ApplyWorldViewMatrix();
}
}
// =======================================================================
// function : ApplyModelWorldMatrix
// purpose :

View File

@ -136,6 +136,7 @@ template<typename theBaseClass_t> struct OpenGl_TmplCore45;
typedef OpenGl_TmplCore45<OpenGl_GlCore44Back> OpenGl_GlCore45Back;
typedef OpenGl_TmplCore45<OpenGl_GlCore44> OpenGl_GlCore45;
class Graphic3d_Camera;
class Graphic3d_PresentationAttributes;
class OpenGl_Aspects;
class OpenGl_FrameBuffer;
@ -678,6 +679,12 @@ public:
//! Returns currently applied polygon offset parameters.
const Graphic3d_PolygonOffset& PolygonOffset() const { return myPolygonOffset; }
//! Returns camera object.
const Handle(Graphic3d_Camera)& Camera() const { return myCamera; }
//! Sets camera object to the context and update matrices.
Standard_EXPORT void SetCamera (const Handle(Graphic3d_Camera)& theCamera);
//! Applies matrix into shader manager stored in ModelWorldState to OpenGl.
//! In "model -> world -> view -> projection" it performs:
//! model -> world
@ -1143,6 +1150,7 @@ private: // context info
private: //! @name fields tracking current state
Handle(Graphic3d_Camera) myCamera; //!< active camera object
Handle(OpenGl_FrameStats) myFrameStats; //!< structure accumulating frame statistics
Handle(OpenGl_ShaderProgram) myActiveProgram; //!< currently active GLSL program
Handle(OpenGl_TextureSet) myActiveTextures; //!< currently bound textures

View File

@ -389,7 +389,7 @@ void OpenGl_FrameStatsPrs::Render (const Handle(OpenGl_Workspace)& theWorkspace)
aCtx->WorldViewState.Push();
if (!myCountersTrsfPers.IsNull())
{
myCountersTrsfPers->Apply (theWorkspace->View()->Camera(),
myCountersTrsfPers->Apply (aCtx->Camera(),
aCtx->ProjectionState.Current(), aCtx->WorldViewState.ChangeCurrent(),
aCtx->VirtualViewport()[2], aCtx->VirtualViewport()[3]);
}

View File

@ -422,7 +422,7 @@ void OpenGl_GraduatedTrihedron::renderAxis (const Handle(OpenGl_Workspace)& theW
const Standard_Integer aHeight = theWorkspace->Height();
// Take into account Transform Persistence
aContext->ModelWorldState.SetCurrent (aTransMode.Compute (theWorkspace->View()->Camera(), aProjection, aWorldView, aWidth, aHeight));
aContext->ModelWorldState.SetCurrent (aTransMode.Compute (aContext->Camera(), aProjection, aWorldView, aWidth, aHeight));
aContext->ApplyModelViewMatrix();
anAxis.Arrow.Render (theWorkspace);

View File

@ -2979,6 +2979,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramStereo (Handle(OpenGl_Sh
}
case Graphic3d_StereoMode_QuadBuffer:
case Graphic3d_StereoMode_SoftPageFlip:
case Graphic3d_StereoMode_OpenVR:
default:
{
/*const Handle(OpenGl_ShaderProgram)& aProgram = myStereoPrograms[Graphic3d_StereoMode_QuadBuffer];

View File

@ -439,7 +439,7 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con
{
aCtx->WorldViewState.Push();
OpenGl_Mat4& aWorldView = aCtx->WorldViewState.ChangeCurrent();
myTrsfPers->Apply (theWorkspace->View()->Camera(),
myTrsfPers->Apply (aCtx->Camera(),
aCtx->ProjectionState.Current(), aWorldView,
aCtx->VirtualViewport()[2], aCtx->VirtualViewport()[3]);

View File

@ -333,7 +333,7 @@ void OpenGl_Text::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
if (myText->HasPlane() && myText->HasOwnAnchorPoint())
{
myOrientationMatrix = theWorkspace->View()->Camera()->OrientationMatrix();
myOrientationMatrix = aCtx->Camera()->OrientationMatrix();
// reset translation part
myOrientationMatrix.ChangeValue (0, 3) = 0.0;
myOrientationMatrix.ChangeValue (1, 3) = 0.0;

View File

@ -61,6 +61,7 @@ OpenGl_View::OpenGl_View (const Handle(Graphic3d_StructureManager)& theMgr,
myFboColorFormat (GL_SRGB8_ALPHA8), // note that GL_SRGB8 is not required to be renderable, unlike GL_RGB8, GL_RGBA8, GL_SRGB8_ALPHA8
myFboDepthFormat (GL_DEPTH24_STENCIL8),
myToFlipOutput (Standard_False),
//
myFrameCounter (0),
myHasFboBlit (Standard_True),
myToDisableOIT (Standard_False),
@ -111,6 +112,7 @@ OpenGl_View::OpenGl_View (const Handle(Graphic3d_StructureManager)& theMgr,
myImmediateSceneFbos[1] = new OpenGl_FrameBuffer();
myImmediateSceneFbosOit[0] = new OpenGl_FrameBuffer();
myImmediateSceneFbosOit[1] = new OpenGl_FrameBuffer();
myXrSceneFbo = new OpenGl_FrameBuffer();
myOpenGlFBO = new OpenGl_FrameBuffer();
myOpenGlFBO2 = new OpenGl_FrameBuffer();
myRaytraceFBO1[0] = new OpenGl_FrameBuffer();
@ -182,6 +184,7 @@ void OpenGl_View::releaseSrgbResources (const Handle(OpenGl_Context)& theCtx)
myImmediateSceneFbos[1] ->Release (theCtx.get());
myImmediateSceneFbosOit[0]->Release (theCtx.get());
myImmediateSceneFbosOit[1]->Release (theCtx.get());
myXrSceneFbo ->Release (theCtx.get());
myOpenGlFBO ->Release (theCtx.get());
myOpenGlFBO2 ->Release (theCtx.get());
myFullScreenQuad .Release (theCtx.get());
@ -209,6 +212,7 @@ void OpenGl_View::ReleaseGlResources (const Handle(OpenGl_Context)& theCtx)
{
myPBREnvironment->Release (theCtx.get());
}
ReleaseXR();
}
// =======================================================================
@ -826,6 +830,7 @@ void OpenGl_View::changePriority (const Handle(Graphic3d_CStructure)& theStructu
void OpenGl_View::DiagnosticInformation (TColStd_IndexedDataMapOfStringString& theDict,
Graphic3d_DiagnosticInfo theFlags) const
{
base_type::DiagnosticInformation (theDict, theFlags);
Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
if (!myWorkspace->Activate()
|| aCtx.IsNull())

View File

@ -523,6 +523,7 @@ protected: //! @name Rendering properties
Handle(OpenGl_FrameBuffer) myMainSceneFbosOit[2]; //!< Additional buffers for transparent draw of main layer.
Handle(OpenGl_FrameBuffer) myImmediateSceneFbos[2]; //!< Additional buffers for immediate layer in stereo mode.
Handle(OpenGl_FrameBuffer) myImmediateSceneFbosOit[2]; //!< Additional buffers for transparency draw of immediate layer.
Handle(OpenGl_FrameBuffer) myXrSceneFbo; //!< additional FBO (without MSAA) for submitting to XR
OpenGl_VertexBuffer myFullScreenQuad; //!< Vertices for full-screen quad rendering.
OpenGl_VertexBuffer myFullScreenQuadFlip;
Standard_Boolean myToFlipOutput; //!< Flag to draw result image upside-down

View File

@ -18,6 +18,7 @@
#include <OpenGl_GlCore11.hxx>
#include <Aspect_XRSession.hxx>
#include <Graphic3d_GraphicDriver.hxx>
#include <Graphic3d_StructureManager.hxx>
#include <Graphic3d_TextureParams.hxx>
@ -158,7 +159,8 @@ void OpenGl_View::Redraw()
return;
}
myWindow->SetSwapInterval();
// implicitly disable VSync when using HMD composer (can be mirrored in window for debugging)
myWindow->SetSwapInterval (IsActiveXR());
++myFrameCounter;
const Graphic3d_StereoMode aStereoMode = myRenderParams.StereoMode;
@ -186,10 +188,22 @@ void OpenGl_View::Redraw()
OpenGl_FrameBuffer* aFrameBuffer = myFBO.get();
bool toSwap = aCtx->IsRender()
&& !aCtx->caps->buffersNoSwap
&& aFrameBuffer == NULL;
&& aFrameBuffer == NULL
&& (!IsActiveXR() || myRenderParams.ToMirrorComposer);
Standard_Integer aSizeX = myWindow->Width();
Standard_Integer aSizeY = myWindow->Height();
if (aFrameBuffer != NULL)
{
aSizeX = aFrameBuffer->GetVPSizeX();
aSizeY = aFrameBuffer->GetVPSizeY();
}
else if (IsActiveXR())
{
aSizeX = myXRSession->RecommendedViewport().x();
aSizeY = myXRSession->RecommendedViewport().y();
}
const Standard_Integer aSizeX = aFrameBuffer != NULL ? aFrameBuffer->GetVPSizeX() : myWindow->Width();
const Standard_Integer aSizeY = aFrameBuffer != NULL ? aFrameBuffer->GetVPSizeY() : myWindow->Height();
const Standard_Integer aRendSizeX = Standard_Integer(myRenderParams.RenderResolutionScale * aSizeX + 0.5f);
const Standard_Integer aRendSizeY = Standard_Integer(myRenderParams.RenderResolutionScale * aSizeY + 0.5f);
if (aSizeX < 1
@ -275,14 +289,33 @@ void OpenGl_View::Redraw()
myMainSceneFbos [1]->Release (aCtx.operator->());
myImmediateSceneFbos[0]->Release (aCtx.operator->());
myImmediateSceneFbos[1]->Release (aCtx.operator->());
myXrSceneFbo ->Release (aCtx.operator->());
myMainSceneFbos [0]->ChangeViewport (0, 0);
myMainSceneFbos [1]->ChangeViewport (0, 0);
myImmediateSceneFbos[0]->ChangeViewport (0, 0);
myImmediateSceneFbos[1]->ChangeViewport (0, 0);
myXrSceneFbo ->ChangeViewport (0, 0);
}
bool hasXRBlitFbo = false;
if (aProjectType == Graphic3d_Camera::Projection_Stereo
&& IsActiveXR()
&& myMainSceneFbos[0]->IsValid())
{
if (aNbSamples != 0
|| aSizeX != aRendSizeX)
{
hasXRBlitFbo = myXrSceneFbo->InitLazy (aCtx, aSizeX, aSizeY, myFboColorFormat, myFboDepthFormat, 0);
if (!hasXRBlitFbo)
{
TCollection_ExtendedString aMsg = TCollection_ExtendedString() + "Error! VR FBO "
+ printFboFormat (myXrSceneFbo) + " initialization has failed";
aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
}
}
}
else if (aProjectType == Graphic3d_Camera::Projection_Stereo
&& myMainSceneFbos[0]->IsValid())
{
const bool wasFailedMain1 = checkWasFailedFbo (myMainSceneFbos[1], myMainSceneFbos[0]);
if (!myMainSceneFbos[1]->InitLazy (aCtx, *myMainSceneFbos[0])
@ -326,6 +359,11 @@ void OpenGl_View::Redraw()
}
}
}
if (!hasXRBlitFbo)
{
myXrSceneFbo->Release (aCtx.get());
myXrSceneFbo->ChangeViewport (0, 0);
}
// process PBR environment
if (myShadingModel == Graphic3d_TOSM_PBR
@ -500,7 +538,18 @@ void OpenGl_View::Redraw()
myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL
};
if (!myTransientDrawToFront)
if (IsActiveXR())
{
// use single frame for both views - caching main scene content makes no sense
// when head position is expected to be updated each frame redraw with high accuracy
aMainFbos[1] = aMainFbos[0];
aMainFbosOit[1] = aMainFbosOit[0];
anImmFbos[0] = aMainFbos[0];
anImmFbos[1] = aMainFbos[1];
anImmFbosOit[0] = aMainFbosOit[0];
anImmFbosOit[1] = aMainFbosOit[1];
}
else if (!myTransientDrawToFront)
{
anImmFbos [0] = aMainFbos [0];
anImmFbos [1] = aMainFbos [1];
@ -539,6 +588,23 @@ void OpenGl_View::Redraw()
aCtx->SwapBuffers();
}
if (IsActiveXR())
{
// push Left frame to HMD display composer
OpenGl_FrameBuffer* anXRFbo = hasXRBlitFbo ? myXrSceneFbo.get() : aMainFbos[0];
if (anXRFbo != aMainFbos[0])
{
blitBuffers (aMainFbos[0], anXRFbo); // resize or resolve MSAA samples
}
#if !defined(GL_ES_VERSION_2_0)
const Aspect_GraphicsLibrary aGraphicsLib = Aspect_GraphicsLibrary_OpenGL;
#else
const Aspect_GraphicsLibrary aGraphicsLib = Aspect_GraphicsLibrary_OpenGLES;
#endif
myXRSession->SubmitEye ((void* )(size_t )anXRFbo->ColorTexture()->TextureId(),
aGraphicsLib, Aspect_ColorSpace_sRGB, Aspect_Eye_Left);
}
#if !defined(GL_ES_VERSION_2_0)
aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_RIGHT : GL_BACK);
#endif
@ -555,7 +621,29 @@ void OpenGl_View::Redraw()
toSwap = false;
}
if (anImmFbos[0] != NULL)
if (IsActiveXR())
{
// push Right frame to HMD display composer
OpenGl_FrameBuffer* anXRFbo = hasXRBlitFbo ? myXrSceneFbo.get() : aMainFbos[1];
if (anXRFbo != aMainFbos[1])
{
blitBuffers (aMainFbos[1], anXRFbo); // resize or resolve MSAA samples
}
#if !defined(GL_ES_VERSION_2_0)
const Aspect_GraphicsLibrary aGraphicsLib = Aspect_GraphicsLibrary_OpenGL;
#else
const Aspect_GraphicsLibrary aGraphicsLib = Aspect_GraphicsLibrary_OpenGLES;
#endif
myXRSession->SubmitEye ((void* )(size_t )anXRFbo->ColorTexture()->TextureId(),
aGraphicsLib, Aspect_ColorSpace_sRGB, Aspect_Eye_Right);
::glFinish();
if (myRenderParams.ToMirrorComposer)
{
blitBuffers (anXRFbo, aFrameBuffer, myToFlipOutput);
}
}
else if (anImmFbos[0] != NULL)
{
aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(), 1.0f);
drawStereoPair (aFrameBuffer);
@ -657,6 +745,7 @@ void OpenGl_View::RedrawImmediate()
if (!myWorkspace->Activate())
return;
// no special handling of HMD display, since it will force full Redraw() due to no frame caching (myBackBufferRestored)
Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
if (!myTransientDrawToFront
|| !myBackBufferRestored
@ -872,9 +961,11 @@ bool OpenGl_View::redrawImmediate (const Graphic3d_Camera::Projection theProject
const Handle(OpenGl_Context)& aCtx = myWorkspace->GetGlContext();
GLboolean toCopyBackToFront = GL_FALSE;
if (theDrawFbo == theReadFbo
&& theDrawFbo != NULL)
&& theDrawFbo != NULL
&& theDrawFbo->IsValid())
{
myBackBufferRestored = Standard_False;
theDrawFbo->BindBuffer (aCtx);
}
else if (theReadFbo != NULL
&& theReadFbo->IsValid()
@ -993,10 +1084,7 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
}
myLocalOrigin.SetCoord (0.0, 0.0, 0.0);
aContext->ProjectionState.SetCurrent (myCamera->ProjectionMatrixF());
aContext->WorldViewState .SetCurrent (myCamera->OrientationMatrixF());
aContext->ApplyProjectionMatrix();
aContext->ApplyWorldViewMatrix();
aContext->SetCamera (myCamera);
if (aManager->ModelWorldState().Index() == 0)
{
aContext->ShaderManager()->UpdateModelWorldStateTo (OpenGl_Mat4());
@ -1042,7 +1130,7 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
#if !defined(GL_ES_VERSION_2_0)
// if the view is scaled normal vectors are scaled to unit
// length for correct displaying of shaded objects
const gp_Pnt anAxialScale = myCamera->AxialScale();
const gp_Pnt anAxialScale = aContext->Camera()->AxialScale();
if (anAxialScale.X() != 1.F ||
anAxialScale.Y() != 1.F ||
anAxialScale.Z() != 1.F)
@ -1060,12 +1148,12 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
// Redraw 3d scene
if (theProjection == Graphic3d_Camera::Projection_MonoLeftEye)
{
aContext->ProjectionState.SetCurrent (myCamera->ProjectionStereoLeftF());
aContext->ProjectionState.SetCurrent (aContext->Camera()->ProjectionStereoLeftF());
aContext->ApplyProjectionMatrix();
}
else if (theProjection == Graphic3d_Camera::Projection_MonoRightEye)
{
aContext->ProjectionState.SetCurrent (myCamera->ProjectionStereoRightF());
aContext->ProjectionState.SetCurrent (aContext->Camera()->ProjectionStereoRightF());
aContext->ApplyProjectionMatrix();
}

View File

@ -809,11 +809,12 @@ void OpenGl_Window::Init()
// function : SetSwapInterval
// purpose :
// =======================================================================
void OpenGl_Window::SetSwapInterval()
void OpenGl_Window::SetSwapInterval (Standard_Boolean theToForceNoSync)
{
if (mySwapInterval != myGlContext->caps->swapInterval)
const Standard_Integer aSwapInterval = theToForceNoSync ? 0 : myGlContext->caps->swapInterval;
if (mySwapInterval != aSwapInterval)
{
mySwapInterval = myGlContext->caps->swapInterval;
mySwapInterval = aSwapInterval;
myGlContext->SetSwapInterval (mySwapInterval);
}
}

View File

@ -73,7 +73,7 @@ public:
Standard_EXPORT virtual Standard_Boolean Activate();
//! Sets swap interval for this window according to the context's settings.
Standard_EXPORT void SetSwapInterval();
Standard_EXPORT void SetSwapInterval (Standard_Boolean theToForceNoSync);
protected:

View File

@ -390,11 +390,12 @@ void OpenGl_Window::Init()
// function : SetSwapInterval
// purpose :
// =======================================================================
void OpenGl_Window::SetSwapInterval()
void OpenGl_Window::SetSwapInterval (Standard_Boolean theToForceNoSync)
{
if (mySwapInterval != myGlContext->caps->swapInterval)
const Standard_Integer aSwapInterval = theToForceNoSync ? 0 : myGlContext->caps->swapInterval;
if (mySwapInterval != aSwapInterval)
{
mySwapInterval = myGlContext->caps->swapInterval;
mySwapInterval = aSwapInterval;
myGlContext->SetSwapInterval (mySwapInterval);
}
}

View File

@ -85,15 +85,18 @@ public:
//! Empties all the tables, removes all selections...
Standard_EXPORT void Clear();
//! returns the Sensitivity of picking
Standard_Real Sensitivity() const { return myTolerances.Tolerance(); }
//! Returns the pixel tolerance.
Standard_Integer PixelTolerance() const { return myTolerances.Tolerance(); }
//! Returns custom pixel tolerance value.
Standard_Integer CustomPixelTolerance() const { return myTolerances.CustomTolerance(); }
//! Sets the pixel tolerance <theTolerance>.
Standard_EXPORT void SetPixelTolerance (const Standard_Integer theTolerance);
//! Returns the largest sensitivity of picking
Standard_Real Sensitivity() const { return myTolerances.Tolerance(); }
//! Returns the largest pixel tolerance.
Standard_Integer PixelTolerance() const { return myTolerances.Tolerance(); }
//! Sorts the detected entites by priority and distance.
//! to be redefined if other criterion are used...
Standard_EXPORT void SortResult();

View File

@ -2,6 +2,7 @@ TKernel
TKMath
CSF_user32
CSF_advapi32
CSF_OpenVR
CSF_OpenGlLibs
CSF_advapi32
CSF_user32

View File

@ -233,6 +233,7 @@ void V3d_View::Update() const
myIsInvalidatedImmediate = Standard_False;
myView->Update();
myView->Compute();
AutoZFit();
myView->Redraw();
}
@ -618,8 +619,6 @@ void V3d_View::SetFront()
aCamera->SetUp (gp_Dir (xu, yu, zu));
AutoZFit();
SwitchSetFront = !SwitchSetFront;
ImmediateUpdate();
@ -675,8 +674,6 @@ void V3d_View::Rotate (const Standard_Real ax,
aCamera->Transform (aTrsf);
AutoZFit();
ImmediateUpdate();
}
@ -733,8 +730,6 @@ void V3d_View::Rotate(const Standard_Real ax, const Standard_Real ay, const Stan
aCamera->Transform (aTrsf);
AutoZFit();
ImmediateUpdate();
}
@ -803,8 +798,6 @@ void V3d_View::Rotate (const V3d_TypeOfAxe theAxe, const Standard_Real theAngle,
aCamera->Transform (aRotation);
AutoZFit();
ImmediateUpdate();
}
@ -840,8 +833,6 @@ void V3d_View::Rotate(const Standard_Real angle, const Standard_Boolean Start)
aCamera->Transform (aRotation);
AutoZFit();
ImmediateUpdate();
}
@ -892,8 +883,6 @@ void V3d_View::Turn(const Standard_Real ax, const Standard_Real ay, const Standa
aCamera->Transform (aTrsf);
AutoZFit();
ImmediateUpdate();
}
@ -948,8 +937,6 @@ void V3d_View::Turn(const Standard_Real angle, const Standard_Boolean Start)
aCamera->Transform (aRotation);
AutoZFit();
ImmediateUpdate();
}
@ -983,8 +970,6 @@ void V3d_View::SetTwist(const Standard_Real angle)
aCamera->SetUp (gp_Dir (myYscreenAxis));
aCamera->Transform (aTrsf);
AutoZFit();
ImmediateUpdate();
}
@ -1004,8 +989,6 @@ void V3d_View::SetEye(const Standard_Real X,const Standard_Real Y,const Standard
SetTwist (aTwistBefore);
AutoZFit();
SetImmediateUpdate (wasUpdateEnabled);
ImmediateUpdate();
@ -1036,8 +1019,6 @@ void V3d_View::SetDepth(const Standard_Real Depth)
aCamera->SetCenter (aCameraCenter);
}
AutoZFit();
ImmediateUpdate();
}
@ -1058,8 +1039,6 @@ void V3d_View::SetProj( const Standard_Real Vx,const Standard_Real Vy, const Sta
SetTwist(aTwistBefore);
AutoZFit();
SetImmediateUpdate (wasUpdateEnabled);
ImmediateUpdate();
@ -1108,8 +1087,6 @@ void V3d_View::SetProj (const V3d_TypeOfOrientation theOrientation,
Panning (anOriginVCS.X(), anOriginVCS.Y());
AutoZFit();
ImmediateUpdate();
}
@ -1127,8 +1104,6 @@ void V3d_View::SetAt(const Standard_Real X,const Standard_Real Y,const Standard_
SetTwist (aTwistBefore);
AutoZFit();
SetImmediateUpdate (wasUpdateEnabled);
ImmediateUpdate();
@ -1154,8 +1129,6 @@ void V3d_View::SetUp (const Standard_Real theVx, const Standard_Real theVy, cons
aCamera->SetUp (gp_Dir (myYscreenAxis));
AutoZFit();
ImmediateUpdate();
}
@ -1179,8 +1152,6 @@ void V3d_View::SetUp (const V3d_TypeOfOrientation theOrientation)
aCamera->SetUp (gp_Dir (myYscreenAxis));
AutoZFit();
ImmediateUpdate();
}
@ -1209,9 +1180,6 @@ void V3d_View::SetViewMappingDefault()
void V3d_View::ResetViewOrientation()
{
Camera()->CopyOrientationData (myDefaultCamera);
AutoZFit();
ImmediateUpdate();
}
@ -1222,9 +1190,6 @@ void V3d_View::ResetViewOrientation()
void V3d_View::ResetViewMapping()
{
Camera()->CopyMappingData (myDefaultCamera);
AutoZFit();
ImmediateUpdate();
}
@ -1236,8 +1201,6 @@ void V3d_View::Reset (const Standard_Boolean theToUpdate)
{
Camera()->Copy (myDefaultCamera);
AutoZFit();
SwitchSetFront = Standard_False;
if (myImmediateUpdate || theToUpdate)
@ -1272,8 +1235,6 @@ void V3d_View::SetSize (const Standard_Real theSize)
aCamera->SetScale (aCamera->Aspect() >= 1.0 ? theSize / aCamera->Aspect() : theSize);
AutoZFit();
ImmediateUpdate();
}
@ -1375,8 +1336,6 @@ void V3d_View::SetZoom (const Standard_Real theCoef,const Standard_Boolean theTo
aCamera->SetCenter (myCamStartOpCenter);
aCamera->SetScale (aCamera->Scale() / aCoef);
AutoZFit();
ImmediateUpdate();
}
@ -1394,8 +1353,6 @@ void V3d_View::SetScale( const Standard_Real Coef )
aCamera->SetAspect (myDefaultCamera->Aspect());
aCamera->SetScale (aDefaultScale / Coef);
AutoZFit();
ImmediateUpdate();
}
@ -1408,8 +1365,6 @@ void V3d_View::SetAxialScale( const Standard_Real Sx, const Standard_Real Sy, co
V3d_BadValue_Raise_if( Sx <= 0. || Sy <= 0. || Sz <= 0.,"V3d_View::SetAxialScale, bad coefficient");
Camera()->SetAxialScale (gp_XYZ (Sx, Sy, Sz));
AutoZFit();
}
//=============================================================================
@ -1463,8 +1418,6 @@ void V3d_View::FitAll (const Bnd_Box& theBox, const Standard_Real theMargin, con
return;
}
AutoZFit();
if (myImmediateUpdate || theToUpdate)
{
Update();
@ -1588,7 +1541,6 @@ void V3d_View::WindowFit (const Standard_Integer theMinXp,
Translate (aCamera, aPanVec.X(), -aPanVec.Y());
Scale (aCamera, aUSize, aVSize);
AutoZFit();
}
else
{
@ -2491,8 +2443,6 @@ void V3d_View::ZoomAtPoint (const Standard_Integer theMouseStartX,
aCamera->SetScale (aCamera->Scale() / aCoef);
Translate (aCamera, aZoomAtPointXv - aDxv, aZoomAtPointYv - aDyv);
AutoZFit();
SetImmediateUpdate (wasUpdateEnabled);
ImmediateUpdate();
@ -2545,8 +2495,6 @@ void V3d_View::FitAll(const Standard_Real theXmin,
Translate (aCamera, (theXmin + theXmax) * 0.5, (theYmin + theYmax) * 0.5);
Scale (aCamera, aFitSizeU, aFitSizeV);
AutoZFit();
ImmediateUpdate();
}
@ -2828,7 +2776,6 @@ Standard_Boolean V3d_View::ToPixMap (Image_PixMap& theImage,
{
aCamera->SetAspect (Standard_Real(aTargetSize.x()) / Standard_Real(aTargetSize.y()));
}
AutoZFit();
// render immediate structures into back buffer rather than front
const Standard_Boolean aPrevImmediateMode = myView->SetImmediateModeDrawToFront (Standard_False);

View File

@ -67,8 +67,6 @@ void V3d_View::Move (const Standard_Real Dx,
+ Dz * gp_Pnt (ZX, ZY, ZZ).XYZ()
);
AutoZFit();
ImmediateUpdate();
}
@ -86,8 +84,6 @@ void V3d_View::Move (const Standard_Real theLength, const Standard_Boolean theSt
aCamera->SetEye (myCamStartOpEye);
aCamera->SetEye (aCamera->Eye().XYZ() + theLength * myDefaultViewAxis.XYZ());
AutoZFit();
ImmediateUpdate();
}
@ -149,8 +145,6 @@ void V3d_View::Translate (const Standard_Real Dx,
- Dz * myZscreenAxis.XYZ()
);
AutoZFit();
ImmediateUpdate();
}
@ -205,7 +199,5 @@ void V3d_View::Translate (const Standard_Real theLength, const Standard_Boolean
gp_Pnt aNewCenter (myCamStartOpCenter.XYZ() - myDefaultViewAxis.XYZ() * theLength);
aCamera->SetCenter (aNewCenter);
AutoZFit();
ImmediateUpdate();
}

View File

@ -65,6 +65,7 @@
#include <StdSelect_ViewerSelector3d.hxx>
#include <TopTools_MapOfShape.hxx>
#include <ViewerTest_AutoUpdater.hxx>
#include <Aspect_XRSession.hxx>
#include <stdio.h>
@ -1155,16 +1156,23 @@ static Standard_Integer VDump (Draw_Interpretor& theDI,
Standard_Integer theArgNb,
Standard_CString* theArgVec)
{
Handle(V3d_View) aView = ViewerTest::CurrentView();
if (theArgNb < 2)
{
Message::SendFail ("Error: wrong number of arguments! Image file name should be specified at least.");
return 1;
}
if (aView.IsNull())
{
Message::SendFail() << "Error: cannot find an active view!";
return 1;
}
Standard_Integer anArgIter = 1;
Standard_CString aFilePath = theArgVec[anArgIter++];
ViewerTest_StereoPair aStereoPair = ViewerTest_SP_Single;
V3d_ImageDumpOptions aParams;
Handle(Graphic3d_Camera) aCustomCam;
aParams.BufferType = Graphic3d_BT_RGB;
aParams.StereoOptions = V3d_SDO_MONO;
for (; anArgIter < theArgNb; ++anArgIter)
@ -1203,6 +1211,41 @@ static Standard_Integer VDump (Draw_Interpretor& theDI,
return 1;
}
}
else if (anArgIter + 1 < theArgNb
&& anArg == "-xrpose")
{
TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
anXRArg.LowerCase();
if (anXRArg == "base")
{
aCustomCam = aView->View()->BaseXRCamera();
}
else if (anXRArg == "head")
{
aCustomCam = aView->View()->PosedXRCamera();
}
else if (anXRArg == "handleft"
|| anXRArg == "handright")
{
if (aView->View()->IsActiveXR())
{
aCustomCam = new Graphic3d_Camera();
aView->View()->ComputeXRPosedCameraFromBase (*aCustomCam, anXRArg == "handleft"
? aView->View()->XRSession()->LeftHandPose()
: aView->View()->XRSession()->RightHandPose());
}
}
else
{
Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
return 1;
}
if (aCustomCam.IsNull())
{
Message::SendFail() << "Error: undefined XR pose";
return 0;
}
}
else if (anArg == "-stereo")
{
if (++anArgIter >= theArgNb)
@ -1324,13 +1367,6 @@ static Standard_Integer VDump (Draw_Interpretor& theDI,
return 1;
}
Handle(V3d_View) aView = ViewerTest::CurrentView();
if (aView.IsNull())
{
Message::SendFail() << "Error: cannot find an active view!";
return 1;
}
if (aParams.Width <= 0 || aParams.Height <= 0)
{
aView->Window()->Size (aParams.Width, aParams.Height);
@ -1347,6 +1383,12 @@ static Standard_Integer VDump (Draw_Interpretor& theDI,
case Graphic3d_BT_Red: aFormat = Image_Format_Gray; break;
}
const bool wasImmUpdate = aView->SetImmediateUpdate (false);
Handle(Graphic3d_Camera) aCamBack = aView->Camera();
if (!aCustomCam.IsNull())
{
aView->SetCamera (aCustomCam);
}
switch (aStereoPair)
{
case ViewerTest_SP_Single:
@ -1415,6 +1457,11 @@ static Standard_Integer VDump (Draw_Interpretor& theDI,
break;
}
}
if (!aCustomCam.IsNull())
{
aView->SetCamera (aCamBack);
}
aView->SetImmediateUpdate (wasImmUpdate);
if (!aPixMap.Save (aFilePath))
{
@ -6691,6 +6738,7 @@ void ViewerTest::Commands(Draw_Interpretor& theCommands)
"vdump <filename>." DUMP_FORMATS " [-width Width -height Height]"
"\n\t\t: [-buffer rgb|rgba|depth=rgb]"
"\n\t\t: [-stereo mono|left|right|blend|sideBySide|overUnder=mono]"
"\n\t\t: [-xrPose base|head|handLeft|handRight=base]"
"\n\t\t: [-tileSize Size=0]"
"\n\t\t: Dumps content of the active view into image file",
__FILE__,VDump,group);

View File

@ -9982,9 +9982,7 @@ static int VAutoZFit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const
}
aCurrentView->SetAutoZFitMode (isOn, aScale);
aCurrentView->AutoZFit();
aCurrentView->Redraw();
return 0;
}
@ -10022,6 +10020,8 @@ static int VCamera (Draw_Interpretor& theDI,
{
theDI << "ProjType: " << projTypeName (aCamera->ProjectionType()) << "\n";
theDI << "FOVy: " << aCamera->FOVy() << "\n";
theDI << "FOVx: " << aCamera->FOVx() << "\n";
theDI << "FOV2d: " << aCamera->FOV2d() << "\n";
theDI << "Distance: " << aCamera->Distance() << "\n";
theDI << "IOD: " << aCamera->IOD() << "\n";
theDI << "IODType: " << (aCamera->GetIODType() == Graphic3d_Camera::IODType_Absolute ? "absolute" : "relative") << "\n";
@ -10177,18 +10177,83 @@ static int VCamera (Draw_Interpretor& theDI,
case Graphic3d_Camera::FocusType_Relative: theDI << "relative "; break;
}
}
else if (anArgCase == "-lockzup"
|| anArgCase == "-turntable")
{
bool toLockUp = true;
if (++anArgIter < theArgsNb
&& !ViewerTest::ParseOnOff (theArgVec[anArgIter], toLockUp))
{
--anArgIter;
}
ViewerTest::CurrentEventManager()->SetLockOrbitZUp (toLockUp);
}
else if (anArgCase == "-fov"
|| anArgCase == "-fovy")
|| anArgCase == "-fovy"
|| anArgCase == "-fovx"
|| anArgCase == "-fov2d")
{
Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
if (anArgValue != NULL
&& *anArgValue != '-')
{
++anArgIter;
aCamera->SetFOVy (Draw::Atof (anArgValue));
if (anArgCase == "-fov2d")
{
aCamera->SetFOV2d (Draw::Atof (anArgValue));
}
else if (anArgCase == "-fovx")
{
aCamera->SetFOVy (Draw::Atof (anArgValue) / aCamera->Aspect());///
}
else
{
aCamera->SetFOVy (Draw::Atof (anArgValue));
}
continue;
}
theDI << aCamera->FOVy() << " ";
if (anArgCase == "-fov2d")
{
theDI << aCamera->FOV2d() << " ";
}
else if (anArgCase == "-fovx")
{
theDI << aCamera->FOVx() << " ";
}
else
{
theDI << aCamera->FOVy() << " ";
}
}
else if (anArgIter + 1 < theArgsNb
&& anArgCase == "-xrpose")
{
TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
anXRArg.LowerCase();
if (anXRArg == "base")
{
aCamera = aView->View()->BaseXRCamera();
}
else if (anXRArg == "head")
{
aCamera = aView->View()->PosedXRCamera();
}
else
{
Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
return 1;
}
if (aCamera.IsNull())
{
Message::SendFail() << "Error: undefined XR pose";
return 0;
}
if (aView->AutoZFitMode())
{
const Bnd_Box aMinMaxBox = aView->View()->MinMaxValues (false);
const Bnd_Box aGraphicBox = aView->View()->MinMaxValues (true);
aCamera->ZFitAll (aView->AutoZFitScaleFactor(), aMinMaxBox, aGraphicBox);
}
}
else if (aPrsName.IsEmpty()
&& !anArgCase.StartsWith ("-"))
@ -10205,7 +10270,6 @@ static int VCamera (Draw_Interpretor& theDI,
if (aPrsName.IsEmpty()
|| theArgsNb > 2)
{
aView->AutoZFit();
aView->Redraw();
}
@ -10233,7 +10297,7 @@ static int VCamera (Draw_Interpretor& theDI,
ViewerTest::GetAISContext()->Erase (aCameraFrustum, false);
aView->ZFitAll();
}
aCameraFrustum->SetCameraFrustum (aView->Camera());
aCameraFrustum->SetCameraFrustum (aCamera);
ViewerTest::Display (aPrsName, aCameraFrustum);
}
@ -10286,6 +10350,11 @@ inline Standard_Boolean parseStereoMode (Standard_CString theArg,
{
theMode = Graphic3d_StereoMode_SoftPageFlip;
}
else if (aFlag == "openvr"
|| aFlag == "vr")
{
theMode = Graphic3d_StereoMode_OpenVR;
}
else
{
return Standard_False;
@ -10361,6 +10430,7 @@ static int VStereo (Draw_Interpretor& theDI,
case Graphic3d_StereoMode_SideBySide : aMode = "sideBySide"; break;
case Graphic3d_StereoMode_OverUnder : aMode = "overUnder"; break;
case Graphic3d_StereoMode_SoftPageFlip : aMode = "softpageflip"; break;
case Graphic3d_StereoMode_OpenVR : aMode = "openVR"; break;
case Graphic3d_StereoMode_Anaglyph :
aMode = "anaglyph";
switch (aView->RenderingParams().AnaglyphFilter)
@ -10430,7 +10500,10 @@ static int VStereo (Draw_Interpretor& theDI,
aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
}
ViewerTest_myDefaultCaps.contextStereo = Standard_True;
return 0;
if (aParams->StereoMode != Graphic3d_StereoMode_OpenVR)
{
return 0;
}
}
else if (aFlag == "-reverse"
|| aFlag == "-reversed"
@ -10491,6 +10564,34 @@ static int VStereo (Draw_Interpretor& theDI,
ViewerTest_myDefaultCaps.contextStereo = Standard_True;
}
}
else if (anArgIter + 1 < theArgNb
&& aFlag == "-hmdfov2d")
{
aParams->HmdFov2d = (float )Draw::Atof (theArgVec[++anArgIter]);
if (aParams->HmdFov2d < 10.0f
|| aParams->HmdFov2d > 180.0f)
{
Message::SendFail() << "Error: FOV is out of range";
return 1;
}
}
else if (aFlag == "-mirror"
|| aFlag == "-mirrorcomposer")
{
Standard_Boolean toEnable = Standard_True;
if (++anArgIter < theArgNb
&& !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
{
--anArgIter;
}
aParams->ToMirrorComposer = toEnable;
}
else if (anArgIter + 1 < theArgNb
&& (aFlag == "-unitfactor"
|| aFlag == "-unitscale"))
{
aView->View()->SetUnitFactor (Draw::Atof (theArgVec[++anArgIter]));
}
else
{
Message::SendFail() << "Syntax error at '" << anArg << "'";
@ -10502,6 +10603,11 @@ static int VStereo (Draw_Interpretor& theDI,
{
aParams->StereoMode = aMode;
aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
if (aParams->StereoMode == Graphic3d_StereoMode_OpenVR)
{
// initiate implicit continuous rendering
ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
}
}
return 0;
}
@ -13372,6 +13478,7 @@ static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
}
const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
const Handle(V3d_View)& aView = ViewerTest::CurrentView();
if (aContext.IsNull())
{
Message::SendFail ("Error: no active viewer");
@ -13380,6 +13487,7 @@ static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
TCollection_AsciiString aFile;
StdSelect_TypeOfSelectionImage aType = StdSelect_TypeOfSelectionImage_NormalizedDepth;
Handle(Graphic3d_Camera) aCustomCam;
Image_Format anImgFormat = Image_Format_BGR;
Standard_Integer aPickedIndex = 1;
for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
@ -13453,6 +13561,30 @@ static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
aPickedIndex = Draw::Atoi (theArgVec[anArgIter]);
}
else if (anArgIter + 1 < theArgsNb
&& aParam == "-xrpose")
{
TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
anXRArg.LowerCase();
if (anXRArg == "base")
{
aCustomCam = aView->View()->BaseXRCamera();
}
else if (anXRArg == "head")
{
aCustomCam = aView->View()->PosedXRCamera();
}
else
{
Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
return 1;
}
if (aCustomCam.IsNull())
{
Message::SendFail() << "Error: undefined XR pose";
return 0;
}
}
else if (aFile.IsEmpty())
{
aFile = theArgVec[anArgIter];
@ -13469,7 +13601,6 @@ static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
return 1;
}
const Handle(V3d_View)& aView = ViewerTest::CurrentView();
Standard_Integer aWidth = 0, aHeight = 0;
aView->Window()->Size (aWidth, aHeight);
@ -13479,11 +13610,24 @@ static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
Message::SendFail ("Error: can't allocate image");
return 1;
}
const bool wasImmUpdate = aView->SetImmediateUpdate (false);
Handle(Graphic3d_Camera) aCamBack = aView->Camera();
if (!aCustomCam.IsNull())
{
aView->SetCamera (aCustomCam);
}
if (!aContext->MainSelector()->ToPixMap (aPixMap, aView, aType, aPickedIndex))
{
Message::SendFail ("Error: can't generate selection image");
return 1;
}
if (!aCustomCam.IsNull())
{
aView->SetCamera (aCamBack);
}
aView->SetImmediateUpdate (wasImmUpdate);
if (!aPixMap.Save (aFile))
{
Message::SendFail ("Error: can't save selection image");
@ -14208,8 +14352,12 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
__FILE__, VVbo, group);
theCommands.Add ("vstereo",
"vstereo [0|1] [-mode Mode] [-reverse {0|1}]"
"\n\t\t: [-mirrorComposer] [-hmdfov2d AngleDegrees] [-unitFactor MetersFactor]"
"\n\t\t: [-anaglyph Filter]"
"\n\t\t: Control stereo output mode. Available modes for -mode:"
"\n\t\t: Control stereo output mode."
"\n\t\t: When -mirrorComposer is specified, VR rendered frame will be mirrored in window (debug)."
"\n\t\t: Parameter -unitFactor specifies meters scale factor for mapping VR input."
"\n\t\t: Available modes for -mode:"
"\n\t\t: quadBuffer - OpenGL QuadBuffer stereo,"
"\n\t\t: requires driver support."
"\n\t\t: Should be called BEFORE vinit!"
@ -14219,6 +14367,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
"\n\t\t: chessBoard - chess-board output"
"\n\t\t: sideBySide - horizontal pair"
"\n\t\t: overUnder - vertical pair"
"\n\t\t: openVR - OpenVR (HMD)"
"\n\t\t: Available Anaglyph filters for -anaglyph:"
"\n\t\t: redCyan, redCyanSimple, yellowBlue, yellowBlueSimple,"
"\n\t\t: greenMagentaSimple",
@ -14387,6 +14536,8 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
"\n\t\t: [-stereo] [-leftEye] [-rightEye]"
"\n\t\t: [-iod [Distance]] [-iodType [absolute|relative]]"
"\n\t\t: [-zfocus [Value]] [-zfocusType [absolute|relative]]"
"\n\t\t: [-fov2d [Angle]] [-lockZup {0|1}]"
"\n\t\t: [-xrPose base|head=base]"
"\n\t\t: Manages camera parameters."
"\n\t\t: Displays frustum when presntation name PrsName is specified."
"\n\t\t: Prints current value when option called without argument."
@ -14395,7 +14546,9 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
"\n\t\t: Perspective camera:"
"\n\t\t: -persp activate perspective projection (mono)"
"\n\t\t: -fovy field of view in y axis, in degrees"
"\n\t\t: -fov2d field of view limit for 2d on-screen elements"
"\n\t\t: -distance distance of eye from camera center"
"\n\t\t: -lockZup lock Z up (tunrtable mode)"
"\n\t\t: Stereoscopic camera:"
"\n\t\t: -stereo perspective projection (stereo)"
"\n\t\t: -leftEye perspective projection (left eye)"
@ -14658,6 +14811,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
theCommands.Add ("vseldump",
"vseldump file -type {depth|unnormDepth|object|owner|selMode|entity}=depth -pickedIndex Index=1"
"\n\t\t: [-xrPose base|head=base]"
"\n\t\t: Generate an image based on detection results:"
"\n\t\t: depth normalized depth values"
"\n\t\t: unnormDepth unnormalized depth values"

9
src/XRResources/FILES Normal file
View File

@ -0,0 +1,9 @@
srcinc:::occtvr_actions.json
srcinc:::occtvr_bindings_generic.json
srcinc:::occtvr_bindings_holographic_hmd.json
srcinc:::occtvr_bindings_index_hmd.json
srcinc:::occtvr_bindings_rift.json
srcinc:::occtvr_bindings_vive.json
srcinc:::occtvr_bindings_vive_controller.json
srcinc:::occtvr_bindings_vive_cosmos.json
srcinc:::occtvr_bindings_vive_pro.json

View File

@ -0,0 +1,225 @@
{
"actions": [
{
"name": "/actions/generic_head/in/headset_on_head",
"type": "boolean",
"requirement": "optional"
},
{
"name": "/actions/generic_left/in/pose_base",
"type": "pose"
},
{
"name": "/actions/generic_right/in/pose_base",
"type": "pose"
},
{
"name": "/actions/generic_left/in/pose_front",
"type": "pose"
},
{
"name": "/actions/generic_right/in/pose_front",
"type": "pose"
},
{
"name": "/actions/generic_left/in/pose_handgrip",
"type": "pose"
},
{
"name": "/actions/generic_right/in/pose_handgrip",
"type": "pose"
},
{
"name": "/actions/generic_left/in/pose_tip",
"type": "pose"
},
{
"name": "/actions/generic_right/in/pose_tip",
"type": "pose"
},
{
"name": "/actions/generic_left/out/haptic",
"type": "vibration"
},
{
"name": "/actions/generic_right/out/haptic",
"type": "vibration"
},
{
"name": "/actions/generic_left/in/appmenu_click",
"type": "boolean"
},
{
"name": "/actions/generic_right/in/appmenu_click",
"type": "boolean"
},
{
"name": "/actions/generic_left/in/sysmenu_click",
"type": "boolean",
"requirement": "optional"
},
{
"name": "/actions/generic_right/in/sysmenu_click",
"type": "boolean",
"requirement": "optional"
},
{
"name": "/actions/generic_left/in/trigger_click",
"type": "boolean"
},
{
"name": "/actions/generic_right/in/trigger_click",
"type": "boolean"
},
{
"name": "/actions/generic_left/in/trigger_pull",
"type": "vector1"
},
{
"name": "/actions/generic_right/in/trigger_pull",
"type": "vector1"
},
{
"name": "/actions/generic_left/in/grip_click",
"type": "boolean"
},
{
"name": "/actions/generic_right/in/grip_click",
"type": "boolean"
},
{
"name": "/actions/generic_left/in/trackpad_position",
"type": "vector2"
},
{
"name": "/actions/generic_right/in/trackpad_position",
"type": "vector2"
},
{
"name": "/actions/generic_left/in/trackpad_touch",
"type": "boolean"
},
{
"name": "/actions/generic_right/in/trackpad_touch",
"type": "boolean"
},
{
"name": "/actions/generic_left/in/trackpad_click",
"type": "boolean"
},
{
"name": "/actions/generic_right/in/trackpad_click",
"type": "boolean"
},
{
"name": "/actions/generic_left/in/thumbstick_position",
"type": "vector2"
},
{
"name": "/actions/generic_right/in/thumbstick_position",
"type": "vector2"
},
{
"name": "/actions/generic_left/in/thumbstick_touch",
"type": "boolean"
},
{
"name": "/actions/generic_right/in/thumbstick_touch",
"type": "boolean"
},
{
"name": "/actions/generic_left/in/thumbstick_click",
"type": "boolean"
},
{
"name": "/actions/generic_right/in/thumbstick_click",
"type": "boolean"
}
],
"action_sets": [
{
"name": "/actions/generic_head",
"usage": "single"
},
{
"name": "/actions/generic_left",
"usage": "leftright"
},
{
"name": "/actions/generic_right",
"usage": "leftright"
}
],
"default_bindings": [
{
"controller_type": "vive_controller",
"binding_url": "occtvr_bindings_vive_controller.json"
},
{
"controller_type": "generic",
"binding_url": "occtvr_bindings_generic.json"
},
{
"controller_type": "holographic_controller",
"binding_url": "occtvr_bindings_holographic_hmd.json"
},
{
"controller_type": "indexhmd",
"binding_url": "occtvr_bindings_index_hmd.json"
},
{
"controller_type": "rift",
"binding_url": "occtvr_bindings_rift.json"
},
{
"controller_type": "vive",
"binding_url": "occtvr_bindings_vive.json"
},
{
"controller_type": "vive_cosmos",
"binding_url": "occtvr_bindings_vive_cosmos.json"
},
{
"controller_type": "vive_pro",
"binding_url": "occtvr_bindings_vive_pro.json"
}
],
"localization": [
{
"language_tag": "en_US",
"/actions/generic_head/in/headset_on_head": "Headset is on head",
"/actions/generic_left/in/appmenu_click": "Left app menu",
"/actions/generic_left/in/sysmenu_click": "Left system menu",
"/actions/generic_left/in/trigger_click": "Left trigger click",
"/actions/generic_left/in/trigger_pull": "Left trigger squeeze",
"/actions/generic_left/in/grip_click": "Left hand full grip",
"/actions/generic_left/in/pose_base": "Left hand base",
"/actions/generic_left/in/pose_front": "Left hand front",
"/actions/generic_left/in/pose_handgrip": "Left handgrip pose",
"/actions/generic_left/in/pose_tip": "Left forefinger tip",
"/actions/generic_left/in/trackpad_position": "Left trackpad position",
"/actions/generic_left/in/trackpad_touch": "Left trackpad touch",
"/actions/generic_left/in/trackpad_click": "Left trackpad click",
"/actions/generic_left/in/thumbstick_position": "Left thumbstick position",
"/actions/generic_left/in/thumbstick_touch": "Left thumbstick touch",
"/actions/generic_left/in/thumbstick_click": "Left thumbstick click",
"/actions/generic_left/out/haptic": "Left hand haptic",
"/actions/generic_right/in/appmenu_click": "Right app menu",
"/actions/generic_right/in/sysmenu_click": "Right system menu",
"/actions/generic_right/in/trigger_click": "Right trigger click",
"/actions/generic_right/in/trigger_pull": "Right trigger squeeze",
"/actions/generic_right/in/grip_click": "Right hand full grip",
"/actions/generic_right/in/pose_base": "Right hand base",
"/actions/generic_right/in/pose_front": "Right hand front",
"/actions/generic_right/in/pose_handgrip": "Right handgrip pose",
"/actions/generic_right/in/pose_tip": "Right forefinger tip",
"/actions/generic_right/in/trackpad_position": "Right trackpad position",
"/actions/generic_right/in/trackpad_touch": "Right trackpad touch",
"/actions/generic_right/in/trackpad_click": "Right trackpad click",
"/actions/generic_right/in/thumbstick_position": "Right thumbstick position",
"/actions/generic_right/in/thumbstick_touch": "Right thumbstick touch",
"/actions/generic_right/in/thumbstick_click": "Right thumbstick click",
"/actions/generic_right/out/haptic": "Right hand haptic"
}
]
}

View File

@ -0,0 +1,87 @@
{
"bindings": {
"/actions/generic_left": {
"haptics": [
{
"output": "/actions/generic_left/out/haptic",
"path": "/user/hand/left/output/haptic"
}
],
"sources": [
{
"inputs": {
"click": { "output": "/actions/generic_left/in/appmenu_click" }
},
"mode": "button",
"path": "/user/hand/left/input/application_menu"
},
{
"inputs": {
"click": { "output": "/actions/generic_left/in/trigger_click" }
},
"mode": "button",
"path": "/user/hand/left/input/trigger"
},
{
"inputs": {
"click": { "output": "/actions/generic_left/in/trackpad_click" },
"touch": { "output": "/actions/generic_left/in/trackpad_touch" },
"position": { "output": "/actions/generic_left/in/trackpad_position" }
},
"mode": "trackpad",
"path": "/user/hand/left/input/trackpad"
},
{
"inputs": {
"click": { "output": "/actions/generic_left/in/grip_click" }
},
"mode": "button",
"path": "/user/hand/left/input/grip"
}
]
},
"/actions/generic_right": {
"haptics": [
{
"output": "/actions/generic_right/out/haptic",
"path": "/user/hand/right/output/haptic"
}
],
"sources": [
{
"inputs": {
"click": { "output": "/actions/generic_right/in/appmenu_click" }
},
"mode": "button",
"path": "/user/hand/right/input/application_menu"
},
{
"inputs": {
"click": { "output": "/actions/generic_right/in/trigger_click" }
},
"mode": "button",
"path": "/user/hand/right/input/trigger"
},
{
"inputs": {
"click": { "output": "/actions/generic_right/in/trackpad_click" },
"touch": { "output": "/actions/generic_right/in/trackpad_touch" },
"position": { "output": "/actions/generic_right/in/trackpad_position" }
},
"mode": "trackpad",
"path": "/user/hand/right/input/trackpad"
},
{
"inputs": {
"click": { "output": "/actions/generic_right/in/grip_click" }
},
"mode": "button",
"path": "/user/hand/right/input/grip"
}
]
}
},
"controller_type": "generic",
"description": "Standard Open CASCADE Technology VR bindings for a generic controller",
"name": "OCCT VR bindings for a generic controller"
}

View File

@ -0,0 +1,18 @@
{
"bindings": {
"/actions/generic_head": {
"sources": [
{
"inputs": {
"click": { "output": "/actions/generic_head/in/headset_on_head" }
},
"mode": "button",
"path": "/user/head/proximity"
}
]
}
},
"controller_type": "holographic_hmd",
"description": "",
"name": "holographic_hmd defaults"
}

View File

@ -0,0 +1,18 @@
{
"bindings": {
"/actions/generic_head": {
"sources": [
{
"inputs": {
"click": { "output": "/actions/generic_head/in/headset_on_head" }
},
"mode": "button",
"path": "/user/head/proximity"
}
]
}
},
"controller_type": "indexhmd",
"description": "",
"name": "index hmd defaults"
}

View File

@ -0,0 +1,18 @@
{
"bindings": {
"/actions/generic_head": {
"sources": [
{
"inputs": {
"click": { "output": "/actions/generic_head/in/headset_on_head" }
},
"mode": "button",
"path": "/user/head/proximity"
}
]
}
},
"controller_type": "rift",
"description": "",
"name": "rift defaults"
}

View File

@ -0,0 +1,18 @@
{
"bindings": {
"/actions/generic_head": {
"sources": [
{
"inputs": {
"click": { "output": "/actions/generic_head/in/headset_on_head" }
},
"mode": "button",
"path": "/user/head/proximity"
}
]
}
},
"controller_type": "vive",
"description": "",
"name": "vive defaults"
}

View File

@ -0,0 +1,139 @@
{
"bindings": {
"/actions/generic_left": {
"haptics": [
{
"output": "/actions/generic_left/out/haptic",
"path": "/user/hand/left/output/haptic"
}
],
"poses": [
{
"output": "/actions/generic_left/in/pose_base",
"path": "/user/hand/left/pose/base"
},
{
"output": "/actions/generic_left/in/pose_front",
"path": "/user/hand/left/pose/front"
},
{
"output": "/actions/generic_left/in/pose_handgrip",
"path": "/user/hand/left/pose/handgrip"
},
{
"output": "/actions/generic_left/in/pose_tip",
"path": "/user/hand/left/pose/tip"
}
],
"sources": [
{
"inputs": {
"click": { "output": "/actions/generic_left/in/appmenu_click" }
},
"mode": "button",
"path": "/user/hand/left/input/application_menu"
},
{
"inputs": {
"click": { "output": "/actions/generic_left/in/trigger_click" },
"pull": { "output": "/actions/generic_left/in/trigger_pull" }
},
"mode": "trigger",
"path": "/user/hand/left/input/trigger"
},
{
"inputs": {
"click": { "output": "/actions/generic_left/in/trackpad_click" },
"touch": { "output": "/actions/generic_left/in/trackpad_touch" },
"position": { "output": "/actions/generic_left/in/trackpad_position" }
},
"mode": "trackpad",
"path": "/user/hand/left/input/trackpad"
},
{
"inputs": {
"click": { "output": "/actions/generic_left/in/grip_click" }
},
"mode": "button",
"path": "/user/hand/left/input/grip"
},
{
"inputs": {
"click": { "output": "/actions/generic_left/in/sysmenu_click" }
},
"mode": "button",
"path": "/user/hand/left/input/system"
}
]
},
"/actions/generic_right": {
"haptics": [
{
"output": "/actions/generic_right/out/haptic",
"path": "/user/hand/right/output/haptic"
}
],
"poses": [
{
"output": "/actions/generic_right/in/pose_base",
"path": "/user/hand/right/pose/base"
},
{
"output": "/actions/generic_right/in/pose_front",
"path": "/user/hand/right/pose/front"
},
{
"output": "/actions/generic_right/in/pose_handgrip",
"path": "/user/hand/right/pose/handgrip"
},
{
"output": "/actions/generic_right/in/pose_tip",
"path": "/user/hand/right/pose/tip"
}
],
"sources": [
{
"inputs": {
"click": { "output": "/actions/generic_right/in/appmenu_click" }
},
"mode": "button",
"path": "/user/hand/right/input/application_menu"
},
{
"inputs": {
"click": { "output": "/actions/generic_right/in/trigger_click" },
"pull": { "output": "/actions/generic_right/in/trigger_pull" }
},
"mode": "trigger",
"path": "/user/hand/right/input/trigger"
},
{
"inputs": {
"click": { "output": "/actions/generic_right/in/trackpad_click" },
"touch": { "output": "/actions/generic_right/in/trackpad_touch" },
"position": { "output": "/actions/generic_right/in/trackpad_position" }
},
"mode": "trackpad",
"path": "/user/hand/right/input/trackpad"
},
{
"inputs": {
"click": { "output": "/actions/generic_right/in/grip_click" }
},
"mode": "button",
"path": "/user/hand/right/input/grip"
},
{
"inputs": {
"click": { "output": "/actions/generic_right/in/sysmenu_click" }
},
"mode": "button",
"path": "/user/hand/right/input/system"
}
]
}
},
"controller_type": "vive_controller",
"description": "Standard Open CASCADE Technology VR bindings for the Vive controller",
"name": "OCCT VR bindings for the Vive controller"
}

View File

@ -0,0 +1,18 @@
{
"bindings": {
"/actions/generic_head": {
"sources": [
{
"inputs": {
"click": { "output": "/actions/generic_head/in/headset_on_head" }
},
"mode": "button",
"path": "/user/head/proximity"
}
]
}
},
"controller_type": "vive_cosmos",
"description": "",
"name": "vive cosmos hmd defaults",
}

View File

@ -0,0 +1,18 @@
{
"bindings": {
"/actions/generic_head": {
"sources": [
{
"inputs": {
"click": { "output": "/actions/generic_head/in/headset_on_head" }
},
"mode": "button",
"path": "/user/head/proximity"
}
]
}
},
"controller_type": "vive_pro",
"description": "",
"name": "vive_pro defaults"
}