Curso completo de DirectX 9 com C\C++
Gameprog - Escola de programação de jogos digitais
Contato: gameprog.br@gmail.com
Fase 01-10
01.10 Triângulo 3d
1.1 Visão geral
A aplicação desse tópico é uma versão modificada do projeto
prj_Triangulo01 ( tópico 01.9 ) para mostrar um triângulo 3d cuja
construção envolve uma alteração no formato de vértice, a adição de
uma câmera na aplicação, a consideração de luz na cena e a
configuração de culling. A câmera em si é representada por 3 matrizes
nas quais qualquer mudança impacta na imagem final da cena.
É importante observar a relação hierárquica ou a interdependência da
movimentação de objetos correlacionados do mundo real para compreender
melhor a replicação digital que o directx faz desses aspectos do
mundo real utilizando conceituação de matemática, física e geometria.
Colocamos a opinião de que a assimilação dos aspectos matemáticos,
físicos e geométricos dos aspectos visuais precisam ser assimilados
primeiro intuitivamente através de observações do mundo real. O
contato direto com a linguagem matemática ou física desses aspectos
visuais pode ser intimidante e desestimulador. É por conta desse
ponto de vista que este curso fala muito pouco dos aspectos
matemáticos e incentiva a assimilação dos mesmos através da observação
e da experimentação prática.
Quando você coloca um prato sobre a mesa e na sequência você move a
mesa naturalmente o prato acompanha a mesa. Se o piso sob a mesa
se movesse a mesa e o prato acompanhariam normalmente esse movimento.
Dizemos que o prato acompanha a orientação da mesa, e a mesa acompanha
a orientação do piso. Então neste exemplo do mundo real uma
transformação em um objeto de base ou na sua orientação se propaga
pelas camadas de objetos empilhados uns sobre os outros. De maneira
semelhante nosso triângulo está colocado sobre um mundo 3d e quando
este mundo tem sua orientação, localização ou rotação modificados
todos os objetos sobre ele acompanham essas transformações. Esse
mundo 3d é visto por uma câmera e quando essa câmera gira ou se move
naturalmente os objetos 3d desse mundo giram e se movem de acordo.
Tranformações
A aplicação deste capítulo apresenta a matriz de espaço mundial cuja
transformação é utilizada para escalar, rotacionar e movimentar os
os objetos 3d dentro de uma cena. Vamos conhecer também a matriz de
projeção e visualização que em conjunto com a matriz de espaço
mundial são usadas para compor a câmera da aplicação 3d.
Formato de vértice
Visto que o triângulo deve sofrer as consequências da transformação
que ocorrer na matriz de espaço mundial e de mudanças no movimento da
câmera o formato de vértice adequado a selecionar é o posicionado
(positioned). Nossa aplicação vai utilizar o formato de
vértice posicionado e colorido representado pela estrutura
CustomVertex_PositionColored.
Culling
g_device->SetRenderState (D3DRS_CULLMODE, D3DCULL_NONE);
Essa linha desativa o culling. O culling é uma técnica para otimizar
a renderização que consiste em evitar a renderização de polígonos que
não aparecem, por exemplo, polígonos do lado de dentro de uma caixa
ou que não estão virados diretamente para a câmera. O culling ligado
pode gerar problemas na visualização ocasionando o desaparecimento de
partes de objetos. Na ilustração acima a caixa vermelha que é uma
cópia da caixa azul está sem o teto e no entanto o seu interior não
aparece.
Iluminação default
g_device->SetRenderState (D3DRS_LIGHTING, false);
Essa opção de iluminação, quando configurada como falsa, o directx
providencia uma iluminação default. Se configurada como true, a
imagem final fica preta se não houver uma luz colocada na cena.
1.2 Estrutura principal da aplicação
Arquivo: motor.cpp
initGfx()
Inicializa objeto Direct3d
Inicializa dispositivo renderizador
chama montar_Geometria() para configurar os vértices
chama inicializar_Camera para configurar a câmera
inicializar_Camera()
Configura matriz de visualização ( g_mtxVisao )
joga matriz de visualização no dispositivo renderizador
inicializa matriz mundial ( g_mtxMundo )
joga matriz mundial no dispositivo renderizador
Configura matriz de projeção ( g_mtxProj )
joga matriz de projeção no dispositivo renderizador
montar_Geometria()
Configura posição dos vértices
renderizar_Geometria()
Declara o formato de vértice utilizado ao directx
Renderiza os vértices com g_device->DrawPrimitiveUP()
atualizar_Camera()
atualiza ângulo de rotação
atualiza matriz mundial com ângulo de rotação
joga matriz mundial no dispositivo renderizador
Renderizar()
Limpa a tela
Desliga o culling
Aciona luz default
chama atualizar_Camera() para girar o triângulo 3d
chama renderizar_Geometria() para desenhar o triângulo
Apresenta a cena
Limpar()
Libera dispositivo renderizador
Libera objeto Direct3d
2.1.1 Aspectos globais - Arquivo: motor.h
// Projeto: prj_Triangulo3d - Arquivo: motor.h
// Esta aplicação ilustra como configurar uma câmera e
// renderizar um triângulo 3d. By www.gameprog.com.br
#ifndef motor_h
#define motor_h
// Esta função inicializa o Direct3D
HRESULT initGfx (HWND hJanela);
// Essa função libera os objetos utilizados
void Limpar();
// Essa função desenha a cena
void Renderizar();
// Essa função monta formas geométricas
void montar_Geometria (void);
// Configura a câmera 3d da cena
void inicializar_Camera(void);
// Atualiza a câmera
void atualizar_Camera(void);
// Renderiza os vértices em formas geométricas
void renderizar_Geometria (void);
// Declaração da função que atende as mensagens da janela
LRESULT CALLBACK processaJanela (HWND hJanela, UINT mensagem,
WPARAM wParam, LPARAM lParam);
#endif
// Essa função desenha a cena
void Renderizar();
Esta função inicialmente configura alguns estados do dispositivo
renderizador, o culling e iluminação default. Antes de renderizar a
cena chama atualizar_Camera() para atualizar uma pequena lógica que
define o aspecto visual da cena: a rotação do triângulo.
// Essa função monta formas geométricas
void montar_Geometria (void);
Essa função monta o triângulo com o tipo de vértice que possui
informação de posição e cor.
// Configura a câmera 3d da cena
void inicializar_Camera(void);
Essa função faz a configuração inicial da câmera que existe na forma
de 3 matrizes: matriz de visão, de mundo (espaço mundial) e de
projeção.
// Atualiza a câmera
void atualizar_Camera(void);
Essa função gira o triângulo no eixo y com a função D3DXMatrixRotationY()
aplicada na matriz de mundo que na sequência é 'jogada' ou estabelecida
dentro da matriz de espaço mundial do dispositivo renderizador.
2.1.2 Aspectos globais - Arquivo: motor.cpp
// Variáveis para controlar a rotação do triângulo
float g_Angulo = 0.0f;
const float nVelocidade = 0.2f;
// Matrizes de configuração da câmera
// Matriz de mundo
D3DXMATRIX g_mtxMundo;
// Matriz de visão
D3DXMATRIX g_mtxVisao;
// Matriz de projeção
D3DXMATRIX g_mtxProj;
// Definição do formato de vértice utilizado pela aplicação
#define CustomVertex_PositionColored_Format(D3DFVF_XYZ | D3DFVF_DIFFUSE)
// Definição da estrutura de vértice customizado
struct CustomVertex_PositionColored
{
float x, y, z;
DWORD cor;
// Construtor default
CustomVertex_PositionColored() {}
// Construtor com inicialização
CustomVertex_PositionColored( float _x, float _y, float _z, DWORD _cor)
{
x = _x;
y = _y;
z = _z;
cor = _cor;
} // fim do construtor
}; // fim da estrutura CustomVertex_PositionColored
// Declaração dos vértices para o triângulo
CustomVertex_PositionColored g_Vertices[3 ];
// Variáveis para controlar a rotação do triângulo
float g_Angulo = 0.0f;
const float nVelocidade = 0.2f;
Estas variáveis são auto-descritivas. A variável g_Angulo sofrerá a
cada frame um incremento no valor de nVelocidade que ocasionará a
rotação do triângulo lenta ou rápida conforme o valor desta
última variável.
// Matrizes de configuração da câmera
// Matriz de mundo
D3DXMATRIX g_mtxMundo;
// Matriz de visão
D3DXMATRIX g_mtxVisao;
// Matriz de projeção
D3DXMATRIX g_mtxProj;
Não existe um objeto câmera no directx. Na verdade, os efeitos de
uma câmera são simulados e criados a partir da manipulação dessas
trêz (3) matrizes. A matriz de projeção ( g_mtxProj ) representa a
configuração da lente da câmera e define o aspecto da imagem bem como
a potência da câmera, o quanto longe a lente percebe do mundo 3d,
o quanto da cena a câmera consegue enquadrar com a abertura angular
da lente. Geralmente, a matriz de projeção é configurada apenas uma
vez na aplicação na inicialização da câmera e depois esquecida.
A matriz de visualização ( g_mtxProj ) representa o que a câmera está
vendo do ponto de vista dela, da posição aonde ela está, para aonde
está apontando, se está virada ou não de cabeça pra baixo. Geralmente,
essa matriz é modificada quando se quer movimentar ou rotacionar a
câmera.
A matriz de mundo ou de espaço mundial ( g_mtxMundo ),world matrix em
inglês, é a mais usada porque indica para a câmera aonde um objeto 3d
está e como está dentro da cena. Essa matriz é utilizada para tirar
os objetos 3d de seu espaço local e trazê-los para o 'espaço mundial'
do mundo 3d; é utilizada para girar, movimentar ou escalar os objetos.
// Definição do formato de vértice utilizado pela aplicação
#define CustomVertex_PositionColored_Format( D3DFVF_XYZ | D3DFVF_DIFFUSE)
Essa é a configuração do formato de vértice com posição e cor. E logo
abaixo temos como esse formato de vértice foi implementado.
// Definição da estrutura de vértice customizado
struct CustomVertex_PositionColored
{
float x, y, z;
DWORD cor;
// Construtor default
CustomVertex_PositionColored() {}
// Construtor com inicialização
CustomVertex_PositionColored( float _x, float _y, float _z, DWORD _cor)
{
x = _x;
y = _y;
z = _z;
cor = _cor;
} // fim do construtor
}; // fim da estrutura CustomVertex_PositionColored
// Declaração dos vértices para o triângulo
CustomVertex_PositionColored g_Vertices[3];
Aqui os 3 vértices necessários para montar o triângulo.
2.2 Inicialização do motor gráfico
Veja que a função initGfx() faz o grande trabalho de inicializar todos
os aspectos de trabalho do motor gráfico da aplicação chamando a
função que monta as formas geométricas ( montar_Geometria() ) da cena
e a função de criação e configuração inicial da câmera
inicializar_Camera()
// initGfx() - Inicializa o Direct3D
HRESULT initGfx( HWND hJanela )
{
// Cria o objeto Direct3D que é necessário para criar o dispositivo gráfico
g_Direct3d = Direct3DCreate9( D3D_SDK_VERSION);
// Verifica se objeto Direct3D foi criado
if(g_Direct3d == NULL)
{
MessageBox (NULL,
"Falha na inialização do Direct3D", "InitGfx()", MB_OK);
return E_FAIL;
} // endif
// Declara a variável para os parâmetros de apresentação
D3DPRESENT_PARAMETERS pps;
// Limpa a estrutura
ZeroMemory( &pps, sizeof(pps) );
// Configura os parâmetros de apresentação
// A aplicação vai ter janela
pps.Windowed = TRUE;
// Esse método vira rapidamente o backbuffer para a tela imediata
pps.SwapEffect = D3DSWAPEFFECT_DISCARD;
// Esse formato vai procurar se encaixar no modo de video corrente
pps.BackBufferFormat = D3DFMT_UNKNOWN;
// Configuração do renderizador a ser criado
// Adaptador default (0)
int nAdaptador = D3DADAPTER_DEFAULT;
// Tipo de dispositivo Hardware ou emulador de referência (software)
D3DDEVTYPE dispositivo_tipo = D3DDEVTYPE_HAL;
// Flags de configuração do dispositivo
DWORD create_flags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
// Criamos aqui o dispositivo renderizador
g_hr = g_Direct3d->CreateDevice( nAdaptador, dispositivo_tipo,
hJanela, create_flags, &pps, &g_device );
// Verifica se houve falha no processo
if( FAILED( g_hr ) ) {
MessageBox (NULL, "Falha na criação: g_device", "initGfx()", MB_OK);
return E_FAIL;
} // endif
// Monta as formas geométricas
montar_Geometria();
// Faz a configuração inicial da câmera
inicializar_Camera();
return S_OK;
} // initGfx().fim
2.3 Criação da câmera
void inicializar_Camera(void)
{
// ***************************************************************************
// Inicializa todas as matrizes para elemento neutro
D3DXMatrixIdentity( &g_mtxMundo );
D3DXMatrixIdentity( &g_mtxVisao );
D3DXMatrixIdentity( &g_mtxProj );
// ***************************************************************************
// Configura a matriz de mundo no dispositivo renderizador
g_device->SetTransform( D3DTS_WORLD, &g_mtxMundo );
// ***************************************************************************
// Dados para a configuração da matriz de visualização
// Aonde está a câmera? - posição da câmera
D3DXVECTOR3 cam_pos (0, 0, 5.0f);
// Para aonde a câmera está apontada ou olhando? Alvo da câmera
D3DXVECTOR3 cam_alvo (0, 0.0f, 0);
// A câmera está de cabeça pra baixo? - orientação da câmera
D3DXVECTOR3 cam_vetorcima (0, 1.0f, 0);
// Configura a matriz de visão
D3DXMatrixLookAtLH( &g_mtxVisao, &cam_pos, &cam_alvo, &cam_vetorcima );
// Configura a matriz de visão no dispositivo renderizador
g_device->SetTransform( D3DTS_VIEW, &g_mtxVisao );
// ***************************************************************************
// Argumentos de configuração da matriz de projeção
// aspecto dos gráficos
float aspecto = (float) g_xtela / g_ytela;
// campo de visão
float campo_visao = D3DX_PI / 4;
// Trapézio de visualização da câmera ( Frustrum )
float corte_perto = 1.0f;
float corte_longe = 1000.0f;
// Configura a matriz de projeção
D3DXMatrixPerspectiveFovLH( &g_mtxProj, campo_visao, aspecto,
corte_perto, corte_longe);
// Configura a matriz de projeção no dispositivo renderizador
g_device->SetTransform( D3DTS_PROJECTION, &g_mtxProj );
} // inicializar_Camera().fim
// ***************************************************************************
// Inicializa todas as matrizes para elemento neutro
D3DXMatrixIdentity( &g_mtxMundo );
D3DXMatrixIdentity( &g_mtxVisao );
D3DXMatrixIdentity( &g_mtxProj );
Aqui as matrizes tomam o valor inicial de uma matriz identidade que é
um valor neutro equivalente ao 1 da multiplicação.
// ***************************************************************************
// Configura a matriz de mundo no dispositivo renderizador
g_device->SetTransform( D3DTS_WORLD, &g_mtxMundo );
Aqui a matriz de espaço mundial é jogada ou estabelecida no dispositivo
renderizador. O método SetTransform() é utilizado para configurar as 3
matrizes no dispositivo:
g_device->SetTransform( D3DTS_WORLD, &g_mtxMundo );
g_device->SetTransform( D3DTS_VIEW, &g_mtxVisao );
g_device->SetTransform( D3DTS_PROJECTION, &g_mtxProj );
Geralmente ocorre primeiro a configuração das matrizes e depois essas
matrizes são instaladas dentro do dispositivo renderizador com
SetTransform().
// ***************************************************************************
// Dados para a configuração da matriz de visualização
// Aonde está a câmera? - posição da câmera
D3DXVECTOR3 cam_pos (0, 0, 5.0f);
// Para aonde a câmera está apontada ou olhando? Alvo da câmera
D3DXVECTOR3 cam_alvo (0, 0.0f, 0);
// A câmera está de cabeça pra baixo? - orientação da câmera
D3DXVECTOR3 cam_vetorcima (0, 1.0f, 0);
// Configura a matriz de visão
D3DXMatrixLookAtLH( &g_mtxVisao, &cam_pos, &cam_alvo, &cam_vetorcima );
// Configura a matriz de visão no dispositivo renderizador
g_device->SetTransform( D3DTS_VIEW, &g_mtxVisao );
A função D3DXMatrixLookAtLH() configura a matriz de visualização da
câmera. Veja que a função recebe 3 vetores 3d com (x, y, z) dando a
posição da câmera ( cam_pos ), o ponto de foco da câmera ( cam_alvo )
e a indicação se a câmera está ou não virada de cabeça pra baixo
( cam_vetorcima ). Lembrando que todas as matrizes são povoadas por
4 vetores com 4 elementos, portanto tem ainda um quarto vetor que
segura informação de rotação e o w que é o quarto elemento de cada
vetor que é usado para uniformizar os cálculos matemáticos em termos
de manter a multiplicação como operação base para todas as
transformações que ocorrem com estas matrizes.
// ***************************************************************************
// Argumentos de configuração da matriz de projeção
// aspecto dos gráficos
float aspecto = (float) g_xtela / g_ytela;
// campo de visão
float campo_visao = D3DX_PI / 4;
// Trapézio de visualização da câmera ( Frustrum )
float corte_perto = 1.0f;
float corte_longe = 1000.0f;
// Configura a matriz de projeção
D3DXMatrixPerspectiveFovLH( &g_mtxProj, campo_visao, aspecto,
corte_perto, corte_longe);
// Configura a matriz de projeção no dispositivo renderizador
g_device->SetTransform( D3DTS_PROJECTION, &g_mtxProj );
Esse bloco configura a matriz de projeção da imagem que geralmente é
utilizada nas últimas etapas de transformação da cena 3d para uma
imagem 2d final.
float aspecto = (float) g_xtela / g_ytela;
O aspecto ou ratio é uma razão da resolução da janela ou monitor, é uma
divisão básica da largura\altura da tela que o sistema gráfico quer saber
para desenhar as formas compensando a desprorpoção entre a largura e a
altura que se for ignorada transforma circulos em esferas ovais e produz
outras deformações na imagem.
float campo_visao = D3DX_PI / 4;
O campo de visão ou fov (field of fiew) define o ângulo que reduz ou amplia o
campo de visão da câmera.
float corte_perto = 1.0f; float corte_longe = 1000.0f;
O enquadramento do espaço, que o directx chama de frustrum define duas
áreas de corte na renderização da cena: o que está fora dessa área que
tem o formato de um trapézio deitado não é renderizado, e a
proximidade com estes limites vai provocando mudanças na escala dos
objetos.
Então, a função D3DXMatrixPerspectiveFovLH() recebe informação de
aspecto, campo de visão e informação do frustrum e configura com esses
dados a matriz de projeção que na sequência é estabelecida dentro do
dispositivo renderizador com a função SetTransform() que já vimos.
2.4 Atualização da câmera
void atualizar_Camera(void)
{
float angulo_final = 0.0f;
// Atualiza ângulo para dar movivento
g_Angulo = g_Angulo + nVelocidade;
angulo_final = g_Angulo / D3DX_PI;
// Rotaciona o triângulo indiretamente através da rotação
// dos eixos da matriz de espaço mundial.
D3DXMatrixRotationY( &g_mtxMundo, angulo_final );
// Configura a matriz de mundo no dispositivo renderizador
g_device->SetTransform( D3DTS_WORLD, &g_mtxMundo );
} // atualizar_Camera().fim
float angulo_final = 0.0f;
Essa variável vai receber o ângulo final de rotação do triângulo.
// Atualiza ângulo para dar movivento
g_Angulo = g_Angulo + nVelocidade;
angulo_final = g_Angulo / D3DX_PI;
Aqui é o cálculo do ângulo final. Inicialmente a variável g_Angulo
é incrementada com nVelocidade para rotacionar o triângulo e na
sequência é dividida por pi ( D3DX_PI ) para não rotacionar muito
rápido.
D3DXMatrixRotationY( &g_mtxMundo, angulo_final );
A função D3DXMatrixRotationY() recebe um ângulo e devolve uma matriz
de rotação no eixo y. Para rodar no eixo x e z basta usar as funções
primas D3DXMatrixRotationX() e D3DXMatrixRotationZ(). Para rodar nos
3 eixos simultâneamente use a função D3DXMatrixRotationYawPitchRoll()
que faz esse trabalho na ordem (y, x, z). A rotação no eixo y é
chamada Yaw; no eixo x é chamada Pitch e no eixo z é Roll.
Nestas funções de rotação o ângulo de entrada deve ser expresso em
radianos. No arquivo d3dx9math.h está definido duas macros para
coverter radianos para graus e vice-versa:
#define D3DXToDegree( radian ) ((radian) * (180.0f / D3DX_PI))
#define D3DXToRadian( degree ) ((degree) * (D3DX_PI / 180.0f))
// Configura a matriz de mundo no dispositivo renderizador
g_device->SetTransform( D3DTS_WORLD, &g_mtxMundo );
Aqui finalmente a matriz de mundo é configurada no dispositivo
renderizador. Esses passos vistos aqui nesta função rotaciona o
triângulo e geralmente esses passos são aplicados em cada objeto da
cena 3d para produzir a movimentação, rotação e escala dos mesmos.
Ao longo das próximas aplicações vamos conhecer as outras funções que
produzem matrizes de escala e movimentação.
2.5 Renderização da cena - Parte 1/2
// -----------------------------------------------------------------------------
// Renderizar() - Desenha a cena
// -----------------------------------------------------------------------------
VOID Renderizar()
{
// Retorne se o dispositivo estiver nulo
if( g_device == NULL) return;
// Limpa o backbuffer com uma cor branca
g_device->Clear( 0, NULL, D3DCLEAR_TARGET, branco, 1.0f, 0);
// Mostra a parte interna do polígono
// Experimente desativar essa linha com a instrução de comentário
g_device->SetRenderState (D3DRS_CULLMODE, D3DCULL_NONE);
// Utiliza iluminação default
// Experimente desativar essa linha com a instrução de comentário
g_device->SetRenderState (D3DRS_LIGHTING, false);
// Atualize a câmera
atualizar_Camera();
// Começa a cena
if( SUCCEEDED( g_device->BeginScene() ) )
{
// Vamos renderizar as formas geométricas
renderizar_Geometria();
// Finalizando a cena
g_device->EndScene();
} // endif
// Apresenta o conteúdo do backbuffer na tela
g_device->Present( NULL, NULL, NULL, NULL);
} // Renderizar().fim
// Limpa o backbuffer com uma cor branca
g_device->Clear( 0, NULL, D3DCLEAR_TARGET, branco, 1.0f, 0);
Essa função você já conhece mas não conhece a ausência dela. Esta arte
foi produzida com a exclusão dessa função com comentários ( // ) e
rodando o triângulo no eixo z:
g_device->SetRenderState (D3DRS_CULLMODE, D3DCULL_NONE);
Essa função desativa o culling. Experimente excluir essa função com a
instrução de comentários e veja que o triângulo desaparece por um
momento ao mostrar as costas invisíveis para a câmera.
g_device->SetRenderState (D3DRS_LIGHTING, false);
Desta forma como está apresentada, esta linha habilita a iluminação
default. Experimente a exclusão dessa linha.
atualizar_Camera();
Aqui a câmera é atualizada para rotacionar o triângulo um pouco antes
do processo de renderização dos vértices.
2.6 Montagem da geometria
void montar_Geometria(void)
{
// Posicionamento de profundidade
float zpos = 0.0f;
// p0 - primeiro vértice
g_Vertices[0] = CustomVertex_PositionColored( 0.0f, 1.0f, zpos, vermelho);
// p1 - segundo vértice
g_Vertices[1] = CustomVertex_PositionColored( -1.0f, -1.0f, zpos, verde);
// p2 - terceiro vértice
g_Vertices[2] = CustomVertex_PositionColored( 1.0f, -1.0f, zpos, azul);
} // montar_Geometria().fim
// p0 - primeiro vértice
g_Vertices[0] = CustomVertex_PositionColored( 0.0f, 1.0f, zpos, vermelho);
A novidade da função montar_Geometria() é esse formato de vértice com
posições não-transformadas que indicam a posição de cada vértice em
relação a cada outro vértice do triângulo. Dizemos que o triângulo foi
construído em um espaço local de referência.
O triângulo para chegar como imagem 2d primeiro é transformado para o
espaço mundial, depois é transformado para o espaço de câmera ou de
visualização e depois é transformado pela matriz de projeção para
aparecer finalmente como imagem 2d na tela do usuário.
2.7 Renderização da cena - Parte 2/2
A novidade da função renderizar_Geometria() é o ajuste no formato de
vértice para posicionado e colorido.
void renderizar_Geometria()
{
// Configura formato de vértice no dispositivo
g_device->SetFVF( CustomVertex_PositionColored_Format);
// Quantidade de primitivas possíveis de acordo com o uso de vértices
UINT nContagem = 1;
// Tamanho do passo para achar o próximo vértice
UINT nPasso = sizeof(CustomVertex_PositionColored);
// Desenha forma geométrica
g_device->DrawPrimitiveUP( D3DPT_TRIANGLELIST, nContagem, &g_Vertices, nPasso);
} // renderizar_Geometria().fim
3. Código fonte do projeto de exemplo: prj_Triangulo3d
// Projeto: prj_Triangulo3d - Arquivo: motor.h
// Esta aplicação ilustra como configurar uma câmera e
// renderizar um triângulo 3d. By www.gameprog.com.br
#ifndef motor_h
#define motor_h
// Esta função inicializa o Direct3D
HRESULT initGfx (
HWND hJanela);
// Essa função libera os objetos utilizados
void Limpar();
// Essa função desenha a cena
void Renderizar();
// Essa função monta formas geométricas
void montar_Geometria (
void);
// Configura a câmera 3d da cena
void inicializar_Camera(
void);
// Atualiza a câmera
void atualizar_Camera(
void);
// Renderiza os vértices em formas geométricas
void renderizar_Geometria (
void);
// Declaração da função que atende as mensagens da janela
LRESULT CALLBACK processaJanela (
HWND hJanela,
UINT mensagem,
WPARAM wParam,
LPARAM lParam);
#endif
// -----------------------------------------------------------------------------
// Projeto: prj_Triangulo3d - arquivo: motor.cpp
// Esta aplicação ilustra como configurar uma câmera e
// renderizar um triângulo 3d. By www.gameprog.com.br
// -----------------------------------------------------------------------------
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <stdio.h>
#include "motor.h"
// Inclui as bibliotecas do Direct3D
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
// Variáveis globais
// Representa o dispositivo Direct3D
LPDIRECT3D9 g_Direct3d = NULL;
// Representa o dispositivo Renderizador
IDirect3DDevice9* g_device = NULL;
// Essa variável recebe informação de erro do Directx
HRESULT g_hr = 0;
// Variáveis para controlar a rotação do triângulo
float g_Angulo = 0.0f;
const float nVelocidade = 0.2f;
// Matrizes de configuração da câmera
// Matriz de mundo
D3DXMATRIX g_mtxMundo;
// Matriz de visão
D3DXMATRIX g_mtxVisao;
// Matriz de projeção
D3DXMATRIX g_mtxProj;
// Tamanho da janela
extern int g_xtela;
extern int g_ytela;
// Constante para cores
const DWORD vermelho = 0xFFFF0000;
const DWORD branco = 0xFFFFFFFF;
const DWORD verde = 0xFF00FF00;
const DWORD azul = 0xFF0000FF;
// Definição do formato de vértice utilizado pela aplicação
#define CustomVertex_PositionColored_Format(D3DFVF_XYZ | D3DFVF_DIFFUSE)
// Definição da estrutura de vértice customizado
struct CustomVertex_PositionColored
{
float x, y, z;
DWORD cor;
// Construtor default
CustomVertex_PositionColored() {}
// Construtor com inicialização
CustomVertex_PositionColored( float _x, float _y, float _z, DWORD _cor)
{
x = _x;
y = _y;
z = _z;
cor = _cor;
} // fim do construtor
}; // fim da estrutura CustomVertex_PositionColored
// Declaração dos vértices para o triângulo
CustomVertex_PositionColored g_Vertices[3 ];
// initGfx() - Inicializa o Direct3D
HRESULT initGfx( HWND hJanela )
{
// Cria o objeto Direct3D que é necessário para criar o dispositivo gráfico
g_Direct3d = Direct3DCreate9( D3D_SDK_VERSION);
// Verifica se objeto Direct3D foi criado
if(g_Direct3d == NULL)
{
MessageBox (NULL,
"Falha na inialização do Direct3D", "InitGfx()", MB_OK);
return E_FAIL;
} // endif
// Declara a variável para os parâmetros de apresentação
D3DPRESENT_PARAMETERS pps;
// Limpa a estrutura
ZeroMemory( &pps, sizeof(pps) );
// Configura os parâmetros de apresentação
// A aplicação vai ter janela
pps.Windowed = TRUE;
// Esse método vira rapidamente o backbuffer para a tela imediata
pps.SwapEffect = D3DSWAPEFFECT_DISCARD;
// Esse formato vai procurar se encaixar no modo de video corrente
pps.BackBufferFormat = D3DFMT_UNKNOWN;
// Configuração do renderizador a ser criado
// Adaptador default (0)
int nAdaptador = D3DADAPTER_DEFAULT;
// Tipo de dispositivo Hardware ou emulador de referência (software)
D3DDEVTYPE dispositivo_tipo = D3DDEVTYPE_HAL;
// Flags de configuração do dispositivo
DWORD create_flags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
// Criamos aqui o dispositivo renderizador
g_hr = g_Direct3d->CreateDevice( nAdaptador, dispositivo_tipo,
hJanela, create_flags, &pps, &g_device );
// Verifica se houve falha no processo
if( FAILED( g_hr ) ) {
MessageBox (NULL, "Falha na criação: g_device", "initGfx()", MB_OK);
return E_FAIL;
} // endif
// Monta as formas geométricas
montar_Geometria();
// Faz a configuração inicial da câmera
inicializar_Camera();
return S_OK;
} // initGfx().fim
void inicializar_Camera(void)
{
// ***************************************************************************
// Inicializa todas as matrizes para elemento neutro
D3DXMatrixIdentity( &g_mtxMundo );
D3DXMatrixIdentity( &g_mtxVisao );
D3DXMatrixIdentity( &g_mtxProj );
// ***************************************************************************
// Configura a matriz de mundo no dispositivo renderizador
g_device->SetTransform( D3DTS_WORLD, &g_mtxMundo );
// ***************************************************************************
// Dados para a configuração da matriz de visualização
// Aonde está a câmera? - posição da câmera
D3DXVECTOR3 cam_pos (0, 0, 5.0f);
// Para aonde a câmera está apontada ou olhando? Alvo da câmera
D3DXVECTOR3 cam_alvo (0, 0.0f, 0);
// A câmera está de cabeça pra baixo? - orientação da câmera
D3DXVECTOR3 cam_vetorcima (0, 1.0f, 0);
// Configura a matriz de visão
D3DXMatrixLookAtLH( &g_mtxVisao, &cam_pos, &cam_alvo, &cam_vetorcima );
// Configura a matriz de visão no dispositivo renderizador
g_device->SetTransform( D3DTS_VIEW, &g_mtxVisao );
// ***************************************************************************
// Argumentos de configuração da matriz de projeção
// aspecto dos gráficos
float aspecto = (float) g_xtela / g_ytela;
// campo de visão
float campo_visao = D3DX_PI / 4;
// Trapézio de visualização da câmera ( Frustrum )
float corte_perto = 1.0f;
float corte_longe = 1000.0f;
// Configura a matriz de projeção
D3DXMatrixPerspectiveFovLH( &g_mtxProj, campo_visao, aspecto,
corte_perto, corte_longe);
// Configura a matriz de projeção no dispositivo renderizador
g_device->SetTransform( D3DTS_PROJECTION, &g_mtxProj );
} // inicializar_Camera().fim
void atualizar_Camera(void)
{
float angulo_final = 0.0f;
// Atualiza ângulo para dar movivento
g_Angulo = g_Angulo + nVelocidade;
angulo_final = g_Angulo / D3DX_PI;
// Rotaciona o triângulo indiretamente através da rotação
// dos eixos da matriz de espaço mundial.
D3DXMatrixRotationY( &g_mtxMundo, angulo_final );
// Configura a matriz de mundo no dispositivo renderizador
g_device->SetTransform( D3DTS_WORLD, &g_mtxMundo );
} // atualizar_Camera().fim
// -----------------------------------------------------------------------------
// Renderizar() - Desenha a cena
// -----------------------------------------------------------------------------
VOID Renderizar()
{
// Retorne se o dispositivo estiver nulo
if( g_device == NULL) return;
// Limpa o backbuffer com uma cor branca
g_device->Clear( 0, NULL, D3DCLEAR_TARGET, branco, 1.0f, 0);
// Mostra a parte interna do polígono
// Experimente desativar essa linha com a instrução de comentário
g_device->SetRenderState (D3DRS_CULLMODE, D3DCULL_NONE);
// Utiliza iluminação default
// Experimente desativar essa linha com a instrução de comentário
g_device->SetRenderState (D3DRS_LIGHTING, false);
// Atualize a câmera
atualizar_Camera();
// Começa a cena
if( SUCCEEDED( g_device->BeginScene() ) )
{
// Vamos renderizar as formas geométricas
renderizar_Geometria();
// Finalizando a cena
g_device->EndScene();
} // endif
// Apresenta o conteúdo do backbuffer na tela
g_device->Present( NULL, NULL, NULL, NULL);
} // Renderizar().fim
void montar_Geometria(void)
{
// Posicionamento de profundidade
float zpos = 0.0f;
// p0 - primeiro vértice
g_Vertices[0] = CustomVertex_PositionColored( 0.0f, 1.0f, zpos, vermelho);
// p1 - segundo vértice
g_Vertices[1] = CustomVertex_PositionColored( -1.0f, -1.0f, zpos, verde);
// p2 - terceiro vértice
g_Vertices[2] = CustomVertex_PositionColored( 1.0f, -1.0f, zpos, azul);
} // montar_Geometria().fim
void renderizar_Geometria()
{
// Configura formato de vértice no dispositivo
g_device->SetFVF( CustomVertex_PositionColored_Format);
// Quantidade de primitivas possíveis de acordo com o uso de vértices
UINT nContagem = 1;
// Tamanho do passo para achar o próximo vértice
UINT nPasso = sizeof(CustomVertex_PositionColored);
// Desenha forma geométrica
g_device->DrawPrimitiveUP( D3DPT_TRIANGLELIST, nContagem, &g_Vertices, nPasso);
} // renderizar_Geometria().fim
// Esta função é chamada por DispatchMessage()
LRESULT CALLBACK processaJanela (HWND hJanela, UINT mensagem,
WPARAM wParam, LPARAM lParam)
{
switch (mensagem)
{
case WM_DESTROY:
// Coloca uma mensagem WM_QUIT na fila de mensagem
Limpar();
PostQuitMessage (0);
break;
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
{
Limpar();
PostQuitMessage( 0);
} // endif
break;
// Essa mensagem vai ocorrer a todo momento
case WM_PAINT:
// Renderiza a cena
Renderizar();
// Invalida a tela para chamar WM_PAINT novamente
InvalidateRect( hJanela, NULL, false);
break;
// Processamento default de mensagens não tratada pela aplicação
default:
return DefWindowProc (hJanela, mensagem, wParam, lParam);
} // endswitch
return 0;
} // processaJanela().fim
// Limpar() - Libera todos os objetos previamente inicializados
// -----------------------------------------------------------------------------
VOID Limpar()
{
// Libera o dispositivo gráfico
if( g_device != NULL) g_device->Release();
// Libera o motor do Direct3D
if( g_Direct3d != NULL) g_Direct3d->Release();
} // Limpar().fim
//-----------------------------------------------------------------------------
// Projeto: prj_Triangulo3d - arquivo: entrada.cpp
// Esta aplicação ilustra como configurar uma câmera e
// renderizar um triângulo 3d. By www.gameprog.com.br
//-----------------------------------------------------------------------------
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#include "motor.h"
// Variável global da classe da janela
char sclasseJanela[ ] = "cls_directx";
// Dimensões da janela
int g_xtela = 640;
int g_ytela = 480;
int WINAPI WinMain (HINSTANCE app_instancia, HINSTANCE app_anterior,
LPSTR sComando,int nExibir) {
// alça da janela
HWND hJanela;
// Estrutura de recepção das mensagens
MSG mensagem;
// Estrutura de descrição da janela
WNDCLASSEX wcls;
// Estrutura que descreve a janela
wcls.hInstance = app_instancia;
wcls.lpszClassName = sclasseJanela;
wcls.lpfnWndProc = processaJanela;
wcls.style = CS_HREDRAW | CS_VREDRAW;
wcls.cbSize = sizeof (WNDCLASSEX);
// O cursor e os ícones da aplicação são default
wcls.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wcls.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wcls.hCursor = LoadCursor (NULL, IDC_ARROW);
// Aplicação sem menu
wcls.lpszMenuName = NULL;
// Nada de espaço extra atrelado a classe da janela (wcls)
wcls.cbClsExtra = 0;
// Nada de espaço extra atrelado a janela
wcls.cbWndExtra = 0;
// Cor default da janela
wcls.hbrBackground = ( HBRUSH) COLOR_BACKGROUND;
// Registra a janela e retorna se esta operação falhar
int status = RegisterClassEx (&wcls);
if(status == 0) {
MessageBox(NULL, "Registro falhou!", "WinMain()", MB_OK);
return 0;
} // endif
// Com a classe criada pode-se criar a janela
DWORD estiloExtra = 0;
const char janelaTitulo[] = "prj_Triangulo3d";
DWORD controleEstilo = WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX;
int xpos = 160;
int ypos = 120;
HWND hjanelaPai = HWND_DESKTOP;
HMENU sem_menu = NULL;
LPVOID dadoExtra = NULL;
// Cria a janela
hJanela = CreateWindowEx(estiloExtra, sclasseJanela, janelaTitulo,
controleEstilo, xpos, xpos, g_xtela, g_ytela, hjanelaPai, sem_menu,
app_instancia, dadoExtra );
// Verifica se janela foi criada
if(hJanela == NULL) {
MessageBox(NULL, "Falha na criação da janela!", "WinMain()", MB_OK);
return 0;
} // endif
// Essa variável recebe informação de erro do Directx
HRESULT hr;
// Inicia o Direct3D
hr = initGfx ( hJanela );
// Encerre a aplicação se houve falha
if(FAILED (hr) ) {
MessageBox (hJanela,
"Direct3D: falha na inicialização", "WinMain()", MB_OK);
UnregisterClass( sclasseJanela, wcls.hInstance);
return E_FAIL;
} // endif
// Mostra a janela
ShowWindow(hJanela, nExibir);
UpdateWindow(hJanela );
// Rode a bombeamento de mensagens até GetMessage() retornar 0
while (GetMessage(&mensagem, NULL, 0, 0))
{
// Traduz mensagem de tecla virtual em mensagem de caracteres
TranslateMessage( &mensagem );
// Despacha a mensagem para a função processaJanela */
DispatchMessage( &mensagem );
} // endwhile
// O valor de retorno é zero(0) passado por PostQuitMessage()
UnregisterClass( sclasseJanela, wcls.hInstance);
return mensagem.wParam;
} // WinMain().fim