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

