// purpose :
// =======================================================================
OpenGl_BVHTreeSelector::OpenGl_BVHTreeSelector()
-: myIsProjectionParallel (Standard_True),
- myProjectionState (0),
- myModelViewState (0)
+: myClipVerts (0, Graphic3d_Camera::FrustumVerticesNB),
+ myIsProjectionParallel (Standard_True),
+ myCamScale (1.0),
+ myPixelSize (1.0)
{
//
}
// =======================================================================
-// function : SetClipVolume
-// purpose : Retrieves view volume's planes equations and its vertices from projection and modelview matrices.
+// function : SetViewVolume
+// purpose : Retrieves view volume's planes equations and its vertices from projection and world-view matrices.
// =======================================================================
void OpenGl_BVHTreeSelector::SetViewVolume (const Handle(Graphic3d_Camera)& theCamera)
{
- myIsProjectionParallel = theCamera->IsOrthographic();
- const OpenGl_Mat4& aProjMat = theCamera->ProjectionMatrixF();
- const OpenGl_Mat4& aModelMat = theCamera->OrientationMatrixF();
-
- Standard_ShortReal nLeft = 0.0f, nRight = 0.0f, nTop = 0.0f, nBottom = 0.0f;
- Standard_ShortReal fLeft = 0.0f, fRight = 0.0f, fTop = 0.0f, fBottom = 0.0f;
- Standard_ShortReal aNear = 0.0f, aFar = 0.0f;
- if (!myIsProjectionParallel)
- {
- // handle perspective projection
- aNear = aProjMat.GetValue (2, 3) / (- 1.0f + aProjMat.GetValue (2, 2));
- aFar = aProjMat.GetValue (2, 3) / ( 1.0f + aProjMat.GetValue (2, 2));
- // Near plane
- nLeft = aNear * (aProjMat.GetValue (0, 2) - 1.0f) / aProjMat.GetValue (0, 0);
- nRight = aNear * (aProjMat.GetValue (0, 2) + 1.0f) / aProjMat.GetValue (0, 0);
- nTop = aNear * (aProjMat.GetValue (1, 2) + 1.0f) / aProjMat.GetValue (1, 1);
- nBottom = aNear * (aProjMat.GetValue (1, 2) - 1.0f) / aProjMat.GetValue (1, 1);
- // Far plane
- fLeft = aFar * (aProjMat.GetValue (0, 2) - 1.0f) / aProjMat.GetValue (0, 0);
- fRight = aFar * (aProjMat.GetValue (0, 2) + 1.0f) / aProjMat.GetValue (0, 0);
- fTop = aFar * (aProjMat.GetValue (1, 2) + 1.0f) / aProjMat.GetValue (1, 1);
- fBottom = aFar * (aProjMat.GetValue (1, 2) - 1.0f) / aProjMat.GetValue (1, 1);
- }
- else
- {
- // handle orthographic projection
- aNear = (1.0f / aProjMat.GetValue (2, 2)) * (aProjMat.GetValue (2, 3) + 1.0f);
- aFar = (1.0f / aProjMat.GetValue (2, 2)) * (aProjMat.GetValue (2, 3) - 1.0f);
- // Near plane
- nLeft = ( 1.0f + aProjMat.GetValue (0, 3)) / (-aProjMat.GetValue (0, 0));
- fLeft = nLeft;
- nRight = ( 1.0f - aProjMat.GetValue (0, 3)) / aProjMat.GetValue (0, 0);
- fRight = nRight;
- nTop = ( 1.0f - aProjMat.GetValue (1, 3)) / aProjMat.GetValue (1, 1);
- fTop = nTop;
- nBottom = (-1.0f - aProjMat.GetValue (1, 3)) / aProjMat.GetValue (1, 1);
- fBottom = nBottom;
- }
+ if (!myWorldViewProjState.IsChanged (theCamera->WorldViewProjState()))
+ return;
- OpenGl_Vec4 aLeftTopNear (nLeft, nTop, -aNear, 1.0f), aRightBottomFar (fRight, fBottom, -aFar, 1.0f);
- OpenGl_Vec4 aLeftBottomNear (nLeft, nBottom, -aNear, 1.0f), aRightTopFar (fRight, fTop, -aFar, 1.0f);
- OpenGl_Vec4 aRightBottomNear (nRight, nBottom, -aNear, 1.0f), aLeftTopFar (fLeft, fTop, -aFar, 1.0f);
- OpenGl_Vec4 aRightTopNear (nRight, nTop, -aNear, 1.0f), aLeftBottomFar (fLeft, fBottom, -aFar, 1.0f);
-
- const OpenGl_Mat4 aViewProj = aModelMat * aProjMat;
- OpenGl_Mat4 anInvModelView;
- aModelMat.Inverted(anInvModelView);
-
- myClipVerts[ClipVert_LeftTopNear] = anInvModelView * aLeftTopNear;
- myClipVerts[ClipVert_RightBottomFar] = anInvModelView * aRightBottomFar;
- myClipVerts[ClipVert_LeftBottomNear] = anInvModelView * aLeftBottomNear;
- myClipVerts[ClipVert_RightTopFar] = anInvModelView * aRightTopFar;
- myClipVerts[ClipVert_RightBottomNear] = anInvModelView * aRightBottomNear;
- myClipVerts[ClipVert_LeftTopFar] = anInvModelView * aLeftTopFar;
- myClipVerts[ClipVert_RightTopNear] = anInvModelView * aRightTopNear;
- myClipVerts[ClipVert_LeftBottomFar] = anInvModelView * aLeftBottomFar;
-
- // UNNORMALIZED!
- myClipPlanes[Plane_Left] = aViewProj.GetRow (3) + aViewProj.GetRow (0);
- myClipPlanes[Plane_Right] = aViewProj.GetRow (3) - aViewProj.GetRow (0);
- myClipPlanes[Plane_Top] = aViewProj.GetRow (3) - aViewProj.GetRow (1);
- myClipPlanes[Plane_Bottom] = aViewProj.GetRow (3) + aViewProj.GetRow (1);
- myClipPlanes[Plane_Near] = aViewProj.GetRow (3) + aViewProj.GetRow (2);
- myClipPlanes[Plane_Far] = aViewProj.GetRow (3) - aViewProj.GetRow (2);
-
- gp_Pnt aPtCenter = theCamera->Center();
- OpenGl_Vec4 aCenter (static_cast<Standard_ShortReal> (aPtCenter.X()),
- static_cast<Standard_ShortReal> (aPtCenter.Y()),
- static_cast<Standard_ShortReal> (aPtCenter.Z()),
- 1.0f);
-
- for (Standard_Integer aPlaneIter = 0; aPlaneIter < PlanesNB; ++aPlaneIter)
+ myIsProjectionParallel = theCamera->IsOrthographic();
+ const gp_Dir aCamDir = theCamera->Direction();
+
+ myCamera = theCamera;
+ myProjectionMat = theCamera->ProjectionMatrix();
+ myWorldViewMat = theCamera->OrientationMatrix();
+ myWorldViewProjState = theCamera->WorldViewProjState();
+ myCamEye.SetValues (theCamera->Eye().X(), theCamera->Eye().Y(), theCamera->Eye().Z());
+ myCamDir.SetValues (aCamDir.X(), aCamDir.Y(), aCamDir.Z());
+ myCamScale = theCamera->IsOrthographic()
+ ? theCamera->Scale()
+ : 2.0 * Tan (theCamera->FOVy() * M_PI / 360.0); // same as theCamera->Scale()/theCamera->Distance()
+
+ // Compute frustum points
+ theCamera->FrustumPoints (myClipVerts);
+
+ // Compute frustum planes
+ // Vertices go in order:
+ // 0, 2, 1
+ const Standard_Integer aLookup1[] = { 0, 1, 0 };
+ const Standard_Integer aLookup2[] = { 0, 0, 1 };
+ Standard_Integer aShifts[] = { 0, 0, 0 };
+
+ // Planes go in order:
+ // LEFT, RIGHT, BOTTOM, TOP, NEAR, FAR
+ for (Standard_Integer aFaceIdx = 0; aFaceIdx < 3; ++aFaceIdx)
{
- OpenGl_Vec4 anEq = myClipPlanes[aPlaneIter];
- if (SignedPlanePointDistance (anEq, aCenter) > 0)
+ for (Standard_Integer i = 0; i < 2; ++i)
{
- anEq *= -1.0f;
- myClipPlanes[aPlaneIter] = anEq;
- }
+ OpenGl_Vec3d aPlanePnts[3];
+ for (Standard_Integer aPntIter = 0; aPntIter < 3; ++aPntIter)
+ {
+ aShifts[aFaceIdx] = i;
+ aShifts[(aFaceIdx + 1) % 3] = aLookup1[aPntIter];
+ aShifts[(aFaceIdx + 2) % 3] = aLookup2[aPntIter];
+
+ aPlanePnts[aPntIter] = myClipVerts[aShifts[0] * 2 * 2 + aShifts[1] * 2 + aShifts[2]];
+ }
+
+ myClipPlanes[aFaceIdx * 2 + i].Origin = aPlanePnts[0];
+ myClipPlanes[aFaceIdx * 2 + i].Normal =
+ OpenGl_Vec3d::Cross (aPlanePnts[1] - aPlanePnts[0],
+ aPlanePnts[2] - aPlanePnts[0]).Normalized() * (i == 0 ? -1.f : 1.f);
+ }
}
}
+// =======================================================================
+// function : SetViewportSize
+// purpose :
+// =======================================================================
+void OpenGl_BVHTreeSelector::SetViewportSize (Standard_Integer theViewportWidth,
+ Standard_Integer theViewportHeight,
+ Standard_Real theResolutionRatio)
+{
+ myViewportHeight = theViewportHeight > 0 ? theViewportHeight : 1;
+ myViewportWidth = theViewportWidth > 0 ? theViewportWidth : 1;
+ myPixelSize = Max (theResolutionRatio / myViewportHeight,
+ theResolutionRatio / myViewportWidth);
+}
+
// =======================================================================
// function : SignedPlanePointDistance
// purpose :
// =======================================================================
-Standard_ShortReal OpenGl_BVHTreeSelector::SignedPlanePointDistance (const OpenGl_Vec4& theNormal,
- const OpenGl_Vec4& thePnt)
+Standard_Real OpenGl_BVHTreeSelector::SignedPlanePointDistance (const OpenGl_Vec4d& theNormal,
+ const OpenGl_Vec4d& thePnt)
{
- const Standard_ShortReal aNormLength = std::sqrt (theNormal.x() * theNormal.x()
- + theNormal.y() * theNormal.y()
- + theNormal.z() * theNormal.z());
-
- if (aNormLength < FLT_EPSILON)
- return 0.0f;
-
- const Standard_ShortReal anInvNormLength = 1.0f / aNormLength;
- const Standard_ShortReal aD = theNormal.w() * anInvNormLength;
- const Standard_ShortReal anA = theNormal.x() * anInvNormLength;
- const Standard_ShortReal aB = theNormal.y() * anInvNormLength;
- const Standard_ShortReal aC = theNormal.z() * anInvNormLength;
+ const Standard_Real aNormLength = std::sqrt (theNormal.x() * theNormal.x()
+ + theNormal.y() * theNormal.y()
+ + theNormal.z() * theNormal.z());
+
+ if (aNormLength < gp::Resolution())
+ return 0.0;
+
+ const Standard_Real anInvNormLength = 1.0 / aNormLength;
+ const Standard_Real aD = theNormal.w() * anInvNormLength;
+ const Standard_Real anA = theNormal.x() * anInvNormLength;
+ const Standard_Real aB = theNormal.y() * anInvNormLength;
+ const Standard_Real aC = theNormal.z() * anInvNormLength;
return aD + (anA * thePnt.x() + aB * thePnt.y() + aC * thePnt.z());
}
+// =======================================================================
+// function : SetCullingDistance
+// purpose :
+// =======================================================================
+void OpenGl_BVHTreeSelector::SetCullingDistance (CullingContext& theCtx,
+ Standard_Real theDistance) const
+{
+ theCtx.DistCull = -1.0;
+ if (!myIsProjectionParallel)
+ {
+ theCtx.DistCull = theDistance > 0.0 && !Precision::IsInfinite (theDistance)
+ ? theDistance
+ : -1.0;
+ }
+}
+
+// =======================================================================
+// function : SetCullingSize
+// purpose :
+// =======================================================================
+void OpenGl_BVHTreeSelector::SetCullingSize (CullingContext& theCtx,
+ Standard_Real theSize) const
+{
+ theCtx.SizeCull2 = -1.0;
+ if (theSize > 0.0 && !Precision::IsInfinite (theSize))
+ {
+ theCtx.SizeCull2 = myPixelSize * theSize;
+ theCtx.SizeCull2 *= myCamScale;
+ theCtx.SizeCull2 *= theCtx.SizeCull2;
+ }
+}
+
// =======================================================================
// function : CacheClipPtsProjections
-// purpose : Caches view volume's vertices projections along its normals and AABBs dimensions
-// Must be called at the beginning of each BVH tree traverse loop
+// purpose :
// =======================================================================
void OpenGl_BVHTreeSelector::CacheClipPtsProjections()
{
+ // project frustum onto its own normals
const Standard_Integer anIncFactor = myIsProjectionParallel ? 2 : 1;
- for (Standard_Integer aPlaneIter = 0; aPlaneIter < 5; aPlaneIter += anIncFactor)
+ for (Standard_Integer aPlaneIter = 0; aPlaneIter < PlanesNB - 1; aPlaneIter += anIncFactor)
{
- const OpenGl_Vec4 aPlane = myClipPlanes[aPlaneIter];
- Standard_ShortReal aMaxProj = -std::numeric_limits<Standard_ShortReal>::max();
- Standard_ShortReal aMinProj = std::numeric_limits<Standard_ShortReal>::max();
- for (Standard_Integer aCornerIter = 0; aCornerIter < ClipVerticesNB; ++aCornerIter)
+ Standard_Real aMaxProj = -std::numeric_limits<Standard_Real>::max();
+ Standard_Real aMinProj = std::numeric_limits<Standard_Real>::max();
+ for (Standard_Integer aCornerIter = 0; aCornerIter < Graphic3d_Camera::FrustumVerticesNB; ++aCornerIter)
{
- Standard_ShortReal aProjection = aPlane.x() * myClipVerts[aCornerIter].x() +
- aPlane.y() * myClipVerts[aCornerIter].y() +
- aPlane.z() * myClipVerts[aCornerIter].z();
+ Standard_Real aProjection = myClipVerts[aCornerIter].Dot (myClipPlanes[aPlaneIter].Normal);
aMaxProj = Max (aProjection, aMaxProj);
aMinProj = Min (aProjection, aMinProj);
}
myMinClipProjectionPts[aPlaneIter] = aMinProj;
}
+ // project frustum onto main axes
+ OpenGl_Vec3d anAxes[] = { OpenGl_Vec3d (1.0, 0.0, 0.0),
+ OpenGl_Vec3d (0.0, 1.0, 0.0),
+ OpenGl_Vec3d (0.0, 0.0, 1.0) };
for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
{
- Standard_ShortReal aMaxProj = -std::numeric_limits<Standard_ShortReal>::max();
- Standard_ShortReal aMinProj = std::numeric_limits<Standard_ShortReal>::max();
- for (Standard_Integer aCornerIter = 0; aCornerIter < ClipVerticesNB; ++aCornerIter)
+ Standard_Real aMaxProj = -std::numeric_limits<Standard_Real>::max();
+ Standard_Real aMinProj = std::numeric_limits<Standard_Real>::max();
+ for (Standard_Integer aCornerIter = 0; aCornerIter < Graphic3d_Camera::FrustumVerticesNB; ++aCornerIter)
{
- Standard_ShortReal aProjection = aDim == 0 ? myClipVerts[aCornerIter].x()
- : (aDim == 1 ? myClipVerts[aCornerIter].y() : myClipVerts[aCornerIter].z());
+ Standard_Real aProjection = myClipVerts[aCornerIter].Dot (anAxes[aDim]);
aMaxProj = Max (aProjection, aMaxProj);
aMinProj = Min (aProjection, aMinProj);
}
myMinOrthoProjectionPts[aDim] = aMinProj;
}
}
-
-// =======================================================================
-// function : Intersect
-// purpose : Detects if AABB overlaps view volume using separating axis theorem (SAT)
-// =======================================================================
-Standard_Boolean OpenGl_BVHTreeSelector::Intersect (const OpenGl_Vec4& theMinPt,
- const OpenGl_Vec4& theMaxPt) const
-{
- // E1
- // |_ E0
- // /
- // E2
-
- // E0 test
- if (theMinPt.x() > myMaxOrthoProjectionPts[0]
- || theMaxPt.x() < myMinOrthoProjectionPts[0])
- {
- return Standard_False;
- }
-
- // E1 test
- if (theMinPt.y() > myMaxOrthoProjectionPts[1]
- || theMaxPt.y() < myMinOrthoProjectionPts[1])
- {
- return Standard_False;
- }
-
- // E2 test
- if (theMinPt.z() > myMaxOrthoProjectionPts[2]
- || theMaxPt.z() < myMinOrthoProjectionPts[2])
- {
- return Standard_False;
- }
-
- Standard_ShortReal aBoxProjMax = 0.0f, aBoxProjMin = 0.0f;
- const Standard_Integer anIncFactor = myIsProjectionParallel ? 2 : 1;
- for (Standard_Integer aPlaneIter = 0; aPlaneIter < 5; aPlaneIter += anIncFactor)
- {
- OpenGl_Vec4 aPlane = myClipPlanes[aPlaneIter];
- aBoxProjMax = (aPlane.x() > 0.f ? (aPlane.x() * theMaxPt.x()) : aPlane.x() * theMinPt.x()) +
- (aPlane.y() > 0.f ? (aPlane.y() * theMaxPt.y()) : aPlane.y() * theMinPt.y()) +
- (aPlane.z() > 0.f ? (aPlane.z() * theMaxPt.z()) : aPlane.z() * theMinPt.z());
- if (aBoxProjMax > myMinClipProjectionPts[aPlaneIter]
- && aBoxProjMax < myMaxClipProjectionPts[aPlaneIter])
- {
- continue;
- }
-
- aBoxProjMin = (aPlane.x() < 0.f ? aPlane.x() * theMaxPt.x() : aPlane.x() * theMinPt.x()) +
- (aPlane.y() < 0.f ? aPlane.y() * theMaxPt.y() : aPlane.y() * theMinPt.y()) +
- (aPlane.z() < 0.f ? aPlane.z() * theMaxPt.z() : aPlane.z() * theMinPt.z());
- if (aBoxProjMin > myMaxClipProjectionPts[aPlaneIter]
- || aBoxProjMax < myMinClipProjectionPts[aPlaneIter])
- {
- return Standard_False;
- }
- }
-
- return Standard_True;
-}