BannerLeft BannerLeft

 

Direct3D FAQ

This page contains some frequently asked questions about the Direct3D API contained within the DirectX SDK. This page is continuously being updated.

Direct3D FAQ


What are the different Direct3D library files?

You should link with debug versions of the libraries when doing a debug build so you get warnings and error messages. Obviously for your final release build you should link with the release libraries.

d3d9.lib - stub library for Direct 3D, link is with d3d9.dll at runtime, debug level controlled by Control Panel
d3dx9.lib - the release library for D3DX, full code no dll
d3dx9d.lib - the stub library for D3DX, link is with the (SDK only) d3dx9d.dll at run time
d3dx9dt.lib - debug library for D3DX, full code no dll - useful if giving to someone without SDK installed for testing.

Note: from the February update of the SDK D3DX has been moved into a .dll. Also the statically linked debug library (D3DX9dt.lib) has been removed; use D3DX9d.lib instead. More info: here

Other useful ones

d3dxof.lib - x file reading templates
dxguid.lib - to use globally unique identifiers
dxerr.lib - used for getting DirectX error strings

See also: Link Errors

How can I use the mouse to pick an object in the world?

I have added some notes on picking. See the page here: Picking

There are a number of D3DX functions that can help with collisions:

D3DXBoxBoundProbe - determines if a ray intersects a bounding box
D3DXIntersect - determines if a ray intersects a mesh
D3DXIntersectTri - more accurate but slower test
D3DXSphereBoundProbe - determines if a ray intersects a bounding sphere
D3DXPlaneIntersectLine - finds the intersection between plane and a line
D3DXVec3Unproject - projects a vector from screen space into object space

Once I have loaded a texture how can I find out its size etc.?

The texture provides an interface called GetLevelDesc(...) this returns information on the loaded texture like its width, height, colour format, memory position etc. To use this function you must declare an instance of the D3DSURFACE_DESC structure. You pass the address of this instance to the GetLevelDesc function and it fills in the values. After the call you can look at the filled values.  An example might be:

D3DSURFACE_DESC desc;
gTexture->GetLevelDesc(0,&desc);

w=desc.Width;

Look in the DX help file for more information.

How do I show the view in wireframe?

You can easily switch to wireframe using the fill mode render state e.g.

void CVisualisation::SetWireframeMode(bool set)
{
     if (set)
         gD3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
     else
         gD3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
}

How do I get the viewing frustum?

The viewing frustum is needed in order to do frustum culling of the scene i.e. do not render objects that are outside the view. Note that the correct term is frustum not frustrum.

In Direct3D to find the viewing frustum you need to combine the view matrix and projection matrix and extract the values. The result will be the six planes: left, right, top, bottom, near and far. In order to describe a plane we need a direction normal and offset (distance). So we can define a structure or class for our plane containing these values and a function to normalise them.

struct TFrustumPlane
{
   D3DXVECTOR3 m_normal;
   float m_distance;

   inline void Normalise()
   {
     float denom = 1 / sqrt((m_normal.x*m_normal.x) + (m_normal.y*m_normal.y) +                   (m_normal.z*m_normal.z));
     m_normal.x = m_normal.x * denom;
     m_normal.y = m_normal.y * denom;
     m_normal.z = m_normal.z * denom;
     m_distance = m_distance * denom;
   }
};

We then combine the view and projection matrices and work out the planes, the code below does this. It assumes you have an array for your planes: TFrustumPlane m_frustumPlanes[6]; a view matrix matView and a projection matrix matProj:

// Get combined matrix
D3DXMATRIXA16 matComb;
D3DXMatrixMultiply(&matComb, matView, matProj);

// Left clipping plane
m_frustumPlanes[0].m_normal.x = matComb._14 + matComb._11;
m_frustumPlanes[0].m_normal.y = matComb._24 + matComb._21;
m_frustumPlanes[0].m_normal.z = matComb._34 + matComb._31;
m_frustumPlanes[0].m_distance = matComb._44 + matComb._41;

// Right clipping plane
m_frustumPlanes[1].m_normal.x = matComb._14 - matComb._11;
m_frustumPlanes[1].m_normal.y = matComb._24 - matComb._21;
m_frustumPlanes[1].m_normal.z = matComb._34 - matComb._31;
m_frustumPlanes[1].m_distance = matComb._44 - matComb._41;

// Top clipping plane
m_frustumPlanes[2].m_normal.x = matComb._14 - matComb._12;
m_frustumPlanes[2].m_normal.y = matComb._24 - matComb._22;
m_frustumPlanes[2].m_normal.z = matComb._34 - matComb._32;
m_frustumPlanes[2].m_distance = matComb._44 - matComb._42;

// Bottom clipping plane
m_frustumPlanes[3].m_normal.x = matComb._14 + matComb._12;
m_frustumPlanes[3].m_normal.y = matComb._24 + matComb._22;
m_frustumPlanes[3].m_normal.z = matComb._34 + matComb._32;
m_frustumPlanes[3].m_distance = matComb._44 + matComb._42;

// Near clipping plane
m_frustumPlanes[4].m_normal.x = matComb._13;
m_frustumPlanes[4].m_normal.y = matComb._23;
m_frustumPlanes[4].m_normal.z = matComb._33;
m_frustumPlanes[4].m_distance = matComb._43;

// Far clipping plane
m_frustumPlanes[5].m_normal.x = matComb._14 - matComb._13;
m_frustumPlanes[5].m_normal.y = matComb._24 - matComb._23;
m_frustumPlanes[5].m_normal.z = matComb._34 - matComb._33;
m_frustumPlanes[5].m_distance = matComb._44 - matComb._43;

See the next question on how to use this data for intersection testing against bounding boxes.

How do I determine if a bounding box has intersected the viewing frustum?

There are three possibilities, either the BB is completely outside the frustum, it is completely inside or it intersects. The following code assumes you have created the plane data as described in the previous answer and you pass in a world space AABB (Axis Aligned Bounding Box).

/*****************************************************************************
Desc: Taking an AABB min and max in world space, work out its interaction with the view frustum
0 is outside
1 is partially in
2 is completely within
Note: the viewing frustum must be calculated first
******************************************************************************/
WORD cullAABB(const D3DXVECTOR3 &aabbMin, const D3DXVECTOR3 &aabbMax)
{
 

    bool intersect = FALSE;
    WORD result=0;
    D3DXVECTOR3 minExtreme,maxExtreme;

    for (WORD i=0;i<6;i++)
    {
        if (m_frustumPlanes[i].m_normal.x <= 0)
        {
           minExtreme.x = aabbMin.x;
           maxExtreme.x = aabbMax.x;
        }
        else
        {
           minExtreme.x = aabbMax.x;
           maxExtreme.x = aabbMin.x;
        }

        if (m_frustumPlanes[i].m_normal.y <= 0)
        {
           minExtreme.y = aabbMin.y;
           maxExtreme.y = aabbMax.y;
        }
        else
        {
           minExtreme.y = aabbMax.y;
           maxExtreme.y = aabbMin.y;
        }

        if (m_frustumPlanes[i].m_normal.z <= 0)
        {
           minExtreme.z = aabbMin.z;
           maxExtreme.z = aabbMax.z;
        }
        else
        {
           minExtreme.z = aabbMax.z;
           maxExtreme.z = aabbMin.z;
        }
       
        if (m_frustumPlanes[i].DistanceToPoint(minExtreme) > 0)
        {
            result = 0;
            return result;
        }

        if (m_frustumPlanes[i].DistanceToPoint(maxExtreme) >= 0)
             intersect = TRUE;
    }

    if (intersect)
         result = 1;
    else
         result = 2;

    return result;

}

The DistanceToPoint function is simply: D3DXVec3Dot(&m_normal, &pnt) + m_distance;

Should I use the D3DX Vectors / Matrix or write my own?

The vector and matrix types that come with Direct3D are highly optimized. There are many functions that can be performed using them, like dot product, cross product etc. which are optimized to run best on the processor. i.e. if your game runs on a Pentium machine these functions will use code optimized by Intel for top speed but if your game runs on an AMD it uses code optimized for that platform. So it would be hard for you to write a vector structure/class and functions that can outperform the D3DX ones. For true black box code you will require your own vectors for calculations outside of the visualization component. A conversion will then need to take place when passing these into the visualization component.

Where can I get models / textures?

Look on the Internet, there are plenty of places where you can download models in various formats. The most common format seems to be .3ds which can be loaded into 3DS Max and saved out as a .x file or converted using the converter. A comprehensive list of good sites can be found in the Resources section of this site.

How can I read colour data from a texture?

You may want to read colour data from a texture if for example you use a texture to encode level data. e.g. a blue colour means put a wall here, a red means an enemy etc.

Firstly you need to create your image in either bmp or tga format. You then need to load it into your program. You must force it to be 32 bit even if it was not originally. It is important to do this so you know the format of the data and hence how to read it. So for example you could create a 24 bit graphic in your art tool and then on load force it to be 32 bit (Direct3D converts it for you). This is how you do it:

// Load the map texture
HRESULT hr=D3DXCreateTextureFromFileEx(gD3dDevice, filename, 0, 0, 1 ,0 ,D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_NONE ,D3DX_FILTER_NONE ,0 ,NULL ,NULL ,&texture );


Its the extended file load version. The D3DFMT_A8R8G8B8 means whatever the original format it will be converted to 32 bit with 8 bits (one byte) for each colour component. It is put in the managed memory pool so Direct3D handles where to put it and you have no filters applied. If it was successful 'texture' will point to the loaded texture.

Now to get the colour information from the file you must lock the texture:

D3DLOCKED_RECT locked;
HRESULT hr=texture->LockRect(0,&locked,NULL,0);


If that is successful it returns a structure 'locked' that contains info about the texture. You can now obtain a pointer that points to the colour in the top left of the image:

BYTE *bytePointer=(BYTE*)locked.pBits;

Now you have a pointer to all the data, you need to interpret it as colours. Since you know it is 32 bit format you can extract the data. You go along the horizontal (x coordinate) reading the values 4 bytes at a time. One gotcha is that a line of data in memory may be longer than the width of the image - this is due to padding for optimisation purposes. So the memory width of a line may actually be different than the image width. You can find it though by looking at locked.Pitch, so:


for (DWORD y=0;y<surfaceDesc.Height;y++)
{
    for (DWORD x=0;x<surfaceDesc.Width;x++)
    {
       DWORD index=(x*4+(y*(locked.Pitch)));
       
       // Blue
       BYTE b=bytePointer[index];

       // Green
       BYTE g=bytePointer[index+1];

       // Red
       BYTE r=bytePointer[index+2];

       // Alpha
       BYTE a=bytePointer[index+3];  
   }
}


And that's it. Once you have finished you must unlock the texture:

texture->UnlockRect(0);

Note: when you create and manipulate texture resources you can specify memory pool and usage etc. for full details on the options please see the D3D Resources page.

How can I display billboards?

Billboards are 2D shapes rotated to always face the camera. You can see this in some games where trees will  look the same whatever angle you view them from. This is because they are being rotated to face you all the time. The advantages of using billboards is that it is only two triangles and a texture rather than the alternative of using a full 3D model with many triangles. The disadvantage is of course that the image is the same wherever you view it from.

To create a billboard you need to create two triangles that make up a square. So there will be 4 vertices, one for each corner of the square. Each vertex should be given a position and a texture co-ordinate. The texture co-ordinates will be 0,0 for the top left vertex and 1,1 for the lower right. So this is all fairly simple, the slightly tricky bit is to render it so that it is always facing the camera. To do that we need to apply a matrix which is the inverse of the current view matrix. We also set the translation component to 0 as we do not want to translate the billboard by the camera position. So in Direct3D we do this:

// Create billboard matrix
D3DXMatrixInverse( &m_matBillboard, NULL, &view );

m_matBillboard._41 = 0.0f;
m_matBillboard._42 = 0.0f;
m_matBillboard._43 = 0.0f;

 

To render our billboard we simply multiply the billboard matrix by our objects scaling matrix (if there is one) and then assign the objects world position as above:

// Create a matrix to scale our billboard
D3DXMatrixScaling(&temp,scale->x,scale->y,scale->z);

// Multiply this by the billboard matrix
D3DXMATRIX result;
D3DXMatrixMultiply(&result,&matBillboardMatrix,&temp);

// Now factor in the objects world position

result._41 = pos->x;
result._42 = pos->y;
result._43 = pos->z;

// Set the final matrix as the world matrix
gDevice->SetTransform(D3DTS_WORLD, &result )

We can now render as normal e.g. set texture, call DrawPrimitive.

How can I render a 3D object with many textures?

Each DrawIndexedPrimitive call uses just one texture so you could split your 3D object into a number of vertex and index buffers for each texture area. You then just render one after the other switching the texture each time. However a more efficient method is to use just one index buffer and one big vertex buffer. The DrawIndexedPrimitive function allows you to specify a range of triangles to render each time rather than always rendering the whole lot. So you can set a texture, render from a part of the vertex buffer, set another texture and render another part etc. An example will make this clearer:

E.g.. rendering a cube with a different texture on each side.

A cube is made up of 6 sides so we could create a 3D model with two triangles forming a square for each side of the cube. That would mean we would have 6*2=12 triangles in our cube. Since we need 3 indexes per triangle that would give us an index buffer containing 12*3=36 entries. We would need 4 vertices for each side of our cube so we would have 4*6=24 vertices altogether. We could share vertices amongst the sides but that would prevent us from having separate texture co-ordinates per triangle which we will require. If all this sounds confusing I suggest you draw it on paper to see how it works or better still get a box and label the corners (this is what I do).

To summarise: we will have 6 textures, one for each side. We have 12 triangles and 24 vertices. So to draw our cube with different textures on each side we would do a loop like this:

for (int i=0;i<6;i++)
{
    gD3dDevice->SetTexture(0,m_texture[i]);
    gD3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,i*4,4,i*6,2);  
}

The DrawIndexedPrimitive takes the following parameters:

    D3DPRIMITIVETYPE Type - the type of storage, normally triangle list
    INT BaseVertexIndex - an offset, always set to 0 for our purposes
    UINT MinIndex - the first vertex we will be using in this call, since there are 4 vertices per side we do i*4
    UINT NumVertices - the number of vertices in this call, this is 4 as there are 4 used per side
    UINT StartIndex - the start index of our triangles in the index buffer
    UINT PrimitiveCount - the number of triangles to draw, this is 2 as we have 2 per side

Note: you could leave MinIndex at 0 and NumVertices as 24 if you want, which means you can use any vertex in the buffer during this call but it is normally better to give as much information to the driver as you can so it can carry out optimisations etc.

How can I create my own texture and write to it?

With Direct3D you can create a texture in memory using the CreateTexture call. Make sure you set it to D3DUSAGE_DYNAMIC because you want to write to it and set the memory pool to D3DPOOL_DEFAULT. You can specify the format you want e.g. for a 32 bit texture you would say D3DFMT_A8R8G8B8. There are many other formats available.

Once you have created it you can write to it by locking the texture. This returns you a pointer to the memory where you can write. When writing remember the width of the data in memory will not always equal the width of the image so you must take the stride into account. Once finished writing you can save to disk using: D3DXSaveTextureToFile

I get frame rate fluctuations in windowed mode

When your device is created the presentation interval is set to D3DPRESENT_INTERVAL_DEFAULT. This setting synchronises your frames to to the window rate so there is only one present allowed per frame. This prevents tearing effects (D3DPRESENT_INTERVAL_IMMEDIATE provides unlimited presents).  However if you are seeing fluctuations in frame rate you might be better to try D3DPRESENT_INTERVAL_ONE, this uses a higher resolution timer than the default setting which improves the quality of the vsync but takes up a bit more processing time. To change this value you need to alter the D3DPRESENT_PARAMETERS PresentationInterval value.

I see flashing green and purple colours - what is going on?

You are not clearing the back buffer correctly. The Direct3D debug runtime clears the back buffer alternately green or purple so if you see these colours you must not be clearing it yourself.

Can I use GDI and Direct3D together?

Yes you can. You can obtain a HDC for normal GDI drawing IDirect3DSurface9::GetDC(), and you can use Windows dialogs to implement user interfaces IDirect3DDevice9::SetDialogBoxMode(). However bear in mind there are a few restrictions - check the DirectX help for details.

How can I retrieve the parts that make up a matrix?

There is a really useful D3DX function: D3DXMatrixDecompose that, when passed a transformation matrix, will return scale, rotation and translation values.

I just updated to the latest version and Direct3D no longer compiles

Updated: from the April DirectX SDK release Visual Studio 6 is no longer supported.

Are you using Visual Studio 6? If so then you need to use the D3DX library found in the extras download. Ultimately I would move to .net. Also see: DirectX 9.0c and missing dll below.

Where else can I find answers?

The resources page lists some useful books and many links to help with Direct3D. There is also a list of generic DirectX questions and answers here: DirectX Q&A

I get missing dll d3dx9_24.dll or d3dx9_25.dll

From the February DirectX update the D3DX library has been changed from a .lib into a .dll. This means that if you compile your program using the February SDK (24) or the April SDK (25) and someone runs it who has not got those SDKs they will get this missing DLL error. The obvious solution is to ship the DLL with the .exe but Microsoft do not allow this. Apparently they are working on a fix for this problem. See also DirectX 9.0c.

I get an output message - Failed to create driver indexbuffer

This is nothing to worry about, if you look closely you will see it is marked as (info) and so is not an error. The reason it appears is that Direct3D tried to create an index buffer in video memory but the video card does not support them. I have yet to find one that does, so it is not a problem.

How can I use the Direct3D symbols?

It is useful to use the Direct3D symbol files for debugging into the code. You can download them or use the Microsoft symbol server. The steps required to get this working are:

  • Load your solution into .net
  • In the "Solution Explorer", right click on the Solution item (the bit that says "Solution 'blah' (1 Project)" and select Properties from the menu that appears.
  • Under Common Properties, select the "Debug Symbol Files" entry.
  • Add the following new path to the "Search these paths for symbol files:" list: SRV*c:\localsymbols*http://msdl.microsoft.com/download/symbols That will first search c:\localsymbols and then second search the MS symbol server in that order.
  • Apply that change and OK the dialog then start your project in the debugger with Break on AllocId enabled.
  • You'll notice that your project takes quite a while to start, this is because MSVC is downloading the symbols for each of the DLLs your application is using, including the Direct3D and D3DX ones.
  • When the AllocId breakpoint fires, when you look down the call stack, the random addresses for the D3D and Windows DLLs will have changed into function names.
  • Stop the debugger and go to the Debug Symbol Files list again and modify the path so that it reads: SRV*c:\localsymbols. The reason for doing this is to stop MSVC from connecting to the MS server for non-Microsoft DLLs; It always searches the local path and then the server if it can't find the symbols locally, but for non-MS DLLs it never will find the symbols locally (or on the server).

I got the above solution originally from a post by Simon O'Conner.

When my game is minimised or I ALT-TAB everything runs slowly

You are hogging all the system resources. It is a good idea to allow other applications time to do some processing when your game is minimised or out of focus. The best way to handle this is to maintain a paused variable. When paused you do not do any rendering and you use the Sleep function to give time over to other applications. In order to determine when your game is not active you need to trap some window API messages:

Pause your game when getting these messages:

  • WM_SIZE when the wParam equals SIZE_MINIMISED
  • WM_ENTERSIZEMOVE
  • WM_ENTERMENULOOP

You need to resume your game when you get these messages:

  • WM_SIZE when the wParam does not equal SIZE_MINIMISED
  • WM_EXITSIZEMOVE
  • WM_ACTIVEAPP when wParam is TRUE
  • WM_EXITMENULOOP

Note: there are few other messages that you may consider that I have not mentioned above, these are to do with power management.

Normally your message loop will be as described on this page: D3D Setup where you render whenever there is no message in the queue. When you are paused you should not render but instead do a Sleep. I recommend a Sleep(10) when paused. It is also an idea to do a Sleep(0) when not paused to give over some time to other applications even when your game is active.

How can I do picture in picture (PIP)?

Picture in picture is when you have two or more views rendered to the screen e.g. a main view and a box in the corner showing a view from elsewhere. There are two ways you can achieve this with Direct3D, the first is to render the second view to a texture and then render that texture onto a quad on the screen. The second way described here is to use Viewports.

Direct3D has a function SetViewport that allows you to specify just a part of the screen to render to. You call it before starting to render.

You can get the main viewport like this:

gD3dDevice->GetViewport( &m_mainViewport );

then make a copy of this viewport for your picture in picture and change the size and screen position:

// Create a PIP viewport
m_pipViewport=m_mainViewport;

// Make it a set size
m_pipViewport.Width=256;
m_pipViewport.Height=256;

// Position
m_pipViewport.X=64;
m_pipViewport.Y=64;


In your render loop set the main viewport using SetViewport and render as normal. Then set the viewport to the PIP viewport and change camera etc whatever you want to do - and render again. Note you only have to clear the z buffer before rendering this and not the target.

Further Reading

Note that there is a demo application with source code showing off a working Direct3D application here: Cube Demo

On this site:

Other: Programmers Heaven DirectX FAQ, Microsoft DirectX 9 Developer FAQ

See the resources page for Books, Links and Assets



© 2004-2014 Keith Ditchburn