Curso completo de DirectX 9 com C\C++
Gameprog - Escola de programação de jogos digitais
Contato: gameprog.br@gmail.com
Fase 01-10

index << >>


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

index << >>

Produzido por Gameprog: Jair Pereira - Agosto/2014 © gameprog.br@gmail.com http://www.gameprog.com.br