[ODE] Re: - dHeightfield 0.1b -
gl
gl at ntlworld.com
Wed Mar 12 11:56:01 2003
Oh yeah, another thing - the collider currently only supports unrotated
heightfields in the left-handed coord system (where X,Z is the 2D plane and
+Y is up).
I don't currently need rotations, but they can be added easily enough, by
transforming geoms into the field's space first.
--
gl
----- Original Message -----
From: "gl" <gl@ntlworld.com>
To: <ode@q12.org>
Sent: Wednesday, March 12, 2003 6:23 PM
Subject: - dHeightfield 0.1b -
>
> A bout of illness later, I've finally got something for you to play with.
>
> http://r-i-l.net/_files/ODE/dHeightfield0.1b.zip
>
> Right now it only implements sphere collision, but I should have my ray
> collider in soon. I've also included skeleton code for other geoms, so if
> anybody can implement those, please do! I know Fabian has been working on
> boxes - cylinders would be really handy too.
>
> Details of how it works are in the dHeighfield header - here's a quick
> overview:
>
> 1) Build the dHeightfield static lib (VC6 workspace included), then
include
> dHeightfield.h in your project and link with the lib.
>
> 2) You supply a terrain_tile struct (blech, bad name, will change for next
> release) for each of your heightfields/tiles (or you can break a large
> heightfield up into collider tiles for performance if you like).
>
> When a geom's AABB overlaps the heightfield's, it requests the triangles
for
> all the quads this AABB potentially intersects (in 2D) from the app via a
> callback function. For effeciency I decided to use a single callback,
where
> you fill in each 'patch' vertex only once, and then fill out a face index
> array (just like indexed rendering). You can also supply face normals if
> you don't want them auto-generated. I've pasted my own tri callback code
to
> get you started (at the end).
>
> Internally I'm using a vertex/face cache per tile, to avoid having to
> allocate memory all the time, and to reuse cached stuff wherever possible.
>
> I ended up using Pierre's suggested method (closest point in tri) for the
> sphere collider - it gives you a guaranteed max 1 contact per triangle,
> which also makes estimating how many contacts to allow easier. This is
> important because if you don't allow enough contacts in a dense
heightfield,
> spheres can actually fall through it! I've written it so that deep
> penetrations are kicked out, as they are with planes, so you can get away
> with relatively few contacts, but some odd things can happen as a result
> (balance away).
>
> Fabian, I haven't tested how this compares performance wise with your
> method, as I never got the edges to work - perhaps you can give it a shot?
> (I'll send you the code I got working, so maybe you can fix the few
> outstanding problems).
>
> Let me know suggestions etc.
> --
> gl
>
>
// -------------------------------------------------------------------------
> -------------------------------
> void ODETriCallback (terrain_tile *tile,
> unsigned minx_vertex, unsigned maxx_vertex,
> unsigned miny_vertex, unsigned maxy_vertex,
> dVector3 *vertices,
> hf_face *faces)
> {
> world_tile &wtile = *(world_tile*)tile;
>
> unsigned min_x = wtile.WorldHeightmapIndexX + minx_vertex;
> unsigned max_x = wtile.WorldHeightmapIndexX + maxx_vertex;
> unsigned min_y = wtile.WorldHeightmapIndexY + miny_vertex;
> unsigned max_y = wtile.WorldHeightmapIndexY + maxy_vertex;
>
> wtile.WorldHeightmap->Open(true);
> dVector3 *vertex = vertices;
>
> // fill the collider-allocated vertex array from sample heights:
> // find the position of the first bottom/left sample
> vec3 tile_pos = vec3(wtile.WorldPosition().x - tile->x_halfsize,
> wtile.WorldPosition().y,
> wtile.WorldPosition().z - tile->y_halfsize);
> tile_pos.x += (minx_vertex * tile->sample_spacing);
> tile_pos.z += (miny_vertex * tile->sample_spacing);
>
> float vert_z = tile_pos.z;
> for(unsigned y=min_y; y<=max_y; y++)
> {
> float vert_x = tile_pos.x;
> for(unsigned x=min_x; x<=max_x; x++)
> {
> float height = (wtile.WorldHeightmap->GetHeight(x,y) / 255.f) - 0.5f;
> height *= wtile.WorldScale();
>
> (*vertex)[0] = vert_x;
> (*vertex)[1] = height;
> (*vertex)[2] = vert_z;
> vertex++;
>
> vert_x += tile->sample_spacing;
> }
> vert_z += tile->sample_spacing;
> }
>
> wtile.WorldHeightmap->Close();
>
> // and fill the face index array (using |\| quad layout in my case)
> const unsigned x_quads = (max_x - min_x);
> const unsigned y_quads = (max_y - min_y);
> const unsigned row = x_quads + 1;
> unsigned row_start = 0;
> for(y=0; y<y_quads; y++)
> {
> unsigned quad = row_start;
> for(unsigned x=0; x<x_quads; x++)
> {
> faces->index[0] = quad;
> faces->index[1] = quad + row;
> faces->index[2] = quad + 1;
> faces++;
>
> faces->index[0] = quad + row;
> faces->index[1] = quad + row + 1;
> faces->index[2] = quad + 1;
> faces++;
>
> quad++;
> }
> row_start += row;
> }
> }
>