0029285: Visualization, V3d_View::UpdateLights() - eliminate implicit redraw
[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()
825aa485 27: myIsProjectionParallel (Standard_True)
b7cd4ba7 28{
29 //
30}
31
32// =======================================================================
825aa485 33// function : SetViewVolume
34// purpose : Retrieves view volume's planes equations and its vertices from projection and world-view matrices.
b7cd4ba7 35// =======================================================================
36void OpenGl_BVHTreeSelector::SetViewVolume (const Handle(Graphic3d_Camera)& theCamera)
37{
97f937cc 38 if (!myWorldViewProjState.IsChanged (theCamera->WorldViewProjState()))
825aa485 39 return;
825aa485 40
b7cd4ba7 41 myIsProjectionParallel = theCamera->IsOrthographic();
825aa485 42
3fe9ce0e 43 myCamera = theCamera;
7c3ef2f7 44 myProjectionMat = theCamera->ProjectionMatrix();
45 myWorldViewMat = theCamera->OrientationMatrix();
825aa485 46 myWorldViewProjState = theCamera->WorldViewProjState();
b7cd4ba7 47
7c3ef2f7 48 Standard_Real nLeft = 0.0, nRight = 0.0, nTop = 0.0, nBottom = 0.0;
49 Standard_Real fLeft = 0.0, fRight = 0.0, fTop = 0.0, fBottom = 0.0;
50 Standard_Real aNear = 0.0, aFar = 0.0;
b7cd4ba7 51 if (!myIsProjectionParallel)
52 {
53 // handle perspective projection
7c3ef2f7 54 aNear = myProjectionMat.GetValue (2, 3) / (- 1.0 + myProjectionMat.GetValue (2, 2));
55 aFar = myProjectionMat.GetValue (2, 3) / ( 1.0 + myProjectionMat.GetValue (2, 2));
b7cd4ba7 56 // Near plane
7c3ef2f7 57 nLeft = aNear * (myProjectionMat.GetValue (0, 2) - 1.0) / myProjectionMat.GetValue (0, 0);
58 nRight = aNear * (myProjectionMat.GetValue (0, 2) + 1.0) / myProjectionMat.GetValue (0, 0);
59 nTop = aNear * (myProjectionMat.GetValue (1, 2) + 1.0) / myProjectionMat.GetValue (1, 1);
60 nBottom = aNear * (myProjectionMat.GetValue (1, 2) - 1.0) / myProjectionMat.GetValue (1, 1);
b7cd4ba7 61 // Far plane
7c3ef2f7 62 fLeft = aFar * (myProjectionMat.GetValue (0, 2) - 1.0) / myProjectionMat.GetValue (0, 0);
63 fRight = aFar * (myProjectionMat.GetValue (0, 2) + 1.0) / myProjectionMat.GetValue (0, 0);
64 fTop = aFar * (myProjectionMat.GetValue (1, 2) + 1.0) / myProjectionMat.GetValue (1, 1);
65 fBottom = aFar * (myProjectionMat.GetValue (1, 2) - 1.0) / myProjectionMat.GetValue (1, 1);
b7cd4ba7 66 }
67 else
68 {
69 // handle orthographic projection
7c3ef2f7 70 aNear = (1.0 / myProjectionMat.GetValue (2, 2)) * (myProjectionMat.GetValue (2, 3) + 1.0);
71 aFar = (1.0 / myProjectionMat.GetValue (2, 2)) * (myProjectionMat.GetValue (2, 3) - 1.0);
b7cd4ba7 72 // Near plane
7c3ef2f7 73 nLeft = ( 1.0 + myProjectionMat.GetValue (0, 3)) / (-myProjectionMat.GetValue (0, 0));
b7cd4ba7 74 fLeft = nLeft;
7c3ef2f7 75 nRight = ( 1.0 - myProjectionMat.GetValue (0, 3)) / myProjectionMat.GetValue (0, 0);
b7cd4ba7 76 fRight = nRight;
7c3ef2f7 77 nTop = ( 1.0 - myProjectionMat.GetValue (1, 3)) / myProjectionMat.GetValue (1, 1);
b7cd4ba7 78 fTop = nTop;
7c3ef2f7 79 nBottom = (-1.0 - myProjectionMat.GetValue (1, 3)) / myProjectionMat.GetValue (1, 1);
b7cd4ba7 80 fBottom = nBottom;
81 }
82
7c3ef2f7 83 OpenGl_Vec4d aLeftTopNear (nLeft, nTop, -aNear, 1.0), aRightBottomFar (fRight, fBottom, -aFar, 1.0);
84 OpenGl_Vec4d aLeftBottomNear (nLeft, nBottom, -aNear, 1.0), aRightTopFar (fRight, fTop, -aFar, 1.0);
85 OpenGl_Vec4d aRightBottomNear (nRight, nBottom, -aNear, 1.0), aLeftTopFar (fLeft, fTop, -aFar, 1.0);
86 OpenGl_Vec4d aRightTopNear (nRight, nTop, -aNear, 1.0), aLeftBottomFar (fLeft, fBottom, -aFar, 1.0);
b7cd4ba7 87
7c3ef2f7 88 const OpenGl_Mat4d aViewProj = myWorldViewMat * myProjectionMat;
89 OpenGl_Mat4d anInvWorldView;
90 myWorldViewMat.Inverted (anInvWorldView);
b7cd4ba7 91
825aa485 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;
b7cd4ba7 100
101 // UNNORMALIZED!
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);
108
109 gp_Pnt aPtCenter = theCamera->Center();
7c3ef2f7 110 OpenGl_Vec4d aCenter (aPtCenter.X(), aPtCenter.Y(), aPtCenter.Z(), 1.0);
b7cd4ba7 111
112 for (Standard_Integer aPlaneIter = 0; aPlaneIter < PlanesNB; ++aPlaneIter)
113 {
7c3ef2f7 114 OpenGl_Vec4d anEq = myClipPlanes[aPlaneIter];
b7cd4ba7 115 if (SignedPlanePointDistance (anEq, aCenter) > 0)
116 {
7c3ef2f7 117 anEq *= -1.0;
b7cd4ba7 118 myClipPlanes[aPlaneIter] = anEq;
119 }
120 }
121}
122
123// =======================================================================
91d96372 124// function : SetViewportSize
125// purpose :
126// =======================================================================
127void OpenGl_BVHTreeSelector::SetViewportSize (const Standard_Integer theViewportWidth,
128 const Standard_Integer theViewportHeight)
129{
130 myViewportHeight = theViewportHeight;
131 myViewportWidth = theViewportWidth;
132}
133
134// =======================================================================
b7cd4ba7 135// function : SignedPlanePointDistance
136// purpose :
137// =======================================================================
7c3ef2f7 138Standard_Real OpenGl_BVHTreeSelector::SignedPlanePointDistance (const OpenGl_Vec4d& theNormal,
139 const OpenGl_Vec4d& thePnt)
b7cd4ba7 140{
7c3ef2f7 141 const Standard_Real aNormLength = std::sqrt (theNormal.x() * theNormal.x()
142 + theNormal.y() * theNormal.y()
143 + theNormal.z() * theNormal.z());
3c648527 144
7c3ef2f7 145 if (aNormLength < gp::Resolution())
146 return 0.0;
3c648527 147
7c3ef2f7 148 const Standard_Real anInvNormLength = 1.0 / aNormLength;
149 const Standard_Real aD = theNormal.w() * anInvNormLength;
150 const Standard_Real anA = theNormal.x() * anInvNormLength;
151 const Standard_Real aB = theNormal.y() * anInvNormLength;
152 const Standard_Real aC = theNormal.z() * anInvNormLength;
b7cd4ba7 153 return aD + (anA * thePnt.x() + aB * thePnt.y() + aC * thePnt.z());
154}
155
156// =======================================================================
157// function : CacheClipPtsProjections
158// purpose : Caches view volume's vertices projections along its normals and AABBs dimensions
159// Must be called at the beginning of each BVH tree traverse loop
160// =======================================================================
161void OpenGl_BVHTreeSelector::CacheClipPtsProjections()
162{
14a35e5d 163 const Standard_Integer anIncFactor = myIsProjectionParallel ? 2 : 1;
164 for (Standard_Integer aPlaneIter = 0; aPlaneIter < 5; aPlaneIter += anIncFactor)
b7cd4ba7 165 {
7c3ef2f7 166 const OpenGl_Vec4d aPlane = myClipPlanes[aPlaneIter];
167 Standard_Real aMaxProj = -std::numeric_limits<Standard_Real>::max();
168 Standard_Real aMinProj = std::numeric_limits<Standard_Real>::max();
b7cd4ba7 169 for (Standard_Integer aCornerIter = 0; aCornerIter < ClipVerticesNB; ++aCornerIter)
170 {
7c3ef2f7 171 Standard_Real aProjection = aPlane.x() * myClipVerts[aCornerIter].x()
172 + aPlane.y() * myClipVerts[aCornerIter].y()
173 + aPlane.z() * myClipVerts[aCornerIter].z();
14a35e5d 174 aMaxProj = Max (aProjection, aMaxProj);
175 aMinProj = Min (aProjection, aMinProj);
b7cd4ba7 176 }
14a35e5d 177 myMaxClipProjectionPts[aPlaneIter] = aMaxProj;
178 myMinClipProjectionPts[aPlaneIter] = aMinProj;
b7cd4ba7 179 }
180
b7cd4ba7 181 for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
182 {
7c3ef2f7 183 Standard_Real aMaxProj = -std::numeric_limits<Standard_Real>::max();
184 Standard_Real aMinProj = std::numeric_limits<Standard_Real>::max();
b7cd4ba7 185 for (Standard_Integer aCornerIter = 0; aCornerIter < ClipVerticesNB; ++aCornerIter)
186 {
7c3ef2f7 187 Standard_Real aProjection = aDim == 0
188 ? myClipVerts[aCornerIter].x()
189 : (aDim == 1
190 ? myClipVerts[aCornerIter].y()
191 : myClipVerts[aCornerIter].z());
14a35e5d 192 aMaxProj = Max (aProjection, aMaxProj);
193 aMinProj = Min (aProjection, aMinProj);
b7cd4ba7 194 }
14a35e5d 195 myMaxOrthoProjectionPts[aDim] = aMaxProj;
196 myMinOrthoProjectionPts[aDim] = aMinProj;
b7cd4ba7 197 }
198}
199
200// =======================================================================
201// function : Intersect
202// purpose : Detects if AABB overlaps view volume using separating axis theorem (SAT)
203// =======================================================================
7c3ef2f7 204Standard_Boolean OpenGl_BVHTreeSelector::Intersect (const OpenGl_Vec3d& theMinPt,
205 const OpenGl_Vec3d& theMaxPt) const
b7cd4ba7 206{
207 // E1
208 // |_ E0
209 // /
210 // E2
b7cd4ba7 211
212 // E0 test
14a35e5d 213 if (theMinPt.x() > myMaxOrthoProjectionPts[0]
214 || theMaxPt.x() < myMinOrthoProjectionPts[0])
b7cd4ba7 215 {
216 return Standard_False;
217 }
218
219 // E1 test
14a35e5d 220 if (theMinPt.y() > myMaxOrthoProjectionPts[1]
221 || theMaxPt.y() < myMinOrthoProjectionPts[1])
b7cd4ba7 222 {
223 return Standard_False;
224 }
225
226 // E2 test
14a35e5d 227 if (theMinPt.z() > myMaxOrthoProjectionPts[2]
228 || theMaxPt.z() < myMinOrthoProjectionPts[2])
b7cd4ba7 229 {
230 return Standard_False;
231 }
232
7c3ef2f7 233 Standard_Real aBoxProjMax = 0.0, aBoxProjMin = 0.0;
b7cd4ba7 234 const Standard_Integer anIncFactor = myIsProjectionParallel ? 2 : 1;
235 for (Standard_Integer aPlaneIter = 0; aPlaneIter < 5; aPlaneIter += anIncFactor)
236 {
7c3ef2f7 237 OpenGl_Vec4d aPlane = myClipPlanes[aPlaneIter];
238 aBoxProjMax = (aPlane.x() > 0.0 ? (aPlane.x() * theMaxPt.x()) : aPlane.x() * theMinPt.x())
239 + (aPlane.y() > 0.0 ? (aPlane.y() * theMaxPt.y()) : aPlane.y() * theMinPt.y())
240 + (aPlane.z() > 0.0 ? (aPlane.z() * theMaxPt.z()) : aPlane.z() * theMinPt.z());
14a35e5d 241 if (aBoxProjMax > myMinClipProjectionPts[aPlaneIter]
242 && aBoxProjMax < myMaxClipProjectionPts[aPlaneIter])
b7cd4ba7 243 {
244 continue;
245 }
246
7c3ef2f7 247 aBoxProjMin = (aPlane.x() < 0.0 ? aPlane.x() * theMaxPt.x() : aPlane.x() * theMinPt.x())
248 + (aPlane.y() < 0.0 ? aPlane.y() * theMaxPt.y() : aPlane.y() * theMinPt.y())
249 + (aPlane.z() < 0.0 ? aPlane.z() * theMaxPt.z() : aPlane.z() * theMinPt.z());
14a35e5d 250 if (aBoxProjMin > myMaxClipProjectionPts[aPlaneIter]
251 || aBoxProjMax < myMinClipProjectionPts[aPlaneIter])
b7cd4ba7 252 {
253 return Standard_False;
254 }
255 }
256
257 return Standard_True;
258}