Une simple grille en 3D

grid

Intro :

Savoir créer une grille en 3D peut être utile pour :

– un éditeur de map

– générer un terrain à partir d’une height map

– représenter la surface d’une eau en mouvement

– etc…

Prérequis :

– Savoir initialiser DirectX 10.1

Explications :

Le fichier Grid.h :

#ifndef GRID_H
#define GRID_H

#include <vector>

#include <d3d10.h>
#include <d3dx10.h>

#include "Defines.h"
#include "D3D10Renderer.h"

class Grid
{
public:
    Grid();
    virtual ~Grid();
 
    bool Initialize();
 
    void Render(float fTimeSinceLastFrame);

    void GenTriGrid(int iNumVertRows, int iNumVertCols,
        float fDx, float fDz, const D3DXVECTOR3& center,
        std::vector<D3DXVECTOR3>& verts, std::vector<uint32>& indices);

private:
    ID3DX10Mesh* m_pMesh;
 
    D3DXMATRIX m_worldMatrix;
    D3DXMATRIX m_viewMatrix;
    D3DXMATRIX m_projMatrix;

    ID3D10EffectMatrixVariable* m_pWorldVariable;
    ID3D10EffectMatrixVariable* m_pViewVariable;
    ID3D10EffectMatrixVariable* m_pProjVariable;
     
    ID3D10Effect* m_pEffect;
    ID3D10EffectTechnique* m_pTechnique;
     
    ID3D10InputLayout* m_pVertexLayout;
};
 
#endif

 

Le fichier Grid.cpp :

#include "Grid.h"

Grid::Grid() :
m_pMesh(nullptr),
m_pWorldVariable(nullptr),
m_pTechnique(nullptr),
m_pEffect(nullptr),
m_pVertexLayout(nullptr)
{
    D3DXMatrixIdentity(&m_worldMatrix);

    D3DXVECTOR3 Eye(0.0f, 22.0f, -46.0f);
    D3DXVECTOR3 At(0.0f, 0.0f, 0.0f);
    D3DXVECTOR3 Up(0.0f, 1.0f, 0.0f);
 
    D3DXMatrixLookAtLH(&m_viewMatrix, &Eye, &At, &Up);
 
    D3DXMatrixPerspectiveFovLH(&m_projMatrix, D3DX_PI * 0.25f,
        (float) D3D10_RENDERER->GetViewportWidth() / (float)D3D10_RENDERER->GetViewportHeight(),
        0.1f, 100.0f);
}
 
Grid::~Grid()
{
    SAFE_RELEASE(m_pMesh);
}
 
bool Grid::Initialize()
{
    std::vector<D3DXVECTOR3> vertices;
    std::vector<uint32> indices;
     
    GenTriGrid(12, 12, 5.0f, 5.0f, D3DXVECTOR3(0, 0, 0), vertices, indices);

    D3D10_INPUT_ELEMENT_DESC layout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
    };

    HRESULT hr;
    hr = D3DX10CreateMesh(D3D10_RENDERER->GetDevice(), layout,  1, "POSITION", vertices.size(), indices.size()/3, D3DX10_MESH_32_BIT, &m_pMesh);
 
    hr = m_pMesh->SetVertexData(0, vertices.front());
 
    if (FAILED(hr))
    {
        ShowMessageBoxDXError(hr);
        return false;
    }
 
    hr = m_pMesh->SetIndexData(indices.data(), indices.size());
 
    if (FAILED(hr))
    {
        ShowMessageBoxDXError(hr);
        return false;
    }
 
    hr = m_pMesh->CommitToDevice();
 
    if (FAILED(hr))
    {
        ShowMessageBoxDXError(hr);
        return false;
    }
 
    ID3D10Blob* pBlob = nullptr;
 
    hr = D3DX10CreateEffectFromFile(L"Grid.fx", nullptr, nullptr, "fx_4_0",
                                    D3D10_SHADER_ENABLE_STRICTNESS | D3D10_SHADER_DEBUG, 0,
                                    D3D10_RENDERER->GetDevice(), nullptr, nullptr, &m_pEffect, &pBlob, nullptr);
    if (FAILED(hr))
    {
        if (pBlob)
        {
            // Affiche l'erreur de compilation du shader
            MessageBoxA(nullptr, (PCSTR)pBlob->GetBufferPointer(), "Erreur dans le fichier shader", MB_ICONHAND | MB_OK);
        }
        else
        {
            ShowMessageBoxDXError(hr);
        }
 
        return false;
    }
 
    m_pTechnique = m_pEffect->GetTechniqueByName("Render");
 
    m_pWorldVariable = m_pEffect->GetVariableByName("World")->AsMatrix();
    m_pViewVariable = m_pEffect->GetVariableByName("View")->AsMatrix();
    m_pProjVariable = m_pEffect->GetVariableByName("Projection")->AsMatrix();
 
    D3D10_PASS_DESC PassDesc;
    m_pTechnique->GetPassByIndex(0)->GetDesc(&PassDesc);
    hr = D3D10_RENDERER->GetDevice()->CreateInputLayout(layout, 1, PassDesc.pIAInputSignature,
                                         PassDesc.IAInputSignatureSize, &m_pVertexLayout);
    if (FAILED(hr))
    {
        ShowMessageBoxDXError(hr);
        return false;
    }

    return true;
}
 
void Grid::Render(float fTimeSinceLastFrame)
{
    D3D10_RENDERER->GetDevice()->IASetInputLayout(m_pVertexLayout);

    // Pour faire tourner la grille autour de l'axe Y
    static float r = 0;
    D3DXMatrixRotationY(&m_worldMatrix, r);
    r += fTimeSinceLastFrame * 0.6f;

    m_pWorldVariable->SetMatrix((float*)&m_worldMatrix);
    m_pViewVariable->SetMatrix((float*)&m_viewMatrix);
    m_pProjVariable->SetMatrix((float*)&m_projMatrix);

    D3D10_TECHNIQUE_DESC techDesc;
    m_pTechnique->GetDesc(&techDesc);

    for (uint32 p = 0; p < techDesc.Passes; p++)
    {
        m_pTechnique->GetPassByIndex(p)->Apply(0);

        m_pMesh->DrawSubset(0);
    }
}

void Grid::GenTriGrid(int iNumVertRows, int iNumVertCols,
        float fDx, float fDz, const D3DXVECTOR3& center,
        std::vector<D3DXVECTOR3>& verts, std::vector<uint32>& indices)
{
    int numVertices = iNumVertRows * iNumVertCols;
    int numCellRows = iNumVertRows - 1;
    int numCellCols = iNumVertCols - 1;

    int numTris = numCellRows*numCellCols*2;

    float width = (float) numCellCols * fDx;
    float depth = (float) numCellRows * fDz;

    /* Construction des vertices */

    /* On construit d'abord la grille centrée  à l'origine */

    verts.resize( numVertices );

    /* Valeurs de décalage pour pour déplacer la grille
       dans le centre du système de coordonnées */
    float xOffset = -width * 0.5f;
    float zOffset =  depth * 0.5f;

    int k = 0;
    for (float i = 0; i < iNumVertRows; ++i)
    {
        for (float j = 0; j < iNumVertCols; ++j)
        {
            verts[k].x =  j * fDx + xOffset;
            verts[k].z = -i * fDz + zOffset;
            verts[k].y =  0.0f;

            /* Opère une translation afin que le centre de la grille
               soit positionné en fonction du centre spécifié en paramètre */
            D3DXMATRIX T;
            D3DXMatrixTranslation(&T, center.x, center.y, center.z);
            D3DXVec3TransformCoord(&verts[k], &verts[k], &T);
            
            ++k;  // Prochain vertex
        }
    }

    /* Construction des indices */ 

    indices.resize(numTris * 3);
    
    // Créé les indices pour chaque face
    k = 0;
    for (DWORD i = 0; i < (DWORD)numCellRows; ++i)
    {
        for (DWORD j = 0; j < (DWORD)numCellCols; ++j)
        {
            indices[k]     =   i   * iNumVertCols + j;
            indices[k + 1] =   i   * iNumVertCols + j + 1;
            indices[k + 2] = (i+1) * iNumVertCols + j;
                    
            indices[k + 3] = (i+1) * iNumVertCols + j;
            indices[k + 4] =   i   * iNumVertCols + j + 1;
            indices[k + 5] = (i+1) * iNumVertCols + j + 1;

            // Prochaine face
            k += 6;
        }
    }
}

 

Résumé :

Nous avons expliqué comment générer une grille en 3D avec le paramétrage de sa longueur et de sa largeur puis la dimensions de ses faces.

Voici les fichiers sources : Simple Grille.zip

Références :

– Introduction to DirectX 9.0c – Frank D. Luna

Laisser un commentaire

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