Upcoming Events
Southwest Gaming Expo
11/20 - 11/22 @ Dallas, TX

Workshop on Network and Systems Support for Games (NetGames 2009)
11/23 - 11/25 @ Paris, France

ICIDS 2009 Interactive Storytelling
12/9 - 12/11 @ Guimarães, Portugal

Global Game Jam
1/29 - 1/31  

More events...


Quick Stats
6397 people currently visiting GDNet.
2341 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!



Link to us

Link to us

  Intel sponsors gamedev.net search:   

Vertex Tweening

And now for something completely different - the actual tweening. Although DirectX 9 implements it in software, you may want to check for Tweening support before you attempt to use it:

D3DCAPS9 caps;
 
d3d_device->GetDeviceCaps( &caps );
if(caps.VertexProcessingCaps & D3DVTXPCAPS_TWEENING)
  // Vertex tweening is supported.
else
  // You're screwed

Note: Actually, you aren't quite screwed. DirectX has a function for switching between hardware and software vertex processing, so you can use supported features in hardware, and unsupported features in software. To do this, you must set D3DCREATE_MIXED_VERTEXPROCESSING when you create the device. Then, when you need to switch to software rendering, use IDirect3DDevice9::SetSoftwareVertexProcessing(TRUE) and then go back to hardware processing when you are done with the feature with IDirect3DDevice9::SetSoftwareVertexProcessing(FALSE). I skirt the issue in the demo by just setting SOFTWARE vertex processing in my device creation.

So you have tweening support. Now what? You need a vertex declaration worthy of tweening, and here's the one I use in the example:

D3DVERTEXELEMENT9 tween_decl_ve[] =
{
  {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
  {1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 1},
  {2, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
  D3DDECL_END() // this macro is still needed as the last item! DON'T FORGET ;)
};
d3d_device->CreateVertexDeclaration(tween_decl_ve, &tween_decl);

As I hope you can see, I define two sets of vertex coordinates and a set of texture coordinates, all on separate streams. Using this declaration, I can have one vertex buffer for each keyframe, and one for all of the keyframes which contains the texture coordinates. Another important thing I want you to notice is the UsageIndex value on the two positional elements. The first UsageIndex is a 0, and the second one is a 1. This is important, because it identifies the two sets of positional data. The 0th set is the beginning vertex we talked about in the interpolation section at the beginning, and the 1st set is the ending vertex. These are the two we will morph between for our smooth animation.

Now, assuming you have the declaration, two vertex buffers of positional data and one of texture data, here's the rendering code:

static float tween_factor = 0.0f; // Remember, 0 is the starting frame
tween_factor += 0.1f;             // Incrementing tween factor moves
                                  // between the two frames
 
if (tween_factor >= 1.0f)         // 1.0 is the ending frame, so this frame
     tween_factor = 0.0f;         // is finished. Start again at 0
 
// Enable tweening and set the TWEENFACTOR
d3d_device->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_TWEENING);
d3d_device->SetRenderState(D3DRS_TWEENFACTOR, FtoDW(tween_factor));
 
// Set our vertex declaration
d3d_device->SetVertexDeclaration(tween_decl);
 
// Set the stream sources that the vertex declaration will point to
d3d_device->SetStreamSource(0, keyframe_VB[0]); // set to your first keyframe
d3d_device->SetStreamSource(1, keyframe_VB[1]); // set to your second keyframe
d3d_device->SetStreamSource(2, texture_VB); // your texture coord buffer
d3d_device->SetIndices(model_IB);

// Draw the tweened model!
d3d_device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, vert_count, 0, tri_count);

And there you go! Make sure to release your vertex declaration (as well as all other COM objects) when you are done:

tween_decl->release();

Conclusion

Using tweening as opposed to interpolating yourself has many benefits. The biggest one I see is that tweening can be done on vertex buffers, so it is faster than continually locking the buffers or using DrawPrimitiveUP. It's also a heck of a lot easier than interpolating on your own. And if the hardware supports it, it's going to be almost as fast as if you didn't interpolate at all!

I hope you have found this article useful. I decided to write it because I struggled to find information on vertex declarations and tweening in DirectX 9 when I was trying to figure it out not too long ago. This is the first article I've contributed, so make sure to tell me what you think! My e-mail is bjmumblingmiles@hotmail.com. Make sure to download the source code and demo project! It includes my MD2 loader class designed for this kind of animation, if you're interested.

Note: One thing I'd encourage you to add to the demo is time-based movement. It's not too complicated, but you should understand the concept of linear interpolation before you try it. If you are interested, here is the equation:

∆(interpolation percentage) = (frames per second)×(current time - last time)

OR

tween_factor += FPS*(current_time - last_time);

The screenshot below is based off the demo project, but you'll have to play around with it to get this scene:




Contents
  Vertex Declarations
  Vertex Tweening

  Printable version
  Discuss this article