0028760: Visualization, TKOpenGl - avoid excessive frustum culling traverse within...
[occt.git] / src / OpenGl / OpenGl_BVHTreeSelector.cxx
1 // Created on: 2013-12-25
2 // Created by: Varvara POSKONINA
3 // Copyright (c) 1999-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <limits>
17
18 #include <OpenGl_BVHTreeSelector.hxx>
19 #include <OpenGl_BVHClipPrimitiveSet.hxx>
20 #include <Graphic3d_GraphicDriver.hxx>
21
22 // =======================================================================
23 // function : OpenGl_BVHTreeSelector
24 // purpose  :
25 // =======================================================================
26 OpenGl_BVHTreeSelector::OpenGl_BVHTreeSelector()
27 : myIsProjectionParallel (Standard_True),
28   myCamScaleInv (1.0),
29   myPixelSize (1.0)
30 {
31   //
32 }
33
34 // =======================================================================
35 // function : SetViewVolume
36 // purpose  : Retrieves view volume's planes equations and its vertices from projection and world-view matrices.
37 // =======================================================================
38 void OpenGl_BVHTreeSelector::SetViewVolume (const Handle(Graphic3d_Camera)& theCamera)
39 {
40   if (!myWorldViewProjState.IsChanged (theCamera->WorldViewProjState()))
41     return;
42
43   myIsProjectionParallel = theCamera->IsOrthographic();
44
45   myCamera             = theCamera;
46   myProjectionMat      = theCamera->ProjectionMatrix();
47   myWorldViewMat       = theCamera->OrientationMatrix();
48   myWorldViewProjState = theCamera->WorldViewProjState();
49   myCamEye.SetValues (theCamera->Eye().X(), theCamera->Eye().Y(), theCamera->Eye().Z());
50   myCamScaleInv = 1.0 / myCamera->Scale();
51
52   Standard_Real nLeft = 0.0, nRight = 0.0, nTop = 0.0, nBottom = 0.0;
53   Standard_Real fLeft = 0.0, fRight = 0.0, fTop = 0.0, fBottom = 0.0;
54   Standard_Real aNear = 0.0, aFar   = 0.0;
55   if (!myIsProjectionParallel)
56   {
57     // handle perspective projection
58     aNear   = myProjectionMat.GetValue (2, 3) / (- 1.0 + myProjectionMat.GetValue (2, 2));
59     aFar    = myProjectionMat.GetValue (2, 3) / (  1.0 + myProjectionMat.GetValue (2, 2));
60     // Near plane
61     nLeft   = aNear * (myProjectionMat.GetValue (0, 2) - 1.0) / myProjectionMat.GetValue (0, 0);
62     nRight  = aNear * (myProjectionMat.GetValue (0, 2) + 1.0) / myProjectionMat.GetValue (0, 0);
63     nTop    = aNear * (myProjectionMat.GetValue (1, 2) + 1.0) / myProjectionMat.GetValue (1, 1);
64     nBottom = aNear * (myProjectionMat.GetValue (1, 2) - 1.0) / myProjectionMat.GetValue (1, 1);
65     // Far plane
66     fLeft   = aFar  * (myProjectionMat.GetValue (0, 2) - 1.0) / myProjectionMat.GetValue (0, 0);
67     fRight  = aFar  * (myProjectionMat.GetValue (0, 2) + 1.0) / myProjectionMat.GetValue (0, 0);
68     fTop    = aFar  * (myProjectionMat.GetValue (1, 2) + 1.0) / myProjectionMat.GetValue (1, 1);
69     fBottom = aFar  * (myProjectionMat.GetValue (1, 2) - 1.0) / myProjectionMat.GetValue (1, 1);
70   }
71   else
72   {
73     // handle orthographic projection
74     aNear   = (1.0 / myProjectionMat.GetValue (2, 2)) * (myProjectionMat.GetValue (2, 3) + 1.0);
75     aFar    = (1.0 / myProjectionMat.GetValue (2, 2)) * (myProjectionMat.GetValue (2, 3) - 1.0);
76     // Near plane
77     nLeft   = ( 1.0 + myProjectionMat.GetValue (0, 3)) / (-myProjectionMat.GetValue (0, 0));
78     fLeft   = nLeft;
79     nRight  = ( 1.0 - myProjectionMat.GetValue (0, 3)) /   myProjectionMat.GetValue (0, 0);
80     fRight  = nRight;
81     nTop    = ( 1.0 - myProjectionMat.GetValue (1, 3)) /   myProjectionMat.GetValue (1, 1);
82     fTop    = nTop;
83     nBottom = (-1.0 - myProjectionMat.GetValue (1, 3)) /   myProjectionMat.GetValue (1, 1);
84     fBottom = nBottom;
85   }
86
87   OpenGl_Vec4d aLeftTopNear     (nLeft,  nTop,    -aNear, 1.0), aRightBottomFar (fRight, fBottom, -aFar, 1.0);
88   OpenGl_Vec4d aLeftBottomNear  (nLeft,  nBottom, -aNear, 1.0), aRightTopFar    (fRight, fTop,    -aFar, 1.0);
89   OpenGl_Vec4d aRightBottomNear (nRight, nBottom, -aNear, 1.0), aLeftTopFar     (fLeft,  fTop,    -aFar, 1.0);
90   OpenGl_Vec4d aRightTopNear    (nRight, nTop,    -aNear, 1.0), aLeftBottomFar  (fLeft,  fBottom, -aFar, 1.0);
91
92   const OpenGl_Mat4d aViewProj = myWorldViewMat * myProjectionMat;
93   OpenGl_Mat4d anInvWorldView;
94   myWorldViewMat.Inverted (anInvWorldView);
95
96   myClipVerts[ClipVert_LeftTopNear]     = anInvWorldView * aLeftTopNear;
97   myClipVerts[ClipVert_RightBottomFar]  = anInvWorldView * aRightBottomFar;
98   myClipVerts[ClipVert_LeftBottomNear]  = anInvWorldView * aLeftBottomNear;
99   myClipVerts[ClipVert_RightTopFar]     = anInvWorldView * aRightTopFar;
100   myClipVerts[ClipVert_RightBottomNear] = anInvWorldView * aRightBottomNear;
101   myClipVerts[ClipVert_LeftTopFar]      = anInvWorldView * aLeftTopFar;
102   myClipVerts[ClipVert_RightTopNear]    = anInvWorldView * aRightTopNear;
103   myClipVerts[ClipVert_LeftBottomFar]   = anInvWorldView * aLeftBottomFar;
104
105   // UNNORMALIZED!
106   myClipPlanes[Plane_Left]   = aViewProj.GetRow (3) + aViewProj.GetRow (0);
107   myClipPlanes[Plane_Right]  = aViewProj.GetRow (3) - aViewProj.GetRow (0);
108   myClipPlanes[Plane_Top]    = aViewProj.GetRow (3) - aViewProj.GetRow (1);
109   myClipPlanes[Plane_Bottom] = aViewProj.GetRow (3) + aViewProj.GetRow (1);
110   myClipPlanes[Plane_Near]   = aViewProj.GetRow (3) + aViewProj.GetRow (2);
111   myClipPlanes[Plane_Far]    = aViewProj.GetRow (3) - aViewProj.GetRow (2);
112
113   gp_Pnt aPtCenter = theCamera->Center();
114   OpenGl_Vec4d aCenter (aPtCenter.X(), aPtCenter.Y(), aPtCenter.Z(), 1.0);
115
116   for (Standard_Integer aPlaneIter = 0; aPlaneIter < PlanesNB; ++aPlaneIter)
117   {
118     OpenGl_Vec4d anEq = myClipPlanes[aPlaneIter];
119     if (SignedPlanePointDistance (anEq, aCenter) > 0)
120     {
121       anEq *= -1.0;
122       myClipPlanes[aPlaneIter] = anEq;
123     }
124   }
125 }
126
127 // =======================================================================
128 // function : SetViewportSize
129 // purpose  :
130 // =======================================================================
131 void OpenGl_BVHTreeSelector::SetViewportSize (Standard_Integer theViewportWidth,
132                                               Standard_Integer theViewportHeight,
133                                               Standard_Real theResolutionRatio)
134 {
135   myViewportHeight = theViewportHeight;
136   myViewportWidth  = theViewportWidth;
137   myPixelSize = Max (theResolutionRatio / theViewportHeight,
138                      theResolutionRatio / theViewportWidth);
139 }
140
141 // =======================================================================
142 // function : SignedPlanePointDistance
143 // purpose  :
144 // =======================================================================
145 Standard_Real OpenGl_BVHTreeSelector::SignedPlanePointDistance (const OpenGl_Vec4d& theNormal,
146                                                                 const OpenGl_Vec4d& thePnt)
147 {
148   const Standard_Real aNormLength = std::sqrt (theNormal.x() * theNormal.x()
149                                              + theNormal.y() * theNormal.y()
150                                              + theNormal.z() * theNormal.z());
151
152   if (aNormLength < gp::Resolution())
153     return 0.0;
154
155   const Standard_Real anInvNormLength = 1.0 / aNormLength;
156   const Standard_Real aD  = theNormal.w() * anInvNormLength;
157   const Standard_Real anA = theNormal.x() * anInvNormLength;
158   const Standard_Real aB  = theNormal.y() * anInvNormLength;
159   const Standard_Real aC  = theNormal.z() * anInvNormLength;
160   return aD + (anA * thePnt.x() + aB * thePnt.y() + aC * thePnt.z());
161 }
162
163 // =======================================================================
164 // function : SetCullingDistance
165 // purpose  :
166 // =======================================================================
167 void OpenGl_BVHTreeSelector::SetCullingDistance (CullingContext& theCtx,
168                                                  Standard_Real theDistance) const
169 {
170   theCtx.DistCull = -1.0;
171   if (!myIsProjectionParallel)
172   {
173     theCtx.DistCull = theDistance > 0.0 && !Precision::IsInfinite (theDistance)
174                     ? theDistance
175                     : -1.0;
176   }
177 }
178
179 // =======================================================================
180 // function : SetCullingSize
181 // purpose  :
182 // =======================================================================
183 void OpenGl_BVHTreeSelector::SetCullingSize (CullingContext& theCtx,
184                                              Standard_Real theSize) const
185 {
186   theCtx.SizeCull2 = -1.0;
187   if (theSize > 0.0 && !Precision::IsInfinite (theSize))
188   {
189     theCtx.SizeCull2 = (myPixelSize * theSize) / myCamScaleInv;
190     theCtx.SizeCull2 *= theCtx.SizeCull2;
191   }
192 }
193
194 // =======================================================================
195 // function : CacheClipPtsProjections
196 // purpose  :
197 // =======================================================================
198 void OpenGl_BVHTreeSelector::CacheClipPtsProjections()
199 {
200   const Standard_Integer anIncFactor = myIsProjectionParallel ? 2 : 1;
201   for (Standard_Integer aPlaneIter = 0; aPlaneIter < 5; aPlaneIter += anIncFactor)
202   {
203     const OpenGl_Vec4d aPlane = myClipPlanes[aPlaneIter];
204     Standard_Real aMaxProj = -std::numeric_limits<Standard_Real>::max();
205     Standard_Real aMinProj =  std::numeric_limits<Standard_Real>::max();
206     for (Standard_Integer aCornerIter = 0; aCornerIter < ClipVerticesNB; ++aCornerIter)
207     {
208       Standard_Real aProjection = aPlane.x() * myClipVerts[aCornerIter].x()
209                                 + aPlane.y() * myClipVerts[aCornerIter].y()
210                                 + aPlane.z() * myClipVerts[aCornerIter].z();
211       aMaxProj = Max (aProjection, aMaxProj);
212       aMinProj = Min (aProjection, aMinProj);
213     }
214     myMaxClipProjectionPts[aPlaneIter] = aMaxProj;
215     myMinClipProjectionPts[aPlaneIter] = aMinProj;
216   }
217
218   for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
219   {
220     Standard_Real aMaxProj = -std::numeric_limits<Standard_Real>::max();
221     Standard_Real aMinProj =  std::numeric_limits<Standard_Real>::max();
222     for (Standard_Integer aCornerIter = 0; aCornerIter < ClipVerticesNB; ++aCornerIter)
223     {
224       Standard_Real aProjection = aDim == 0
225                                 ? myClipVerts[aCornerIter].x()
226                                 : (aDim == 1
227                                  ? myClipVerts[aCornerIter].y()
228                                  : myClipVerts[aCornerIter].z());
229       aMaxProj = Max (aProjection, aMaxProj);
230       aMinProj = Min (aProjection, aMinProj);
231     }
232     myMaxOrthoProjectionPts[aDim] = aMaxProj;
233     myMinOrthoProjectionPts[aDim] = aMinProj;
234   }
235 }