News
DirectX
Links
Contact Me

In Association with Amazon.com
In Association with Amazon.ca

$5 via PayPal


Colour Key Tutorial



Colour Key Transparency

The first thing I did was remove all references to the triangle from Lesson 2a. The square will be enough for our needs.

Then I modified the vertex declarations so we have texture coordinates in our vertex structure.

struct my_vertex{
    float x, y, z, rhw; // The transformed position for the vertex.
    float tu,tv;        // The vertex texture coordinates.
};

#define D3D8T_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_TEX1)


my_vertex g_square_vertices[] ={
    { 200.0f,  346.0f, 0.5f, 1.0f, 0.0f, 1.0f },
    { 200.0f,  90.0f,  0.5f, 1.0f, 0.0f, 0.0f },
    { 456.0f,  346.0f, 0.5f, 1.0f, 1.0f, 1.0f },
    { 456.0f,  90.0f,  0.5f, 1.0f, 1.0f, 0.0f }
};

I want to be able to toggle blending on and off, so I declare a global boolean to track the current state. I also declare our texture and initialize it to NULL.

//Are we blending or not?
BOOL g_alpha_on=TRUE;

IDirect3DTexture8 *g_texture=NULL;

In kill_scene(), we make sure that we free our texture

   if(g_texture){
      g_texture->Release();
      g_texture=NULL;
   }

We make 2 small changes to render().

The variable background colour will slowly change each frame so that we're clearing the background to a different colour each time. This is done to make it easier to see the transparent areas of our texture.

We also add the SetTexture call so our texture will be used.

Since it's small I've included the entire function here

// Function: render
// Whazzit:Clears the screen to a pseudo-random colour, draws a square
//         and then presents the results.
void render(void){
static background_colour=0;

   //Clear the buffer to our new colour.
   g_d3d_device->Clear( 0, NULL, D3DCLEAR_TARGET, background_colour++,1.0f, 0 );

   //Notify the device that we're ready to render
   if(SUCCEEDED(g_d3d_device->BeginScene())){

      g_d3d_device->SetVertexShader(D3D8T_CUSTOMVERTEX);

      g_d3d_device->SetStreamSource(0,g_square,sizeof(my_vertex));

      g_d3d_device->SetTexture(0,g_texture);

      g_d3d_device->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2);

      g_d3d_device->EndScene();
   }

   //Show the results
   g_d3d_device->Present( NULL, NULL, NULL, NULL );

}

To make the effects of the AlphaBlending more apparent, we add the ability to turn it off and on. Either the 'A' or 'B' key will toggle AlphaBlending. This change is made to default_window_proc().

      case WM_KEYDOWN:  // A key has been pressed
         switch(virt_key){
            case 'A':
            case 'B':
               g_alpha_on=!g_alpha_on;
               g_d3d_device->SetRenderState(D3DRS_ALPHABLENDENABLE,g_alpha_on);
               break;
            default:
               g_app_done=true;
               break;
         }
         return 0;

Most of our changes are in init_scene, that's why I saved it for last. The first change is the loading of the texture. Here's that piece of code:

   //D3DXCreateTextureFromFileEx takes a lot of paramters. 
   //We pass it our device and the file name of our texture.
   //We set Width & Height to D3DX_DEFAULT so it uses the values in the file.
   //We want an alpha channel so we tell it to use D3DFMT_A8R8G8B8 because it's a
   //    very common texture format, it should work on just about everything.
   //We set our Colour Key to opaque black (0xFF000000, watch the alpha component!)
   hr=D3DXCreateTextureFromFileEx(g_d3d_device, //Our D3D Device
                                  "Tex.bmp",    //Filename of our texture
                                  D3DX_DEFAULT, //Width:D3DX_DEFAULT = Take from file 
                                  D3DX_DEFAULT, //Height:D3DX_DEFAULT = Take from file
                                  1,            //MipLevels
                                  0,            //Usage, Is this to be used as a Render Target? 0 == No
                                  D3DFMT_A8R8G8B8, //32-bit with Alpha, everything should support this
                                  D3DPOOL_MANAGED,//Pool, let D3D Manage our memory
                                  D3DX_DEFAULT, //Filter:Default filtering
                                  D3DX_DEFAULT, //MipFilter, used for filtering mipmaps
                                  0xFF000000,   //ColourKey
                                  NULL,         //SourceInfo, returns extra info if we want it (we don't)
                                  NULL,         //Palette:We're not using one
                                  &g_texture);  // Our texture goes here.
   if(FAILED(hr)){
      FatalError(hr,"Error Loading Texture");
   }

Now we have to make sure all of our Render States and TextureStageStates are correct. Some of you may notice that I set these even when I want their default value. It's good practice to explicitly set any states that you rely on. Defaults can change and many problems can be caused by code you add later. By setting these explicity you stand a much better chance of having your app perform as expected and be lower maintenance.

First we set our Colour texture states. Nothing new here if you've looked at any of the tutorials that include textures.

   g_d3d_device->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_SELECTARG1);

   //D3DTSS_COLORARG1 is set to D3DTA_TEXTURE which means that colour1 is
   //entirely taken from the texture and nothing else.
   g_d3d_device->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE);

Our Alpha states are the same as our colour states. Again, if you've read the previous tutorials there's nothing you haven't seen here.

   //Similarly to the COLOR TextureStageStates, the D3DTOP_SELECTARG1
   //says to take the result from arguement 1. We set D3DTSS_ALPHAARG1
   //to D3DTA_TEXTURE, which makes the alpha value for each pixel comes
   //from the alpha component of the texture pixel (texel).
   g_d3d_device->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_SELECTARG1);
   g_d3d_device->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE);

Finally, we set our Render States and we're done!

   //The next 2 RenderStates determine how the blending is done.
   //The source is our object, destination is the drawing surface.
   //SRCBLEND specifies that the final colour should be 50% (because
   //that's what we set our souce alpha to) from our source and 50%
   //(INVSRCALPHA, 100%-SRCALPHA(50% in this case))
   g_d3d_device->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
   g_d3d_device->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);

   //This enables Alpha Blending
   g_d3d_device->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);