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