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 
20 
21 
23 (
24 int heightStickWidth, int heightStickLength, const void* heightfieldData,
25 btScalar heightScale, btScalar minHeight, btScalar maxHeight,int upAxis,
26 PHY_ScalarType hdt, bool flipQuadEdges
27 )
28 {
29  initialize(heightStickWidth, heightStickLength, heightfieldData,
30  heightScale, minHeight, maxHeight, upAxis, hdt,
31  flipQuadEdges);
32 }
33 
34 
35 
36 btHeightfieldTerrainShape::btHeightfieldTerrainShape(int heightStickWidth, int heightStickLength,const void* heightfieldData,btScalar maxHeight,int upAxis,bool useFloatData,bool flipQuadEdges)
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 
53 
55 (
56 int heightStickWidth, int heightStickLength, const void* heightfieldData,
57 btScalar heightScale, btScalar minHeight, btScalar maxHeight, int upAxis,
58 PHY_ScalarType hdt, bool flipQuadEdges
59 )
60 {
61  // validation
62  btAssert(heightStickWidth > 1 && "bad width");
63  btAssert(heightStickLength > 1 && "bad length");
64  btAssert(heightfieldData && "null heightfield data");
65  // btAssert(heightScale) -- do we care? Trust caller here
66  btAssert(minHeight <= maxHeight && "bad min/max height");
67  btAssert(upAxis >= 0 && upAxis < 3 &&
68  "bad upAxis--should be in range [0,2]");
69  btAssert(hdt != PHY_UCHAR || hdt != PHY_FLOAT || hdt != PHY_SHORT &&
70  "Bad height data type enum");
71 
72  // initialize member variables
73  m_shapeType = TERRAIN_SHAPE_PROXYTYPE;
74  m_heightStickWidth = heightStickWidth;
75  m_heightStickLength = heightStickLength;
76  m_minHeight = minHeight;
77  m_maxHeight = maxHeight;
78  m_width = (btScalar) (heightStickWidth - 1);
79  m_length = (btScalar) (heightStickLength - 1);
80  m_heightScale = heightScale;
81  m_heightfieldDataUnknown = heightfieldData;
82  m_heightDataType = hdt;
83  m_flipQuadEdges = flipQuadEdges;
84  m_useDiamondSubdivision = false;
85  m_useZigzagSubdivision = false;
86  m_upAxis = upAxis;
87  m_localScaling.setValue(btScalar(1.), btScalar(1.), btScalar(1.));
88 
89  // determine min/max axis-aligned bounding box (aabb) values
90  switch (m_upAxis)
91  {
92  case 0:
93  {
94  m_localAabbMin.setValue(m_minHeight, 0, 0);
95  m_localAabbMax.setValue(m_maxHeight, m_width, m_length);
96  break;
97  }
98  case 1:
99  {
100  m_localAabbMin.setValue(0, m_minHeight, 0);
101  m_localAabbMax.setValue(m_width, m_maxHeight, m_length);
102  break;
103  };
104  case 2:
105  {
106  m_localAabbMin.setValue(0, 0, m_minHeight);
107  m_localAabbMax.setValue(m_width, m_length, m_maxHeight);
108  break;
109  }
110  default:
111  {
112  //need to get valid m_upAxis
113  btAssert(0 && "Bad m_upAxis");
114  }
115  }
116 
117  // remember origin (defined as exact middle of aabb)
118  m_localOrigin = btScalar(0.5) * (m_localAabbMin + m_localAabbMax);
119 }
120 
121 
122 
124 {
125 }
126 
127 
128 
130 {
132 
133  btVector3 localOrigin(0, 0, 0);
134  localOrigin[m_upAxis] = (m_minHeight + m_maxHeight) * btScalar(0.5);
135  localOrigin *= m_localScaling;
136 
137  btMatrix3x3 abs_b = t.getBasis().absolute();
138  btVector3 center = t.getOrigin();
139  btVector3 extent = halfExtents.dot3(abs_b[0], abs_b[1], abs_b[2]);
140  extent += btVector3(getMargin(),getMargin(),getMargin());
141 
142  aabbMin = center - extent;
143  aabbMax = center + extent;
144 }
145 
146 
150 btScalar
152 {
153  btScalar val = 0.f;
154  switch (m_heightDataType)
155  {
156  case PHY_FLOAT:
157  {
159  break;
160  }
161 
162  case PHY_UCHAR:
163  {
164  unsigned char heightFieldValue = m_heightfieldDataUnsignedChar[(y*m_heightStickWidth)+x];
165  val = heightFieldValue * m_heightScale;
166  break;
167  }
168 
169  case PHY_SHORT:
170  {
171  short hfValue = m_heightfieldDataShort[(y * m_heightStickWidth) + x];
172  val = hfValue * m_heightScale;
173  break;
174  }
175 
176  default:
177  {
178  btAssert(!"Bad m_heightDataType");
179  }
180  }
181 
182  return val;
183 }
184 
185 
186 
187 
189 void btHeightfieldTerrainShape::getVertex(int x,int y,btVector3& vertex) const
190 {
191  btAssert(x>=0);
192  btAssert(y>=0);
195 
196  btScalar height = getRawHeightFieldValue(x,y);
197 
198  switch (m_upAxis)
199  {
200  case 0:
201  {
202  vertex.setValue(
203  height - m_localOrigin.getX(),
204  (-m_width/btScalar(2.0)) + x,
205  (-m_length/btScalar(2.0) ) + y
206  );
207  break;
208  }
209  case 1:
210  {
211  vertex.setValue(
212  (-m_width/btScalar(2.0)) + x,
213  height - m_localOrigin.getY(),
214  (-m_length/btScalar(2.0)) + y
215  );
216  break;
217  };
218  case 2:
219  {
220  vertex.setValue(
221  (-m_width/btScalar(2.0)) + x,
222  (-m_length/btScalar(2.0)) + y,
223  height - m_localOrigin.getZ()
224  );
225  break;
226  }
227  default:
228  {
229  //need to get valid m_upAxis
230  btAssert(0);
231  }
232  }
233 
234  vertex*=m_localScaling;
235 }
236 
237 
238 
239 static inline int
241 (
242 btScalar x
243 )
244 {
245  if (x < 0.0) {
246  return (int) (x - 0.5);
247  }
248  return (int) (x + 0.5);
249 }
250 
251 
252 
254 
262 void btHeightfieldTerrainShape::quantizeWithClamp(int* out, const btVector3& point,int /*isMax*/) const
263 {
264  btVector3 clampedPoint(point);
265  clampedPoint.setMax(m_localAabbMin);
266  clampedPoint.setMin(m_localAabbMax);
267 
268  out[0] = getQuantized(clampedPoint.getX());
269  out[1] = getQuantized(clampedPoint.getY());
270  out[2] = getQuantized(clampedPoint.getZ());
271 
272 }
273 
274 
275 
277 
284 {
285  // scale down the input aabb's so they are in local (non-scaled) coordinates
286  btVector3 localAabbMin = aabbMin*btVector3(1.f/m_localScaling[0],1.f/m_localScaling[1],1.f/m_localScaling[2]);
287  btVector3 localAabbMax = aabbMax*btVector3(1.f/m_localScaling[0],1.f/m_localScaling[1],1.f/m_localScaling[2]);
288 
289  // account for local origin
290  localAabbMin += m_localOrigin;
291  localAabbMax += m_localOrigin;
292 
293  //quantize the aabbMin and aabbMax, and adjust the start/end ranges
294  int quantizedAabbMin[3];
295  int quantizedAabbMax[3];
296  quantizeWithClamp(quantizedAabbMin, localAabbMin,0);
297  quantizeWithClamp(quantizedAabbMax, localAabbMax,1);
298 
299  // expand the min/max quantized values
300  // this is to catch the case where the input aabb falls between grid points!
301  for (int i = 0; i < 3; ++i) {
302  quantizedAabbMin[i]--;
303  quantizedAabbMax[i]++;
304  }
305 
306  int startX=0;
307  int endX=m_heightStickWidth-1;
308  int startJ=0;
309  int endJ=m_heightStickLength-1;
310 
311  switch (m_upAxis)
312  {
313  case 0:
314  {
315  if (quantizedAabbMin[1]>startX)
316  startX = quantizedAabbMin[1];
317  if (quantizedAabbMax[1]<endX)
318  endX = quantizedAabbMax[1];
319  if (quantizedAabbMin[2]>startJ)
320  startJ = quantizedAabbMin[2];
321  if (quantizedAabbMax[2]<endJ)
322  endJ = quantizedAabbMax[2];
323  break;
324  }
325  case 1:
326  {
327  if (quantizedAabbMin[0]>startX)
328  startX = quantizedAabbMin[0];
329  if (quantizedAabbMax[0]<endX)
330  endX = quantizedAabbMax[0];
331  if (quantizedAabbMin[2]>startJ)
332  startJ = quantizedAabbMin[2];
333  if (quantizedAabbMax[2]<endJ)
334  endJ = quantizedAabbMax[2];
335  break;
336  };
337  case 2:
338  {
339  if (quantizedAabbMin[0]>startX)
340  startX = quantizedAabbMin[0];
341  if (quantizedAabbMax[0]<endX)
342  endX = quantizedAabbMax[0];
343  if (quantizedAabbMin[1]>startJ)
344  startJ = quantizedAabbMin[1];
345  if (quantizedAabbMax[1]<endJ)
346  endJ = quantizedAabbMax[1];
347  break;
348  }
349  default:
350  {
351  //need to get valid m_upAxis
352  btAssert(0);
353  }
354  }
355 
356 
357 
358 
359  for(int j=startJ; j<endJ; j++)
360  {
361  for(int x=startX; x<endX; x++)
362  {
363  btVector3 vertices[3];
364  if (m_flipQuadEdges || (m_useDiamondSubdivision && !((j+x) & 1))|| (m_useZigzagSubdivision && !(j & 1)))
365  {
366  //first triangle
367  getVertex(x,j,vertices[0]);
368  getVertex(x+1,j,vertices[1]);
369  getVertex(x+1,j+1,vertices[2]);
370  callback->processTriangle(vertices,x,j);
371  //second triangle
372  // getVertex(x,j,vertices[0]);//already got this vertex before, thanks to Danny Chapman
373  getVertex(x+1,j+1,vertices[1]);
374  getVertex(x,j+1,vertices[2]);
375  callback->processTriangle(vertices,x,j);
376  } else
377  {
378  //first triangle
379  getVertex(x,j,vertices[0]);
380  getVertex(x,j+1,vertices[1]);
381  getVertex(x+1,j,vertices[2]);
382  callback->processTriangle(vertices,x,j);
383  //second triangle
384  getVertex(x+1,j,vertices[0]);
385  //getVertex(x,j+1,vertices[1]);
386  getVertex(x+1,j+1,vertices[2]);
387  callback->processTriangle(vertices,x,j);
388  }
389  }
390  }
391 
392 
393 
394 }
395 
397 {
398  //moving concave objects not supported
399 
400  inertia.setValue(btScalar(0.),btScalar(0.),btScalar(0.));
401 }
402 
404 {
405  m_localScaling = scaling;
406 }
408 {
409  return m_localScaling;
410 }
void setValue(const btScalar &_x, const btScalar &_y, const btScalar &_z)
Definition: btVector3.h:640
virtual void setLocalScaling(const btVector3 &scaling)
virtual void processTriangle(btVector3 *triangle, int partId, int triangleIndex)=0
#define btAssert(x)
Definition: btScalar.h:101
virtual void processAllTriangles(btTriangleCallback *callback, const btVector3 &aabbMin, const btVector3 &aabbMax) const
process all triangles within the provided axis-aligned bounding box
void quantizeWithClamp(int *out, const btVector3 &point, int isMax) const
given input vector, return quantized version
const btScalar & getZ() const
Return the z value.
Definition: btVector3.h:565
const unsigned char * m_heightfieldDataUnsignedChar
void initialize(int heightStickWidth, int heightStickLength, const void *heightfieldData, btScalar heightScale, btScalar minHeight, btScalar maxHeight, int upAxis, PHY_ScalarType heightDataType, bool flipQuadEdges)
protected initialization
virtual btScalar getRawHeightFieldValue(int x, int y) const
This returns the "raw" (user's initial) height, not the actual height.
btVector3 & getOrigin()
Return the origin vector translation.
Definition: btTransform.h:117
btMatrix3x3 absolute() const
Return the matrix with all values non negative.
Definition: btMatrix3x3.h:959
btHeightfieldTerrainShape(int heightStickWidth, int heightStickLength, const void *heightfieldData, btScalar heightScale, btScalar minHeight, btScalar maxHeight, int upAxis, PHY_ScalarType heightDataType, bool flipQuadEdges)
preferred constructor
The btTriangleCallback provides a callback for each overlapping triangle when calling processAllTrian...
void getVertex(int x, int y, btVector3 &vertex) const
this returns the vertex in bullet-local coordinates
const btScalar & getY() const
Return the y value.
Definition: btVector3.h:563
btMatrix3x3 & getBasis()
Return the basis matrix for the rotation.
Definition: btTransform.h:112
const btScalar & getX() const
Return the x value.
Definition: btVector3.h:561
static int getQuantized(btScalar x)
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...
btVector3 can be used to represent 3D points and vectors.
Definition: btVector3.h:83
The btTransform class supports rigid transforms with only translation and rotation and no scaling/she...
Definition: btTransform.h:34
btVector3 dot3(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2) const
Definition: btVector3.h:718
virtual const btVector3 & getLocalScaling() const
The btMatrix3x3 class implements a 3x3 rotation matrix, to perform linear algebra in combination with...
Definition: btMatrix3x3.h:48
virtual btScalar getMargin() const
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
virtual void calculateLocalInertia(btScalar mass, btVector3 &inertia) const
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
float btScalar
The btScalar type abstracts floating point numbers, to easily switch between double and single floati...
Definition: btScalar.h:266
PHY_ScalarType
PHY_ScalarType enumerates possible scalar types.