1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-09 13:22:24 +03:00

0030640: Visualization, Graphic3d_Camera - add option creating Projection matrix with [0,1] depth range

Added new property Graphic3d_Camera::IsZeroToOneDepth() and OpenGl_Caps::useZeroToOneDepth
for activating [0,1] depth range instead of [-1,1] range using glClipControl() within OpenGL 4.5+.
This commit is contained in:
kgv
2019-04-08 19:47:20 +03:00
parent 1d09c51ac2
commit 5b5f819f51
15 changed files with 124 additions and 19 deletions

View File

@@ -87,6 +87,7 @@ Graphic3d_Camera::Graphic3d_Camera()
myZNear (DEFAULT_ZNEAR),
myZFar (DEFAULT_ZFAR),
myAspect (1.0),
myIsZeroToOneDepth (false),
myScale (1000.0),
myZFocus (1.0),
myZFocusType (FocusType_Relative),
@@ -979,7 +980,7 @@ void Graphic3d_Camera::OrthoProj (const Elem_t theLeft,
const Elem_t theTop,
const Elem_t theNear,
const Elem_t theFar,
NCollection_Mat4<Elem_t>& theOutMx)
NCollection_Mat4<Elem_t>& theOutMx) const
{
// row 0
theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theRight - theLeft);
@@ -996,8 +997,16 @@ void Graphic3d_Camera::OrthoProj (const Elem_t theLeft,
// row 2
theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear);
theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear);
if (myIsZeroToOneDepth)
{
theOutMx.ChangeValue (2, 2) = Elem_t (-1.0) / (theFar - theNear);
theOutMx.ChangeValue (2, 3) = -theNear / (theFar - theNear);
}
else
{
theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear);
theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear);
}
// row 3
theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
@@ -1017,7 +1026,7 @@ void Graphic3d_Camera::PerspectiveProj (const Elem_t theLeft,
const Elem_t theTop,
const Elem_t theNear,
const Elem_t theFar,
NCollection_Mat4<Elem_t>& theOutMx)
NCollection_Mat4<Elem_t>& theOutMx) const
{
// column 0
theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theRight - theLeft);
@@ -1034,13 +1043,27 @@ void Graphic3d_Camera::PerspectiveProj (const Elem_t theLeft,
// column 2
theOutMx.ChangeValue (0, 2) = (theRight + theLeft) / (theRight - theLeft);
theOutMx.ChangeValue (1, 2) = (theTop + theBottom) / (theTop - theBottom);
theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear);
if (myIsZeroToOneDepth)
{
theOutMx.ChangeValue (2, 2) = theFar / (theNear - theFar);
}
else
{
theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear);
}
theOutMx.ChangeValue (3, 2) = Elem_t (-1.0);
// column 3
theOutMx.ChangeValue (0, 3) = Elem_t (0.0);
theOutMx.ChangeValue (1, 3) = Elem_t (0.0);
theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear);
if (myIsZeroToOneDepth)
{
theOutMx.ChangeValue (2, 3) = -(theFar * theNear) / (theFar - theNear);
}
else
{
theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear);
}
theOutMx.ChangeValue (3, 3) = Elem_t (0.0);
}
@@ -1058,7 +1081,7 @@ void Graphic3d_Camera::StereoEyeProj (const Elem_t theLeft,
const Elem_t theIOD,
const Elem_t theZFocus,
const Standard_Boolean theIsLeft,
NCollection_Mat4<Elem_t>& theOutMx)
NCollection_Mat4<Elem_t>& theOutMx) const
{
Elem_t aDx = theIsLeft ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD;
Elem_t aDXStereoShift = aDx * theNear / theZFocus;
@@ -1405,12 +1428,10 @@ void Graphic3d_Camera::FrustumPoints (NCollection_Array1<Graphic3d_Vec3d>& thePo
Standard_Real nLeft = 0.0, nRight = 0.0, nTop = 0.0, nBottom = 0.0;
Standard_Real fLeft = 0.0, fRight = 0.0, fTop = 0.0, fBottom = 0.0;
Standard_Real aNear = 0.0, aFar = 0.0;
Standard_Real aNear = myZNear, aFar = myZFar;
if (!IsOrthographic())
{
// handle perspective projection
aNear = aProjectionMat.GetValue (2, 3) / (-1.0 + aProjectionMat.GetValue (2, 2));
aFar = aProjectionMat.GetValue (2, 3) / ( 1.0 + aProjectionMat.GetValue (2, 2));
// Near plane
nLeft = aNear * (aProjectionMat.GetValue (0, 2) - 1.0) / aProjectionMat.GetValue (0, 0);
nRight = aNear * (aProjectionMat.GetValue (0, 2) + 1.0) / aProjectionMat.GetValue (0, 0);
@@ -1425,8 +1446,6 @@ void Graphic3d_Camera::FrustumPoints (NCollection_Array1<Graphic3d_Vec3d>& thePo
else
{
// handle orthographic projection
aNear = (1.0 / aProjectionMat.GetValue (2, 2)) * (aProjectionMat.GetValue (2, 3) + 1.0);
aFar = (1.0 / aProjectionMat.GetValue (2, 2)) * (aProjectionMat.GetValue (2, 3) - 1.0);
// Near plane
nLeft = ( 1.0 + aProjectionMat.GetValue (0, 3)) / (-aProjectionMat.GetValue (0, 0));
fLeft = nLeft;

View File

@@ -326,6 +326,20 @@ public:
return myZFar;
}
//! Return TRUE if camera should calculate projection matrix for [0, 1] depth range or for [-1, 1] range.
//! FALSE by default.
Standard_Boolean IsZeroToOneDepth() const { return myIsZeroToOneDepth; }
//! Set using [0, 1] depth range or [-1, 1] range.
void SetZeroToOneDepth (Standard_Boolean theIsZeroToOne)
{
if (myIsZeroToOneDepth != theIsZeroToOne)
{
myIsZeroToOneDepth = theIsZeroToOne;
InvalidateProjection();
}
}
//! Changes width / height display ratio.
//! @param theAspect [in] the display ratio.
Standard_EXPORT void SetAspect (const Standard_Real theAspect);
@@ -562,14 +576,14 @@ private:
//! @param theFar [in] the far mapping (clipping) coordinate.
//! @param theOutMx [out] the projection matrix.
template <typename Elem_t>
static void
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);
NCollection_Mat4<Elem_t>& theOutMx) const;
//! Compose perspective projection matrix for
//! the passed camera volume mapping.
@@ -581,14 +595,14 @@ private:
//! @param theFar [in] the far mapping (clipping) coordinate.
//! @param theOutMx [out] the projection matrix.
template <typename Elem_t>
static void
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);
NCollection_Mat4<Elem_t>& theOutMx) const;
//! Compose projection matrix for L/R stereo eyes.
//! @param theLeft [in] the left mapping (clipping) coordinate.
@@ -603,7 +617,7 @@ private:
//! @param theIsLeft [in] boolean flag to choose between L/R eyes.
//! @param theOutMx [out] the projection matrix.
template <typename Elem_t>
static void
void
StereoEyeProj (const Elem_t theLeft,
const Elem_t theRight,
const Elem_t theBottom,
@@ -613,7 +627,7 @@ private:
const Elem_t theIOD,
const Elem_t theZFocus,
const Standard_Boolean theIsLeft,
NCollection_Mat4<Elem_t>& theOutMx);
NCollection_Mat4<Elem_t>& theOutMx) const;
//! Construct "look at" orientation transformation.
//! Reference point differs for perspective and ortho modes
@@ -666,6 +680,7 @@ private:
Standard_Real myZNear; //!< Distance to near clipping plane.
Standard_Real myZFar; //!< Distance to far clipping plane.
Standard_Real myAspect; //!< Width to height display ratio.
Standard_Boolean myIsZeroToOneDepth; //!< use [0, 1] depth range or [-1, 1]
Standard_Real myScale; //!< Specifies parallel scale for orthographic projection.
Standard_Real myZFocus; //!< Stereographic focus value.

View File

@@ -36,6 +36,7 @@ OpenGl_Caps::OpenGl_Caps()
useSystemBuffer (Standard_True),
#endif
swapInterval (1),
useZeroToOneDepth (true), ///(Standard_False),
buffersNoSwap (Standard_False),
contextStereo (Standard_False),
#ifdef OCCT_DEBUG
@@ -70,6 +71,7 @@ OpenGl_Caps& OpenGl_Caps::operator= (const OpenGl_Caps& theCopy)
ffpEnable = theCopy.ffpEnable;
useSystemBuffer = theCopy.useSystemBuffer;
swapInterval = theCopy.swapInterval;
useZeroToOneDepth = theCopy.useZeroToOneDepth;
buffersNoSwap = theCopy.buffersNoSwap;
contextStereo = theCopy.contextStereo;
contextDebug = theCopy.contextDebug;

View File

@@ -34,6 +34,7 @@ public: //! @name flags to disable particular functionality, should be used only
Standard_Boolean usePolygonMode; //!< Enables Polygon Mode instead of built-in GLSL programs (OFF by default; unsupported on OpenGL ES)
Standard_Boolean useSystemBuffer; //!< Enables usage of system backbuffer for blitting (OFF by default on desktop OpenGL and ON on OpenGL ES for testing)
Standard_Integer swapInterval; //!< controls swap interval - 0 for VSync off and 1 for VSync on, 1 by default
Standard_Boolean useZeroToOneDepth; //!< use [0, 1] depth range instead of [-1, 1] range, when possible (OFF by default)
public: //! @name context creation parameters

View File

@@ -136,6 +136,7 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
arbTexBindless (NULL),
arbTBO (NULL),
arbTboRGB32 (Standard_False),
arbClipControl (Standard_False),
arbIns (NULL),
arbDbg (NULL),
arbFBO (NULL),
@@ -1272,6 +1273,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
core45back = NULL;
arbTBO = NULL;
arbTboRGB32 = Standard_False;
arbClipControl = Standard_False;
arbIns = NULL;
arbDbg = NULL;
arbFBO = NULL;
@@ -2549,6 +2551,12 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
arbTexBindless = (OpenGl_ArbTexBindless* )(&(*myFuncs));
}
if (CheckExtension ("GL_ARB_clip_control")
&& FindProcShort (glClipControl))
{
arbClipControl = Standard_True;
}
if (!has12)
{
checkWrongVersion (1, 2);
@@ -2775,6 +2783,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
return;
}
core45 = (OpenGl_GlCore45* )(&(*myFuncs));
arbClipControl = Standard_True;
if (!isCoreProfile)
{
core45back = (OpenGl_GlCore45Back* )(&(*myFuncs));

View File

@@ -881,6 +881,7 @@ public: //! @name extensions
OpenGl_ArbTexBindless* arbTexBindless; //!< GL_ARB_bindless_texture
OpenGl_ArbTBO* arbTBO; //!< GL_ARB_texture_buffer_object
Standard_Boolean arbTboRGB32; //!< GL_ARB_texture_buffer_object_rgb32 (3-component TBO), in core since 4.0
Standard_Boolean arbClipControl; //!< GL_ARB_clip_control, in core since 4.5
OpenGl_ArbIns* arbIns; //!< GL_ARB_draw_instanced
OpenGl_ArbDbg* arbDbg; //!< GL_ARB_debug_output
OpenGl_ArbFBO* arbFBO; //!< GL_ARB_framebuffer_object

View File

@@ -662,6 +662,9 @@ protected: //! @name data types related to ray-tracing
//! Actual ray-tracing depth (number of ray bounces).
Standard_Integer NbBounces;
//! Define depth computation
Standard_Boolean IsZeroToOneDepth;
//! Enables/disables light propagation through transparent media.
Standard_Boolean TransparentShadows;
@@ -696,6 +699,7 @@ protected: //! @name data types related to ray-tracing
RaytracingParams()
: StackSize (THE_DEFAULT_STACK_SIZE),
NbBounces (THE_DEFAULT_NB_BOUNCES),
IsZeroToOneDepth (Standard_False),
TransparentShadows (Standard_False),
GlobalIllumination (Standard_False),
UseBindlessTextures (Standard_False),

View File

@@ -1115,6 +1115,11 @@ TCollection_AsciiString OpenGl_View::generateShaderPrefix (const Handle(OpenGl_C
TCollection_AsciiString ("#define STACK_SIZE ") + TCollection_AsciiString (myRaytraceParameters.StackSize) + "\n" +
TCollection_AsciiString ("#define NB_BOUNCES ") + TCollection_AsciiString (myRaytraceParameters.NbBounces);
if (myRaytraceParameters.IsZeroToOneDepth)
{
aPrefixString += TCollection_AsciiString ("\n#define ZERO_TO_ONE_DEPTH");
}
if (myRaytraceParameters.TransparentShadows)
{
aPrefixString += TCollection_AsciiString ("\n#define TRANSPARENT_SHADOWS");
@@ -1377,12 +1382,16 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Standard_Integer theS
}
}
if (myRenderParams.RaytracingDepth != myRaytraceParameters.NbBounces
const bool isZeroToOneDepth = myCaps->useZeroToOneDepth
&& myWorkspace->GetGlContext()->arbClipControl;
if (isZeroToOneDepth != myRaytraceParameters.IsZeroToOneDepth
|| myRenderParams.RaytracingDepth != myRaytraceParameters.NbBounces
|| myRenderParams.IsTransparentShadowEnabled != myRaytraceParameters.TransparentShadows
|| myRenderParams.IsGlobalIlluminationEnabled != myRaytraceParameters.GlobalIllumination
|| myRenderParams.TwoSidedBsdfModels != myRaytraceParameters.TwoSidedBsdfModels
|| myRaytraceGeometry.HasTextures() != myRaytraceParameters.UseBindlessTextures)
{
myRaytraceParameters.IsZeroToOneDepth = isZeroToOneDepth;
myRaytraceParameters.NbBounces = myRenderParams.RaytracingDepth;
myRaytraceParameters.TransparentShadows = myRenderParams.IsTransparentShadowEnabled;
myRaytraceParameters.GlobalIllumination = myRenderParams.IsGlobalIlluminationEnabled;

View File

@@ -168,6 +168,17 @@ void OpenGl_View::Redraw()
aCtx->FrameStats()->FrameStart (myWorkspace->View(), false);
aCtx->SetLineFeather (myRenderParams.LineFeather);
#if !defined(GL_ES_VERSION_2_0)
if (aCtx->arbClipControl)
{
if (myCaps->useZeroToOneDepth != myCamera->IsZeroToOneDepth())
{
myCamera->SetZeroToOneDepth (myCaps->useZeroToOneDepth);
}
aCtx->Functions()->glClipControl (GL_LOWER_LEFT, myCamera->IsZeroToOneDepth() ? GL_ZERO_TO_ONE : GL_NEGATIVE_ONE_TO_ONE);
}
#endif
// release pending GL resources
aCtx->ReleaseDelayed();

View File

@@ -180,6 +180,7 @@ static NCollection_Vec4<Standard_Real> safePointCast (const gp_Pnt& thePnt)
//=======================================================================
gp_Pnt SelectMgr_FrustumBuilder::unProject (const gp_Pnt& thePnt) const
{
/// TODO why these are not cached?
Graphic3d_Mat4d aInvView;
Graphic3d_Mat4d aInvProj;
@@ -217,6 +218,7 @@ gp_Pnt SelectMgr_FrustumBuilder::ProjectPntOnViewPlane (const Standard_Real& the
{
aX = 2.0 * theX / myWidth - 1.0;
anY = (myHeight - 1 - theY) / myHeight * 2.0 - 1.0;
/// TODO wrong NDC
aZ = 2.0 * theZ - 1.0;
}
else

View File

@@ -804,7 +804,11 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse, in int theNbSamples)
vec4 aNDCPoint = uViewMat * vec4 (theRay.Origin, 1.f);
float aPolygonOffset = PolygonOffset (aHit.Normal, theRay.Origin);
#ifdef ZERO_TO_ONE_DEPTH
aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w + aPolygonOffset * POLYGON_OFFSET_SCALE);
#else
aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w + aPolygonOffset * POLYGON_OFFSET_SCALE) * 0.5f + 0.5f;
#endif
}
SBSDF aBSDF;

View File

@@ -1012,7 +1012,11 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
vec4 aNDCPoint = uViewMat * vec4 (theRay.Origin, 1.f);
float aPolygonOffset = PolygonOffset (aHit.Normal, theRay.Origin);
#ifdef ZERO_TO_ONE_DEPTH
aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w + aPolygonOffset * POLYGON_OFFSET_SCALE);
#else
aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w + aPolygonOffset * POLYGON_OFFSET_SCALE) * 0.5f + 0.5f;
#endif
}
vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);

View File

@@ -807,7 +807,11 @@ static const char Shaders_PathtraceBase_fs[] =
" vec4 aNDCPoint = uViewMat * vec4 (theRay.Origin, 1.f);\n"
"\n"
" float aPolygonOffset = PolygonOffset (aHit.Normal, theRay.Origin);\n"
" #ifdef ZERO_TO_ONE_DEPTH\n"
" aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w + aPolygonOffset * POLYGON_OFFSET_SCALE);\n"
" #else\n"
" aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w + aPolygonOffset * POLYGON_OFFSET_SCALE) * 0.5f + 0.5f;\n"
" #endif\n"
" }\n"
"\n"
" SBSDF aBSDF;\n"

View File

@@ -1015,7 +1015,11 @@ static const char Shaders_RaytraceBase_fs[] =
" vec4 aNDCPoint = uViewMat * vec4 (theRay.Origin, 1.f);\n"
"\n"
" float aPolygonOffset = PolygonOffset (aHit.Normal, theRay.Origin);\n"
" #ifdef ZERO_TO_ONE_DEPTH\n"
" aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w + aPolygonOffset * POLYGON_OFFSET_SCALE);\n"
" #else\n"
" aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w + aPolygonOffset * POLYGON_OFFSET_SCALE) * 0.5f + 0.5f;\n"
" #endif\n"
" }\n"
"\n"
" vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);\n"

View File

@@ -6250,6 +6250,7 @@ static int VCaps (Draw_Interpretor& theDI,
theDI << "SoftMode:" << (aCaps->contextNoAccel ? "1" : "0") << "\n";
theDI << "FFP: " << (aCaps->ffpEnable ? "1" : "0") << "\n";
theDI << "PolygonMode: " << (aCaps->usePolygonMode ? "1" : "0") << "\n";
theDI << "DepthZeroToOne: " << (aCaps->useZeroToOneDepth ? "1" : "0") << "\n";
theDI << "VSync: " << aCaps->swapInterval << "\n";
theDI << "Compatible:" << (aCaps->contextCompatible ? "1" : "0") << "\n";
theDI << "Stereo: " << (aCaps->contextStereo ? "1" : "0") << "\n";
@@ -6319,6 +6320,19 @@ static int VCaps (Draw_Interpretor& theDI,
}
aCaps->pntSpritesDisable = !toEnable;
}
else if (anArgCase == "-depthzerotoone"
|| anArgCase == "-zerotoonedepth"
|| anArgCase == "-usezerotoonedepth"
|| anArgCase == "-iszerotoonedepth")
{
Standard_Boolean toEnable = Standard_True;
if (++anArgIter < theArgNb
&& !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
{
--anArgIter;
}
aCaps->useZeroToOneDepth = toEnable;
}
else if (anArgCase == "-softmode")
{
Standard_Boolean toEnable = Standard_True;
@@ -12993,6 +13007,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
__FILE__, VStereo, group);
theCommands.Add ("vcaps",
"vcaps [-vbo {0|1}] [-sprites {0|1}] [-ffp {0|1}] [-polygonMode {0|1}]"
"\n\t\t: [-zeroToOneDepth {0|1}]"
"\n\t\t: [-compatibleProfile {0|1}]"
"\n\t\t: [-vsync {0|1}] [-useWinBuffer {0|1}]"
"\n\t\t: [-quadBuffer {0|1}] [-stereo {0|1}]"
@@ -13007,6 +13022,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
"\n\t\t: sprite - use textured sprites instead of bitmaps"
"\n\t\t: vsync - switch VSync on or off"
"\n\t\t: winBuffer - allow using window buffer for rendering"
"\n\t\t: zeroToOneDepth - use [0,1] depth range instead of [-1,1] range"
"\n\t\t: Context creation options:"
"\n\t\t: softMode - software OpenGL implementation"
"\n\t\t: compatibleProfile - backward-compatible profile"