Platform SDK: DirectX

Step 2.3: Perform the 3-D Transformation

[Visual Basic]

The information in this section pertains only to applications written in C and C++. See Direct3D Immediate Mode Visual Basic Tutorials.

[C++]

Your scene is nearly completed; however, you still need to manually rotate, transform, and scale the cube's vertices. First, fill the array of D3DTLVERTEX structures, g_pvCube, with untransformed data for the cube. Note that the first three parameters represent the untransformed position of each vertex in screen coordinates:

    g_pvCube[0] = D3DTLVERTEX( D3DVECTOR(-1,-1,-1 ), 0, 0xffffffff, 0, 0, 0 );
    g_pvCube[1] = D3DTLVERTEX( D3DVECTOR( 1,-1,-1 ), 0, 0xff00ffff, 0, 0, 0 );
    g_pvCube[2] = D3DTLVERTEX( D3DVECTOR(-1, 1,-1 ), 0, 0xffff00ff, 0, 0, 0 );
    g_pvCube[3] = D3DTLVERTEX( D3DVECTOR( 1, 1,-1 ), 0, 0xff0000ff, 0, 0, 0 );
    g_pvCube[4] = D3DTLVERTEX( D3DVECTOR(-1,-1, 1 ), 0, 0xffffff00, 0, 0, 0 );
    g_pvCube[5] = D3DTLVERTEX( D3DVECTOR( 1,-1, 1 ), 0, 0xff00ff00, 0, 0, 0 );
    g_pvCube[6] = D3DTLVERTEX( D3DVECTOR(-1, 1, 1 ), 0, 0xffff0000, 0, 0, 0 );
    g_pvCube[7] = D3DTLVERTEX( D3DVECTOR( 1, 1, 1 ), 0, 0xff000000, 0, 0, 0 );

Now, call the programmer-defined function TransformVertices to manually transform the cube's eight vertices:

    TransformVertices( pd3dDevice, g_pvCube, 8 );

However, before implementing your 3-D transformation, you will need to retrieve the height and width of the viewport. This information is used to scale the transformed vertices to fit the render window:

HRESULT TransformVertices( LPDIRECT3DDEVICE7 pd3dDevice,
                           D3DTLVERTEX* pvVertices, DWORD dwNumVertices )
{
    // Get the width and height of the viewport. This is needed to scale the
    // transformed vertices to fit the render window.
    D3DVIEWPORT7 vp;
    pd3dDevice->GetViewport( &vp );
    DWORD dwClipWidth  = vp.dwWidth/2;
    DWORD dwClipHeight = vp.dwHeight/2;

Direct3D uses matrices to perform transformations. In order to execute a 3-D transformation, you need to retrieve the values of the current matrix set. You do this by calling IDirect3DDevice7::GetTransform on the rendering device:

    D3DMATRIX matWorld, matView, matProj;
    pd3dDevice->GetTransform( D3DTRANSFORMSTATE_WORLD,      &matWorld );
    pd3dDevice->GetTransform( D3DTRANSFORMSTATE_VIEW,       &matView );
    pd3dDevice->GetTransform( D3DTRANSFORMSTATE_PROJECTION, &matProj );
    

You use matrix multiplication to concatenate the matrices:

    D3DMATRIX matTemp = matWorld * matView;
    D3DMATRIX matSet = matTemp * matProj;

In the preceding code, a composite matrix, matSet, is calculated to represent the product of the desired transformations. During concatenation, ensure that the matrices are multiplied in the order in which you want them to operate.

For more information on matrix concatenation, see Matrix Concatenation.

Now, you transform each vertex through the current matrix set:

    for( DWORD i=0; i<dwNumVertices; i++ )
    {
        // Get the untransformed vertex position
        FLOAT x = pvVertices[i].sx;
        FLOAT y = pvVertices[i].sy;
        FLOAT z = pvVertices[i].sz;
 
        // Transform it through the current matrix set
        FLOAT xp = matSet._11*x + matSet._21*y + matSet._31*z + matSet._41;
        FLOAT yp = matSet._12*x + matSet._22*y + matSet._32*z + matSet._42;
        FLOAT zp = matSet._13*x + matSet._23*y + matSet._33*z + matSet._43;
        FLOAT wp = matSet._14*x + matSet._24*y + matSet._34*z + matSet._44;

Finally, scale the vertices to screen coordinates. In the following code, the first step flattens the coordinates from 3-D space to 2-D device coordinates by dividing each coordinate by the wp value. Then, the x- and y-components are transformed from device coordinates to screen coordinates.

        pvVertices[i].sx  = ( 1.0f + (xp/wp) ) * dwClipWidth;
        pvVertices[i].sy  = ( 1.0f - (yp/wp) ) * dwClipHeight;
        pvVertices[i].sz  = zp / wp;
        pvVertices[i].rhw = wp;
    }

For more information on 3-D transformations, see 3-D Transformations.

Note  Device coordinates range from -1 to +1 in the viewport. Also, the sz-coordinate will be used in the z-buffer.

Now that you have transformed the cube's eight vertices, you can render a frame of the completed the scene. This is shown in Step 2.4: Render the Scene.