[ask]how to generate havok heightfield using vertices x y z

[ask]how to generate havok heightfield using vertices x y z

hi.

how do i generate havok heightfield using vertices x y z.?
i am using directx, and have generated the heightmap using raw file. and i have the vertex buffer.

the vertex buffer has this xyz values.

how to convert those xyz value to suit the variable needed for HeightFieldShape(ci, heightData);

in the sample i found these code

for (int x = 0; x < xRes; x++)
{
for (int z = 0; z < zRes; z++)
{
hkReal dx,dz,height = 0;
int octave = 1;
// Add togther a few sine and cose waves
for (int i=0; i< 3; i++)
{
dx = hkReal(x * octave) / xRes;
dz = hkReal(z * octave) / zRes;

height += (5 - (i * 2)) * hkMath::cos(dx * HK_REAL_PI) * hkMath::sin(dz * HK_REAL_PI);
octave *= 4;
}

// Convert to 16 bit
m_heightData[x*zRes + z] = static_cast ( hkUint16(-1) * (height + 10.0f) / 20.0f );
}
}

so how do i do it with the already generated xyz from raw file??

thank you

15 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

so, what i already have is

 m_vb.getVB()->Lock(0,sizeof( PositionTextured ), (void**) & tVertices,0 );   
      {   
           for (int j = 0; j < m_width; j++) {  
                for(int k = 0; k < m_width; k++){  
                     for (int i=0; i< 3; i++){  
                          hkReal dx,dz,height = 0;   
                          dx = tVertices[j*m_width + k].m_x;  
                          dz = tVertices[j*m_width + k].m_z;   
                          height = tVertices[j].m_y;  
                     }  
                     // Convert to 16 bit   
                     m_heightData[j*m_width + k] = static_cast ( hkUint16(-1) * (height) );   
                }   
           }  
      }  
      // unlock the buffer as we're done working with the vertices  
      m_vb.getVB()->Unlock();   

is this correct? because i feel something weird happening in the effect of the simulation

Hey there R4ccoon

Have you tried looking at the heightfield in the Havok Visual Debugger (VDB)? You can visually check the resultant heightfield yourself to see if it matches your graphics representation.

Could you describe the "weirdness" in your simulation?

Patrick

Developer Support Engineer
Havok
www.havok.com

Quoting - PatrickAtHavok

Hey there R4ccoon

Have you tried looking at the heightfield in the Havok Visual Debugger (VDB)? You can visually check the resultant heightfield yourself to see if it matches your graphics representation.

Could you describe the "weirdness" in your simulation?

actually it is not simulating anything.
it s crashed when doing stepDeltaTime.

i found this thread on the http://software.intel.com/en-us/forums/showthread.php?t=59300/reply/add/...
but he doesnt put any answer on it.

but what i want to do is different from him. i just want to try with single thread.

hi. i got the visual debugger up.
it shows 2 instances.
the box rigid body and the height field.

it looks like that the field becomes Flat.

but it doesnt move. because i commented the mworld->stepdelatatime. because it still crashes when i uncommented it.

would you please check if my formula from converting the heightmap from directx vertices correct or not?

i have the box rolling to the ground now. but the dimension of the rigidbody is not the same as the dimension of the crate.

and the worst thing is, the program initiate breakpoints twice when it s running.

like run debug then it initiates break point. then i have to press break. then press the play button in debug toolbar. and then it initiates the other break, i have to press the break button. then press the play button again.

than the crate starts rolling.

Best Reply

Hi again, r4ccoon

I just took a proper look at your code and a bunch of problems were immediately apparent - I probably should have looked closer at it before pointing you to the VDB.

The reason your heightfield is flat is because you are setting it to be zero everywhere. Your for-loop (the one looping over i) does nothing, since every variable it maipulates is defined only in the scope of the loop - so the value of "height" you use to set m_heightData is probably the same as when you initialised it, wherever you did that. "i" is never used, so you are doing exactly the same never-used calculations three times.

I would suggest you do it something like this:

for (int j = 0; j < m_width; j++)
{
     for(int k = 0; k < m_width; k++)
     {
          float height = tVertices[j*m_width + k].m_y; // assuming y is "up"
          m_heightData[j*m_width + k] = static_cast ( hkUint16(-1) * (height) );
     }
}

The exact details of this depend on the data structure you're using.

You also need to clarify what you mean by "initiate breakpoints". I assume you mean that your code is throwing asserts? If that is so, the text of the assert (which you will see in the output window) is important, as is its position in the code. Both can tell you a lot about what is going wrong, as can looking at the relevant variable values at the time that the assert is hit. Can you let me know what the asserts are saying?

If you actually are hitting a breakpoint and not an assert, just disable it (click on the red dot if you're using Visual Studio), it's a feature of your IDE and not a bug in your code.

Patrick

Developer Support Engineer
Havok
www.havok.com

thanks for the reply.

i think what i meant about "breakpoint" was the assert :).
and i just need to hit "continue" to keep run the debug.

ok now, i arrived at this class

class MySampledHeightFieldShape: public hkpSampledHeightFieldShape

this class has

HK_FORCE_INLINE hkReal getHeightAtImpl( int x, int z ) const
{
return hkReal(m_data[x * m_zRes + z]) / hkReal( hkUint16(-1) );
}

and when i debug it, it always never returns more than 1

and this is my hkm file
http://www.box.net/shared/5lp4o2uif2

Hi again

If the program is hitting an assert, that means something is going fundamentally wrong. You should not ignore or skip these asserts. What messages does the assert give you? Look in the output window or the console to find the messages.

Also, what do you mean "always never returns more than 1"? Is that a problem or what you expect? Is this happening after the assert? Nothing that happens after an assert should really be trusted.

What range of height values would you expect to see in your m_data array? Note that in that sample we are storing the heights as 16 bit integers - this is not necessarily what you want to do in your case. Try just returning m_data[x * m_zRes + z] from getHeightAtImpl() if you are storing 32 bits floats.

Patrick

Developer Support Engineer
Havok
www.havok.com

Quoting - PatrickAtHavok
Hi again

If the program is hitting an assert, that means something is going fundamentally wrong. You should not ignore or skip these asserts. What messages does the assert give you? Look in the output window or the console to find the messages.

Also, what do you mean "always never returns more than 1"? Is that a problem or what you expect? Is this happening after the assert? Nothing that happens after an assert should really be trusted.

What range of height values would you expect to see in your m_data array? Note that in that sample we are storing the heights as 16 bit integers - this is not necessarily what you want to do in your case. Try just returning m_data[x * m_zRes + z] from getHeightAtImpl() if you are storing 32 bits floats.

how do i "not ignore" it?
i dont have console kind of thing. how do i see it. is it on the stack dropdown box( i use VS studio 2008)?

actually i have 32 bit height map generated.
i am trying to play around this. now i have the height map resembles the program heightmap. but it is not valid. what i mean by not valid is because i apply the transform to the vertices, but not to the height field.

so even though the heightfield looks the same, but it positioned different then the actual position of the rendered height map on my program.

Hi again

Here's a forum thread on how to report a crash. You need more information on what is causing your asserts.

How are you setting the position of your heightfield? I'd normally go with setting the m_position of its rigid body. To center the heightfield, for example, go with the following pseudocode, taken from the sampled height field demo:

heightFieldRigidBody.m_position.setmul4( -0.5f, heightFieldShape->m_extents );

This demo can be found in DemoDemosPhysicsApiCollideShapesHeightFieldSampledHeightFieldSampledHeightFieldDemo.cpp

It sounds like there might be a problem where you are setting up your heightfield data. You would probably do well to debug in there too a bit.

Patrick

Developer Support Engineer
Havok
www.havok.com

Quoting - PatrickAtHavok
Hi again

Here's a forum thread on how to report a crash. You need more information on what is causing your asserts.

How are you setting the position of your heightfield? I'd normally go with setting the m_position of its rigid body. To center the heightfield, for example, go with the following pseudocode, taken from the sampled height field demo:

heightFieldRigidBody.m_position.setmul4( -0.5f, heightFieldShape->m_extents );

This demo can be found in DemoDemosPhysicsApiCollideShapesHeightFieldSampledHeightFieldSampledHeightFieldDemo.cpp

It sounds like there might be a problem where you are setting up your heightfield data. You would probably do well to debug in there too a bit.

thanks again for the reply.

what i meant about the meshes (i would say d3d mesh) and the rigid body is not at the same exact position. even though they have the same float number as the position.

for example. my cube is positioned at 0.0f,0.0f,0.0f,
and as of the rigid body, i have

hkpRigidBodyCinfo ci;
ci.m_motionType = hkpMotion::MOTION_SPHERE_INERTIA;
ci.m_shape = shape;
ci.m_mass = 4.f;
ci.m_inertiaTensor.setDiagonal( .3f,.3f,.3f );
ci.m_position.set(
myD3DMesh->GetPosition()->x,
myD3DMesh->GetPosition()->y,
myD3DMesh->GetPosition()->z );

as the logic says, it should position the rigidbody the same as the myd3dmesh.

but what happened is they are not on the same position, or maybe it is because of my own mistake. or because i dont know how to align the rigid body and the directx mesh correctly.

or maybe you can tell me how to align them correctly.
by setting up the mesh based on the rigid body?? so i would position the rigid body. then use the hkTransform to set the position for the d3d mesh. or like i did, use the position of the mesh, and set the rigid body position based on that.

thank you

alright. i am managed to almost. realy almost. i still have slight difference in position of my generated height map from directx and the height which i supply to havok heightfield. i know this is my mistake.

ok this is what i do.

first. ofcourse you need the raw file. the script to generate from it and display it.

you must have this kind of line on your program

 // Allocate memory and read the data  
   m_pHeight = new UCHAR[m_numVertices];  
   heightStream.read( (char *)m_pHeight, m_numVertices );  
   heightStream.close();  

and m_pHeight is UCHAR, means from 0 to 255. any other data type is fine. i think... so that m_pHeight is the one that i supplied to havok. as of the terrain, i wrote this as my new method of the terrain class

 void CTerrain::initHKHeightFields(){  
      m_heightDatas = hkAllocate(m_numVertices, HK_MEMORY_CLASS_DEMO);  
      D3DXMATRIX tranform = m_scale * m_rotate * m_translate; ;  
      Vertex *tVertices = NULL;  
      m_vb.getVB()->Lock(0,sizeof( PositionTextured ), (void**) & tVertices,0 );   
      {   
           for (UINT j = 0; j < m_width; j++) {  
                for(UINT k = 0; k < m_width; k++){   
                     float height = (  
                          tVertices[j*m_width+k].m_x * tranform._12  +  
                          tVertices[j*m_width+k].m_y * tranform._22  +  
                          tVertices[j*m_width+k].m_z * tranform._32  +  
                          1                                * tranform._42);  
                     //m_heightDatas[j*m_width+k] = height ;        
                     m_heightDatas[j*m_width+k] = (hkReal)m_pHeight[j*m_width+k];   
                }   
           }  
      }  
      // unlock the buffer as we're done working with the vertices  
      m_vb.getVB()->Unlock();   
 }  

and because i am following the sample, ofcourse i have a class that gets the data from the terrain, and supply it to the heightfield physic class

 class MySampledHeightFieldShape: public hkpSampledHeightFieldShape  
 {  
      public:   
           MySampledHeightFieldShape( const hkpSampledHeightFieldBaseCinfo& ci, hkReal* datas )  
                :     hkpSampledHeightFieldShape(ci),  
                      m_datas(datas)   
           {  
           }  
           // Generate a rough terrain  
           HK_FORCE_INLINE hkReal getHeightAtImpl( int x, int z ) const  
           {   
                hkReal a = m_datas[x * m_zRes + z];  
                return a;  
           }  
           //     This should return true if the two triangles share the edge p00-p11  
           // otherwise it should return false if the triangles share the edge p01-p10  
           HK_FORCE_INLINE hkBool getTriangleFlipImpl() const  
           {       
                return false;  
           }  
           virtual void collideSpheres( const CollideSpheresInput& input, SphereCollisionOutput* outputArray) const  
           {  
                hkSampledHeightFieldShape_collideSpheres(*this, input, outputArray);  
           }  
      private:   
           hkReal* m_datas;   
 };  

this class had a little modification from the original source. they are the member variable, and getheightatimpl() method. hmm looks terrible. :P next i wrote these lines by following the sample; this will create the phisics that needed for the simulation.

 hkpSampledHeightFieldBaseCinfo ci;  
      ci.m_xRes = m_terrain.getWidth();  
      ci.m_zRes = m_terrain.getWidth();   
      ci.m_maxHeight = 600.0f;  
      ci.m_minHeight = 0.0f;  
      ci.m_useProjectionBasedHeight = true;   
      ci.m_scale= hkVector4(   
           m_terrain.GetScaling()->_11,   
           m_terrain.GetScaling()->_22 ,   
           m_terrain.GetScaling()->_33  
      );   
      //initialize heightmap data in m_terrain CTerrain  
      m_terrain.initHKHeightFields();   
      MySampledHeightFieldShape* heightFieldShape = new MySampledHeightFieldShape( ci , m_terrain.getHKHeightFields() );  
      {  
           hkpRigidBodyCinfo rci;  
           rci.m_motionType = hkpMotion::MOTION_FIXED;   
           rci.m_shape = heightFieldShape;  
           rci.m_friction = 0.3f;  
           rci.m_position.set(   
                m_terrain.getTopLeft().x,  
                m_terrain.GetPosition().y,  
                m_terrain.getTopLeft().z   
           );     
           hkpRigidBody* body = new hkpRigidBody( rci );  
           mHavokWorld->addEntity(body);  
           body->removeReference();   
           // Just need to remove the reference we hold to the shape, and that is it.  
           heightFieldShape->removeReference();    
      }   
      //height map rigid////////  

i spent a lot of time fixing the position and matching the position of the terrain and the height field.
the terrain and the heightfield physic are not sync and on different position
what i had to do is to create a simple terrain raw file. make sure they have different thing on the top left and right. and then i found out that i need to rotate my terrain 90 degree clockwise to match with the physic height field. what you can do beside that is ofcourse, rotate the physic height field instead of the terrain. even that i still have to tweak a bit. and still i have left with no luck. but i m still working on it. but my assessment is due tomorrow. so i will submit it with this horrible bug. next... hmm i think that s all.. as of the vehicle i mentioned above in some of the posts.. they are on the same position. again, they are not on the same direction. so i had to modify my model to face 90 degree clock wise to match the physic.

just want somebody who read this post aware of this small thing before spending a lot of time debugging it.

and for the crashes i got. it was because the world size is too small for the height field. it was not crash.. actually... it was some asserts. after i resize the world, and/or resize the terrain those asserts gone.

as a beginner in c++ i just found out that this was the asserts doing. and we need a lot of assert to debug this kind of thing. so i will study more on assert and using it.

following this samples have been fun for me. my coding style got changed a bit. and i got something like "hei you can do something like that in c++" :)

todo: for me ---
need to know how the assert working
need to know how to turn off the assert - if sometimes i hate the assert -

thank you.

alright. i am managed to almost. realy almost. i still have slight difference in position of my generated height map from directx and the height which i supply to havok heightfield. i know this is my mistake.

ok this is what i do.

first. ofcourse you need the raw file. the script to generate from it and display it.

you must have this kind of line on your program

 // Allocate memory and read the data  
   m_pHeight = new UCHAR[m_numVertices];  
   heightStream.read( (char *)m_pHeight, m_numVertices );  
   heightStream.close();  

and m_pHeight is UCHAR, means from 0 to 255. any other data type is fine. i think... so that m_pHeight is the one that i supplied to havok. as of the terrain, i wrote this as my new method of the terrain class

 void CTerrain::initHKHeightFields(){  
      m_heightDatas = hkAllocate(m_numVertices, HK_MEMORY_CLASS_DEMO);  
      D3DXMATRIX tranform = m_scale * m_rotate * m_translate; ;  
      Vertex *tVertices = NULL;  
      m_vb.getVB()->Lock(0,sizeof( PositionTextured ), (void**) & tVertices,0 );   
      {   
           for (UINT j = 0; j < m_width; j++) {  
                for(UINT k = 0; k < m_width; k++){   
                     float height = (  
                          tVertices[j*m_width+k].m_x * tranform._12  +  
                          tVertices[j*m_width+k].m_y * tranform._22  +  
                          tVertices[j*m_width+k].m_z * tranform._32  +  
                          1                                * tranform._42);  
                     //m_heightDatas[j*m_width+k] = height ;        
                     m_heightDatas[j*m_width+k] = (hkReal)m_pHeight[j*m_width+k];   
                }   
           }  
      }  
      // unlock the buffer as we're done working with the vertices  
      m_vb.getVB()->Unlock();   
 }  

and because i am following the sample, ofcourse i have a class that gets the data from the terrain, and supply it to the heightfield physic class

 class MySampledHeightFieldShape: public hkpSampledHeightFieldShape  
 {  
      public:   
           MySampledHeightFieldShape( const hkpSampledHeightFieldBaseCinfo& ci, hkReal* datas )  
                :     hkpSampledHeightFieldShape(ci),  
                      m_datas(datas)   
           {  
           }  
           // Generate a rough terrain  
           HK_FORCE_INLINE hkReal getHeightAtImpl( int x, int z ) const  
           {   
                hkReal a = m_datas[x * m_zRes + z];  
                return a;  
           }  
           //     This should return true if the two triangles share the edge p00-p11  
           // otherwise it should return false if the triangles share the edge p01-p10  
           HK_FORCE_INLINE hkBool getTriangleFlipImpl() const  
           {       
                return false;  
           }  
           virtual void collideSpheres( const CollideSpheresInput& input, SphereCollisionOutput* outputArray) const  
           {  
                hkSampledHeightFieldShape_collideSpheres(*this, input, outputArray);  
           }  
      private:   
           hkReal* m_datas;   
 };  

this class had a little modification from the original source. they are the member variable, and getheightatimpl() method. hmm looks terrible. :P next i wrote these lines by following the sample; this will create the phisics that needed for the simulation.

 hkpSampledHeightFieldBaseCinfo ci;  
      ci.m_xRes = m_terrain.getWidth();  
      ci.m_zRes = m_terrain.getWidth();   
      ci.m_maxHeight = 600.0f;  
      ci.m_minHeight = 0.0f;  
      ci.m_useProjectionBasedHeight = true;   
      ci.m_scale= hkVector4(   
           m_terrain.GetScaling()->_11,   
           m_terrain.GetScaling()->_22 ,   
           m_terrain.GetScaling()->_33  
      );   
      //initialize heightmap data in m_terrain CTerrain  
      m_terrain.initHKHeightFields();   
      MySampledHeightFieldShape* heightFieldShape = new MySampledHeightFieldShape( ci , m_terrain.getHKHeightFields() );  
      {  
           hkpRigidBodyCinfo rci;  
           rci.m_motionType = hkpMotion::MOTION_FIXED;   
           rci.m_shape = heightFieldShape;  
           rci.m_friction = 0.3f;  
           rci.m_position.set(   
                m_terrain.getTopLeft().x,  
                m_terrain.GetPosition().y,  
                m_terrain.getTopLeft().z   
           );     
           hkpRigidBody* body = new hkpRigidBody( rci );  
           mHavokWorld->addEntity(body);  
           body->removeReference();   
           // Just need to remove the reference we hold to the shape, and that is it.  
           heightFieldShape->removeReference();    
      }   
      //height map rigid////////  

i spent a lot of time fixing the position and matching the position of the terrain and the height field.
the terrain and the heightfield physic are not sync and on different position
what i had to do is to create a simple terrain raw file. make sure they have different thing on the top left and right. and then i found out that i need to rotate my terrain 90 degree clockwise to match with the physic height field. what you can do beside that is ofcourse, rotate the physic height field instead of the terrain. even that i still have to tweak a bit. and still i have left with no luck. but i m still working on it. but my assessment is due tomorrow. so i will submit it with this horrible bug. next... hmm i think that s all.. as of the vehicle i mentioned above in some of the posts.. they are on the same position. again, they are not on the same direction. so i had to modify my model to face 90 degree clock wise to match the physic.

just want somebody who read this post aware of this small thing before spending a lot of time debugging it.

and for the crashes i got. it was because the world size is too small for the height field. it was not crash.. actually... it was some asserts. after i resize the world, and/or resize the terrain those asserts gone.

as a beginner in c++ i just found out that this was the asserts doing. and we need a lot of assert to debug this kind of thing. so i will study more on assert and using it.

following this samples have been fun for me. my coding style got changed a bit. and i got something like "hei you can do something like that in c++" :)

todo: for me ---
need to know how the assert working
need to know how to turn off the assert - if sometimes i hate the assert -

thank you.

Hey again, R4ccoon

Great to hear you got it sorted out, but there are a few issues raised that I feel I should point out for other readers.

#1) There are still calculations you make in your code that are never used. For example, in your k-loop, you calculate float height = (tVertices[...]...), then never use it, since you commented out its only other occurence - why not also comment out its calculation to save yourself some flops?

#2) I'm confused as to why you declare your m_pHeight buffer as UCHAR[n] then cast it to hkReal on first (and only, from what I can see) use when you copy it into your m_heightDatas buffer. Why not just declare one hkReal buffer here? For other readers, note as well that the getHeightAtImpl() method is the all-important part here. It is entirely up to the user as to how they implement this, ie: what type of buffer to use, or whether to use a buffer at all. The only requirement is that that method returns a hkReal.

#3) You should note that there isn't a steady convention as to which world axis should be "up". Havok uses y as up for its heightfields (so that it is, in essence, a function (x,z) -> y), but your game world may use z as up (for example). Havok also considers the origin of the heightfield to be its lower left corner.

So unless your renderer uses the same convention, you will have to do some work on your end to make sure they match up. This is unavoidable since Havok has no knowledge of what your renderer does. You are correctly doing this transformation by setting the heightfield rigid body position. Note that you can also set the heightfield rigid body rotation. That should avoid you having to re-export the data to rotate it 'correctly'.

I suspect you should also look at your scales, too - Havok uses SI units (meters etc). The cube in your VDB recording was suspiciously huge... There is a large variety of different units used by the different modellers. For that reason, the Havok Content Tools provide a simple filter (Transform Scene) to do the necessary rescales and/or axis swaps.

Patrick

Developer Support Engineer
Havok
www.havok.com

Leave a Comment

Please sign in to add a comment. Not a member? Join today