todo : changer en m_pLayoutDesc
todo : enlever le prefixe des enums !
Intro :
Voici une classe qui vous aidera à déclarer et à définir vos fichiers shaders facilement.
Cette classe gestionnaire vous permettra de définir les variables shaders utilisées et même de paramétrer automatiquement certaines types de variables.
Explications :
Voici le fichier ShaderTechnique.h :
#ifndef SHADER_TECHNIQUE_H
#define SHADER_TECHNIQUE_H
enum ShaderVariableType
{
WORLD,
VIEW,
PROJECTION,
WVP,
WORLD_INVERSE,
WORLD_INVERSE_TRANSPOSE,
LIGHT_POS,
EYE_POS,
TEXTURE_0,
TEXTURE_1,
TEXTURE_2,
ANY
};
class ShaderTechnique
{
public:
ShaderTechnique(const std::string& sEffectFileName, const std::string& sEffectTechniqueName,
VertexLayoutType layoutType = VertexLayoutType::PTN_VERTEX);
virtual ~ShaderTechnique();
virtual bool Initialize();
ID3D10EffectTechnique* GetShaderTechnique();
ID3D10InputLayout* GetVertexLayout();
D3D10_INPUT_ELEMENT_DESC* GetLayout();
void AddTexture(const std::string& sTextureFileName);
void RegisterMatrixVariable(std::string sVariableName,
ShaderVariableType variableType = ShaderVariableType::ANY);
void RegisterVectorVariable(std::string sVariableName,
ShaderVariableType variableType = ShaderVariableType::ANY);
void RegisterScalarVariable(std::string sVariableName,
ShaderVariableType variableType = ShaderVariableType::ANY);
void RegisterVariable(std::string sVariableName,
ShaderVariableType variableType = ShaderVariableType::ANY);
void RegisterTextureVariable(std::string sTextureName,
ShaderVariableType variableType = ShaderVariableType::ANY);
void SetMatrix(const std::string& sMatrixName, D3DXMATRIX* mat);
void SetColor(const std::string& sVectorName, D3DXCOLOR& col);
void SetVector(const std::string& sVectorName, D3DXVECTOR3& vec);
void SetVector(const std::string& sVectorName, D3DXVECTOR2& vec);
void SetScalar(const std::string& sScalarName, float fValue);
void SetVariable(const std::string& sVariableName, void* pValue, unsigned int iSizeInBytes);
void SetTexture(const std::string& sTextureName, const std::string& sTextureAlias);
void SetTexture(const std::string& sTextureName, unsigned int iSlot);
void SetTextureRV(const std::string& sTextureName, ID3D10ShaderResourceView* pTextureRV);
std::string GetShaderVariableName(ShaderVariableType variableType);
void SetAutoMatrix(ShaderVariableType variableType);
void SetAutoVector(ShaderVariableType variableType);
virtual void SetupShaderVariables() {}
virtual void Update(float fTimeSinceLastFrame) {}
void SetCurrentWorldMatrix(const D3DXMATRIX& pWorldMatrix);
private:
ID3D10Effect* m_pEffect;
ID3D10EffectTechnique* m_pTechnique;
D3D10_INPUT_ELEMENT_DESC* m_layout;
ID3D10InputLayout* m_pVertexLayout;
std::map<std::string, ID3D10EffectMatrixVariable*> m_matrixVariables;
std::map<std::string, ID3D10EffectVectorVariable*> m_vectorVariables;
std::map<std::string, ID3D10EffectScalarVariable*> m_scalarVariables;
// On peut se servir de variables génériques afin de passer des structures
// au programme shader
std::map<std::string, ID3D10EffectVariable*> m_variables;
std::map<std::string, ID3D10EffectShaderResourceVariable*> m_ressourceVariables;
std::map<std::string, unsigned int> m_texturesAliasSlot;
// Un tableau pour la gestion automatique des variables shader
std::map<ShaderVariableType, std::string> m_variablesTypes;
std::string m_sEffectFileName;
std::string m_sEffectTechniqueName;
VertexLayoutType m_layoutType;
bool m_bInitDone;
D3DXMATRIX m_pCurrentWorld;
unsigned int m_iCurrentTextureSlot;
static unsigned int m_iCurrentShaderTechnique;
};
#endif
Voici le fichier ShaderTechnique.cpp :
#include "ShaderTechnique.h"
unsigned int ShaderTechnique::m_iCurrentShaderTechnique = 0;
ShaderTechnique::ShaderTechnique(const std::string& sEffectFileName, const std::string& sEffectTechniqueName, VertexLayoutType layoutType) :
m_pEffect(nullptr),
m_pTechnique(nullptr),
m_pVertexLayout(nullptr),
m_layout(nullptr),
m_bInitDone(false),
m_sEffectFileName(sEffectFileName),
m_sEffectTechniqueName(sEffectTechniqueName),
m_layoutType(layoutType),
m_iCurrentTextureSlot(0)
{
D3DXMatrixIdentity(&m_pCurrentWorld);
m_iCurrentShaderTechnique++;
}
ShaderTechnique::~ShaderTechnique()
{
SAFE_RELEASE(m_pEffect);
SAFE_RELEASE(m_pVertexLayout);
}
bool ShaderTechnique::Initialize()
{
if (m_bInitDone)
{
return false;
}
DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
// Permet d'afficher les éventuelles erreurs de la compilation d'un shader
dwShaderFlags |= D3D10_SHADER_DEBUG;
#endif
HRESULT hr;
ID3D10Blob* pBlob = nullptr;
// Pour la création du shader, on le compile
hr = D3DX10CreateEffectFromFileA(m_sEffectFileName.c_str(), nullptr, nullptr, "fx_4_0", dwShaderFlags, 0, D3D10_RENDERER->GetDevice(), nullptr,
nullptr, &m_pEffect, &pBlob, nullptr);
if (FAILED(hr))
{
if (pBlob)
{
// Affiche l'erreur de compilation du shader
MessageBoxA(NULL, (PCSTR)pBlob->GetBufferPointer(), "Erreur sur le fichier shader", MB_ICONHAND | MB_OK);
}
else
{
ShowMessageBoxDXError(hr);
}
return false;
}
unsigned int iNumElements = 0;
if (m_layoutType == PTN_VERTEX) // Position, texture, normal
{
m_layout = new D3D10_INPUT_ELEMENT_DESC[3];
memcpy(m_layout, layoutPTN, sizeof(D3D10_INPUT_ELEMENT_DESC) * 3);
iNumElements = sizeof( layoutPTN ) / sizeof( layoutPTN[0] );
}
else if (m_layoutType == PT_VERTEX)
{
m_layout = new D3D10_INPUT_ELEMENT_DESC[2];
memcpy(m_layout, layoutPT, sizeof(D3D10_INPUT_ELEMENT_DESC) * 2);
iNumElements = sizeof( layoutPT ) / sizeof( layoutPT[0] );
}
else if (m_layoutType == PN_VERTEX) // Position, Normal
{
m_layout = new D3D10_INPUT_ELEMENT_DESC[2];
memcpy(m_layout, layoutPN, sizeof(D3D10_INPUT_ELEMENT_DESC) * 2);
iNumElements = sizeof( layoutPN ) / sizeof( layoutPN[0] );
}
else if (m_layoutType == PC_VERTEX) // Position, couleur
{
m_layout = new D3D10_INPUT_ELEMENT_DESC[2];
memcpy(m_layout, layoutPC, sizeof(D3D10_INPUT_ELEMENT_DESC) * 2);
iNumElements = sizeof( layoutPC ) / sizeof( layoutPC[0] );
}
else if (m_layoutType == PTC_VERTEX) // Position, couleur
{
m_layout = new D3D10_INPUT_ELEMENT_DESC[3];
memcpy(m_layout, layoutPTC, sizeof(D3D10_INPUT_ELEMENT_DESC) * 3);
iNumElements = sizeof( layoutPTC ) / sizeof( layoutPTC[0] );
}
else if (m_layoutType == WATER_VERTEX)
{
m_layout = new D3D10_INPUT_ELEMENT_DESC[3];
memcpy(m_layout, layoutWater, sizeof(D3D10_INPUT_ELEMENT_DESC) * 3);
iNumElements = sizeof( layoutWater ) / sizeof( layoutWater[0] );
}
else
{
FastMessageBox("Erreur de type de layout !");
return false;
}
// On acquiert la technique du shader HLSL
m_pTechnique = m_pEffect->GetTechniqueByName(m_sEffectTechniqueName.c_str());
if (m_pTechnique == nullptr)
{
FastMessageBox("Erreur du nom de la technique passé en paramètre");
return false;
}
D3D10_PASS_DESC PassDesc;
m_pTechnique->GetPassByIndex(0)->GetDesc(&PassDesc);
if (!m_pTechnique->IsValid())
{
std::string sErrorMsg = "Erreur sur la technique du fichier shader : " + m_sEffectFileName;
FastMessageBox(sErrorMsg.c_str());
return false;
}
hr = D3D10_RENDERER->GetDevice()->CreateInputLayout(m_layout, iNumElements, PassDesc.pIAInputSignature,
PassDesc.IAInputSignatureSize, &m_pVertexLayout);
if (FAILED(hr))
{
ShowMessageBoxDXError(hr);
return false;
}
m_bInitDone = true;
return true;
}
ID3D10EffectTechnique* ShaderTechnique::GetShaderTechnique()
{
return m_pTechnique;
}
ID3D10InputLayout* ShaderTechnique::GetVertexLayout()
{
return m_pVertexLayout;
}
D3D10_INPUT_ELEMENT_DESC* ShaderTechnique::GetLayout()
{
return m_layout;
}
// Ajoute une texture au gestionnaire de texture et fait correspondre
// un slot à cette classe
void ShaderTechnique::AddTexture(const std::string& sTextureFileName)
{
std::string sTextureAliasName = std::to_string(m_iCurrentShaderTechnique) + std::to_string(m_iCurrentTextureSlot++);
m_texturesAliasSlot[sTextureAliasName] = m_iCurrentTextureSlot;
TEXTURE_MANAGER->AddTexture(sTextureFileName, sTextureAliasName);
}
void ShaderTechnique::RegisterTextureVariable(std::string sTextureName, ShaderVariableType variableType)
{
ID3D10EffectShaderResourceVariable* pDiffuseVariable = nullptr;
pDiffuseVariable = m_pEffect->GetVariableByName(sTextureName.c_str())->AsShaderResource();
m_ressourceVariables[sTextureName] = pDiffuseVariable;
}
void ShaderTechnique::RegisterMatrixVariable(std::string sVariableName, ShaderVariableType variableType)
{
ID3D10EffectMatrixVariable* pMatrixVariable = nullptr;
pMatrixVariable = m_pEffect->GetVariableByName(sVariableName.c_str())->AsMatrix();
m_matrixVariables[sVariableName] = pMatrixVariable;
m_variablesTypes[variableType] = sVariableName;
}
void ShaderTechnique::RegisterVectorVariable(std::string sVariableName, ShaderVariableType variableType)
{
ID3D10EffectVectorVariable* pVectorVariable = nullptr;
pVectorVariable = m_pEffect->GetVariableByName(sVariableName.c_str())->AsVector();
m_vectorVariables[sVariableName] = pVectorVariable;
m_variablesTypes[variableType] = sVariableName;
}
void ShaderTechnique::RegisterScalarVariable(std::string sVariableName, ShaderVariableType variableType)
{
ID3D10EffectScalarVariable* pScalarVariable = nullptr;
pScalarVariable = m_pEffect->GetVariableByName(sVariableName.c_str())->AsScalar();
m_scalarVariables[sVariableName] = pScalarVariable;
m_variablesTypes[variableType] = sVariableName;
}
void ShaderTechnique::RegisterVariable(std::string sVariableName, ShaderVariableType variableType)
{
ID3D10EffectVariable* pVariable = nullptr;
pVariable = m_pEffect->GetVariableByName(sVariableName.c_str());
m_variables[sVariableName] = pVariable;
m_variablesTypes[variableType] = sVariableName;
}
void ShaderTechnique::SetMatrix(const std::string& sMatrixName, D3DXMATRIX* mat)
{
if (m_matrixVariables.count(sMatrixName) > 0)
{
m_matrixVariables[sMatrixName]->SetMatrix((float*)mat);
}
}
void ShaderTechnique::SetColor(const std::string& sVectorName, D3DXCOLOR& col)
{
if (m_vectorVariables.count(sVectorName) > 0)
{
m_vectorVariables[sVectorName]->SetFloatVector(col);
}
}
void ShaderTechnique::SetVector(const std::string& sVectorName, D3DXVECTOR3& vec)
{
if (m_vectorVariables.count(sVectorName) > 0)
{
m_vectorVariables[sVectorName]->SetFloatVector(vec);
}
}
void ShaderTechnique::SetVector(const std::string& sVectorName, D3DXVECTOR2& vec)
{
if (m_vectorVariables.count(sVectorName) > 0)
{
m_vectorVariables[sVectorName]->SetFloatVector(vec);
}
}
void ShaderTechnique::SetScalar(const std::string& sScalarName, float fValue)
{
if (m_scalarVariables.count(sScalarName) > 0)
{
m_scalarVariables[sScalarName]->SetFloat(fValue);
}
}
void ShaderTechnique::SetVariable(const std::string& sVariableName, void* pValue, unsigned int iSizeInBytes)
{
if (m_variables.count(sVariableName) > 0)
{
m_variables[sVariableName]->SetRawValue(pValue, 0, iSizeInBytes);
}
}
void ShaderTechnique::SetTexture(const std::string& sTextureName, unsigned int iSlot)
{
std::string sTextureAliasName = std::to_string(m_iCurrentShaderTechnique) + std::to_string(iSlot);
if (m_texturesAliasSlot.count(sTextureAliasName) > 0)
{
ID3D10ShaderResourceView* pTextureRV = TEXTURE_MANAGER->GetTexture(sTextureAliasName);
if (pTextureRV != nullptr)
{
m_ressourceVariables[sTextureName]->SetResource(pTextureRV);
}
}
}
void ShaderTechnique::SetTexture(const std::string& sTextureName, const std::string& sTextureAlias)
{
if (TEXTURE_MANAGER->HasTexture(sTextureAlias))
{
ID3D10ShaderResourceView* pTextureRV = TEXTURE_MANAGER->GetTexture(sTextureAlias);
if (pTextureRV != nullptr)
{
m_ressourceVariables[sTextureName]->SetResource(pTextureRV);
}
}
}
void ShaderTechnique::SetTextureRV(const std::string& sTextureName, ID3D10ShaderResourceView* pTextureRV)
{
if (m_ressourceVariables.count(sTextureName) > 0)
{
m_ressourceVariables[sTextureName]->SetResource(pTextureRV);
}
}
std::string ShaderTechnique::GetShaderVariableName(ShaderVariableType variableType)
{
if (m_variablesTypes.count(variableType))
{
return m_variablesTypes[variableType];
}
else
{
return UNKNOWN;
}
}
void ShaderTechnique::SetCurrentWorldMatrix(const D3DXMATRIX& pWorldMatrix)
{
m_pCurrentWorld = pWorldMatrix;
}
void ShaderTechnique::SetAutoMatrix(ShaderVariableType variableType)
{
std::string sVariableName = GetShaderVariableName(variableType);
switch (variableType)
{
case ShaderVariableType::WORLD:
{
SetMatrix(sVariableName, &m_pCurrentWorld);
break;
}
case ShaderVariableType::VIEW:
{
SetMatrix(sVariableName, SCENE_MANAGER->GetActiveCamera()->GetViewMatrix());
break;
}
case ShaderVariableType::PROJECTION:
{
SetMatrix(sVariableName, SCENE_MANAGER->GetActiveCamera()->GetProjectionMatrix());
break;
}
case ShaderVariableType::WORLD_INVERSE:
{
D3DXMATRIX worldInverse;
D3DXMatrixIdentity(&m_pCurrentWorld);
D3DXMatrixInverse(&worldInverse, nullptr, &m_pCurrentWorld);
SetMatrix(sVariableName, &worldInverse);
break;
}
case ShaderVariableType::WORLD_INVERSE_TRANSPOSE:
{
D3DXMATRIX worldInverseTranspose;
D3DXMatrixTranspose(&worldInverseTranspose, &worldInverseTranspose);
D3DXMatrixInverse(&worldInverseTranspose, nullptr, &m_pCurrentWorld);
SetMatrix(sVariableName, &worldInverseTranspose);
break;
}
}
}
void ShaderTechnique::SetAutoVector(ShaderVariableType variableType)
{
std::string sVariableName = GetShaderVariableName(variableType);
switch (variableType)
{
case ShaderVariableType::EYE_POS:
{
SetVector(sVariableName, SCENE_MANAGER->GetActiveCamera()->GetPosition());
break;
}
case ShaderVariableType::LIGHT_POS:
{
static float r = 0.0f;
r += 0.00008f;
D3DXVECTOR3 lightPos = D3D10_RENDERER->MatrixRotationAxis(D3DXVECTOR3(0.0f, 1.0f, 0.0f), D3DXVECTOR3(0.0f, 0.0f, -5.0f), r);
SetVector(sVariableName, lightPos);
break;
}
}
}
Résumé :
Cette classe vous permettra de paramétrer vos fichiers shaders facilement.

