1 // Created on: 2013-12-25
2 // Created by: Varvara POSKONINA
3 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
18 #include <OpenGl_BVHTreeSelector.hxx>
19 #include <OpenGl_BVHClipPrimitiveSet.hxx>
20 #include <Graphic3d_GraphicDriver.hxx>
22 // =======================================================================
23 // function : OpenGl_BVHTreeSelector
25 // =======================================================================
26 OpenGl_BVHTreeSelector::OpenGl_BVHTreeSelector()
27 : myIsProjectionParallel (Standard_True)
32 // =======================================================================
33 // function : SetViewVolume
34 // purpose : Retrieves view volume's planes equations and its vertices from projection and world-view matrices.
35 // =======================================================================
36 void OpenGl_BVHTreeSelector::SetViewVolume (const Handle(Graphic3d_Camera)& theCamera)
38 if (!myWorldViewProjState.IsChanged (theCamera->WorldViewProjState()))
41 myIsProjectionParallel = theCamera->IsOrthographic();
44 myProjectionMat = theCamera->ProjectionMatrixF();
45 myWorldViewMat = theCamera->OrientationMatrixF();
46 myWorldViewProjState = theCamera->WorldViewProjState();
48 Standard_ShortReal nLeft = 0.0f, nRight = 0.0f, nTop = 0.0f, nBottom = 0.0f;
49 Standard_ShortReal fLeft = 0.0f, fRight = 0.0f, fTop = 0.0f, fBottom = 0.0f;
50 Standard_ShortReal aNear = 0.0f, aFar = 0.0f;
51 if (!myIsProjectionParallel)
53 // handle perspective projection
54 aNear = myProjectionMat.GetValue (2, 3) / (- 1.0f + myProjectionMat.GetValue (2, 2));
55 aFar = myProjectionMat.GetValue (2, 3) / ( 1.0f + myProjectionMat.GetValue (2, 2));
57 nLeft = aNear * (myProjectionMat.GetValue (0, 2) - 1.0f) / myProjectionMat.GetValue (0, 0);
58 nRight = aNear * (myProjectionMat.GetValue (0, 2) + 1.0f) / myProjectionMat.GetValue (0, 0);
59 nTop = aNear * (myProjectionMat.GetValue (1, 2) + 1.0f) / myProjectionMat.GetValue (1, 1);
60 nBottom = aNear * (myProjectionMat.GetValue (1, 2) - 1.0f) / myProjectionMat.GetValue (1, 1);
62 fLeft = aFar * (myProjectionMat.GetValue (0, 2) - 1.0f) / myProjectionMat.GetValue (0, 0);
63 fRight = aFar * (myProjectionMat.GetValue (0, 2) + 1.0f) / myProjectionMat.GetValue (0, 0);
64 fTop = aFar * (myProjectionMat.GetValue (1, 2) + 1.0f) / myProjectionMat.GetValue (1, 1);
65 fBottom = aFar * (myProjectionMat.GetValue (1, 2) - 1.0f) / myProjectionMat.GetValue (1, 1);
69 // handle orthographic projection
70 aNear = (1.0f / myProjectionMat.GetValue (2, 2)) * (myProjectionMat.GetValue (2, 3) + 1.0f);
71 aFar = (1.0f / myProjectionMat.GetValue (2, 2)) * (myProjectionMat.GetValue (2, 3) - 1.0f);
73 nLeft = ( 1.0f + myProjectionMat.GetValue (0, 3)) / (-myProjectionMat.GetValue (0, 0));
75 nRight = ( 1.0f - myProjectionMat.GetValue (0, 3)) / myProjectionMat.GetValue (0, 0);
77 nTop = ( 1.0f - myProjectionMat.GetValue (1, 3)) / myProjectionMat.GetValue (1, 1);
79 nBottom = (-1.0f - myProjectionMat.GetValue (1, 3)) / myProjectionMat.GetValue (1, 1);
83 OpenGl_Vec4 aLeftTopNear (nLeft, nTop, -aNear, 1.0f), aRightBottomFar (fRight, fBottom, -aFar, 1.0f);
84 OpenGl_Vec4 aLeftBottomNear (nLeft, nBottom, -aNear, 1.0f), aRightTopFar (fRight, fTop, -aFar, 1.0f);
85 OpenGl_Vec4 aRightBottomNear (nRight, nBottom, -aNear, 1.0f), aLeftTopFar (fLeft, fTop, -aFar, 1.0f);
86 OpenGl_Vec4 aRightTopNear (nRight, nTop, -aNear, 1.0f), aLeftBottomFar (fLeft, fBottom, -aFar, 1.0f);
88 const OpenGl_Mat4 aViewProj = myWorldViewMat * myProjectionMat;
89 OpenGl_Mat4 anInvWorldView;
90 myWorldViewMat.Inverted(anInvWorldView);
92 myClipVerts[ClipVert_LeftTopNear] = anInvWorldView * aLeftTopNear;
93 myClipVerts[ClipVert_RightBottomFar] = anInvWorldView * aRightBottomFar;
94 myClipVerts[ClipVert_LeftBottomNear] = anInvWorldView * aLeftBottomNear;
95 myClipVerts[ClipVert_RightTopFar] = anInvWorldView * aRightTopFar;
96 myClipVerts[ClipVert_RightBottomNear] = anInvWorldView * aRightBottomNear;
97 myClipVerts[ClipVert_LeftTopFar] = anInvWorldView * aLeftTopFar;
98 myClipVerts[ClipVert_RightTopNear] = anInvWorldView * aRightTopNear;
99 myClipVerts[ClipVert_LeftBottomFar] = anInvWorldView * aLeftBottomFar;
102 myClipPlanes[Plane_Left] = aViewProj.GetRow (3) + aViewProj.GetRow (0);
103 myClipPlanes[Plane_Right] = aViewProj.GetRow (3) - aViewProj.GetRow (0);
104 myClipPlanes[Plane_Top] = aViewProj.GetRow (3) - aViewProj.GetRow (1);
105 myClipPlanes[Plane_Bottom] = aViewProj.GetRow (3) + aViewProj.GetRow (1);
106 myClipPlanes[Plane_Near] = aViewProj.GetRow (3) + aViewProj.GetRow (2);
107 myClipPlanes[Plane_Far] = aViewProj.GetRow (3) - aViewProj.GetRow (2);
109 gp_Pnt aPtCenter = theCamera->Center();
110 OpenGl_Vec4 aCenter (static_cast<Standard_ShortReal> (aPtCenter.X()),
111 static_cast<Standard_ShortReal> (aPtCenter.Y()),
112 static_cast<Standard_ShortReal> (aPtCenter.Z()),
115 for (Standard_Integer aPlaneIter = 0; aPlaneIter < PlanesNB; ++aPlaneIter)
117 OpenGl_Vec4 anEq = myClipPlanes[aPlaneIter];
118 if (SignedPlanePointDistance (anEq, aCenter) > 0)
121 myClipPlanes[aPlaneIter] = anEq;
126 // =======================================================================
127 // function : SetViewportSize
129 // =======================================================================
130 void OpenGl_BVHTreeSelector::SetViewportSize (const Standard_Integer theViewportWidth,
131 const Standard_Integer theViewportHeight)
133 myViewportHeight = theViewportHeight;
134 myViewportWidth = theViewportWidth;
137 // =======================================================================
138 // function : SignedPlanePointDistance
140 // =======================================================================
141 Standard_ShortReal OpenGl_BVHTreeSelector::SignedPlanePointDistance (const OpenGl_Vec4& theNormal,
142 const OpenGl_Vec4& thePnt)
144 const Standard_ShortReal aNormLength = std::sqrt (theNormal.x() * theNormal.x()
145 + theNormal.y() * theNormal.y()
146 + theNormal.z() * theNormal.z());
148 if (aNormLength < FLT_EPSILON)
151 const Standard_ShortReal anInvNormLength = 1.0f / aNormLength;
152 const Standard_ShortReal aD = theNormal.w() * anInvNormLength;
153 const Standard_ShortReal anA = theNormal.x() * anInvNormLength;
154 const Standard_ShortReal aB = theNormal.y() * anInvNormLength;
155 const Standard_ShortReal aC = theNormal.z() * anInvNormLength;
156 return aD + (anA * thePnt.x() + aB * thePnt.y() + aC * thePnt.z());
159 // =======================================================================
160 // function : CacheClipPtsProjections
161 // purpose : Caches view volume's vertices projections along its normals and AABBs dimensions
162 // Must be called at the beginning of each BVH tree traverse loop
163 // =======================================================================
164 void OpenGl_BVHTreeSelector::CacheClipPtsProjections()
166 const Standard_Integer anIncFactor = myIsProjectionParallel ? 2 : 1;
167 for (Standard_Integer aPlaneIter = 0; aPlaneIter < 5; aPlaneIter += anIncFactor)
169 const OpenGl_Vec4 aPlane = myClipPlanes[aPlaneIter];
170 Standard_ShortReal aMaxProj = -std::numeric_limits<Standard_ShortReal>::max();
171 Standard_ShortReal aMinProj = std::numeric_limits<Standard_ShortReal>::max();
172 for (Standard_Integer aCornerIter = 0; aCornerIter < ClipVerticesNB; ++aCornerIter)
174 Standard_ShortReal aProjection = aPlane.x() * myClipVerts[aCornerIter].x() +
175 aPlane.y() * myClipVerts[aCornerIter].y() +
176 aPlane.z() * myClipVerts[aCornerIter].z();
177 aMaxProj = Max (aProjection, aMaxProj);
178 aMinProj = Min (aProjection, aMinProj);
180 myMaxClipProjectionPts[aPlaneIter] = aMaxProj;
181 myMinClipProjectionPts[aPlaneIter] = aMinProj;
184 for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
186 Standard_ShortReal aMaxProj = -std::numeric_limits<Standard_ShortReal>::max();
187 Standard_ShortReal aMinProj = std::numeric_limits<Standard_ShortReal>::max();
188 for (Standard_Integer aCornerIter = 0; aCornerIter < ClipVerticesNB; ++aCornerIter)
190 Standard_ShortReal aProjection = aDim == 0 ? myClipVerts[aCornerIter].x()
191 : (aDim == 1 ? myClipVerts[aCornerIter].y() : myClipVerts[aCornerIter].z());
192 aMaxProj = Max (aProjection, aMaxProj);
193 aMinProj = Min (aProjection, aMinProj);
195 myMaxOrthoProjectionPts[aDim] = aMaxProj;
196 myMinOrthoProjectionPts[aDim] = aMinProj;
200 // =======================================================================
201 // function : Intersect
202 // purpose : Detects if AABB overlaps view volume using separating axis theorem (SAT)
203 // =======================================================================
204 Standard_Boolean OpenGl_BVHTreeSelector::Intersect (const OpenGl_Vec4& theMinPt,
205 const OpenGl_Vec4& theMaxPt) const
213 if (theMinPt.x() > myMaxOrthoProjectionPts[0]
214 || theMaxPt.x() < myMinOrthoProjectionPts[0])
216 return Standard_False;
220 if (theMinPt.y() > myMaxOrthoProjectionPts[1]
221 || theMaxPt.y() < myMinOrthoProjectionPts[1])
223 return Standard_False;
227 if (theMinPt.z() > myMaxOrthoProjectionPts[2]
228 || theMaxPt.z() < myMinOrthoProjectionPts[2])
230 return Standard_False;
233 Standard_ShortReal aBoxProjMax = 0.0f, aBoxProjMin = 0.0f;
234 const Standard_Integer anIncFactor = myIsProjectionParallel ? 2 : 1;
235 for (Standard_Integer aPlaneIter = 0; aPlaneIter < 5; aPlaneIter += anIncFactor)
237 OpenGl_Vec4 aPlane = myClipPlanes[aPlaneIter];
238 aBoxProjMax = (aPlane.x() > 0.f ? (aPlane.x() * theMaxPt.x()) : aPlane.x() * theMinPt.x()) +
239 (aPlane.y() > 0.f ? (aPlane.y() * theMaxPt.y()) : aPlane.y() * theMinPt.y()) +
240 (aPlane.z() > 0.f ? (aPlane.z() * theMaxPt.z()) : aPlane.z() * theMinPt.z());
241 if (aBoxProjMax > myMinClipProjectionPts[aPlaneIter]
242 && aBoxProjMax < myMaxClipProjectionPts[aPlaneIter])
247 aBoxProjMin = (aPlane.x() < 0.f ? aPlane.x() * theMaxPt.x() : aPlane.x() * theMinPt.x()) +
248 (aPlane.y() < 0.f ? aPlane.y() * theMaxPt.y() : aPlane.y() * theMinPt.y()) +
249 (aPlane.z() < 0.f ? aPlane.z() * theMaxPt.z() : aPlane.z() * theMinPt.z());
250 if (aBoxProjMin > myMaxClipProjectionPts[aPlaneIter]
251 || aBoxProjMax < myMinClipProjectionPts[aPlaneIter])
253 return Standard_False;
257 return Standard_True;