Ripping Models From Directx9 Games Part 2 – Implementing

wowmodel

[Introduction]

In this part we’ll talk about what needs to be done under the hood to implement a directx9 model ripper.  To implement 3d geometry I used hooking.  I won’t get into the details of how to hook directx calls here since that subject has been more than covered online.  You should be familiar with that subject before continuing this tutorial.

[Getting Geometry Data From DirectX9]

If you read part one of this tutorial you know that we need to get access to the index and vertex buffers which is where the geometry information is stored.  To get the index buffer we hook IDirect3DDevice9::SetIndices, which takes in the index buffer as a parameter.  Even though directx9 allows for multiple streams with different vertexbuffers, there is only one index buffer, and hooking this function gives you access to it.

To get access to the vertexbuffer we can hook IDirect3DDevice9::SetStreamSource, but this is where things get a bit complicated.  Directx9 lets you have multiple streams, with multiple vertex buffers tied to each stream.  Theoretically only one of these vertex buffers has the geometry’s vertices, with the other buffers carrying information on texture mappings, colors, normals, etc.  In games using multiple streams you might find yourself getting weird results.  I always aim to get the vertexbuffer tied to stream 0, and I’ve had moderate success so far, but it is definitely something to look out for.  From SetStreamSource we also get the stride for the given vertexbuffer.  The stride is the size, in bytes, of the vertices in the buffer, and we use it to properly iterate through the vertexbuffer since we don’t know what the actual vertex structs look like on the game’s end.  We can access the begining of each vertex in the vertexbuffer like so: i*stride.

Once we have access to the index buffer and the vertex buffer, all we need to do is access them in the correct order to get the correct representation of the geometry we want to dump.  We do this by hooking IDirect3DDevice9::DrawIndexedPrimitive. This is the function that you would call if you were the one doing the rendering of the geometry, and just about the only legitimate way to render 3d geometry in an efficient manner.  DrawIndexedPrimitive takes multiple parameters that are best explained here. The only parameters we care about are StartIndex, BaseVertexIndex, Type, and PrimCount.

StartIndex is the position into the indexbuffer where the first index for the vertex of the geometry being rendered is located.  BaseVertexIndex is used when doing offset rendering, the value in BaseVertexIndex is added to the value retrieved from the index buffer before doing a lookup into the vertex buffer.  Type is the type of primitive to render, this is a d3d enumeration which can be found here.  If you’re looking at models you’re either looking at trianglelists or trianglestrips.  PrimCount is just how many primitives are used to render the geometry being rendered in this particular draw call.  If the game is using triangle strips or triangle lists, a primitive is just a polygon, which is composed of three 3d vertices (three points make a triangle).  But keep in mind that if the model is being rendered using a trianglestrip you will have 2/3 of the primitives required to build the model missing from the buffer.

Once we have all of this in place, all that we need to do is iterate through the vertex buffer and drop the indices to some format that 3d modeling software can recognize, and that’s all there is to it.  If the model is being rendered from triangle lists, then the whole process just requires us to go from StartIndex to StartIndex+PrimCount*3.  So basically starting from the beginning of the index buffer, we want to dump PrimCount(the amount of primitives in the model) * 3(the amount of vertices per primitive/polygon) vertices. If the model is being rendered using a trianglestrip then we need to rebuild the missing 2/3 vertices that are missing from the vertexbuffer to make a trianglelist.

The code for dumping a model from inside a DIP hook looks like this:

HRESULT WINAPI MyDrawIndexedPrimitive(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE Type, INT BaseVertexIndex, UINT MinIndex,
UINT NumVertices, UINT StartIndex, UINT PrimitiveCount)
{
     pDevice->GetIndices(&bound_indices);
     if(!dumped && PrimitiveCount == primcount && NumVertices == numverts)
     {
         if(bound_vertices != NULL)
         {
             void * data;
             bound_vertices->Lock(0,0, &data, 0);
             byte * vertices = (byte*)data;
             PopulateIndices(PrimitiveCount, StartIndex, MinIndex, NumVertices, BaseVertexIndex, Type, data);
             bound_vertices->Unlock();
         }
         dumped = true;
      }	
      return DrawIndexedPrimitive(pDevice, Type, BaseVertexIndex, MinIndex, NumVertices, StartIndex, PrimitiveCount);
}

Where PopulateIndices is defined as:

HRESULT WINAPI PopulateIndices(UINT PrimCount, UINT StartIndex, UINT MinIndex, UINT NumVertices, INT BaseVertexIndex, D3DPRIMITIVETYPE Type, void * verts)
{
    if(bound_indices == NULL)
    {
        return 1;
    }
    void * d;
    bound_indices->Lock(0,PrimCount * 3 * sizeof(WORD), &d,0);
    WORD * indices = (WORD*)d;
    int f = 0;
    if(Type == D3DPT_TRIANGLELIST)
        PopulateTriangleList(PrimCount, "", StartIndex, MinIndex, BaseVertexIndex, NumVertices, indices, verts);
    else if(Type == D3DPT_TRIANGLESTRIP)
        PopulateTriangleStrip(PrimCount, "", StartIndex, MinIndex, BaseVertexIndex, NumVertices, indices, verts);
    bound_indices->Unlock();
    return 0;
}

[Turning a TriangleStrip into a TriangleList]

A trianglestrip is a way of representing triangles where every triangle shares two vertices with every other triangle in the strip.  Basically shrinks the number of vertices needed to be stored in the buffer.  Say you have a triangle composed of the vertices A,B,C; and a triangle composed of vertices B, C, D.  In a triangle list these triangles would look like:

vertbuff[0] = A;
vertbuff[1] = B;
vertbuff[2] = C;
vertbuff[3] = B;
vertbuff[4] = C;
vertbuff[5] = D;

or 6 vertices.  However, the same two triangles in a trianglestrip can be represented like this:

vertbuff[0] = A;
vertbuff[1] = B;
vertbuff[2] = C;
vertbuff[3] = D;

or only 4 vertices.  The idea is that the previous two vertices in the buffer are used to make a triangle with the next vertex in the buffer.  Similarly, we could have a third triangle with only an additional vertex added to the buffer.  Adding another vertex D to the buffer creates a third triangle with vertices C, D, D.

[Conclusion]

That’s pretty much it.  By doing the above you get access to the vertexbuffers and index buffer needed to dump the 3d geometry in directx9 games.  To see source code for putting this in action look here.  In the next part of this tutorial I’ll talk about turning this information into OBJ format, which is understood by most 3d modeling tools out there.

2 Responses to Ripping Models From Directx9 Games Part 2 – Implementing

  1. Codeblack says:

    Hey! Thanks alot. This is a realy nice tutorial =). I tryed it also with Wow but the problem is that an error message with the following content applys:

    “Failed setting debug privilegs”

    and if(bound_vertices != NULL) is alsways NULL.

    The game is World of Warcraft.

    Thanks for this nice and well done guide!

Leave a Reply

Your email address will not be published. Required fields are marked *