Bullet Collision Detection & Physics Library: btHeightfieldTerrainShape.cpp Source File

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
16 #include "btHeightfieldTerrainShape.h"
17
18 #include "LinearMath/btTransformUtil.h"
19
20 btHeightfieldTerrainShape::btHeightfieldTerrainShape(
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
52 void btHeightfieldTerrainShape::initialize(
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
67 m_shapeType = TERRAIN_SHAPE_PROXYTYPE;
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;
78 m_useDiamondSubdivision = false;
79 m_useZigzagSubdivision = false;
80 m_flipTriangleWinding = false;
81 m_upAxis = upAxis;
82 m_localScaling.setValue(btScalar(1.), btScalar(1.), btScalar(1.));
83
84 m_vboundsChunkSize = 0;
85 m_vboundsGridWidth = 0;
86 m_vboundsGridLength = 0;
87
88 // determine min/max axis-aligned bounding box (aabb) values
89 switch (m_upAxis)
90 {
91 case 0:
92 {
93 m_localAabbMin.setValue(m_minHeight, 0, 0);
94 m_localAabbMax.setValue(m_maxHeight, m_width, m_length);
95 break;
96 }
97 case 1:
98 {
99 m_localAabbMin.setValue(0, m_minHeight, 0);
100 m_localAabbMax.setValue(m_width, m_maxHeight, m_length);
101 break;
102 };
103 case 2:
104 {
105 m_localAabbMin.setValue(0, 0, m_minHeight);
106 m_localAabbMax.setValue(m_width, m_length, m_maxHeight);
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)
117 m_localOrigin = btScalar(0.5) * (m_localAabbMin + m_localAabbMax);
118 }
119
120 btHeightfieldTerrainShape::~btHeightfieldTerrainShape()
121 {
122 clearAccelerator();
123 }
124
125 void btHeightfieldTerrainShape::getAabb(const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const
126 {
127 btVector3 halfExtents = (m_localAabbMax - m_localAabbMin) * m_localScaling * btScalar(0.5);
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
146 btHeightfieldTerrainShape::getRawHeightFieldValue(int x, int y) const
147 {
148 btScalar val = 0.f;
149 switch (m_heightDataType)
150 {
151 case PHY_FLOAT:
152 {
153 val = m_heightfieldDataFloat[(y * m_heightStickWidth) + x];
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);
185 btAssert(x < m_heightStickWidth);
186 btAssert(y < m_heightStickLength);
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
227 getQuantized(
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 };
346 if (m_flipTriangleWinding)
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
382 void btHeightfieldTerrainShape::calculateLocalInertia(btScalar, btVector3& inertia) const
383 {
384 //moving concave objects not supported
385
386 inertia.setValue(btScalar(0.), btScalar(0.), btScalar(0.));
387 }
388
389 void btHeightfieldTerrainShape::setLocalScaling(const btVector3& scaling)
390 {
391 m_localScaling = scaling;
392 }
393 const btVector3& btHeightfieldTerrainShape::getLocalScaling() const
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
553 struct ProcessTrianglesAction
554 {
555 const btHeightfieldTerrainShape* shape;
556 bool flipQuadEdges;
557 bool useDiamondSubdivision;
558 int width;
559 int length;
560 btTriangleCallback* callback;
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
610 struct ProcessVBoundsAction
611 {
612 const btAlignedObjectArray<btHeightfieldTerrainShape::Range>& vbounds;
613 int width;
614 int length;
615 int chunkSize;
616
617 btVector3 rayBegin;
618 btVector3 rayEnd;
619 btVector3 rayDir;
620
621 int* m_indices;
622 ProcessTrianglesAction processTriangles;
623
624 ProcessVBoundsAction(const btAlignedObjectArray<btHeightfieldTerrainShape::Range>& bnd, int* indices)
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;
691 processTriangles.useDiamondSubdivision = m_useDiamondSubdivision;
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
750 void btHeightfieldTerrainShape::buildAccelerator(int chunkSize)
751 {
752 if (chunkSize <= 0)
753 {
754 clearAccelerator();
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 {
773 clearAccelerator();
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
848 void btHeightfieldTerrainShape::clearAccelerator()
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
@ 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:74
PHY_FLOAT
@ PHY_FLOAT
Definition: btConcaveShape.h:27
ProcessTrianglesAction::width
int width
Definition: btHeightfieldTerrainShape.cpp:558
btTransformUtil.h
btHeightfieldTerrainShape::Range
Definition: btHeightfieldTerrainShape.h:77
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:554
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:26
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:48
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:24
btTransform
The btTransform class supports rigid transforms with only translation and rotation and no scaling/she...
Definition: btTransform.h:30
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:82
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:611
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
@ 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
@ 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