0029283: Visualization - allow defining more than 8 light sources
[occt.git] / src / OpenGl / OpenGl_BVHTreeSelector.cxx
CommitLineData
b7cd4ba7 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
14a35e5d 16#include <limits>
17
b7cd4ba7 18#include <OpenGl_BVHTreeSelector.hxx>
19#include <OpenGl_BVHClipPrimitiveSet.hxx>
c04c30b3 20#include <Graphic3d_GraphicDriver.hxx>
b7cd4ba7 21
b7cd4ba7 22// =======================================================================
23// function : OpenGl_BVHTreeSelector
24// purpose :
25// =======================================================================
26OpenGl_BVHTreeSelector::OpenGl_BVHTreeSelector()
4ecf34cc 27: myIsProjectionParallel (Standard_True),
28 myCamScaleInv (1.0),
29 myDistCull (-1.0),
30 myPixelSize (1.0),
31 mySizeCull2 (-1.0)
b7cd4ba7 32{
33 //
34}
35
36// =======================================================================
825aa485 37// function : SetViewVolume
38// purpose : Retrieves view volume's planes equations and its vertices from projection and world-view matrices.
b7cd4ba7 39// =======================================================================
40void OpenGl_BVHTreeSelector::SetViewVolume (const Handle(Graphic3d_Camera)& theCamera)
41{
97f937cc 42 if (!myWorldViewProjState.IsChanged (theCamera->WorldViewProjState()))
825aa485 43 return;
825aa485 44
b7cd4ba7 45 myIsProjectionParallel = theCamera->IsOrthographic();
825aa485 46
3fe9ce0e 47 myCamera = theCamera;
7c3ef2f7 48 myProjectionMat = theCamera->ProjectionMatrix();
49 myWorldViewMat = theCamera->OrientationMatrix();
825aa485 50 myWorldViewProjState = theCamera->WorldViewProjState();
4ecf34cc 51 myCamEye.SetValues (theCamera->Eye().X(), theCamera->Eye().Y(), theCamera->Eye().Z());
52 myCamScaleInv = 1.0 / myCamera->Scale();
b7cd4ba7 53
7c3ef2f7 54 Standard_Real nLeft = 0.0, nRight = 0.0, nTop = 0.0, nBottom = 0.0;
55 Standard_Real fLeft = 0.0, fRight = 0.0, fTop = 0.0, fBottom = 0.0;
56 Standard_Real aNear = 0.0, aFar = 0.0;
b7cd4ba7 57 if (!myIsProjectionParallel)
58 {
59 // handle perspective projection
7c3ef2f7 60 aNear = myProjectionMat.GetValue (2, 3) / (- 1.0 + myProjectionMat.GetValue (2, 2));
61 aFar = myProjectionMat.GetValue (2, 3) / ( 1.0 + myProjectionMat.GetValue (2, 2));
b7cd4ba7 62 // Near plane
7c3ef2f7 63 nLeft = aNear * (myProjectionMat.GetValue (0, 2) - 1.0) / myProjectionMat.GetValue (0, 0);
64 nRight = aNear * (myProjectionMat.GetValue (0, 2) + 1.0) / myProjectionMat.GetValue (0, 0);
65 nTop = aNear * (myProjectionMat.GetValue (1, 2) + 1.0) / myProjectionMat.GetValue (1, 1);
66 nBottom = aNear * (myProjectionMat.GetValue (1, 2) - 1.0) / myProjectionMat.GetValue (1, 1);
b7cd4ba7 67 // Far plane
7c3ef2f7 68 fLeft = aFar * (myProjectionMat.GetValue (0, 2) - 1.0) / myProjectionMat.GetValue (0, 0);
69 fRight = aFar * (myProjectionMat.GetValue (0, 2) + 1.0) / myProjectionMat.GetValue (0, 0);
70 fTop = aFar * (myProjectionMat.GetValue (1, 2) + 1.0) / myProjectionMat.GetValue (1, 1);
71 fBottom = aFar * (myProjectionMat.GetValue (1, 2) - 1.0) / myProjectionMat.GetValue (1, 1);
b7cd4ba7 72 }
73 else
74 {
75 // handle orthographic projection
7c3ef2f7 76 aNear = (1.0 / myProjectionMat.GetValue (2, 2)) * (myProjectionMat.GetValue (2, 3) + 1.0);
77 aFar = (1.0 / myProjectionMat.GetValue (2, 2)) * (myProjectionMat.GetValue (2, 3) - 1.0);
b7cd4ba7 78 // Near plane
7c3ef2f7 79 nLeft = ( 1.0 + myProjectionMat.GetValue (0, 3)) / (-myProjectionMat.GetValue (0, 0));
b7cd4ba7 80 fLeft = nLeft;
7c3ef2f7 81 nRight = ( 1.0 - myProjectionMat.GetValue (0, 3)) / myProjectionMat.GetValue (0, 0);
b7cd4ba7 82 fRight = nRight;
7c3ef2f7 83 nTop = ( 1.0 - myProjectionMat.GetValue (1, 3)) / myProjectionMat.GetValue (1, 1);
b7cd4ba7 84 fTop = nTop;
7c3ef2f7 85 nBottom = (-1.0 - myProjectionMat.GetValue (1, 3)) / myProjectionMat.GetValue (1, 1);
b7cd4ba7 86 fBottom = nBottom;
87 }
88
7c3ef2f7 89 OpenGl_Vec4d aLeftTopNear (nLeft, nTop, -aNear, 1.0), aRightBottomFar (fRight, fBottom, -aFar, 1.0);
90 OpenGl_Vec4d aLeftBottomNear (nLeft, nBottom, -aNear, 1.0), aRightTopFar (fRight, fTop, -aFar, 1.0);
91 OpenGl_Vec4d aRightBottomNear (nRight, nBottom, -aNear, 1.0), aLeftTopFar (fLeft, fTop, -aFar, 1.0);
92 OpenGl_Vec4d aRightTopNear (nRight, nTop, -aNear, 1.0), aLeftBottomFar (fLeft, fBottom, -aFar, 1.0);
b7cd4ba7 93
7c3ef2f7 94 const OpenGl_Mat4d aViewProj = myWorldViewMat * myProjectionMat;
95 OpenGl_Mat4d anInvWorldView;
96 myWorldViewMat.Inverted (anInvWorldView);
b7cd4ba7 97
825aa485 98 myClipVerts[ClipVert_LeftTopNear] = anInvWorldView * aLeftTopNear;
99 myClipVerts[ClipVert_RightBottomFar] = anInvWorldView * aRightBottomFar;
100 myClipVerts[ClipVert_LeftBottomNear] = anInvWorldView * aLeftBottomNear;
101 myClipVerts[ClipVert_RightTopFar] = anInvWorldView * aRightTopFar;
102 myClipVerts[ClipVert_RightBottomNear] = anInvWorldView * aRightBottomNear;
103 myClipVerts[ClipVert_LeftTopFar] = anInvWorldView * aLeftTopFar;
104 myClipVerts[ClipVert_RightTopNear] = anInvWorldView * aRightTopNear;
105 myClipVerts[ClipVert_LeftBottomFar] = anInvWorldView * aLeftBottomFar;
b7cd4ba7 106
107 // UNNORMALIZED!
108 myClipPlanes[Plane_Left] = aViewProj.GetRow (3) + aViewProj.GetRow (0);
109 myClipPlanes[Plane_Right] = aViewProj.GetRow (3) - aViewProj.GetRow (0);
110 myClipPlanes[Plane_Top] = aViewProj.GetRow (3) - aViewProj.GetRow (1);
111 myClipPlanes[Plane_Bottom] = aViewProj.GetRow (3) + aViewProj.GetRow (1);
112 myClipPlanes[Plane_Near] = aViewProj.GetRow (3) + aViewProj.GetRow (2);
113 myClipPlanes[Plane_Far] = aViewProj.GetRow (3) - aViewProj.GetRow (2);
114
115 gp_Pnt aPtCenter = theCamera->Center();
7c3ef2f7 116 OpenGl_Vec4d aCenter (aPtCenter.X(), aPtCenter.Y(), aPtCenter.Z(), 1.0);
b7cd4ba7 117
118 for (Standard_Integer aPlaneIter = 0; aPlaneIter < PlanesNB; ++aPlaneIter)
119 {
7c3ef2f7 120 OpenGl_Vec4d anEq = myClipPlanes[aPlaneIter];
b7cd4ba7 121 if (SignedPlanePointDistance (anEq, aCenter) > 0)
122 {
7c3ef2f7 123 anEq *= -1.0;
b7cd4ba7 124 myClipPlanes[aPlaneIter] = anEq;
125 }
126 }
127}
128
129// =======================================================================
91d96372 130// function : SetViewportSize
131// purpose :
132// =======================================================================
4ecf34cc 133void OpenGl_BVHTreeSelector::SetViewportSize (Standard_Integer theViewportWidth,
134 Standard_Integer theViewportHeight,
135 Standard_Real theResolutionRatio)
91d96372 136{
137 myViewportHeight = theViewportHeight;
4ecf34cc 138 myViewportWidth = theViewportWidth;
139 myPixelSize = Max (theResolutionRatio / theViewportHeight,
140 theResolutionRatio / theViewportWidth);
91d96372 141}
142
143// =======================================================================
b7cd4ba7 144// function : SignedPlanePointDistance
145// purpose :
146// =======================================================================
7c3ef2f7 147Standard_Real OpenGl_BVHTreeSelector::SignedPlanePointDistance (const OpenGl_Vec4d& theNormal,
148 const OpenGl_Vec4d& thePnt)
b7cd4ba7 149{
7c3ef2f7 150 const Standard_Real aNormLength = std::sqrt (theNormal.x() * theNormal.x()
151 + theNormal.y() * theNormal.y()
152 + theNormal.z() * theNormal.z());
3c648527 153
7c3ef2f7 154 if (aNormLength < gp::Resolution())
155 return 0.0;
3c648527 156
7c3ef2f7 157 const Standard_Real anInvNormLength = 1.0 / aNormLength;
158 const Standard_Real aD = theNormal.w() * anInvNormLength;
159 const Standard_Real anA = theNormal.x() * anInvNormLength;
160 const Standard_Real aB = theNormal.y() * anInvNormLength;
161 const Standard_Real aC = theNormal.z() * anInvNormLength;
b7cd4ba7 162 return aD + (anA * thePnt.x() + aB * thePnt.y() + aC * thePnt.z());
163}
164
165// =======================================================================
4ecf34cc 166// function : SetCullingDistance
167// purpose :
168// =======================================================================
169void OpenGl_BVHTreeSelector::SetCullingDistance (Standard_Real theDistance)
170{
171 myDistCull = -1.0;
172 if (!myIsProjectionParallel)
173 {
174 myDistCull = theDistance > 0.0 && !Precision::IsInfinite (theDistance)
175 ? theDistance
176 : -1.0;
177 }
178}
179
180// =======================================================================
181// function : SetCullingSize
182// purpose :
183// =======================================================================
184void OpenGl_BVHTreeSelector::SetCullingSize (Standard_Real theSize)
185{
186 mySizeCull2 = -1.0;
187 if (theSize > 0.0 && !Precision::IsInfinite (theSize))
188 {
189 mySizeCull2 = (myPixelSize * theSize) / myCamScaleInv;
190 mySizeCull2 *= mySizeCull2;
191 }
192}
193
194// =======================================================================
b7cd4ba7 195// function : CacheClipPtsProjections
4ecf34cc 196// purpose :
b7cd4ba7 197// =======================================================================
198void OpenGl_BVHTreeSelector::CacheClipPtsProjections()
199{
14a35e5d 200 const Standard_Integer anIncFactor = myIsProjectionParallel ? 2 : 1;
201 for (Standard_Integer aPlaneIter = 0; aPlaneIter < 5; aPlaneIter += anIncFactor)
b7cd4ba7 202 {
7c3ef2f7 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();
b7cd4ba7 206 for (Standard_Integer aCornerIter = 0; aCornerIter < ClipVerticesNB; ++aCornerIter)
207 {
7c3ef2f7 208 Standard_Real aProjection = aPlane.x() * myClipVerts[aCornerIter].x()
209 + aPlane.y() * myClipVerts[aCornerIter].y()
210 + aPlane.z() * myClipVerts[aCornerIter].z();
14a35e5d 211 aMaxProj = Max (aProjection, aMaxProj);
212 aMinProj = Min (aProjection, aMinProj);
b7cd4ba7 213 }
14a35e5d 214 myMaxClipProjectionPts[aPlaneIter] = aMaxProj;
215 myMinClipProjectionPts[aPlaneIter] = aMinProj;
b7cd4ba7 216 }
217
b7cd4ba7 218 for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
219 {
7c3ef2f7 220 Standard_Real aMaxProj = -std::numeric_limits<Standard_Real>::max();
221 Standard_Real aMinProj = std::numeric_limits<Standard_Real>::max();
b7cd4ba7 222 for (Standard_Integer aCornerIter = 0; aCornerIter < ClipVerticesNB; ++aCornerIter)
223 {
7c3ef2f7 224 Standard_Real aProjection = aDim == 0
225 ? myClipVerts[aCornerIter].x()
226 : (aDim == 1
227 ? myClipVerts[aCornerIter].y()
228 : myClipVerts[aCornerIter].z());
14a35e5d 229 aMaxProj = Max (aProjection, aMaxProj);
230 aMinProj = Min (aProjection, aMinProj);
b7cd4ba7 231 }
14a35e5d 232 myMaxOrthoProjectionPts[aDim] = aMaxProj;
233 myMinOrthoProjectionPts[aDim] = aMinProj;
b7cd4ba7 234 }
235}
236
237// =======================================================================
238// function : Intersect
239// purpose : Detects if AABB overlaps view volume using separating axis theorem (SAT)
240// =======================================================================
7c3ef2f7 241Standard_Boolean OpenGl_BVHTreeSelector::Intersect (const OpenGl_Vec3d& theMinPt,
242 const OpenGl_Vec3d& theMaxPt) const
b7cd4ba7 243{
244 // E1
245 // |_ E0
246 // /
247 // E2
b7cd4ba7 248
249 // E0 test
14a35e5d 250 if (theMinPt.x() > myMaxOrthoProjectionPts[0]
251 || theMaxPt.x() < myMinOrthoProjectionPts[0])
b7cd4ba7 252 {
253 return Standard_False;
254 }
255
256 // E1 test
14a35e5d 257 if (theMinPt.y() > myMaxOrthoProjectionPts[1]
258 || theMaxPt.y() < myMinOrthoProjectionPts[1])
b7cd4ba7 259 {
260 return Standard_False;
261 }
262
263 // E2 test
14a35e5d 264 if (theMinPt.z() > myMaxOrthoProjectionPts[2]
265 || theMaxPt.z() < myMinOrthoProjectionPts[2])
b7cd4ba7 266 {
267 return Standard_False;
268 }
269
7c3ef2f7 270 Standard_Real aBoxProjMax = 0.0, aBoxProjMin = 0.0;
b7cd4ba7 271 const Standard_Integer anIncFactor = myIsProjectionParallel ? 2 : 1;
272 for (Standard_Integer aPlaneIter = 0; aPlaneIter < 5; aPlaneIter += anIncFactor)
273 {
7c3ef2f7 274 OpenGl_Vec4d aPlane = myClipPlanes[aPlaneIter];
275 aBoxProjMax = (aPlane.x() > 0.0 ? (aPlane.x() * theMaxPt.x()) : aPlane.x() * theMinPt.x())
276 + (aPlane.y() > 0.0 ? (aPlane.y() * theMaxPt.y()) : aPlane.y() * theMinPt.y())
277 + (aPlane.z() > 0.0 ? (aPlane.z() * theMaxPt.z()) : aPlane.z() * theMinPt.z());
14a35e5d 278 if (aBoxProjMax > myMinClipProjectionPts[aPlaneIter]
279 && aBoxProjMax < myMaxClipProjectionPts[aPlaneIter])
b7cd4ba7 280 {
281 continue;
282 }
283
7c3ef2f7 284 aBoxProjMin = (aPlane.x() < 0.0 ? aPlane.x() * theMaxPt.x() : aPlane.x() * theMinPt.x())
285 + (aPlane.y() < 0.0 ? aPlane.y() * theMaxPt.y() : aPlane.y() * theMinPt.y())
286 + (aPlane.z() < 0.0 ? aPlane.z() * theMaxPt.z() : aPlane.z() * theMinPt.z());
14a35e5d 287 if (aBoxProjMin > myMaxClipProjectionPts[aPlaneIter]
288 || aBoxProjMax < myMinClipProjectionPts[aPlaneIter])
b7cd4ba7 289 {
290 return Standard_False;
291 }
292 }
293
4ecf34cc 294 // distance culling - discard node if distance to it's bounding box from camera eye is less than specified culling distance
295 if (myDistCull > 0.0)
296 {
297 // check distance to the bounding sphere as fast approximation
298 const Graphic3d_Vec3d aSphereCenter = (theMinPt + theMaxPt) * 0.5;
299 const Standard_Real aSphereRadius = (theMaxPt - theMinPt).maxComp() * 0.5;
300 if ((aSphereCenter - myCamEye).Modulus() - aSphereRadius > myDistCull)
301 {
302 return Standard_False;
303 }
304 }
305
306 // size culling - discard node if diagonal of it's bounding box is less than specified culling size
307 if (mySizeCull2 > 0.0)
308 {
309 if ((theMaxPt - theMinPt).SquareModulus() < mySizeCull2)
310 {
311 return Standard_False;
312 }
313 }
314
b7cd4ba7 315 return Standard_True;
316}