Sign in to follow this  
  • entries
    132
  • comments
    99
  • views
    88603

Programmable Pipeline Goodness

Sign in to follow this  
Driv3MeFar

238 views



Okay, so it may not look like I've made any progress (in fact, based on screen shots alone, it would appear I've regressed since my last ISO update), but this picture in fact represents a big step forward.

You see, my tiles are now being drawn with the magic of pixel shaders! Yay! Now that I've got my shader system sort of working (more on that in a bit), I can start working on my component based system and render command queue, so this was a pretty important step towards where I want to go.

As for how my drawing now works, well, it's actually really simple. I hold all my effects in xml files, that look something like this:
testeffect.xml

"1.0" ?>
"test.fx">

g_mWorldViewProjection
g_Texture





This tells me the name of the .fx file, and all the variables needed for that shader. This information is all loaded in by my Effect class:
Effect.h

#ifndef EFFECT_H
#define EFFECT_H

#include
#include
#include
#include
#include "../../Main/Header Files/Serialize.h"

namespace ISO
{
namespace Graphics
{
class BaseShaderVariable
{
public:
virtual ~BaseShaderVariable() {}

virtual void Set(ID3DXEffect *d3dEffect) = 0;
};

template <class T>
class ShaderVariable : public BaseShaderVariable
{
public:
ShaderVariable(std::string& _name = "", T _val = T()) : val(_val), name(_name) {}
T val;
std::string name;
virtual void Set(ID3DXEffect *d3dEffect)
{
d3dEffect->SetValue(name.c_str(), &val, sizeof(T));
}
};

//ShaderVariable Set specializations
void ShaderVariable::Set(ID3DXEffect *d3dEffect)
{
d3dEffect->SetMatrix(name.c_str(), &val);
}

void ShaderVariable<float>::Set(ID3DXEffect *d3dEffect)
{
d3dEffect->SetFloat(name.c_str(), val);
}

void ShaderVariable<int>::Set(ID3DXEffect *d3dEffect)
{
d3dEffect->SetInt(name.c_str(), val);
}

void ShaderVariable::Set(ID3DXEffect *d3dEffect)
{
d3dEffect->SetTexture(name.c_str(), val);
}

class Effect : public ISerializable
{
public:
Effect(LPDIRECT3DDEVICE9 _device);
~Effect();

bool Set();

LPD3DXEFFECT GetEffect();

stdext::hash_map m_ShaderVars;
protected:
//write (serialize) to file
virtual bool operator<<(const std::string &filename);
//read (deserialize) from file
virtual bool operator>>(const std::string &filename);
private:
LPD3DXEFFECT m_D3dEffect;
LPDIRECT3DDEVICE9 m_Device;
};
}
}

#endif




Effect.cpp

#include "../Header Files/Effect.h"
//#include
//#include
#include
#include "../../tinyxml/tinyxml.h"

ISO::Graphics::Effect::Effect(LPDIRECT3DDEVICE9 _device)
: m_Device(_device)
{
}

ISO::Graphics::Effect::~Effect()
{
for (stdext::hash_map::iterator it = m_ShaderVars.begin(); it != m_ShaderVars.end(); ++it)
{
delete it->second;
}
}

bool ISO::Graphics::Effect::Set()
{
/*std::for_each(m_ShaderVars.begin(), m_ShaderVars.end(),
std::bind2nd(std::mem_fun(&ISO::Graphics::BaseShaderVariable::Set), m_D3dEffect) );*/

for (stdext::hash_map::iterator it = m_ShaderVars.begin(); it != m_ShaderVars.end(); ++it)
{
it->second->Set(m_D3dEffect);
}
return true;
}

LPD3DXEFFECT ISO::Graphics::Effect::GetEffect()
{
return m_D3dEffect;
}

/********************************************************************************************
* ISerializable Interface *
********************************************************************************************/

//write (serialize) to file
bool ISO::Graphics::Effect::operator<<(const std::string &/*filename*/)
{
//@todo: implement this, maybe?
assert(0);
return false;
}

//read (deserialize) from file
bool ISO::Graphics::Effect::operator>>(const std::string &filename)
{
TiXmlDocument doc(filename);
if (!doc.LoadFile())
{
return false;
}

TiXmlHandle hDoc(&doc);
TiXmlHandle hRoot(NULL);

//name
TiXmlElement *pElem = hDoc.FirstChildElement().Element();
if (!pElem)
{
return false;
}
hRoot = TiXmlHandle(pElem);

//std::string name = "..\\Effects\\";
std::string name = pElem->Attribute("name");
HRESULT hr = D3DXCreateEffectFromFile(m_Device, name.c_str(), NULL, NULL, D3DXFX_NOT_CLONEABLE | D3DXSHADER_DEBUG | D3DXSHADER_NO_PRESHADER, NULL, &m_D3dEffect, NULL);
if (FAILED(hr))
{
return false;
}

TiXmlElement *VarNode = hRoot.FirstChild( "Variables" ).FirstChild().Element();
while (VarNode)
{
std::string varType = VarNode->ValueStr();
assert(VarNode->FirstChild());
std::string varName = VarNode->FirstChild()->ValueStr();
//test hackery
assert(m_ShaderVars.find(varName) == m_ShaderVars.end());
if (varType == "int")
{
m_ShaderVars[varName] = new ShaderVariable<int>(varName);
}
else if (varType == "float")
{
m_ShaderVars[varName] = new ShaderVariable<float>(varName);
}
else if (varType == "float2")
{
m_ShaderVars[varName] = new ShaderVariable(varName);
}
else if (varType == "float3")
{
m_ShaderVars[varName] = new ShaderVariable(varName);
}
else if (varType == "float4")
{
m_ShaderVars[varName] = new ShaderVariable(varName);
}
else if (varType == "matrix")
{
m_ShaderVars[varName] = new ShaderVariable(varName);
}
else if (varType == "texture")
{
m_ShaderVars[varName] = new ShaderVariable(varName, NULL);
}
else
{
assert(0);
//?
}
VarNode = VarNode->NextSiblingElement();
}
return true;
}




You can probably already see what I was trying to do. The renderer doesn't really need to know anything about the shader to get it working. Each component can have it's own related effect, and can muck about with the variables as needed. Then, it passes this off to the renderer, which simply Sets the shader, and draws whatever geometry is needed. It's still pretty WIP (for example, I think instead of storing variables by name I'm going to store them by semantic to make things more generic), but it works. Here's what the new render loop looks like:
Renderer.cpp

if( SUCCEEDED( m_D3DDevice->BeginScene() ) )
{
//m_D3DDevice->SetTransform(D3DTS_PROJECTION, &m_MatProj);
D3DXMATRIX view;
D3DXVECTOR3 eye = m_Cam.GetEyeVec();
D3DXVECTOR3 at = m_Cam.GetAtVec();
D3DXVECTOR3 up = m_Cam.GetUpVec();
D3DXMatrixLookAtLH(&view, &eye, &at, &up );
//m_D3DDevice->SetTransform(D3DTS_VIEW, &view);

D3DXMATRIX viewProj;
D3DXMatrixMultiply(&viewProj, &view, &m_MatProj);
ShaderVariable* matVar = dynamic_cast*>(m_Effect->m_ShaderVars["g_mWorldViewProjection"]);
assert(matVar);
matVar->val = viewProj;

m_D3DDevice->SetStreamSource(0, m_MasterGeometry->GetVertexBufferPointer(), 0, sizeof(MapVertex));
m_D3DDevice->SetIndices(m_MasterGeometry->GetIndexBufferPointer());
m_D3DDevice->SetFVF(m_MasterGeometry->GetFVF());
for (std::vector::iterator it = m_DrawInfos.begin(); it != m_DrawInfos.end(); ++it)
{

ShaderVariable* texVar = dynamic_cast*>(m_Effect->m_ShaderVars["g_Texture"]);
assert(texVar);
texVar->val = m_TextureBuffer[it->TextureIndex].GetTexturePointer();

m_Effect->Set();
HRESULT hr = m_Effect->GetEffect()->SetTechnique("RenderScene");
if (FAILED(hr))
{
_asm
{
int 3
}
}
//m_D3DDevice->SetTexture(0, m_TextureBuffer[it->TextureIndex].GetTexturePointer());
UINT numPasses = 0;
m_Effect->GetEffect()->Begin(&numPasses, 0);
for (UINT i = 0; i < numPasses; ++i)
{
m_Effect->GetEffect()->BeginPass(i);
HRESULT hr = m_D3DDevice->DrawIndexedPrimitive( it->Type,
it->BaseVertexIndex,
it->MinIndex,
it->NumVertices,
it->StartIndex,
it->PrimitiveCount );
if (FAILED(hr))
{
assert(0);
}
m_Effect->GetEffect()->EndPass();
}
m_Effect->GetEffect()->End();
}

// End the scene
m_D3DDevice->EndScene();
}




An here are the stupid little test shaders I'm using:
test.fx

//--------------------------------------------------------------------------------------
// Global variables
//--------------------------------------------------------------------------------------
float4x4 g_mWorldViewProjection; // World * View * Projection matrix
texture g_Texture;

//--------------------------------------------------------------------------------------
// Texture samplers
//--------------------------------------------------------------------------------------
sampler TextureSampler =
sampler_state
{
Texture = ;
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
};

//--------------------------------------------------------------------------------------
// Vertex shader output structure
//--------------------------------------------------------------------------------------
struct VS_OUTPUT
{
float4 Position : POSITION; // vertex position
float2 TextureUV : TEXCOORD0; // vertex texture coords
};


//--------------------------------------------------------------------------------------
// This shader computes standard transform and lighting
//--------------------------------------------------------------------------------------
VS_OUTPUT RenderSceneVS( float4 vPos : POSITION,
float3 vNormal : NORMAL,
float2 vTexCoord0 : TEXCOORD0 )
{
VS_OUTPUT Output;
// Transform the position from object space to homogeneous projection space
Output.Position = mul(vPos, g_mWorldViewProjection);

Output.TextureUV = vTexCoord0;
return Output;
}


//--------------------------------------------------------------------------------------
// Pixel shader output structure
//--------------------------------------------------------------------------------------
struct PS_OUTPUT
{
float4 RGBColor : COLOR0; // Pixel color
};


//--------------------------------------------------------------------------------------
// This shader outputs the pixel's color by modulating the texture's
// color with diffuse material color
//--------------------------------------------------------------------------------------
PS_OUTPUT RenderScenePS( VS_OUTPUT In )
{
PS_OUTPUT Output;

Output.RGBColor = tex2D(TextureSampler, In.TextureUV);

return Output;
}


//--------------------------------------------------------------------------------------
// Renders scene to render target
//--------------------------------------------------------------------------------------
technique RenderScene
{
pass P0
{
VertexShader = compile vs_2_0 RenderSceneVS();
PixelShader = compile ps_2_0 RenderScenePS(); // trivial pixel shader (could use FF instead if desired)
}
}

Sign in to follow this  


0 Comments


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now