Programmable Pipeline Goodness

Published December 22, 2007
Advertisement


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 filebool ISO::Graphics::Effect::operator<<(const std::string &/*filename*/){	//@todo: implement this, maybe?	assert(0);	return false;}//read (deserialize) from filebool 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 matrixtexture  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)    }}
0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement

Latest Entries

/facepalm

1719 views

Baby Steps

1280 views

...

720 views

Stuff

1320 views

Productivity++

1207 views

Rock Band FTW

1239 views

Seattle Opera

1283 views

Christ

1208 views

I maek gaem!

1184 views
Advertisement