I Love My DX9!!!
Daily 08/29/03a
After the disappointment of not getting my effect files to load properly this morning, I was determined to get it to work by the next work day. I want to get to the TRON style blur!
After much frustration, I finally decided to start from scratch again and do what I always do. Examine, deconstruct, and copy an example. I decided to look at the shaders in my "DirectX 9 Programmable Graphics Pipeline" book. A crappy book, but it's got great resources on disk.
I had to hack into Political Machine because that was the only project I was working on that currently supports DX9. Just wait though pretty soon, all our projects that use 3d will. Isn't power wonderful?
Anyways, here's where I hope this development journal really pays off. Most books and articles discuss theories. I'm here to put practice these theories and put them to the test. Here are my results.
1) I started to add a generic CEffectObject. Any object that has an effect associated with it. Basically, for this type of thing, we need a mesh object with some extra data to hold the effects. Here's my class.
class CEffectObject
{
// typedefs
typedef std::vector<D3DMATERIAL9> MaterialArray;
typedef std::vector<LPDIRECT3DTEXTURE9> TexturePtrArray;
public:
CEffectObject();
virtual ~CEffectObject();
// Attributes
public:
void SetPath(const std::string& strPath);
void SetMesh(const std::string& strMesh);
void SetEffect(const std::string& strEffect);
void SetTransforms(LPD3DXMATRIX pMatWorld,
;
LPD3DXMATRIX pMatView,
;
LPD3DXMATRIX pMatProj);
void SetPosition(D3DXVECTOR3 vPos);
// Operations
public:
HRESULT Init(LPDIRECT3DDEVICE9 pDevice);
HRESULT Render(LPDIRECT3DDEVICE9 pDevice);
HRESULT Restore(LPDIRECT3DDEVICE9 pDevice);
protected:
void DestroyDeviceObjects();
// Implementation
protected:
// Texture vertex shader
std::string m_strEffect;
LPD3DXEFFECT m_pEffect;
// Mesh
std::string m_strMesh;
LPD3DXMESH m_pMesh;
MaterialArray m_aMaterials;
TexturePtrArray m_aTexturePtrs;
// Transforms
D3DXMATRIXA16 m_matWorld;
D3DXMATRIXA16 m_matView;
D3DXMATRIXA16 m_matProj;
// Misc
std::string m_strPath;
D3DXVECTOR3 m_vPos;
};
As you can see, it's really just a mesh object with the extra effect
data. I also added the matrices in the class because effects are often dependant
on them.
2) Define the load function. I'm going to trim from here on down because it's late and I'm getting tired of typing. (So much for full examples)
HRESULT CEffectObject::Init(LPDIRECT3DDEVICE9
pDevice)
{
HRESULT hr;
// Snip....
// Just do the basic object loading...
// Here's the meat. Load the effect and validate the technique
// Here's where I lost interest in making it generic. I only handle
// the first technique.
strFullPath = m_strPath + "/" + m_strEffect;
hr = D3DXCreateEffectFromFile(pDevice,
;
strFullPath.data(),
;
NULL, // D3DXMACROs
;
NULL, // #includes
;
D3DXSHADER_DEBUG,
;
NULL, // memory pool
;
&m_pEffect,
;
NULL); // compilation errors
D3DXHANDLE hTech = m_pEffect->GetTechnique(0);
hr = m_pEffect->ValidateTechnique(hTech);
return hr;
}
A lot of powerful stuff happens in those three calls. Believe me. Another reason I love my DX9. According to docs, the ValidateTechnique is needed before an effect an be rendered. I'm not sure of that. I haven't tested it without. Sounds like a good thing to do anyways.
3) Define the Render function. Just like my last daily really. I'll add it here for completeness.
HRESULT CEffectObject::Render(LPDIRECT3DDEVICE9
pDevice)
{
HRESULT hr = S_OK;
if(m_pEffect)
{
// Snip...
// A bunch of matrix transforms to get the object
// In the right place, orientation, and scale.
// If you really want the stuff, drop me a line.
D3DXMATRIX matWorldView;
D3DXMatrixMultiply(&matWorldView, &matWorld, &m_matView);
m_pEffect->SetMatrix("WorldView", &matWorldView);
m_pEffect->SetMatrix("Projection", &m_matProj);
m_pEffect->SetTechnique(m_pEffect->GetTechnique(0));
UINT numPasses;
int i;
hr = m_pEffect->Begin(&numPasses, 0);
hr = m_pEffect->Pass(0);
for( i=0; i < m_aMaterials.size(); i++ )
{
// Set the material and texture
for this subset
pDevice->SetMaterial(&m_aMaterials[i]);
pDevice->SetTexture(0,
m_aTexturePtrs[i]);
// Draw the mesh subset
m_pMesh->DrawSubset(i);
}
hr = m_pEffect->End();
}
return hr;
}
Simple dimple eh? Took me long enough to get to this point.
4) Finally, create the effect. This effect has some defintions at the top to satisfy EffectEdit. There's a hidden beauty here. Those defs don't effect how the effect works outside of effect edit. That means that they can stay there without worrying about screwing up the version for the game.
// EffectEdit defs
string XFile = "ColonyShip.x";
texture CSTexture < string name = "ColonyShipDiffuseMap.dds"; >;
float4x3 WorldView : WORLDVIEW;
float4x4 Projection : PROJECTION;
sampler CSSampler =
sampler_state
{
Texture = <CSTexture>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
};
struct VS_OUTPUT
{
float4 Position : POSITION;
float4 Diffuse : COLOR;
float2 TexCoord : TEXCOORD0;
};
VS_OUTPUT VS_Texture(float4 Position : POSITION,
;
float3 Normal : NORMAL,
;
float2 TexCoord : TEXCOORD0)
{
VS_OUTPUT Out = (VS_OUTPUT)0;
Out.Position = mul(float4(P, 1), Projection);
Out.Diffuse = float4(1, 0, 0, 1);
Out.TexCoord = TexCoord;
return Out;
}
technique Tech0
{
pass Texture
{
Lighting = False;
Sampler[0] = <CSSampler>;
// Stage0
ColorOp[0] = BlendTextureAlpha;
ColorArg1[0] = Texture;
ColorArg2[0] = Diffuse;
AlphaOp[0] = Disable;
// Stage1
ColorOp[1] = Disable;
AlphaOp[1] = Disable;
VertexShader = compile vs_1_1 VS_Texture();
}
}
Simple shader, but think of the possibilities. In this one file, we can
define the shader for the low, medium, and high detail graphics. We can reuse
passes and techniques. The possibilities are almost endless. I think ![]()
Here's the payoff. I can run the application that uses this effect and load it up in the EffectEdit program at the SAME time! This also means that the effect can now be edited on the fly in the EffectEdit and just run in the program without a compile or link. I guess for ultimate completeness, there should be an option to reload the fx from the file so that the changes can be seen immediately in the program without shutting it down. Wouldn't that be kewl!


Here's the US being attacked by a bunch of red colony ships while simultaneously modifying the effect in EffectEdit. I love this stuff!
It may be simple enough for the artists to even hack around the
shader file. After a little education of course. No offense to the artists ![]()