Make heightmap shape usable from PhysicsServer

- Fixed bad size check
- Fixed bad member initialization
- Removed unused cell_size (Bullet expects us to use localScaling)
- Accept precomputed min/max height, will be calculated if not provided

(cherry picked from commit a66e1af168)
This commit is contained in:
Marc Gilleron 2018-03-27 21:45:27 +02:00 committed by Hein-Pieter van Braam
parent 98609279b6
commit 4d7aa0b762
2 changed files with 47 additions and 14 deletions

View File

@ -125,14 +125,13 @@ btScaledBvhTriangleMeshShape *ShapeBullet::create_shape_concave(btBvhTriangleMes
}
}
btHeightfieldTerrainShape *ShapeBullet::create_shape_height_field(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size) {
btHeightfieldTerrainShape *ShapeBullet::create_shape_height_field(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) {
const btScalar ignoredHeightScale(1);
const btScalar fieldHeight(500); // Meters
const int YAxis = 1; // 0=X, 1=Y, 2=Z
const bool flipQuadEdges = false;
const void *heightsPtr = p_heights.read().ptr();
return bulletnew(btHeightfieldTerrainShape(p_width, p_depth, heightsPtr, ignoredHeightScale, -fieldHeight, fieldHeight, YAxis, PHY_FLOAT, flipQuadEdges));
return bulletnew(btHeightfieldTerrainShape(p_width, p_depth, heightsPtr, ignoredHeightScale, p_min_height, p_max_height, YAxis, PHY_FLOAT, flipQuadEdges));
}
btRayShape *ShapeBullet::create_shape_ray(real_t p_length) {
@ -385,19 +384,44 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) {
Dictionary d = p_data;
ERR_FAIL_COND(!d.has("width"));
ERR_FAIL_COND(!d.has("depth"));
ERR_FAIL_COND(!d.has("cell_size"));
ERR_FAIL_COND(!d.has("heights"));
real_t l_min_height = 0.0;
real_t l_max_height = 0.0;
// If specified, min and max height will be used as precomputed values
if (d.has("min_height"))
l_min_height = d["min_height"];
if (d.has("max_height"))
l_max_height = d["max_height"];
ERR_FAIL_COND(l_min_height > l_max_height);
int l_width = d["width"];
int l_depth = d["depth"];
real_t l_cell_size = d["cell_size"];
PoolVector<real_t> l_heights = d["heights"];
ERR_FAIL_COND(l_width <= 0);
ERR_FAIL_COND(l_depth <= 0);
ERR_FAIL_COND(l_cell_size <= CMP_EPSILON);
ERR_FAIL_COND(l_heights.size() != (width * depth));
setup(heights, width, depth, cell_size);
ERR_FAIL_COND(l_heights.size() != (l_width * l_depth));
// Compute min and max heights if not specified.
if (!d.has("min_height") && !d.has("max_height")) {
PoolVector<real_t>::Read r = heights.read();
int heights_size = heights.size();
for (int i = 0; i < heights_size; ++i) {
real_t h = r[i];
if (h < l_min_height)
l_min_height = h;
else if (h > l_max_height)
l_max_height = h;
}
}
setup(l_heights, l_width, l_depth, l_min_height, l_max_height);
}
Variant HeightMapShapeBullet::get_data() const {
@ -408,8 +432,14 @@ PhysicsServer::ShapeType HeightMapShapeBullet::get_type() const {
return PhysicsServer::SHAPE_HEIGHTMAP;
}
void HeightMapShapeBullet::setup(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size) {
void HeightMapShapeBullet::setup(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) {
// TODO cell size must be tweaked using localScaling, which is a shared property for all Bullet shapes
{ // Copy
// TODO If Godot supported 16-bit integer image format, we could share the same memory block for heightfields
// without having to copy anything, optimizing memory and loading performance (Bullet only reads and doesn't take ownership of the data).
const int heights_size = p_heights.size();
heights.resize(heights_size);
PoolVector<real_t>::Read p_heights_r = p_heights.read();
@ -418,14 +448,16 @@ void HeightMapShapeBullet::setup(PoolVector<real_t> &p_heights, int p_width, int
heights_w[i] = p_heights_r[i];
}
}
width = p_width;
depth = p_depth;
cell_size = p_cell_size;
min_height = p_min_height;
max_height = p_max_height;
notifyShapeChanged();
}
btCollisionShape *HeightMapShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) {
btCollisionShape *cs(ShapeBullet::create_shape_height_field(heights, width, depth, cell_size));
btCollisionShape *cs(ShapeBullet::create_shape_height_field(heights, width, depth, min_height, max_height));
cs->setLocalScaling(p_implicit_scale);
prepare(cs);
cs->setMargin(p_margin);

View File

@ -85,7 +85,7 @@ public:
/// IMPORTANT: Remember to delete the shape interface by calling: delete my_shape->getMeshInterface();
static class btConvexPointCloudShape *create_shape_convex(btAlignedObjectArray<btVector3> &p_vertices, const btVector3 &p_local_scaling = btVector3(1, 1, 1));
static class btScaledBvhTriangleMeshShape *create_shape_concave(btBvhTriangleMeshShape *p_mesh_shape, const btVector3 &p_local_scaling = btVector3(1, 1, 1));
static class btHeightfieldTerrainShape *create_shape_height_field(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size);
static class btHeightfieldTerrainShape *create_shape_height_field(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height);
static class btRayShape *create_shape_ray(real_t p_length);
};
@ -199,7 +199,8 @@ public:
PoolVector<real_t> heights;
int width;
int depth;
real_t cell_size;
real_t min_height;
real_t max_height;
HeightMapShapeBullet();
@ -209,7 +210,7 @@ public:
virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
private:
void setup(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size);
void setup(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height);
};
class RayShapeBullet : public ShapeBullet {