Bullet Collision Detection & Physics Library
btHeightfieldTerrainShape.cpp
Go to the documentation of this file.
1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
4 
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
10 
11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
14 */
15 
17 
19 
21  int heightStickWidth, int heightStickLength, const void* heightfieldData,
22  btScalar heightScale, btScalar minHeight, btScalar maxHeight, int upAxis,
23  PHY_ScalarType hdt, bool flipQuadEdges)
24  :m_userIndex2(-1),
25  m_userValue3(0),
26  m_triangleInfoMap(0)
27 {
28  initialize(heightStickWidth, heightStickLength, heightfieldData,
29  heightScale, minHeight, maxHeight, upAxis, hdt,
30  flipQuadEdges);
31 }
32 
33 btHeightfieldTerrainShape::btHeightfieldTerrainShape(int heightStickWidth, int heightStickLength, const void* heightfieldData, btScalar maxHeight, int upAxis, bool useFloatData, bool flipQuadEdges)
34  :m_userIndex2(-1),
35  m_userValue3(0),
36  m_triangleInfoMap(0)
37 {
38  // legacy constructor: support only float or unsigned char,
39  // and min height is zero
40  PHY_ScalarType hdt = (useFloatData) ? PHY_FLOAT : PHY_UCHAR;
41  btScalar minHeight = 0.0f;
42 
43  // previously, height = uchar * maxHeight / 65535.
44  // So to preserve legacy behavior, heightScale = maxHeight / 65535
45  btScalar heightScale = maxHeight / 65535;
46 
47  initialize(heightStickWidth, heightStickLength, heightfieldData,
48  heightScale, minHeight, maxHeight, upAxis, hdt,
49  flipQuadEdges);
50 }
51 
53  int heightStickWidth, int heightStickLength, const void* heightfieldData,
54  btScalar heightScale, btScalar minHeight, btScalar maxHeight, int upAxis,
55  PHY_ScalarType hdt, bool flipQuadEdges)
56 {
57  // validation
58  btAssert(heightStickWidth > 1); // && "bad width");
59  btAssert(heightStickLength > 1); // && "bad length");
60  btAssert(heightfieldData); // && "null heightfield data");
61  // btAssert(heightScale) -- do we care? Trust caller here
62  btAssert(minHeight <= maxHeight); // && "bad min/max height");
63  btAssert(upAxis >= 0 && upAxis < 3); // && "bad upAxis--should be in range [0,2]");
64  btAssert(hdt != PHY_UCHAR || hdt != PHY_FLOAT || hdt != PHY_SHORT); // && "Bad height data type enum");
65 
66  // initialize member variables
68  m_heightStickWidth = heightStickWidth;
69  m_heightStickLength = heightStickLength;
70  m_minHeight = minHeight;
71  m_maxHeight = maxHeight;
72  m_width = (btScalar)(heightStickWidth - 1);
73  m_length = (btScalar)(heightStickLength - 1);
74  m_heightScale = heightScale;
75  m_heightfieldDataUnknown = heightfieldData;
76  m_heightDataType = hdt;
77  m_flipQuadEdges = flipQuadEdges;
79  m_useZigzagSubdivision = false;
80  m_flipTriangleWinding = false;
81  m_upAxis = upAxis;
83 
87 
88  // determine min/max axis-aligned bounding box (aabb) values
89  switch (m_upAxis)
90  {
91  case 0:
92  {
95  break;
96  }
97  case 1:
98  {
101  break;
102  };
103  case 2:
104  {
107  break;
108  }
109  default:
110  {
111  //need to get valid m_upAxis
112  btAssert(0); // && "Bad m_upAxis");
113  }
114  }
115 
116  // remember origin (defined as exact middle of aabb)
118 }
119 
121 {
123 }
124 
125 void btHeightfieldTerrainShape::getAabb(const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const
126 {
128 
129  btVector3 localOrigin(0, 0, 0);
130  localOrigin[m_upAxis] = (m_minHeight + m_maxHeight) * btScalar(0.5);
131  localOrigin *= m_localScaling;
132 
133  btMatrix3x3 abs_b = t.getBasis().absolute();
134  btVector3 center = t.getOrigin();
135  btVector3 extent = halfExtents.dot3(abs_b[0], abs_b[1], abs_b[2]);
136  extent += btVector3(getMargin(), getMargin(), getMargin());
137 
138  aabbMin = center - extent;
139  aabbMax = center + extent;
140 }
141 
145 btScalar
147 {
148  btScalar val = 0.f;
149  switch (m_heightDataType)
150  {
151  case PHY_FLOAT:
152  {
154  break;
155  }
156 
157  case PHY_UCHAR:
158  {
159  unsigned char heightFieldValue = m_heightfieldDataUnsignedChar[(y * m_heightStickWidth) + x];
160  val = heightFieldValue * m_heightScale;
161  break;
162  }
163 
164  case PHY_SHORT:
165  {
166  short hfValue = m_heightfieldDataShort[(y * m_heightStickWidth) + x];
167  val = hfValue * m_heightScale;
168  break;
169  }
170 
171  default:
172  {
173  btAssert(!"Bad m_heightDataType");
174  }
175  }
176 
177  return val;
178 }
179 
181 void btHeightfieldTerrainShape::getVertex(int x, int y, btVector3& vertex) const
182 {
183  btAssert(x >= 0);
184  btAssert(y >= 0);
187 
188  btScalar height = getRawHeightFieldValue(x, y);
189 
190  switch (m_upAxis)
191  {
192  case 0:
193  {
194  vertex.setValue(
195  height - m_localOrigin.getX(),
196  (-m_width / btScalar(2.0)) + x,
197  (-m_length / btScalar(2.0)) + y);
198  break;
199  }
200  case 1:
201  {
202  vertex.setValue(
203  (-m_width / btScalar(2.0)) + x,
204  height - m_localOrigin.getY(),
205  (-m_length / btScalar(2.0)) + y);
206  break;
207  };
208  case 2:
209  {
210  vertex.setValue(
211  (-m_width / btScalar(2.0)) + x,
212  (-m_length / btScalar(2.0)) + y,
213  height - m_localOrigin.getZ());
214  break;
215  }
216  default:
217  {
218  //need to get valid m_upAxis
219  btAssert(0);
220  }
221  }
222 
223  vertex *= m_localScaling;
224 }
225 
226 static inline int
228  btScalar x)
229 {
230  if (x < 0.0)
231  {
232  return (int)(x - 0.5);
233  }
234  return (int)(x + 0.5);
235 }
236 
238 
246 void btHeightfieldTerrainShape::quantizeWithClamp(int* out, const btVector3& point, int /*isMax*/) const
247 {
248  btVector3 clampedPoint(point);
249  clampedPoint.setMax(m_localAabbMin);
250  clampedPoint.setMin(m_localAabbMax);
251 
252  out[0] = getQuantized(clampedPoint.getX());
253  out[1] = getQuantized(clampedPoint.getY());
254  out[2] = getQuantized(clampedPoint.getZ());
255 }
256 
258 
264 void btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback, const btVector3& aabbMin, const btVector3& aabbMax) const
265 {
266  // scale down the input aabb's so they are in local (non-scaled) coordinates
267  btVector3 localAabbMin = aabbMin * btVector3(1.f / m_localScaling[0], 1.f / m_localScaling[1], 1.f / m_localScaling[2]);
268  btVector3 localAabbMax = aabbMax * btVector3(1.f / m_localScaling[0], 1.f / m_localScaling[1], 1.f / m_localScaling[2]);
269 
270  // account for local origin
271  localAabbMin += m_localOrigin;
272  localAabbMax += m_localOrigin;
273 
274  //quantize the aabbMin and aabbMax, and adjust the start/end ranges
275  int quantizedAabbMin[3];
276  int quantizedAabbMax[3];
277  quantizeWithClamp(quantizedAabbMin, localAabbMin, 0);
278  quantizeWithClamp(quantizedAabbMax, localAabbMax, 1);
279 
280  // expand the min/max quantized values
281  // this is to catch the case where the input aabb falls between grid points!
282  for (int i = 0; i < 3; ++i)
283  {
284  quantizedAabbMin[i]--;
285  quantizedAabbMax[i]++;
286  }
287 
288  int startX = 0;
289  int endX = m_heightStickWidth - 1;
290  int startJ = 0;
291  int endJ = m_heightStickLength - 1;
292 
293  switch (m_upAxis)
294  {
295  case 0:
296  {
297  if (quantizedAabbMin[1] > startX)
298  startX = quantizedAabbMin[1];
299  if (quantizedAabbMax[1] < endX)
300  endX = quantizedAabbMax[1];
301  if (quantizedAabbMin[2] > startJ)
302  startJ = quantizedAabbMin[2];
303  if (quantizedAabbMax[2] < endJ)
304  endJ = quantizedAabbMax[2];
305  break;
306  }
307  case 1:
308  {
309  if (quantizedAabbMin[0] > startX)
310  startX = quantizedAabbMin[0];
311  if (quantizedAabbMax[0] < endX)
312  endX = quantizedAabbMax[0];
313  if (quantizedAabbMin[2] > startJ)
314  startJ = quantizedAabbMin[2];
315  if (quantizedAabbMax[2] < endJ)
316  endJ = quantizedAabbMax[2];
317  break;
318  };
319  case 2:
320  {
321  if (quantizedAabbMin[0] > startX)
322  startX = quantizedAabbMin[0];
323  if (quantizedAabbMax[0] < endX)
324  endX = quantizedAabbMax[0];
325  if (quantizedAabbMin[1] > startJ)
326  startJ = quantizedAabbMin[1];
327  if (quantizedAabbMax[1] < endJ)
328  endJ = quantizedAabbMax[1];
329  break;
330  }
331  default:
332  {
333  //need to get valid m_upAxis
334  btAssert(0);
335  }
336  }
337 
338  // TODO If m_vboundsGrid is available, use it to determine if we really need to process this area
339 
340  for (int j = startJ; j < endJ; j++)
341  {
342  for (int x = startX; x < endX; x++)
343  {
344  btVector3 vertices[3];
345  int indices[3] = { 0, 1, 2 };
347  {
348  indices[0] = 2;
349  indices[2] = 0;
350  }
351 
352  if (m_flipQuadEdges || (m_useDiamondSubdivision && !((j + x) & 1)) || (m_useZigzagSubdivision && !(j & 1)))
353  {
354  //first triangle
355  getVertex(x, j, vertices[indices[0]]);
356  getVertex(x, j + 1, vertices[indices[1]]);
357  getVertex(x + 1, j + 1, vertices[indices[2]]);
358  callback->processTriangle(vertices, 2 * x, j);
359  //second triangle
360  // getVertex(x,j,vertices[0]);//already got this vertex before, thanks to Danny Chapman
361  getVertex(x + 1, j + 1, vertices[indices[1]]);
362  getVertex(x + 1, j, vertices[indices[2]]);
363  callback->processTriangle(vertices, 2 * x+1, j);
364  }
365  else
366  {
367  //first triangle
368  getVertex(x, j, vertices[indices[0]]);
369  getVertex(x, j + 1, vertices[indices[1]]);
370  getVertex(x + 1, j, vertices[indices[2]]);
371  callback->processTriangle(vertices, 2 * x, j);
372  //second triangle
373  getVertex(x + 1, j, vertices[indices[0]]);
374  //getVertex(x,j+1,vertices[1]);
375  getVertex(x + 1, j + 1, vertices[indices[2]]);
376  callback->processTriangle(vertices, 2 * x+1, j);
377  }
378  }
379  }
380 }
381 
383 {
384  //moving concave objects not supported
385 
386  inertia.setValue(btScalar(0.), btScalar(0.), btScalar(0.));
387 }
388 
390 {
391  m_localScaling = scaling;
392 }
394 {
395  return m_localScaling;
396 }
397 
398 namespace
399 {
400  struct GridRaycastState
401  {
402  int x; // Next quad coords
403  int z;
404  int prev_x; // Previous quad coords
405  int prev_z;
406  btScalar param; // Exit param for previous quad
407  btScalar prevParam; // Enter param for previous quad
408  btScalar maxDistanceFlat;
409  btScalar maxDistance3d;
410  };
411 }
412 
413 // TODO Does it really need to take 3D vectors?
417 template <typename Action_T>
418 void gridRaycast(Action_T& quadAction, const btVector3& beginPos, const btVector3& endPos, int indices[3])
419 {
420  GridRaycastState rs;
421  rs.maxDistance3d = beginPos.distance(endPos);
422  if (rs.maxDistance3d < 0.0001)
423  {
424  // Consider the ray is too small to hit anything
425  return;
426  }
427 
428 
429  btScalar rayDirectionFlatX = endPos[indices[0]] - beginPos[indices[0]];
430  btScalar rayDirectionFlatZ = endPos[indices[2]] - beginPos[indices[2]];
431  rs.maxDistanceFlat = btSqrt(rayDirectionFlatX * rayDirectionFlatX + rayDirectionFlatZ * rayDirectionFlatZ);
432 
433  if (rs.maxDistanceFlat < 0.0001)
434  {
435  // Consider the ray vertical
436  rayDirectionFlatX = 0;
437  rayDirectionFlatZ = 0;
438  }
439  else
440  {
441  rayDirectionFlatX /= rs.maxDistanceFlat;
442  rayDirectionFlatZ /= rs.maxDistanceFlat;
443  }
444 
445  const int xiStep = rayDirectionFlatX > 0 ? 1 : rayDirectionFlatX < 0 ? -1 : 0;
446  const int ziStep = rayDirectionFlatZ > 0 ? 1 : rayDirectionFlatZ < 0 ? -1 : 0;
447 
448  const float infinite = 9999999;
449  const btScalar paramDeltaX = xiStep != 0 ? 1.f / btFabs(rayDirectionFlatX) : infinite;
450  const btScalar paramDeltaZ = ziStep != 0 ? 1.f / btFabs(rayDirectionFlatZ) : infinite;
451 
452  // pos = param * dir
453  btScalar paramCrossX; // At which value of `param` we will cross a x-axis lane?
454  btScalar paramCrossZ; // At which value of `param` we will cross a z-axis lane?
455 
456  // paramCrossX and paramCrossZ are initialized as being the first cross
457  // X initialization
458  if (xiStep != 0)
459  {
460  if (xiStep == 1)
461  {
462  paramCrossX = (ceil(beginPos[indices[0]]) - beginPos[indices[0]]) * paramDeltaX;
463  }
464  else
465  {
466  paramCrossX = (beginPos[indices[0]] - floor(beginPos[indices[0]])) * paramDeltaX;
467  }
468  }
469  else
470  {
471  paramCrossX = infinite; // Will never cross on X
472  }
473 
474  // Z initialization
475  if (ziStep != 0)
476  {
477  if (ziStep == 1)
478  {
479  paramCrossZ = (ceil(beginPos[indices[2]]) - beginPos[indices[2]]) * paramDeltaZ;
480  }
481  else
482  {
483  paramCrossZ = (beginPos[indices[2]] - floor(beginPos[indices[2]])) * paramDeltaZ;
484  }
485  }
486  else
487  {
488  paramCrossZ = infinite; // Will never cross on Z
489  }
490 
491  rs.x = static_cast<int>(floor(beginPos[indices[0]]));
492  rs.z = static_cast<int>(floor(beginPos[indices[2]]));
493 
494  // Workaround cases where the ray starts at an integer position
495  if (paramCrossX == 0.0)
496  {
497  paramCrossX += paramDeltaX;
498  // If going backwards, we should ignore the position we would get by the above flooring,
499  // because the ray is not heading in that direction
500  if (xiStep == -1)
501  {
502  rs.x -= 1;
503  }
504  }
505 
506  if (paramCrossZ == 0.0)
507  {
508  paramCrossZ += paramDeltaZ;
509  if (ziStep == -1)
510  rs.z -= 1;
511  }
512 
513  rs.prev_x = rs.x;
514  rs.prev_z = rs.z;
515  rs.param = 0;
516 
517  while (true)
518  {
519  rs.prev_x = rs.x;
520  rs.prev_z = rs.z;
521  rs.prevParam = rs.param;
522 
523  if (paramCrossX < paramCrossZ)
524  {
525  // X lane
526  rs.x += xiStep;
527  // Assign before advancing the param,
528  // to be in sync with the initialization step
529  rs.param = paramCrossX;
530  paramCrossX += paramDeltaX;
531  }
532  else
533  {
534  // Z lane
535  rs.z += ziStep;
536  rs.param = paramCrossZ;
537  paramCrossZ += paramDeltaZ;
538  }
539 
540  if (rs.param > rs.maxDistanceFlat)
541  {
542  rs.param = rs.maxDistanceFlat;
543  quadAction(rs);
544  break;
545  }
546  else
547  {
548  quadAction(rs);
549  }
550  }
551 }
552 
554 {
558  int width;
559  int length;
561 
562  void exec(int x, int z) const
563  {
564  if (x < 0 || z < 0 || x >= width || z >= length)
565  {
566  return;
567  }
568 
569  btVector3 vertices[3];
570 
571  // TODO Since this is for raycasts, we could greatly benefit from an early exit on the first hit
572 
573  // Check quad
574  if (flipQuadEdges || (useDiamondSubdivision && (((z + x) & 1) > 0)))
575  {
576  // First triangle
577  shape->getVertex(x, z, vertices[0]);
578  shape->getVertex(x + 1, z, vertices[1]);
579  shape->getVertex(x + 1, z + 1, vertices[2]);
580  callback->processTriangle(vertices, x, z);
581 
582  // Second triangle
583  shape->getVertex(x, z, vertices[0]);
584  shape->getVertex(x + 1, z + 1, vertices[1]);
585  shape->getVertex(x, z + 1, vertices[2]);
586  callback->processTriangle(vertices, x, z);
587  }
588  else
589  {
590  // First triangle
591  shape->getVertex(x, z, vertices[0]);
592  shape->getVertex(x, z + 1, vertices[1]);
593  shape->getVertex(x + 1, z, vertices[2]);
594  callback->processTriangle(vertices, x, z);
595 
596  // Second triangle
597  shape->getVertex(x + 1, z, vertices[0]);
598  shape->getVertex(x, z + 1, vertices[1]);
599  shape->getVertex(x + 1, z + 1, vertices[2]);
600  callback->processTriangle(vertices, x, z);
601  }
602  }
603 
604  void operator()(const GridRaycastState& bs) const
605  {
606  exec(bs.prev_x, bs.prev_z);
607  }
608 };
609 
611 {
613  int width;
614  int length;
616 
620 
621  int* m_indices;
623 
625  : vbounds(bnd),
626  m_indices(indices)
627  {
628  }
629  void operator()(const GridRaycastState& rs) const
630  {
631  int x = rs.prev_x;
632  int z = rs.prev_z;
633 
634  if (x < 0 || z < 0 || x >= width || z >= length)
635  {
636  return;
637  }
638 
639  const btHeightfieldTerrainShape::Range chunk = vbounds[x + z * width];
640 
641  btVector3 enterPos;
642  btVector3 exitPos;
643 
644  if (rs.maxDistanceFlat > 0.0001)
645  {
646  btScalar flatTo3d = chunkSize * rs.maxDistance3d / rs.maxDistanceFlat;
647  btScalar enterParam3d = rs.prevParam * flatTo3d;
648  btScalar exitParam3d = rs.param * flatTo3d;
649  enterPos = rayBegin + rayDir * enterParam3d;
650  exitPos = rayBegin + rayDir * exitParam3d;
651 
652  // We did enter the flat projection of the AABB,
653  // but we have to check if we intersect it on the vertical axis
654  if (enterPos[1] > chunk.max && exitPos[m_indices[1]] > chunk.max)
655  {
656  return;
657  }
658  if (enterPos[1] < chunk.min && exitPos[m_indices[1]] < chunk.min)
659  {
660  return;
661  }
662  }
663  else
664  {
665  // Consider the ray vertical
666  // (though we shouldn't reach this often because there is an early check up-front)
667  enterPos = rayBegin;
668  exitPos = rayEnd;
669  }
670 
671  gridRaycast(processTriangles, enterPos, exitPos, m_indices);
672  // Note: it could be possible to have more than one grid at different levels,
673  // to do this there would be a branch using a pointer to another ProcessVBoundsAction
674  }
675 };
676 
677 // TODO How do I interrupt the ray when there is a hit? `callback` does not return any result
680 void btHeightfieldTerrainShape::performRaycast(btTriangleCallback* callback, const btVector3& raySource, const btVector3& rayTarget) const
681 {
682  // Transform to cell-local
683  btVector3 beginPos = raySource / m_localScaling;
684  btVector3 endPos = rayTarget / m_localScaling;
685  beginPos += m_localOrigin;
686  endPos += m_localOrigin;
687 
688  ProcessTrianglesAction processTriangles;
689  processTriangles.shape = this;
690  processTriangles.flipQuadEdges = m_flipQuadEdges;
692  processTriangles.callback = callback;
693  processTriangles.width = m_heightStickWidth - 1;
694  processTriangles.length = m_heightStickLength - 1;
695 
696  // TODO Transform vectors to account for m_upAxis
697  int indices[3] = { 0, 1, 2 };
698  if (m_upAxis == 2)
699  {
700  indices[1] = 2;
701  indices[2] = 1;
702  }
703  int iBeginX = static_cast<int>(floor(beginPos[indices[0]]));
704  int iBeginZ = static_cast<int>(floor(beginPos[indices[2]]));
705  int iEndX = static_cast<int>(floor(endPos[indices[0]]));
706  int iEndZ = static_cast<int>(floor(endPos[indices[2]]));
707 
708  if (iBeginX == iEndX && iBeginZ == iEndZ)
709  {
710  // The ray will never cross quads within the plane,
711  // so directly process triangles within one quad
712  // (typically, vertical rays should end up here)
713  processTriangles.exec(iBeginX, iEndZ);
714  return;
715  }
716 
717 
718 
719  if (m_vboundsGrid.size()==0)
720  {
721  // Process all quads intersecting the flat projection of the ray
722  gridRaycast(processTriangles, beginPos, endPos, &indices[0]);
723  }
724  else
725  {
726  btVector3 rayDiff = endPos - beginPos;
727  btScalar flatDistance2 = rayDiff[indices[0]] * rayDiff[indices[0]] + rayDiff[indices[2]] * rayDiff[indices[2]];
728  if (flatDistance2 < m_vboundsChunkSize * m_vboundsChunkSize)
729  {
730  // Don't use chunks, the ray is too short in the plane
731  gridRaycast(processTriangles, beginPos, endPos, &indices[0]);
732  }
733 
734  ProcessVBoundsAction processVBounds(m_vboundsGrid, &indices[0]);
735  processVBounds.width = m_vboundsGridWidth;
736  processVBounds.length = m_vboundsGridLength;
737  processVBounds.rayBegin = beginPos;
738  processVBounds.rayEnd = endPos;
739  processVBounds.rayDir = rayDiff.normalized();
740  processVBounds.processTriangles = processTriangles;
741  processVBounds.chunkSize = m_vboundsChunkSize;
742  // The ray is long, run raycast on a higher-level grid
743  gridRaycast(processVBounds, beginPos / m_vboundsChunkSize, endPos / m_vboundsChunkSize, indices);
744  }
745 }
746 
751 {
752  if (chunkSize <= 0)
753  {
755  return;
756  }
757 
758  m_vboundsChunkSize = chunkSize;
759  int nChunksX = m_heightStickWidth / chunkSize;
760  int nChunksZ = m_heightStickLength / chunkSize;
761 
762  if (m_heightStickWidth % chunkSize > 0)
763  {
764  ++nChunksX; // In case terrain size isn't dividable by chunk size
765  }
766  if (m_heightStickLength % chunkSize > 0)
767  {
768  ++nChunksZ;
769  }
770 
771  if (m_vboundsGridWidth != nChunksX || m_vboundsGridLength != nChunksZ)
772  {
774  m_vboundsGridWidth = nChunksX;
775  m_vboundsGridLength = nChunksZ;
776  }
777 
778  if (nChunksX == 0 || nChunksZ == 0)
779  {
780  return;
781  }
782 
783  // This data structure is only reallocated if the required size changed
784  m_vboundsGrid.resize(nChunksX * nChunksZ);
785 
786  // Compute min and max height for all chunks
787  for (int cz = 0; cz < nChunksZ; ++cz)
788  {
789  int z0 = cz * chunkSize;
790 
791  for (int cx = 0; cx < nChunksX; ++cx)
792  {
793  int x0 = cx * chunkSize;
794 
795  Range r;
796 
797  r.min = getRawHeightFieldValue(x0, z0);
798  r.max = r.min;
799 
800  // Compute min and max height for this chunk.
801  // We have to include one extra cell to account for neighbors.
802  // Here is why:
803  // Say we have a flat terrain, and a plateau that fits a chunk perfectly.
804  //
805  // Left Right
806  // 0---0---0---1---1---1
807  // | | | | | |
808  // 0---0---0---1---1---1
809  // | | | | | |
810  // 0---0---0---1---1---1
811  // x
812  //
813  // If the AABB for the Left chunk did not share vertices with the Right,
814  // then we would fail collision tests at x due to a gap.
815  //
816  for (int z = z0; z < z0 + chunkSize + 1; ++z)
817  {
818  if (z >= m_heightStickLength)
819  {
820  continue;
821  }
822 
823  for (int x = x0; x < x0 + chunkSize + 1; ++x)
824  {
825  if (x >= m_heightStickWidth)
826  {
827  continue;
828  }
829 
830  btScalar height = getRawHeightFieldValue(x, z);
831 
832  if (height < r.min)
833  {
834  r.min = height;
835  }
836  else if (height > r.max)
837  {
838  r.max = height;
839  }
840  }
841  }
842 
843  m_vboundsGrid[cx + cz * nChunksX] = r;
844  }
845  }
846 }
847 
849 {
850  m_vboundsGrid.clear();
851 }
btHeightfieldTerrainShape::m_localAabbMin
btVector3 m_localAabbMin
Definition: btHeightfieldTerrainShape.h:83
btHeightfieldTerrainShape::m_heightStickLength
int m_heightStickLength
Definition: btHeightfieldTerrainShape.h:89
ProcessTrianglesAction::useDiamondSubdivision
bool useDiamondSubdivision
Definition: btHeightfieldTerrainShape.cpp:557
btHeightfieldTerrainShape::initialize
void initialize(int heightStickWidth, int heightStickLength, const void *heightfieldData, btScalar heightScale, btScalar minHeight, btScalar maxHeight, int upAxis, PHY_ScalarType heightDataType, bool flipQuadEdges)
protected initialization
Definition: btHeightfieldTerrainShape.cpp:52
ProcessVBoundsAction::rayEnd
btVector3 rayEnd
Definition: btHeightfieldTerrainShape.cpp:618
TERRAIN_SHAPE_PROXYTYPE
Definition: btBroadphaseProxy.h:59
btHeightfieldTerrainShape::m_heightDataType
PHY_ScalarType m_heightDataType
Definition: btHeightfieldTerrainShape.h:102
btHeightfieldTerrainShape::getVertex
void getVertex(int x, int y, btVector3 &vertex) const
this returns the vertex in bullet-local coordinates
Definition: btHeightfieldTerrainShape.cpp:181
btVector3::dot3
btVector3 dot3(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2) const
Definition: btVector3.h:720
btHeightfieldTerrainShape::quantizeWithClamp
void quantizeWithClamp(int *out, const btVector3 &point, int isMax) const
given input vector, return quantized version
Definition: btHeightfieldTerrainShape.cpp:246
btVector3::setValue
void setValue(const btScalar &_x, const btScalar &_y, const btScalar &_z)
Definition: btVector3.h:640
btScalar
float btScalar
The btScalar type abstracts floating point numbers, to easily switch between double and single floati...
Definition: btScalar.h:314
ProcessTrianglesAction::callback
btTriangleCallback * callback
Definition: btHeightfieldTerrainShape.cpp:560
btHeightfieldTerrainShape::m_vboundsGridLength
int m_vboundsGridLength
Definition: btHeightfieldTerrainShape.h:114
btHeightfieldTerrainShape::setLocalScaling
virtual void setLocalScaling(const btVector3 &scaling)
Definition: btHeightfieldTerrainShape.cpp:389
getQuantized
static int getQuantized(btScalar x)
Definition: btHeightfieldTerrainShape.cpp:227
ProcessVBoundsAction::ProcessVBoundsAction
ProcessVBoundsAction(const btAlignedObjectArray< btHeightfieldTerrainShape::Range > &bnd, int *indices)
Definition: btHeightfieldTerrainShape.cpp:624
ProcessVBoundsAction::chunkSize
int chunkSize
Definition: btHeightfieldTerrainShape.cpp:615
btHeightfieldTerrainShape
btHeightfieldTerrainShape simulates a 2D heightfield terrain
Definition: btHeightfieldTerrainShape.h:72
PHY_FLOAT
Definition: btConcaveShape.h:27
ProcessTrianglesAction::width
int width
Definition: btHeightfieldTerrainShape.cpp:558
btTransformUtil.h
btHeightfieldTerrainShape::Range
Definition: btHeightfieldTerrainShape.h:76
ProcessVBoundsAction::rayDir
btVector3 rayDir
Definition: btHeightfieldTerrainShape.cpp:619
ProcessVBoundsAction::processTriangles
ProcessTrianglesAction processTriangles
Definition: btHeightfieldTerrainShape.cpp:622
btHeightfieldTerrainShape::calculateLocalInertia
virtual void calculateLocalInertia(btScalar mass, btVector3 &inertia) const
Definition: btHeightfieldTerrainShape.cpp:382
btHeightfieldTerrainShape::m_localAabbMax
btVector3 m_localAabbMax
Definition: btHeightfieldTerrainShape.h:84
ProcessTrianglesAction
Definition: btHeightfieldTerrainShape.cpp:553
btVector3::getX
const btScalar & getX() const
Return the x value.
Definition: btVector3.h:561
btCollisionShape::m_shapeType
int m_shapeType
Definition: btCollisionShape.h:30
btHeightfieldTerrainShape::m_useDiamondSubdivision
bool m_useDiamondSubdivision
Definition: btHeightfieldTerrainShape.h:104
btHeightfieldTerrainShape::m_width
btScalar m_width
Definition: btHeightfieldTerrainShape.h:92
btHeightfieldTerrainShape::Range::min
btScalar min
Definition: btHeightfieldTerrainShape.h:78
btAssert
#define btAssert(x)
Definition: btScalar.h:153
btHeightfieldTerrainShape::processAllTriangles
virtual void processAllTriangles(btTriangleCallback *callback, const btVector3 &aabbMin, const btVector3 &aabbMax) const
process all triangles within the provided axis-aligned bounding box
Definition: btHeightfieldTerrainShape.cpp:264
btHeightfieldTerrainShape::m_heightfieldDataFloat
const btScalar * m_heightfieldDataFloat
Definition: btHeightfieldTerrainShape.h:98
btFabs
btScalar btFabs(btScalar x)
Definition: btScalar.h:497
btHeightfieldTerrainShape::m_upAxis
int m_upAxis
Definition: btHeightfieldTerrainShape.h:107
ProcessVBoundsAction::rayBegin
btVector3 rayBegin
Definition: btHeightfieldTerrainShape.cpp:617
btHeightfieldTerrainShape::getLocalScaling
virtual const btVector3 & getLocalScaling() const
Definition: btHeightfieldTerrainShape.cpp:393
btHeightfieldTerrainShape::m_heightfieldDataUnknown
const void * m_heightfieldDataUnknown
Definition: btHeightfieldTerrainShape.h:99
ProcessVBoundsAction::length
int length
Definition: btHeightfieldTerrainShape.cpp:614
btTransform::getBasis
btMatrix3x3 & getBasis()
Return the basis matrix for the rotation.
Definition: btTransform.h:108
ProcessTrianglesAction::length
int length
Definition: btHeightfieldTerrainShape.cpp:559
btVector3::setMax
void setMax(const btVector3 &other)
Set each element to the max of the current values and the values of another btVector3.
Definition: btVector3.h:609
btHeightfieldTerrainShape::getRawHeightFieldValue
virtual btScalar getRawHeightFieldValue(int x, int y) const
This returns the "raw" (user's initial) height, not the actual height.
Definition: btHeightfieldTerrainShape.cpp:146
PHY_ScalarType
PHY_ScalarType
PHY_ScalarType enumerates possible scalar types.
Definition: btConcaveShape.h:25
btHeightfieldTerrainShape::m_flipQuadEdges
bool m_flipQuadEdges
Definition: btHeightfieldTerrainShape.h:103
ProcessTrianglesAction::flipQuadEdges
bool flipQuadEdges
Definition: btHeightfieldTerrainShape.cpp:556
btMatrix3x3
The btMatrix3x3 class implements a 3x3 rotation matrix, to perform linear algebra in combination with...
Definition: btMatrix3x3.h:46
ProcessVBoundsAction::operator()
void operator()(const GridRaycastState &rs) const
Definition: btHeightfieldTerrainShape.cpp:629
btTriangleCallback
The btTriangleCallback provides a callback for each overlapping triangle when calling processAllTrian...
Definition: btTriangleCallback.h:23
btTransform
The btTransform class supports rigid transforms with only translation and rotation and no scaling/she...
Definition: btTransform.h:28
ProcessTrianglesAction::shape
const btHeightfieldTerrainShape * shape
Definition: btHeightfieldTerrainShape.cpp:555
btHeightfieldTerrainShape::getAabb
virtual void getAabb(const btTransform &t, btVector3 &aabbMin, btVector3 &aabbMax) const
getAabb returns the axis aligned bounding box in the coordinate frame of the given transform t.
Definition: btHeightfieldTerrainShape.cpp:125
btVector3
btVector3 can be used to represent 3D points and vectors.
Definition: btVector3.h:80
btHeightfieldTerrainShape::m_length
btScalar m_length
Definition: btHeightfieldTerrainShape.h:93
btHeightfieldTerrainShape::Range::max
btScalar max
Definition: btHeightfieldTerrainShape.h:79
btHeightfieldTerrainShape::m_minHeight
btScalar m_minHeight
Definition: btHeightfieldTerrainShape.h:90
btHeightfieldTerrainShape::m_useZigzagSubdivision
bool m_useZigzagSubdivision
Definition: btHeightfieldTerrainShape.h:105
btHeightfieldTerrainShape::m_heightfieldDataUnsignedChar
const unsigned char * m_heightfieldDataUnsignedChar
Definition: btHeightfieldTerrainShape.h:96
btTransform::getOrigin
btVector3 & getOrigin()
Return the origin vector translation.
Definition: btTransform.h:113
btHeightfieldTerrainShape::btHeightfieldTerrainShape
btHeightfieldTerrainShape(int heightStickWidth, int heightStickLength, const void *heightfieldData, btScalar heightScale, btScalar minHeight, btScalar maxHeight, int upAxis, PHY_ScalarType heightDataType, bool flipQuadEdges)
preferred constructor
Definition: btHeightfieldTerrainShape.cpp:20
btHeightfieldTerrainShape::~btHeightfieldTerrainShape
virtual ~btHeightfieldTerrainShape()
Definition: btHeightfieldTerrainShape.cpp:120
btTriangleCallback::processTriangle
virtual void processTriangle(btVector3 *triangle, int partId, int triangleIndex)=0
btVector3::getZ
const btScalar & getZ() const
Return the z value.
Definition: btVector3.h:565
btHeightfieldTerrainShape.h
btHeightfieldTerrainShape::m_heightStickWidth
int m_heightStickWidth
terrain data
Definition: btHeightfieldTerrainShape.h:88
btAlignedObjectArray< btHeightfieldTerrainShape::Range >
btVector3::getY
const btScalar & getY() const
Return the y value.
Definition: btVector3.h:563
btVector3::setMin
void setMin(const btVector3 &other)
Set each element to the min of the current values and the values of another btVector3.
Definition: btVector3.h:626
ProcessVBoundsAction::width
int width
Definition: btHeightfieldTerrainShape.cpp:613
btHeightfieldTerrainShape::m_vboundsChunkSize
int m_vboundsChunkSize
Definition: btHeightfieldTerrainShape.h:115
btHeightfieldTerrainShape::m_vboundsGrid
btAlignedObjectArray< Range > m_vboundsGrid
Definition: btHeightfieldTerrainShape.h:112
btHeightfieldTerrainShape::m_heightfieldDataShort
const short * m_heightfieldDataShort
Definition: btHeightfieldTerrainShape.h:97
ProcessVBoundsAction::m_indices
int * m_indices
Definition: btHeightfieldTerrainShape.cpp:621
ProcessVBoundsAction
Definition: btHeightfieldTerrainShape.cpp:610
ProcessTrianglesAction::exec
void exec(int x, int z) const
Definition: btHeightfieldTerrainShape.cpp:562
btHeightfieldTerrainShape::m_vboundsGridWidth
int m_vboundsGridWidth
Definition: btHeightfieldTerrainShape.h:113
btMatrix3x3::absolute
btMatrix3x3 absolute() const
Return the matrix with all values non negative.
Definition: btMatrix3x3.h:1012
btConcaveShape::getMargin
virtual btScalar getMargin() const
Definition: btConcaveShape.h:52
PHY_UCHAR
Definition: btConcaveShape.h:32
btHeightfieldTerrainShape::m_flipTriangleWinding
bool m_flipTriangleWinding
Definition: btHeightfieldTerrainShape.h:106
gridRaycast
void gridRaycast(Action_T &quadAction, const btVector3 &beginPos, const btVector3 &endPos, int indices[3])
Iterates through a virtual 2D grid of unit-sized square cells, and executes an action on each cell in...
Definition: btHeightfieldTerrainShape.cpp:418
btHeightfieldTerrainShape::m_localOrigin
btVector3 m_localOrigin
Definition: btHeightfieldTerrainShape.h:85
btHeightfieldTerrainShape::m_localScaling
btVector3 m_localScaling
Definition: btHeightfieldTerrainShape.h:109
btHeightfieldTerrainShape::clearAccelerator
void clearAccelerator()
Definition: btHeightfieldTerrainShape.cpp:848
btSqrt
btScalar btSqrt(btScalar y)
Definition: btScalar.h:466
ProcessTrianglesAction::operator()
void operator()(const GridRaycastState &bs) const
Definition: btHeightfieldTerrainShape.cpp:604
btHeightfieldTerrainShape::performRaycast
void performRaycast(btTriangleCallback *callback, const btVector3 &raySource, const btVector3 &rayTarget) const
Performs a raycast using a hierarchical Bresenham algorithm.
Definition: btHeightfieldTerrainShape.cpp:680
btHeightfieldTerrainShape::m_maxHeight
btScalar m_maxHeight
Definition: btHeightfieldTerrainShape.h:91
btVector3::normalized
btVector3 normalized() const
Return a normalized version of this vector.
Definition: btVector3.h:949
btVector3::distance
btScalar distance(const btVector3 &v) const
Return the distance between the ends of this and another vector This is symantically treating the vec...
Definition: btVector3.h:944
btHeightfieldTerrainShape::m_heightScale
btScalar m_heightScale
Definition: btHeightfieldTerrainShape.h:94
PHY_SHORT
Definition: btConcaveShape.h:30
ProcessVBoundsAction::vbounds
const btAlignedObjectArray< btHeightfieldTerrainShape::Range > & vbounds
Definition: btHeightfieldTerrainShape.cpp:612
btHeightfieldTerrainShape::buildAccelerator
void buildAccelerator(int chunkSize=16)
Builds a grid data structure storing the min and max heights of the terrain in chunks.
Definition: btHeightfieldTerrainShape.cpp:750