
Intro :
Pour que votre scène soit réaliste, il peut être utile d’afficher un décor de ciel de grande taille autour de la caméra.
Ceci constitue une première approche à l’affichage d’une Skybox.
Prérequis :
– Savoir utiliser la classe ShaderTechnique. Voir cet article.
– Savoir utiliser la classe MeshSceneNode. Voir cet article.
– Savoir un peu utiliser DirectX 10.
Explications :
Tout d’abord la classe dérivant ShaderTechnique :
//------------------------------------------------------
// Une simple effet affichant une SkyBox
//------------------------------------------------------
class ShaderTechnique_SkyBox : public ShaderTechnique
{
public:
friend class SkyBoxSceneNode;
ShaderTechnique_SkyBox();
virtual ~ShaderTechnique_SkyBox();
virtual bool Initialize();
virtual void SetupShaderVariables();
virtual void Update(float fTimeSinceLastFrame);
};
Voici ensuite le fichier ShaderTechnique_SkyBox.cpp :
ShaderTechnique_SkyBox::ShaderTechnique_SkyBox() :
ShaderTechnique("SkyBox.fx", "Render", VertexLayoutType::PTN_VERTEX)
{
}
ShaderTechnique_SkyBox::~ShaderTechnique_SkyBox()
{
}
bool ShaderTechnique_SkyBox::Initialize()
{
ShaderTechnique::Initialize();
SetupShaderVariables();
return true;
}
void ShaderTechnique_SkyBox::SetupShaderVariables()
{
RegisterMatrixVariable("World", ShaderVariableType::WORLD);
RegisterMatrixVariable("View", ShaderVariableType::VIEW);
RegisterMatrixVariable("Projection", ShaderVariableType::PROJECTION);
RegisterTextureVariable("txFace");
}
void ShaderTechnique_SkyBox::Update(float fTimeSinceLastFrame)
{
SetAutoMatrix(ShaderVariableType::WORLD);
SetAutoMatrix(ShaderVariableType::VIEW);
SetAutoMatrix(ShaderVariableType::PROJECTION);
}
Voici le fichier SkyBoxSceneNode.h :
#ifndef SKY_BOX_SCENE_NODE_H
#define SKY_BOX_SCENE_NODE_H
class SkyBoxSceneNode : public MeshSceneNode
{
public:
SkyBoxSceneNode(ID3D10ShaderResourceView* pTop, ID3D10ShaderResourceView* pBottom,
ID3D10ShaderResourceView* pLeft, ID3D10ShaderResourceView* pRight,
ID3D10ShaderResourceView* pFront, ID3D10ShaderResourceView* pBack);
virtual ~SkyBoxSceneNode();
virtual bool Initialize();
virtual void Render(float fTimeSinceLastFrame);
protected:
virtual void OnPreRender(float fTimeSinceLastFrame);
virtual void OnPostRender(float fTimeSinceLastFrame);
private:
PTNVertex SetVertex(D3DXVECTOR3 p, D3DXVECTOR2 t, D3DXVECTOR3 n);
private:
ID3D10ShaderResourceView* m_pFrontTex;
ID3D10ShaderResourceView* m_pLeftTex;
ID3D10ShaderResourceView* m_pBackTex;
ID3D10ShaderResourceView* m_pRightTex;
ID3D10ShaderResourceView* m_pTopTex;
ID3D10ShaderResourceView* m_pBottomTex;
ID3D10Buffer* m_pFrontVB;
ID3D10Buffer* m_pLeftVB;
ID3D10Buffer* m_pBackVB;
ID3D10Buffer* m_pRightVB;
ID3D10Buffer* m_pTopVB;
ID3D10Buffer* m_pBottomVB;
};
#endif
Voici le fichier SkyBoxSceneNode.cpp :
#include "SkyBoxSceneNode.h"
SkyBoxSceneNode::SkyBoxSceneNode(ID3D10ShaderResourceView* pTop, ID3D10ShaderResourceView* pBottom,
ID3D10ShaderResourceView* pLeft, ID3D10ShaderResourceView* pRight,
ID3D10ShaderResourceView* pFront, ID3D10ShaderResourceView* pBack) :
m_pFrontVB(nullptr),
m_pLeftVB(nullptr),
m_pBackVB(nullptr),
m_pRightVB(nullptr),
m_pTopVB(nullptr),
m_pBottomVB(nullptr),
m_pFrontTex(pFront),
m_pLeftTex(pLeft),
m_pBackTex(pBack),
m_pRightTex(pRight),
m_pTopTex(pTop),
m_pBottomTex(pBottom)
{
SetVertexType(VertexLayoutType::PTN_VERTEX);
SetDrawMethod(DrawMethod::DRAW_INDEXED);
SetTopology(D3D_PRIMITIVE_TOPOLOGY::D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
SetShaderTechnique( SHADER_MANAGER->GetShader("SkyBox") );
}
SkyBoxSceneNode::~SkyBoxSceneNode()
{
}
PTNVertex SkyBoxSceneNode::SetVertex(D3DXVECTOR3 p, D3DXVECTOR2 t, D3DXVECTOR3 n)
{
PTNVertex vertex;
vertex.position = p;
vertex.texture = t;
vertex.normal = n;
return vertex;
}
bool SkyBoxSceneNode::Initialize()
{
std::vector<unsigned short> indices;
indices.push_back(3);
indices.push_back(1);
indices.push_back(0);
indices.push_back(2);
indices.push_back(1);
indices.push_back(3);
BuildIB(indices);
// On redecoupe les bords des textures pour éviter
// d'afficher les arrêtes du cube
float fTextureWidth = GetShaderTextureViewSize(m_pBottomTex).x;
float onepixel = 1.0f / (fTextureWidth * 1.5f);
float t = 1.0f - onepixel;
float o = 0.0f + onepixel;
std::vector<PTNVertex> vertices;
// Front side
vertices.push_back( SetVertex(D3DXVECTOR3(-1,-1,-1), D3DXVECTOR2(t, t), D3DXVECTOR3(0, 0, 1.0f)));
vertices.push_back( SetVertex(D3DXVECTOR3(1,-1,-1), D3DXVECTOR2(o, t), D3DXVECTOR3(0, 0, 1.0f)));
vertices.push_back( SetVertex(D3DXVECTOR3(1, 1,-1), D3DXVECTOR2(o, o), D3DXVECTOR3(0, 0, 1.0f)));
vertices.push_back( SetVertex(D3DXVECTOR3(-1, 1,-1), D3DXVECTOR2(t, o), D3DXVECTOR3(0, 0, 1.0f)));
BuildVB(vertices);
m_pFrontVB = GetVertexBuffer();
// Left side
vertices.clear();
vertices.push_back( SetVertex(D3DXVECTOR3(1,-1,-1), D3DXVECTOR2(t, t), D3DXVECTOR3(-1, 0, 0)));
vertices.push_back( SetVertex(D3DXVECTOR3(1,-1, 1), D3DXVECTOR2(o, t), D3DXVECTOR3(-1, 0, 0)));
vertices.push_back( SetVertex(D3DXVECTOR3(1, 1, 1), D3DXVECTOR2(o, o), D3DXVECTOR3(-1, 0, 0)));
vertices.push_back( SetVertex(D3DXVECTOR3(1, 1,-1), D3DXVECTOR2(t, o), D3DXVECTOR3(-1, 0, 0)));
BuildVB(vertices);
m_pLeftVB = GetVertexBuffer();
// Back side
vertices.clear();
vertices.push_back( SetVertex(D3DXVECTOR3( 1,-1, 1), D3DXVECTOR2(t, t), D3DXVECTOR3(0, 0, -1.0f)));
vertices.push_back( SetVertex(D3DXVECTOR3(-1,-1, 1), D3DXVECTOR2(o, t), D3DXVECTOR3(0, 0, -1.0f)));
vertices.push_back( SetVertex(D3DXVECTOR3(-1, 1, 1), D3DXVECTOR2(o, o), D3DXVECTOR3(0, 0, -1.0f)));
vertices.push_back( SetVertex(D3DXVECTOR3( 1, 1, 1), D3DXVECTOR2(t, o), D3DXVECTOR3(0, 0, -1.0f)));
BuildVB(vertices);
m_pBackVB = GetVertexBuffer();
// Right side
vertices.clear();
vertices.push_back( SetVertex(D3DXVECTOR3(-1,-1, 1), D3DXVECTOR2(t, t), D3DXVECTOR3(1, 0, 0)));
vertices.push_back( SetVertex(D3DXVECTOR3(-1,-1,-1), D3DXVECTOR2(o, t), D3DXVECTOR3(1, 0, 0)));
vertices.push_back( SetVertex(D3DXVECTOR3(-1, 1,-1), D3DXVECTOR2(o, o), D3DXVECTOR3(1, 0, 0)));
vertices.push_back( SetVertex(D3DXVECTOR3(-1, 1, 1), D3DXVECTOR2(t, o), D3DXVECTOR3(1, 0, 0)));
BuildVB(vertices);
m_pRightVB = GetVertexBuffer();
// Top side
vertices.clear();
vertices.push_back( SetVertex(D3DXVECTOR3( 1, 1,-1), D3DXVECTOR2(t, t), D3DXVECTOR3(0, -1, 0)));
vertices.push_back( SetVertex(D3DXVECTOR3( 1, 1, 1), D3DXVECTOR2(o, t), D3DXVECTOR3(0, -1, 0)));
vertices.push_back( SetVertex(D3DXVECTOR3(-1, 1, 1), D3DXVECTOR2(o, o), D3DXVECTOR3(0, -1, 0)));
vertices.push_back( SetVertex(D3DXVECTOR3(-1, 1,-1), D3DXVECTOR2(t, o), D3DXVECTOR3(0, -1, 0)));
BuildVB(vertices);
m_pTopVB = GetVertexBuffer();
// Bottom side
vertices.clear();
vertices.push_back( SetVertex(D3DXVECTOR3( 1,-1, 1), D3DXVECTOR2(t, t), D3DXVECTOR3(0, 1, 0)));
vertices.push_back( SetVertex(D3DXVECTOR3( 1,-1,-1), D3DXVECTOR2(o, t), D3DXVECTOR3(0, 1, 0)));
vertices.push_back( SetVertex(D3DXVECTOR3(-1,-1,-1), D3DXVECTOR2(o, o), D3DXVECTOR3(0, 1, 0)));
vertices.push_back( SetVertex(D3DXVECTOR3(-1,-1, 1), D3DXVECTOR2(t, o), D3DXVECTOR3(0, 1, 0)));
BuildVB(vertices);
m_pBottomVB = GetVertexBuffer();
return true;
}
void SkyBoxSceneNode::Render(float fTimeSinceLastFrame)
{
D3D10_RENDERER->EnableZBuffer(false);
SetVertexBuffer(m_pFrontVB);
GetShaderTechnique()->SetTextureRV("txFace", m_pFrontTex);
Renderable::Render(fTimeSinceLastFrame);
SetVertexBuffer(m_pLeftVB);
GetShaderTechnique()->SetTextureRV("txFace", m_pLeftTex);
Renderable::Render(fTimeSinceLastFrame);
SetVertexBuffer(m_pBackVB);
GetShaderTechnique()->SetTextureRV("txFace", m_pBackTex);
Renderable::Render(fTimeSinceLastFrame);
SetVertexBuffer(m_pRightVB);
GetShaderTechnique()->SetTextureRV("txFace", m_pRightTex);
Renderable::Render(fTimeSinceLastFrame);
SetVertexBuffer(m_pTopVB);
GetShaderTechnique()->SetTextureRV("txFace", m_pTopTex);
Renderable::Render(fTimeSinceLastFrame);
SetVertexBuffer(m_pBottomVB);
GetShaderTechnique()->SetTextureRV("txFace", m_pBottomTex);
Renderable::Render(fTimeSinceLastFrame);
D3D10_RENDERER->EnableZBuffer(true);
}
void SkyBoxSceneNode::OnPreRender(float fTimeSinceLastFrame)
{
Camera* pCamera = SCENE_MANAGER->GetActiveCamera();
D3DXMATRIX finalMatrix;
D3DXMATRIX translate;
D3DXVECTOR3 cameraPos = pCamera->GetPosition();
// On centre toujours la skybox autour de la position de la caméra
D3DXMatrixTranslation(&translate, cameraPos.x, cameraPos.y, cameraPos.z);
float viewDistance = (pCamera->GerNearValue() + pCamera->GetFarValue()) * 0.5f;
// On agrandie la skybox pour qu'elle est une bonne taille
D3DXMATRIX scale;
D3DXMatrixScaling(&scale, viewDistance, viewDistance, viewDistance);
finalMatrix = scale * translate;
SCENE_MANAGER->PushAndSetMatrix(finalMatrix);
}
void SkyBoxSceneNode::OnPostRender(float fTimeSinceLastFrame)
{
SCENE_MANAGER->PopMatrix();
}
Voici le fichier SkyBox.fx :
matrix World;
matrix View;
matrix Projection;
Texture2D txFace;
SamplerState samLinear
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};
struct VS_INPUT
{
float4 Pos : POSITION;
float2 Tex : TEXCOORD;
float3 Norm : NORMAL;
};
struct PS_INPUT
{
float4 Pos : SV_POSITION;
float2 Tex : TEXCOORD0;
float3 Norm : NORMAL;
};
PS_INPUT VS( VS_INPUT input )
{
PS_INPUT output = (PS_INPUT)0;
output.Pos = mul( input.Pos, World );
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Tex = input.Tex;
output.Norm = mul( input.Norm, World );
return output;
}
float4 PS( PS_INPUT input) : SV_Target
{
float4 textureColor = txFace.Sample(samLinear, input.Tex);
return textureColor;
}
technique10 Render
{
pass P0
{
SetVertexShader( CompileShader( vs_4_0, VS() ) );
SetGeometryShader( NULL );
SetPixelShader( CompileShader( ps_4_0, PS() ) );
}
}
Résumé :
Nous avons présenté un énorme cube autour de la caméra qui servira de ciel ou de décor.