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]);
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 }