Une classe ShaderTechnique pour représenter facilement vos effets shaders

shader_tech

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.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *