Archives pour la catégorie Shaders

La technique du Parallax Mapping

GPU

Intro :

Avant tout, que veux dire « parallax » ou parallaxe ? La parallaxe désigne le phénomène physique et dynamique à propos d’un objet qui visiblement change de forme à cause du point de vue de l’œil de l’observateur.

La technique du Parallax Mapping est une technique de déplacement de surface.
La surface traitée donne un résultat de profondeur et est similaire avec la technique utilisée dans le « bump mapping ».

Cela donne un résultat très joli. En effet, elle permet d’émuler le relief d’un objet à partir d’une texture.

Comme toutes les techniques de déplacement de surface, la technique du PM utilise une image texture spéciale pour effectuer le rendu.

Explications :

Il s’agit d’appliquer un décalage des coordonnées (offset) de la texture diffuse directement dans le pixel shader.

Ce décalage dépend de la direction et de la position de la caméra qui observe la scène.
La surface ainsi dessinée à l’écran doit évoluer correctement en respectant la position de la caméra.

La technique du PM utilise une image / texture de couleur noire et blanche.

La simulation s’opère dans l’espace des textures. On opère un décalage des coordonnées des textures avec le vecteur de vue de la caméra plus la valeur courante de la « height map » de texture utilisée.

Utilisation du type TextureArray

TextureArray

Intro :

Souvent à l’étape pixel shader, on a besoin d’accéder à plusieurs textures en même temps.

Prérequis :

– Savoir lire du C++

– Savoir initialiser DirectX

Explications :

Voici une fonction qui créé un objet Texture2D :

ID3D10Texture2D* CreateTexture(const std::string& sImageFileName)
{
    ID3D10Texture2D* pLoadedTexture = nullptr;

    D3DX10_IMAGE_LOAD_INFO loadinfo;
    ZeroMemory(&loadinfo, sizeof(D3DX10_IMAGE_LOAD_INFO));

    loadinfo.Width = D3DX10_FROM_FILE;
    loadinfo.Height = D3DX10_FROM_FILE;
    loadinfo.Depth = D3DX10_FROM_FILE;

    loadinfo.FirstMipLevel = 0;
    loadinfo.MipLevels = D3DX10_FROM_FILE;
    loadinfo.Usage = D3D10_USAGE_STAGING;

    loadinfo.BindFlags = 0;
    loadinfo.CpuAccessFlags = D3D10_CPU_ACCESS_READ | D3D10_CPU_ACCESS_WRITE;
    loadinfo.MiscFlags = 0;

    loadinfo.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    loadinfo.Filter = D3DX10_FILTER_NONE;
    loadinfo.MipFilter = D3DX10_FILTER_NONE;
    loadinfo.pSrcInfo = 0;

    D3DX10CreateTextureFromFileA(D3D10_RENDERER->GetDevice(),
        sImageFileName.c_str(), &loadinfo, 0, (ID3D10Resource**)&pLoadedTexture, 0);

    return pLoadedTexture;
}


Voici une fonction qui créé un objet Texture2D assemblé et combiné de plusieurs Texture2D :


ID3D10Texture2D* CreateTextureArray(std::vector<ID3D10Texture2D*>& textures)
{
    if (textures.size() == 0)
    {
        return nullptr;
    }

    ID3D10Texture2D* pTexturesArray = nullptr;

    D3D10_TEXTURE2D_DESC textElementDesc;
    ZeroMemory(&textElementDesc, sizeof(D3D10_TEXTURE2D_DESC));

    textures[0]->GetDesc(&textElementDesc);

    D3D10_TEXTURE2D_DESC textArrayDesc;

    textArrayDesc.Width = textElementDesc.Width;
    textArrayDesc.Height = textElementDesc.Height;
    textArrayDesc.MipLevels = textElementDesc.MipLevels;
    textArrayDesc.ArraySize = textures.size();
    textArrayDesc.Format = textElementDesc.Format;
    textArrayDesc.SampleDesc.Count = 1;
    textArrayDesc.SampleDesc.Quality = 0;
    textArrayDesc.Usage = D3D10_USAGE_DEFAULT;
    textArrayDesc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
    textArrayDesc.CPUAccessFlags = 0;
    textArrayDesc.MiscFlags = 0;

    D3D10_RENDERER->GetDevice()->CreateTexture2D(&textArrayDesc, 0, &pTexturesArray);

    // On copie toutes les textures dans le tableau !
    for (uint16 i = 0; i < textures.size(); i++)
    {
        for (uint16 j = 0; j < textElementDesc.MipLevels; j++)
        {
            D3D10_MAPPED_TEXTURE2D mappedTex2D;

            ID3D10Texture2D* pCurrentTexture = textures[i];

            pCurrentTexture->Map(j, D3D10_MAP_READ, 0, &mappedTex2D);

            uint32 c = D3D10CalcSubresource(j, i, textElementDesc.MipLevels);

            D3D10_RENDERER->GetDevice()->UpdateSubresource(pTexturesArray, c,
                0, mappedTex2D.pData, mappedTex2D.RowPitch, 0);

            pCurrentTexture->Unmap(j);
        }
    }

    return pTexturesArray;
}

 

Voici la fonction qui créée une texture ressource shader pour le programme HLSL :


ID3D10ShaderResourceView* FontTextManager::GetTextureRVArray(ID3D10Texture2D* pTexArray)
{
    if (pTexArray == nullptr)
    {
        return nullptr;
    }

    ID3D10ShaderResourceView* pArrayRV = nullptr;

    D3D10_SHADER_RESOURCE_VIEW_DESC viewDesc;
    ZeroMemory(&viewDesc, sizeof(D3D10_SHADER_RESOURCE_VIEW_DESC));

    D3D10_TEXTURE2D_DESC textArrayDesc;
    pTexArray->GetDesc(&textArrayDesc);

    viewDesc.Format = textArrayDesc.Format;
    viewDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2DARRAY;
    viewDesc.Texture1DArray.MostDetailedMip = 0;
    viewDesc.Texture1DArray.MipLevels = textArrayDesc.MipLevels;
    viewDesc.Texture1DArray.FirstArraySlice = 0;
    viewDesc.Texture1DArray.ArraySize = textArrayDesc.ArraySize;

    D3D10_RENDERER->GetDevice()->CreateShaderResourceView(pTexArray, &viewDesc, &pArrayRV);

    return pArrayRV;
}

 

Utilisation : 

std::vector<ID3D10Texture2D*> textures;

textures.push_back( CreateTexture("UneImage.png") ) ;
textures.push_back( CreateTexture("UneAutreImage.png") ) ;
                                                   
ID3D10Texture2D* pTextureArray = CreateTextureArray(textures);

// On libère la mémoire
for (uint32 i = 0; i < textures.size(); i++)
{
    ID3D10Texture2D* pCurrentTexture = textures[i];
    SAFE_RELEASE(pCurrentTexture);
}

// Cette ressource est prête à être utilisée par un programme HLSL
ID3D10ShaderResourceView* pRVArray = GetTextureRVArray(pTextureArray);

SAFE_RELEASE(pTextureArray);

Résumé :

Nous avons présenté une façon d’accéder à une variable représentant un tableau de textures directement dans le shader !

Références :

– Franck D.Luna – DirectX 10

Le langage shader HLSL

shader

Intro :

Le HLSL signifie : High Level Shading Language. C’est un langage (qui a la même syntaxe que le C) qui permet de programmer le processeur de la carte graphique afin d’effectuer des algorithmes de rendus spécifiques.

Prérequis :

– Savoir configurer DirectX 10

Explications :

Le HLSL permet de générer la diffusion de la lumière, la texture à utiliser, les réflexions et réfractions, l’ombrage, le déplacement de primitives et les effets post-traitement.

C’est un outil très puissant qui permet de créer une vaste gamme d’effets graphiques et esthétiques pour les jeux modernes.

Avant l’existence du langage HLSL il fallait écrire les instructions en langage d’assembleur pour la carte graphique.

Un programme HLSL (en DirectX 11) est constitué par 5 étapes de chaîne rendu :

– Le vertex shader
– Le compute shader
– Le geometry shader
– Le tessellation shader
– Le domain shader
– Le pixel shader

Les vertex et pixel shaders doivent être obligatoirement programmés ; les autres ne doivent pas être nécessairement être programmés.

Le vertex shader :

Le vertex shader opère les transformations de repère, le skinning (l’animation squelettale), le déplacement de vertex et le calcul d’attributs de vertex pour les materials.

Le pixel shader :

Le pixel shader opère le blending de texturage, le calcul lumineux, etc…

Exemple :

Voici quelques fonctions intrinsèques utilisables dans le HLSL :

abs(x) : valeur absolue
ceil(x) : retourne le plus petit entier qui est égale ou supérieur à x
clamp(x, min, max) : retourne x dans l’intervalle [min, max]
cos(x) : retourne le cosinus de x
clip(x) : ignore le pixel en cours si x est inférieur à 0
cross(x, y) : retourne le produit vectoriel de deux vecteurs 3D
dot(x, y) : retourne le produit scalaire de deux vecteurs
length(v) : retourne la longueur du vecteur v
lerp(x, y, s) : retourne x + s(y – x)
normalize(x) : retourne un vecteur normalisé
max(x, y) : retourne le plus grand entier entre x et y
min(x, y) : retourne le plus petit entier entre x et y
mul(x, y) : retourne la multiplication des matrices x et y
reflect(i, n) : retourne un vecteur de reflection en utilisant le rayon d’insidence et la normale à la surface
refract(i, n, η) : retourne un vecteur de refraction en utilisant un rayon d’entrée, la normale à la surface, et un index de refraction
saturate(x) : clamp entre les valeurs 0 et 1
sqrt(x) : retourne la racine carrée de x
transpose(x) : retourne la matrice transposée de x
tex2D(s, t) : retourne une texture samplée

 


 

Les variables globales se déclarent et se définissent ainsi :

static const float2 bodyTexSize = {512, 512};
static const float2 faceLowerTexSize = {256, 128};
static const float2 faceUpperTexSize = {256, 64};

 

Voici un petit exemple d’un programme écrit en HLSL qui créé un effet « bois » procédural en tant que texture.

matrix WorldViewProjMatrix;
matrix TextureMatrix;

struct VS_OUTPUT
{
	float4 Pos : POSITION;
	float3 Pshade : TEXCOORD0;
};

VS_OUTPUT main (float4 vPosition : POSITION)
{
	VS_OUTPUT Out = (VS_OUTPUT) 0; 

	// Transforme la position du vertex vers l'espace 2D de l'écran
	Out.Pos = mul (WorldViewProjectionMatrix, vPosition);

	// Transforme les coordonnées de la texture
	Out.Pshade = mul (texture_matrix0, vPosition);

	return Out;
}

Comment créer un effet shader à parti d’un fichier .fx :

HRESULT D3DX10CreateEffectFromFile(
  _In_        LPCTSTR            pFileName, // Nom du fichier shader .fx
  _In_  const D3D10_SHADER_MACRO *pDefines, // Liste de macros  (peut être mis à nullptr)
  _In_        ID3D10Include      *pInclude, // Inteface d'include (peut être mis à nullptr)
  _In_        LPCSTR             pProfile, // Spécifie le profile ; ex : "fx_4_0"
  _In_        UINT               HLSLFlags, // Options du compilateur
  _In_        UINT               FXFlags, // Options de l'effet shader
  _In_        ID3D10Device       *pDevice, // Le device de DirectX 10.1
  _In_        ID3D10EffectPool   *pEffectPool,
  _In_        ID3DX10ThreadPump  *pPump,
  _Out_       ID3D10Effect       **ppEffect, // Pointeur de retour vers l'effet créé
  _Out_       ID3D10Blob         **ppErrors, // Pointeur de retour vers un objet représentant les erreurs
  _Out_       HRESULT            *pHResult
);

 

 

Résumé :

Le langage shader HLSL est un outil très puissant pour le rendu graphique des jeux vidéo.

Tous les effets graphiques dans les jeux DirectX d’aujourd’hui sont construits à partir de fichier script shader HLSL.

Références :

– http://www.neatware.com/lbstudio/web/hlsl.html

– https://msdn.microsoft.com/fr-fr/library/ms810449.aspx

Une classe ShaderManager pour gérer vos fichier shaders

AMD_6990

Intro :

Prérequis :

– Savoir utiliser un peu DirectX 10

– Savoir utiliser la classe Singleton. Voir cet article.

– Savoir ce qu’est un fichier shader.

– Savoir utiliser la classe ShaderTechnique.

Explications :

Voici le fichier ShaderManager.h :

#ifndef SHADERS_MANAGER_H
#define SHADERS_MANAGER_H 

class ShaderManager : public Singleton<ShaderManager>
{
public:
     ShaderManager();
     virtual ~ShaderManager();

     void RegisterShader(ShaderTechnique* pShader, const std::string& sName);
     void UnRegisterShader(std::string sName);

     ShaderTechnique* GetShader(std::string sName);

private:
    std::map<std::string, ShaderTechnique*> m_shaders;
};

#endif

 

Voici le fichier ShaderManager.cpp :

#include "ShaderManager.h"

template<> ShaderManager* Singleton<ShaderManager>::ms_instance = nullptr;

ShaderManager::ShaderManager()
{
}

ShaderManager::~ShaderManager()
{
}

void ShaderManager::RegisterShader(ShaderTechnique* pShader, const std::string& sName)
{
    Assert(pShader);

    m_shaders[sName] = pShader;
}

void ShaderManager::UnRegisterShader(std::string sName)
{
    Assert(m_shaders.count(sName) > 0);

    delete m_shaders[sName];

    m_shaders.erase(sName);

}

ShaderTechnique* ShaderManager::GetShader(std::string sName)
{
    Assert(m_shaders.count(sName) > 0);

    return m_shaders[sName];
}

 

Résumé :

Voici une classe toute simple qui permettra de rassembler tous vos shaders encapsulés dans une collection std::map.

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.

Debugguez vos fichiers .FX avec l’interface ID3D10Blob

AMD_6990

Intro :

Quand on compile un effet shader .fx, on a besoin de savoir où se situe l’erreur de compilation lorsque la compilation a échouée.

Explications :

Voici comment procéder avec le bout de code suivant :

#define ShowMessageBoxDXError(hr) char buf[2048]; \
       sprintf(buf, "Error: %s error description: %s\n", DXGetErrorStringA(hr), \
       DXGetErrorDescriptionA(hr)); \
       MessageBoxA(nullptr, buf, "Erreur", MB_ICONHAND | MB_OK);

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

#define SAFE_RELEASE(x) if (x != nullptr) { x->Release(); x = nullptr; }

ID3D10Blob* pBlob = nullptr;
// Pour la création du shader, on le compile
HRESULT hr = D3DX10CreateEffectFromFile(L"Effet.fx", NULL, NULL, "fx_4_0", dwShaderFlags, 0,
                                D3D10_RENDERER->GetDevice(), NULL,
                                NULL, &m_pEffect, &pBlob, NULL);

if (FAILED(hr))
{
    if (pBlob)
    {
        // Affiche l'erreur de compilation du shader
        MessageBoxA(NULL, (PCSTR)pBlob->GetBufferPointer(), "Erreur dans le fichier shader", MB_ICONHAND | MB_OK);
    }
    else
    {
        ShowMessageBoxDXError(hr);
    }

    SAFE_RELEASE(pBlob);

    return false;
}

SAFE_RELEASE(pBlob);

 

Résumé :

On a expliqué comment procéder pour savoir et afficher où se situe l’erreur de compilation d’un fichier shader .fx.

Théorie sur les lumières

light

Intro :

Dans les jeux vidéo, la gestion du rendu des lumières est cruciale pour effectuer un rendu à la fois réaliste et joli.

Dans cet article nous allons présenter les rudiments de la théorie sur le rendu des lumières.

Le rendu lumineux est un sujet vaste et complexe et pour cause le sujet est encore soumis à des recherches académiques ou en R&D.

En effet, ces dernières années les jeux vidéos les plus récents affichent des rendus de lumière de plus en plus réalistes, en utilisant par exemple un type de rendu nommé Deferred Shading.

[éclater en plusieurs articles]

Prérequis : 

– Savoir ce qu’est une normale

– Savoir lire du C++

– Savoir lire un programme shader HLSL

Explications :

Avant tout, éclaircissons un peu de vocabulaire.

Les deux notions qui suivent ont des propriétés de nature différente :

Les propriétés d’un matériau donnée (or, glace, bois, métal, etc…) déterminent comment un modèle est affiché :

Emissive :

– ce terme désigne la valeur d’émission d’un matériau permettant d’émettre une couleur de lumière comme si elles avaient été toutes désactivées. Notée Ke.

Ambient :

– ce terme désigne la valeur ambiante d’émission d’une lumière, comme le soleil.

Diffuse :

– ce terme désigne la couleur diffuse qu’émet la lumière dans toutes les directions.

Specular :

Specular power :

– représente le degré d’éclat de brillance.

Les propriétés d’une lumière donnée déterminent comment la scène est affichée :

Type de lumière :

– il y a 3 types de lumière :

Point : une lumière qui émet dans toutes les directions.

Spot : une lumière qui émet dans une direction spécifique.

Directional : une lumière qui a une direction donnée mais n’a pas de position donnée, comme par exemple le soleil.

Color :

– la couleur de la source de lumière

Position :

– définie la position de la lumière par trois valeurs de coordonnées

–  Direction :

– définie la direction à laquelle pointe la lumière

Le but du calcul lumineux est de combiner ces deux catégories de propriétés afin déterminer la couleur finale de la lumière (avec ses nuances d’ombre).

Lumière ambiante :

La lumière ambiante désigne, comme son nom l’indique, une lumière qui éclaire dans toutes les directions. C’est comme un soleil qui illumine partout.

L’équation est toute simple :

Ip = pa  * Ia 

[utiliser ambient = Ka + Ga]

Ia désigne l’intensité de la lumière ; et pa le coefficient de réflexion de la lumière ambiante. Ip désigne l’intensité de la lumière résultant de la réflexion sur la surface finale.

Ce principe de calcul de la lumière illuminative est très rudimentaire car il n’affiche pas les ombres des modèles que font apparaître indirectement la lumière émissive.

[image lumière ambiante]

La réflexion diffuse :

Le principe de la réflexion diffuse consiste à considérer la position d’émission d’une lumière quelconque (ou plusieurs)

On a remarqué, mathématiquement, que l’intensité en un point de l’effet d’une lumière quelconque dépend de l’angle formé entre le rayon de lumière qui touche le point de la surface et la normale à la surface.

Il se trouve que, plus l’angle formé entre le rayon de lumière et la normale au plan est faible, plus l’intensité lumineuse réfléchie visible par l’observateur est forte.

[ajouter schéma dot product]

Diffuse-Lighting

Types de calcul lumineux :

 

 

 

Résumé :

Références :

– http://irrlicht-fr.org/lire_tuto.php?id=1014

–  https://takinginitiative.wordpress.com/2010/08/30/directx-10-tutorial-8-lighting-theory-and-hlsl/

– http://www.3dgep.com/texturing-lighting-directx-11/

– http://http.developer.nvidia.com/CgTutorial/cg_tutorial_chapter05.html