GteBspNode.cpp
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.0 (2016/06/19)
7 
8 #include <GTEnginePCH.h>
9 #include <Graphics/GteBspNode.h>
10 #include <Graphics/GteCamera.h>
11 using namespace gte;
12 
13 
15  :
16  mModelPlane({ 0.0f, 0.0f, 0.0f, 0.0f }),
17  mWorldPlane({ 0.0f, 0.0f, 0.0f, 0.0f })
18 {
19  mChild.push_back(nullptr); // left child
20  mChild.push_back(nullptr); // middle child
21  mChild.push_back(nullptr); // right child
22 }
23 
24 BspNode::BspNode(Plane3<float> const& modelPlane)
25 {
26  SetModelPlane(modelPlane);
27  SetWorldPlane(modelPlane);
28  mChild.push_back(nullptr); // left child
29  mChild.push_back(nullptr); // middle child
30  mChild.push_back(nullptr); // right child
31 }
32 
34 {
35  mModelPlane[0] = plane.normal[0];
36  mModelPlane[1] = plane.normal[1];
37  mModelPlane[2] = plane.normal[2];
38  mModelPlane[3] = -plane.constant;
40 }
41 
43 {
44  Plane3<float> plane;
45  plane.normal[0] = mModelPlane[0];
46  plane.normal[1] = mModelPlane[1];
47  plane.normal[2] = mModelPlane[2];
48  plane.constant = -mModelPlane[3];
49  return plane;
50 }
51 
53 {
54  Plane3<float> plane;
55  plane.normal[0] = mWorldPlane[0];
56  plane.normal[1] = mWorldPlane[1];
57  plane.normal[2] = mWorldPlane[2];
58  plane.constant = -mWorldPlane[3];
59  return plane;
60 }
61 
63 {
64  std::shared_ptr<Spatial> posChild = GetPositiveChild();
65  std::shared_ptr<Spatial> negChild = GetNegativeChild();
66 
67  if (posChild || negChild)
68  {
69  BspNode* bspChild;
70 
71  if (WhichSide(point) < 0)
72  {
73  bspChild = dynamic_cast<BspNode*>(negChild.get());
74  if (bspChild)
75  {
76  return bspChild->GetContainingNode(point);
77  }
78  else
79  {
80  return negChild.get();
81  }
82  }
83  else
84  {
85  bspChild = dynamic_cast<BspNode*>(posChild.get());
86  if (bspChild)
87  {
88  return bspChild->GetContainingNode(point);
89  }
90  else
91  {
92  return posChild.get();
93  }
94  }
95  }
96 
97  return this;
98 }
99 
101 {
102  // Normalize to make (n0,n1,n2,-c), where (n0,n1,n2) is unit length.
103  Vector3<float> normal{ plane[0], plane[1], plane[2] };
104  float length = Normalize(normal);
105  plane[0] = normal[0];
106  plane[1] = normal[1];
107  plane[2] = normal[2];
108  plane[3] /= length;
109 }
110 
112 {
113  mWorldPlane[0] = plane.normal[0];
114  mWorldPlane[1] = plane.normal[1];
115  mWorldPlane[2] = plane.normal[2];
116  mWorldPlane[3] = -plane.constant;
118 }
119 
120 void BspNode::UpdateWorldData(double applicationTime)
121 {
122  Node::UpdateWorldData(applicationTime);
123 
124 #if defined(GTE_USE_MAT_VEC)
126 #else
128 #endif
130 }
131 
133  std::shared_ptr<Camera> const& camera, bool noCull)
134 {
135  // Get visible geometry in back-to-front order. If a global effect is
136  // active, the geometry objects in the subtree will be drawn using it.
137  std::shared_ptr<Spatial> posChild = GetPositiveChild();
138  std::shared_ptr<Spatial> copChild = GetCoplanarChild();
139  std::shared_ptr<Spatial> negChild = GetNegativeChild();
140 
141  int positionSide = WhichSide(camera->GetPosition());
142  int frustumSide = WhichSide(camera);
143 
144  if (positionSide > 0)
145  {
146  // Camera origin on positive side of plane.
147 
148  if (frustumSide <= 0)
149  {
150  // The frustum is on the negative side of the plane or straddles
151  // the plane. In either case, the negative child is potentially
152  // visible.
153  if (negChild)
154  {
155  negChild->OnGetVisibleSet(culler, camera, noCull);
156  }
157  }
158 
159  if (frustumSide == 0)
160  {
161  // The frustum straddles the plane. The coplanar child is
162  // potentially visible.
163  if (copChild)
164  {
165  copChild->OnGetVisibleSet(culler, camera, noCull);
166  }
167  }
168 
169  if (frustumSide >= 0)
170  {
171  // The frustum is on the positive side of the plane or straddles
172  // the plane. In either case, the positive child is potentially
173  // visible.
174  if (posChild)
175  {
176  posChild->OnGetVisibleSet(culler, camera, noCull);
177  }
178  }
179  }
180  else if (positionSide < 0)
181  {
182  // Camera origin on negative side of plane.
183 
184  if (frustumSide >= 0)
185  {
186  // The frustum is on the positive side of the plane or straddles
187  // the plane. In either case, the positive child is potentially
188  // visible.
189  if (posChild)
190  {
191  posChild->OnGetVisibleSet(culler, camera, noCull);
192  }
193  }
194 
195  if (frustumSide == 0)
196  {
197  // The frustum straddles the plane. The coplanar child is
198  // potentially visible.
199  if (copChild)
200  {
201  copChild->OnGetVisibleSet(culler, camera, noCull);
202  }
203  }
204 
205  if (frustumSide <= 0)
206  {
207  // The frustum is on the negative side of the plane or straddles
208  // the plane. In either case, the negative child is potentially
209  // visible.
210  if (negChild)
211  {
212  negChild->OnGetVisibleSet(culler, camera, noCull);
213  }
214  }
215  }
216  else
217  {
218  // Camera origin on plane itself. Both sides of the plane are
219  // potentially visible as well as the plane itself. Select the
220  // first-to-be-drawn half space to be the one to which the camera
221  // direction points.
222  float NdD = Dot(mWorldPlane, camera->GetDVector());
223  if (NdD >= 0.0f)
224  {
225  if (posChild)
226  {
227  posChild->OnGetVisibleSet(culler, camera, noCull);
228  }
229 
230  if (copChild)
231  {
232  copChild->OnGetVisibleSet(culler, camera, noCull);
233  }
234 
235  if (negChild)
236  {
237  negChild->OnGetVisibleSet(culler, camera, noCull);
238  }
239  }
240  else
241  {
242  if (negChild)
243  {
244  negChild->OnGetVisibleSet(culler, camera, noCull);
245  }
246 
247  if (copChild)
248  {
249  copChild->OnGetVisibleSet(culler, camera, noCull);
250  }
251 
252  if (posChild)
253  {
254  posChild->OnGetVisibleSet(culler, camera, noCull);
255  }
256  }
257  }
258 }
259 
260 int BspNode::WhichSide(Vector4<float> const& point) const
261 {
262  float dot = Dot(mWorldPlane, point);
263  return (dot > 0.0f ? +1 : (dot < 0.0f ? -1 : 0));
264 }
265 
266 int BspNode::WhichSide(std::shared_ptr<Camera> const& camera) const
267 {
268  float const* frustum = camera->GetFrustum();
269 
270  // The plane is N*(X-C) = 0 where the * indicates dot product. The signed
271  // distance from the camera location E to the plane is N*(E-C).
272  float NdEmC = Dot(mWorldPlane, camera->GetPosition());
273 
274  Vector4<float> normal{
275  mWorldPlane[0], mWorldPlane[1], mWorldPlane[2], 0.0f};
276  float NdD = Dot(normal, camera->GetDVector());
277  float NdU = Dot(normal, camera->GetUVector());
278  float NdR = Dot(normal, camera->GetRVector());
279  float FdN = frustum[Camera::VF_DMAX] / frustum[Camera::VF_DMIN];
280 
281  int positive = 0, negative = 0;
282  float sgnDist;
283 
284  // Check near-plane vertices.
285  float PDMin = frustum[Camera::VF_DMIN] * NdD;
286  float NUMin = frustum[Camera::VF_UMIN] * NdU;
287  float NUMax = frustum[Camera::VF_UMAX] * NdU;
288  float NRMin = frustum[Camera::VF_RMIN] * NdR;
289  float NRMax = frustum[Camera::VF_RMAX] * NdR;
290 
291  // V = E + dmin*D + umin*U + rmin*R
292  // N*(V-C) = N*(E-C) + dmin*(N*D) + umin*(N*U) + rmin*(N*R)
293  sgnDist = NdEmC + PDMin + NUMin + NRMin;
294  if (sgnDist > 0.0f)
295  {
296  ++positive;
297  }
298  else if (sgnDist < 0.0f)
299  {
300  ++negative;
301  }
302 
303  // V = E + dmin*D + umin*U + rmax*R
304  // N*(V-C) = N*(E-C) + dmin*(N*D) + umin*(N*U) + rmax*(N*R)
305  sgnDist = NdEmC + PDMin + NUMin + NRMax;
306  if (sgnDist > 0.0f)
307  {
308  ++positive;
309  }
310  else if (sgnDist < 0.0f)
311  {
312  ++negative;
313  }
314 
315  // V = E + dmin*D + umax*U + rmin*R
316  // N*(V-C) = N*(E-C) + dmin*(N*D) + umax*(N*U) + rmin*(N*R)
317  sgnDist = NdEmC + PDMin + NUMax + NRMin;
318  if (sgnDist > 0.0f)
319  {
320  ++positive;
321  }
322  else if (sgnDist < 0.0f)
323  {
324  ++negative;
325  }
326 
327  // V = E + dmin*D + umax*U + rmax*R
328  // N*(V-C) = N*(E-C) + dmin*(N*D) + umax*(N*U) + rmax*(N*R)
329  sgnDist = NdEmC + PDMin + NUMax + NRMax;
330  if (sgnDist > 0.0f)
331  {
332  ++positive;
333  }
334  else if (sgnDist < 0.0f)
335  {
336  ++negative;
337  }
338 
339  // check far-plane vertices (s = dmax/dmin)
340  float PDMax = frustum[Camera::VF_DMAX] * NdD;
341  float FUMin = FdN * NUMin;
342  float FUMax = FdN * NUMax;
343  float FRMin = FdN * NRMin;
344  float FRMax = FdN * NRMax;
345 
346  // V = E + dmax*D + umin*U + rmin*R
347  // N*(V-C) = N*(E-C) + dmax*(N*D) + s*umin*(N*U) + s*rmin*(N*R)
348  sgnDist = NdEmC + PDMax + FUMin + FRMin;
349  if (sgnDist > 0.0f)
350  {
351  ++positive;
352  }
353  else if (sgnDist < 0.0f)
354  {
355  ++negative;
356  }
357 
358  // V = E + dmax*D + umin*U + rmax*R
359  // N*(V-C) = N*(E-C) + dmax*(N*D) + s*umin*(N*U) + s*rmax*(N*R)
360  sgnDist = NdEmC + PDMax + FUMin + FRMax;
361  if (sgnDist > 0.0f)
362  {
363  ++positive;
364  }
365  else if (sgnDist < 0.0f)
366  {
367  ++negative;
368  }
369 
370  // V = E + dmax*D + umax*U + rmin*R
371  // N*(V-C) = N*(E-C) + dmax*(N*D) + s*umax*(N*U) + s*rmin*(N*R)
372  sgnDist = NdEmC + PDMax + FUMax + FRMin;
373  if (sgnDist > 0.0f)
374  {
375  ++positive;
376  }
377  else if (sgnDist < 0.0f)
378  {
379  ++negative;
380  }
381 
382  // V = E + dmax*D + umax*U + rmax*R
383  // N*(V-C) = N*(E-C) + dmax*(N*D) + s*umax*(N*U) + s*rmax*(N*R)
384  sgnDist = NdEmC + PDMax + FUMax + FRMax;
385  if (sgnDist > 0.0f)
386  {
387  ++positive;
388  }
389  else if (sgnDist < 0.0f)
390  {
391  ++negative;
392  }
393 
394  if (positive > 0)
395  {
396  if (negative > 0)
397  {
398  // Frustum straddles the plane.
399  return 0;
400  }
401 
402  // Frustum is fully on the positive side.
403  return +1;
404  }
405 
406  // Frustum is fully on the negative side.
407  return -1;
408 }
409 
void SetWorldPlane(Plane3< float > const &plane)
Definition: GteBspNode.cpp:111
virtual void UpdateWorldData(double applicationTime)
Definition: GteNode.cpp:156
Plane3< float > GetWorldPlane() const
Definition: GteBspNode.cpp:52
std::shared_ptr< Spatial > GetNegativeChild()
Definition: GteBspNode.h:131
std::shared_ptr< Spatial > GetCoplanarChild()
Definition: GteBspNode.h:126
Transform worldTransform
Definition: GteSpatial.h:50
virtual void UpdateWorldData(double applicationTime)
Definition: GteBspNode.cpp:120
DualQuaternion< Real > Dot(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
Real Normalize(GVector< Real > &v, bool robust=false)
Definition: GteGVector.h:454
std::shared_ptr< Spatial > GetPositiveChild()
Definition: GteBspNode.h:121
Spatial * GetContainingNode(Vector4< float > const &point)
Definition: GteBspNode.cpp:62
Plane3< float > GetModelPlane() const
Definition: GteBspNode.cpp:42
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:790
Vector4< float > mModelPlane
Definition: GteBspNode.h:84
std::vector< std::shared_ptr< Spatial > > mChild
Definition: GteNode.h:100
Vector< N, Real > normal
Definition: GteHyperplane.h:40
GLfloat f
Definition: glcorearb.h:1921
void NormalizePlane(Vector4< float > &plane)
Definition: GteBspNode.cpp:100
int WhichSide(Vector4< float > const &point) const
Definition: GteBspNode.cpp:260
virtual void GetVisibleSet(Culler &culler, std::shared_ptr< Camera > const &camera, bool noCull)
Definition: GteBspNode.cpp:132
Matrix4x4< float > const & GetHInverse() const
void SetModelPlane(Plane3< float > const &plane)
Definition: GteBspNode.cpp:33
Vector4< float > mWorldPlane
Definition: GteBspNode.h:84


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 03:59:59