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

index << >>


06.4 Produção de partículas

1.1 Visão geral
1.2 Estrutura principal da aplicação
2.1 Aspectos globais: arquivo motor.h
2.2 Aspectos globais: arquivo motor.cpp
2.3 initGfx()                 -  Inicialização do motor gráfico (Direct3D)
2.4 inicializar_Pointsprite() - Inicialização das partículas
2.5 renderizar_Pointsprite()  - Renderização das partículas
2.6 Renderizar()              - Renderização da cena
Anx. Código fonte do projeto de exemplo: prj_Pointsprite

[topo] 1.1 Visão geral
A aplicação desse exemplo mostra como utilizar o suporte que o directx dá na construção de um sistema de partículas. A base do sistema de partículas reside em um recurso chamado pointsprite que transforma cada vértice no centro de um quad texturizável. Geralmente o quad é texturizado com uma pequena imagem que quando combinada com os efeitos de alpha blending dá origem aos efeitos especiais de partículas. A partir desse momento vamos utilizar o termo pontosprite ocasionalmente para nos referirmos também ao recurso de pointsprite. Não há uma interface dedicada para utilizar o pontosprite e assim a implementação de um sistema de partículas é baseado numa configuração particular do formato de vértice, do vertexbuffer e da configuração de certos estados de renderização. A partícula Através do uso interno de alpha blending essa partícula ganhará a cor do vértice. Visto que o fundo da imagem é preto, a cor de limpeza do backbuffer é preto para ocorrer a mistura adequada da partícula na cena.
[topo] 1.2 Estrutura principal da aplicação
Arquivo: motor.cpp
inicializar_Pointsprite() Habilita o uso de pointsprites e configura os estados pertinentes Configura os fatores de escala que contribuem na definição do tamanho final da partícula Habilita a iluminação automática. Desliga o uso do buffer de profundidade. Configura os estados do recurso de alpha blending. Configura formato de vértice com g_device->SetFVF( CustomVertex_PointSprite_Format ) Elabora e configura o vertexbuffer Carrega a textura da partícula renderizar_Pointsprite() Configura matriz mundo do sistema de partículas com posição e rotação. Declara a textura e o vertexbuffer ao dispositivo renderizador. Renderiza as partículas com g_device->DrawPrimitive(D3DPT_POINTLIST, 0, 4) Atualiza ângulo de rotação das partículas inicializar_Camera() Faz a preparação inicial da câmera Obtém as dimensões reais da área desenhável para produzir aspecto correto dos gráficos na matriz de projeção. initGfx() // (...) chama inicializar_Camera() para a configuração inicial da câmera chama inicializar_Pointsprite() para inicializar os objetos e estados pertinentes da produção de partículas. Renderizar() Limpa a tela chama renderizar_Pointsprite() para renderizar as partículas. Apresenta a cena Limpar() Libera os objetos utilizados.
[topo] 2.1 Aspectos globais - arquivo motor.h
#ifndef motor_h #define motor_h // Definição do formato de vértice de suporte ao pontosprite #define CustomVertex_PointSprite_Format (D3DFVF_XYZ | D3DFVF_PSIZE | D3DFVF_DIFFUSE) // Formato de vértice de suporte ao ponto sprite struct CustomVertex_PointSprite { // Posição e tamanho do pontosprite float x, y, z, nTamanho; // Cor do pontosprite DWORD dwCor; }; // Inicializar a configuração de pointsprite void inicializar_Pointsprite(void); // Renderiza o objeto Pointsprite void renderizar_Pointsprite(); // 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(); // Configuração inicial da câmera void inicializar_Camera(void); // Declaração da função que atende as mensagens da janela LRESULT CALLBACK processaJanela ( HWND hJanela, UINT mensagem, WPARAM wParam, LPARAM lParam); #endif
Definição do formato de vértice de suporte ao pontosprite #define CustomVertex_PointSprite_Format (D3DFVF_XYZ | D3DFVF_PSIZE | D3DFVF_DIFFUSE) A chave da implementação de um sistema de partículas reside fortemente no formato de vértice que traz uma posição 3d ( D3DFVF_XYZ ), o tamanho da partícula dado em um tipo float ( D3DFVF_PSIZE ) e uma cor D3DFVF_DIFFUSE codificada no tipo DWORD. Formato de vértice de suporte ao ponto sprite
struct CustomVertex_PointSprite { // Posição e tamanho do pontosprite float x, y, z, nTamanho; // Cor do pontosprite DWORD dwCor; };
Aqui está a estrutura que tipifica o formato de vértice que será utilizado para produzir cada partícula. Posteriormente no espaço global vamos criar uma array de vértices ( g_Pontos ) contendo 4 vértices posicionados na formação de um quadrado. void inicializar_Pointsprite(void); Essa função inicializa os objetos e configura os estados que vão compor as partículas. Isso envolve produzir o vertexbuffer com uma configuração específica para receber pointsprites, configurar o recurso de alpha blending e alguns fatores que determinam o tamanho final da partícula na cena. void renderizar_Pointsprite(); Essa função renderiza as partículas. Isso envolve declarar a textura e o vertexbuffer para o dispositivo renderizador e também configurar a matriz mundo do sistema de partículas. A partícula é representada pela primitiva do tipo D3DPT_POINTLIST. [topo] 2.2 Aspectos globais: arquivo motor.cpp
// Preparação para pointsprites // ---------------------------------------------------------------------------- // Vertexbuffer IDirect3DVertexBuffer9 *g_pVertexbuffer = NULL; // Textura IDirect3DTexture9 *g_pTex = NULL; // matriz de posição e orientação do pontosprite D3DXMATRIX g_mtxPos, g_mtxRot; // Tamanho de cada sprite const float nTamanho = 6.0f; // Posição, tamanho e cor de cada pontosprite CustomVertex_PointSprite g_Pontos[] = { { -100.0f, 100.0f, 5.0f, nTamanho, amarelo }, { 100.0f, -100.0f, 5.0f, nTamanho, azul }, { -100.0f, -100.0f, 5.0f, nTamanho, verde }, { 100.0f, 100.0f, 5.0f, nTamanho, vermelho } }; // Controla o ângulo de rotação do objeto 3d float g_angulo = 0.0f; // Ponteiro de acesso aos dados do vertexbuffer void *g_pDados;
Segue abaixo os objetos e estruturas que vão dar o suporte existencial das partículas:
IDirect3DVertexBuffer9 *g_pVertexbuffer = NULL; IDirect3DTexture9 *g_pTex = NULL;
Aqui estão a interface de textura e de vertexbuffer do sistema de partículas. D3DXMATRIX g_mtxPos, g_mtxRot; Estas matrizes vão receber posição e rotação e na sequência são usadas na montagem da matriz mundo do sistema de partículas. const float nTamanho = 6.0f; Essa constante define o tamanho das sprites na tela. Usamos o mesmo valor para todas entretanto poderia ser definido um valor individual para cada partícula. Array de vértices
// Posição, tamanho e cor de cada pontosprite CustomVertex_PointSprite g_Pontos[] = { { -100.0f, 100.0f, 5.0f, nTamanho, amarelo }, { 100.0f, -100.0f, 5.0f, nTamanho, azul }, { -100.0f, -100.0f, 5.0f, nTamanho, verde }, { 100.0f, 100.0f, 5.0f, nTamanho, vermelho } };
Esse bloco de vértices vai dar origem ao sistema de partículas. O directx transforma cada vértice em um quad texturizado e colorido. Na ordem das coisas cada elemento dessa array é copiado para o vertexbuffer ( g_pVertexbuffer ) do sistema de partículas. void *g_pDados; Esse ponteiro é usado para acessar a área de dados do vertexbuffer para o preenchimento do mesmo com os elementos da array acima. float g_angulo = 0.0f; Esta variável é utilizada para animar a rotação das partículas. [topo] 2.3 initGfx() - Inicialização do motor gráfico (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 o 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) ); // Vamos ativar o buffer de profundidade pps.EnableAutoDepthStencil = true; pps.AutoDepthStencilFormat = D3DFMT_D16; // Configura os parâmetros de apresentação // A aplicação vai ter janela pps.Windowed = TRUE; // Esse método transfere rapidamente o backbuffer para a tela imediata pps.SwapEffect = D3DSWAPEFFECT_DISCARD; // Esse formato vai permitir o uso de alpha blending pps.BackBufferFormat = D3DFMT_A8R8G8B8; // 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 // Configura a câmera inicializar_Camera(); // Inicializa o ambiente e objetos pertinentes da produção // de pointsprites. inicializar_Pointsprite(); return S_OK; } // initGfx().fim
inicializar_Pointsprite(); Essa função é chamada em initGfx() para inicializar o ambiente e os objetos pertinentes da produção de pointsprites. [topo] 2.4 inicializar_Pointsprite()- Inicialização das partículas
void inicializar_Pointsprite(void) { // Configuração dos estados pertinentes a sprites g_device->SetRenderState(D3DRS_POINTSPRITEENABLE, true); g_device->SetRenderState(D3DRS_POINTSCALEENABLE, true); // Configuração de tamanho de ponto float nPointSize = 1.0f; g_device->SetRenderState(D3DRS_POINTSIZE, *((DWORD*) &nPointSize)); // Configuração do tamanho mínimo float nMinPointSize = 1.0f; g_device->SetRenderState(D3DRS_POINTSIZE_MIN, *((DWORD*) &nMinPointSize)); // Configuração do fator de escala float nPointScaleB = 1.0f; g_device->SetRenderState(D3DRS_POINTSCALE_B, *((DWORD*) &nPointScaleB)); // Aciona iluminação automática g_device->SetRenderState(D3DRS_LIGHTING, false); // Desliga uso do z buffer g_device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); // Configuração de alpha blending g_device->SetRenderState(D3DRS_ALPHABLENDENABLE, true); g_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); g_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO); // Configura o formato de vértice g_device->SetFVF( CustomVertex_PointSprite_Format); // Elaboração do vertexbuffer g_device->CreateVertexBuffer(sizeof( g_Pontos), D3DUSAGE_POINTS | D3DUSAGE_WRITEONLY, CustomVertex_PointSprite_Format, D3DPOOL_MANAGED, &g_pVertexbuffer, NULL); // Tranca o vertexbuffer para inicializar o ponteiro de dados g_pVertexbuffer->Lock(0, 0, &g_pDados, 0); // Transfere os dados para o vertexbuffer memcpy(g_pDados, g_Pontos, sizeof(g_Pontos) ); // Destranca o vertexbuffer g_pVertexbuffer->Unlock(); // Carrega a textura D3DXCreateTextureFromFile(g_device, "particula.png", &g_pTex); } // inicializar_Pointsprite()
g_device->SetRenderState(D3DRS_POINTSPRITEENABLE, true); Habilitamos aqui o uso de pointsprites. g_device->SetRenderState(D3DRS_POINTSCALEENABLE, true); Habilitamos aqui o uso de fatores de escala na contribuição do tamanho final da partícula. Os fatores que impactam no tamanho final da partícula estão definidos logo abaixo. Configuração dos fatores de escala
// Configuração de tamanho de ponto float nPointSize = 1.0f; g_device->SetRenderState(D3DRS_POINTSIZE, *((DWORD*) &nPointSize)); // Configuração do tamanho mínimo float nMinPointSize = 1.0f; g_device->SetRenderState(D3DRS_POINTSIZE_MIN, *((DWORD*) &nMinPointSize)); // Configuração do fator de escala float nPointScaleB = 1.0f; g_device->SetRenderState(D3DRS_POINTSCALE_B, *((DWORD*) &nPointScaleB));
Este bloco configura os fatores de escala que impactam no tamanho final da partícula. g_device->SetRenderState(D3DRS_LIGHTING, false); Aqui desligamos a iluminação manual para utilizarmos a iluminação automática default. g_device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); Desligamos o uso do buffer de profundidade. Configuração de alpha blending
g_device->SetRenderState(D3DRS_ALPHABLENDENABLE, true); g_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); g_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);
Este bloco faz a configuração do recurso de alpha blending. Essa configuração vai permitir a cor do formato de vértice tomar conta totalmente da cor branca presente na textura da partícula. g_device->SetFVF( CustomVertex_PointSprite_Format); Apontamos aqui o formato de vértice adequado para renderizar pointsprites. Elaboração do vertexbuffer
g_device->CreateVertexBuffer(sizeof( g_Pontos), D3DUSAGE_POINTS | D3DUSAGE_WRITEONLY, CustomVertex_PointSprite_Format, D3DPOOL_MANAGED, &g_pVertexbuffer, NULL);
Esta linha faz a criação do vertexbuffer. O ponto mais chave na especificação do sistema de partículas é a declaração de uso com o flag D3DUSAGE_POINTS que indica a presença de pointsprites no vertexbuffer. g_pVertexbuffer->Lock(0, 0, &g_pDados, 0); Aqui trancamos o vertexbuffer para desta forma inicializar o ponteiro com o endereço inicial da área de dados do mesmo. memcpy(g_pDados, g_Pontos, sizeof(g_Pontos) ); Nesta linha copiamos nossa array de vértices para o vertexbuffer. g_pVertexbuffer->Unlock(); Aqui liberamos o vertexbuffer para uso do directx. D3DXCreateTextureFromFile(g_device, "particula.png", &g_pTex); Aqui carregamos a textura que deve estar na pasta do projeto da aplicação e também estar presente no diretório do executável para a aplicação funcionar fora do ambiente do visual studio. [topo] 2.5 renderizar_Pointsprite() - Renderização das partículas
void renderizar_Pointsprite() { // Configura transformação do objeto Pointsprite D3DXMatrixRotationZ(&g_mtxRot, g_angulo ); D3DXMatrixTranslation(&g_mtxPos, 0.0f, 0.0f, 0.0f); g_device->SetTransform(D3DTS_WORLD, &( g_mtxRot * g_mtxPos ) ); // Declara a textura e o vertexbuffer g_device->SetTexture(0, g_pTex); g_device->SetStreamSource(0, g_pVertexbuffer, 0, sizeof( CustomVertex_PointSprite) ); // Desenha o objeto pointsprite g_device->DrawPrimitive(D3DPT_POINTLIST, 0, 4); // Atualiza ângulo para a próxima renderização g_angulo += 0.10f; } // renderizar_Pointsprite().fim
Definição da matriz mundo
D3DXMatrixRotationZ (&g_mtxRot, g_angulo ); D3DXMatrixTranslation ( &g_mtxPos, 0.0f, 0.0f, 0.0f); g_device->SetTransform(D3DTS_WORLD, &( g_mtxRot * g_mtxPos ) );
Gradualmente definimos aqui a matriz mundo que comporta a posição e rotação do sistema de partículas. Declaração da textura e do vertexbuffer ao dispositivo gráfico:
g_device->SetTexture(0, g_pTex); g_device->SetStreamSource(0, g_pVertexbuffer, 0, sizeof( CustomVertex_PointSprite) );
g_device->DrawPrimitive(D3DPT_POINTLIST, 0, 4); Aqui é a forma de se desenhar adequadamente o sistema de partículas. g_angulo += 0.10f; A atualização dessa variável a cada frame garante a rotação animada do sistema de partículas. [topo] 2.6 Renderizar() - Renderização da cena
VOID Renderizar() { // Fundo preto para combinar com o fundo da textura do pontosprite const DWORD dwPreto = 0; // 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 | D3DCLEAR_ZBUFFER, dwPreto, 1.0f, 0); // Começa a cena if( SUCCEEDED( g_device->BeginScene() ) ) { renderizar_Pointsprite(); // Finalizando a cena g_device->EndScene(); } // endif // Apresenta o conteúdo do backbuffer na tela g_device->Present( NULL, NULL, NULL, NULL); } // Renderizar().fim
const DWORD dwPreto = 0; A cor de fundo do backbuffer foi definida como preto para combinar com o fundo preto da textura do pontosprite. renderizar_Pointsprite(); Essa função é chamada para renderizar o sistema de partículas.
[topo] Anx. Código fonte do projeto de exemplo: prj_Pointsprite
// ----------------------------------------------------------------------------- // Projeto: prj_PointSprite - Arquivo: motor.h // Esta aplicação mostra como renderizar partículas com pontosprites // By www.gameprog.com.br // ----------------------------------------------------------------------------- #include <d3d9.h> #include <d3dx9.h> // Inclui as bibliotecas do Direct3D #pragma comment(lib, "d3d9.lib") #pragma comment(lib, "d3dx9.lib") #ifndef motor_h #define motor_h // Definição do formato de vértice de suporte ao pontosprite #define CustomVertex_PointSprite_Format (D3DFVF_XYZ | D3DFVF_PSIZE | D3DFVF_DIFFUSE) // Formato de vértice de suporte ao ponto sprite struct CustomVertex_PointSprite { // Posição e tamanho do pontosprite float x, y, z, nTamanho; // Cor do pontosprite DWORD dwCor; }; // Inicializar a configuração de pointsprite void inicializar_Pointsprite(void); // Renderiza o objeto Pointsprite void renderizar_Pointsprite(); // 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(); // Configuração inicial da câmera void inicializar_Camera(void); // Declaração da função que atende as mensagens da janela LRESULT CALLBACK processaJanela ( HWND hJanela, UINT mensagem, WPARAM wParam, LPARAM lParam); #endif // fim do arquivo: motor.h
// ----------------------------------------------------------------------------- // Projeto: prj_PointSprite - arquivo: motor.cpp // Esta aplicação mostra como renderizar partículas com pontosprites // By www.gameprog.com.br // ----------------------------------------------------------------------------- #include <windows.h> #include <d3d9.h> #include <d3dx9.h> #include <string.h> #include "motor.h" // Desliga aviso de 'função insegura' devido ao uso das // funções de string antigas( strcat etc->. ) #pragma warning( disable:4996 ) // Variáveis globais // Representa o dispositivo Direct3D IDirect3D9 *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; // Tamanho da janela extern int g_xtela; extern int g_ytela; extern HWND hJanela; // Constante para cores const DWORD branco = 0xFFFFFFFF; const DWORD vermelho = 0xFFFF0000; const DWORD verde = 0xFF00FF00; const DWORD azul = 0xFF0000FF; const DWORD amarelo = 0xFFFFFF00; // Matrizes de configuração da câmera D3DXMATRIX g_mtxMundo; D3DXMATRIX g_mtxVisao; D3DXMATRIX g_mtxProj; // Preparação para pointsprites // ---------------------------------------------------------------------------- // Vertexbuffer IDirect3DVertexBuffer9 *g_pVertexbuffer = NULL; // Textura IDirect3DTexture9 *g_pTex = NULL; // matriz de posição e orientação do pontosprite D3DXMATRIX g_mtxPos, g_mtxRot; // Tamanho de cada sprite const float nTamanho = 6.0f; // Posição, tamanho e cor de cada pontosprite CustomVertex_PointSprite g_Pontos[] = { { -100.0f, 100.0f, 5.0f, nTamanho, amarelo }, { 100.0f, -100.0f, 5.0f, nTamanho, azul }, { -100.0f, -100.0f, 5.0f, nTamanho, verde }, { 100.0f, 100.0f, 5.0f, nTamanho, vermelho } }; // Controla o ângulo de rotação do objeto 3d float g_angulo = 0.0f; // Ponteiro de acesso aos dados do vertexbuffer void *g_pDados; 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 o 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) ); // Vamos ativar o buffer de profundidade pps.EnableAutoDepthStencil = true; pps.AutoDepthStencilFormat = D3DFMT_D16; // Configura os parâmetros de apresentação // A aplicação vai ter janela pps.Windowed = TRUE; // Esse método transfere rapidamente o backbuffer para a tela imediata pps.SwapEffect = D3DSWAPEFFECT_DISCARD; // Esse formato vai permitir o uso de alpha blending pps.BackBufferFormat = D3DFMT_A8R8G8B8; // 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 // Configura a câmera inicializar_Camera(); // Inicializa o ambiente e objetos pertinentes da produção // de pointsprites. inicializar_Pointsprite(); return S_OK; } // initGfx().fim void inicializar_Pointsprite(void) { // Configuração dos estados pertinentes a sprites g_device->SetRenderState(D3DRS_POINTSPRITEENABLE, true); g_device->SetRenderState(D3DRS_POINTSCALEENABLE, true); // Configuração de tamanho de ponto float nPointSize = 1.0f; g_device->SetRenderState(D3DRS_POINTSIZE, *((DWORD*) &nPointSize)); // Configuração do tamanho mínimo float nMinPointSize = 1.0f; g_device->SetRenderState(D3DRS_POINTSIZE_MIN, *((DWORD*) &nMinPointSize)); // Configuração do fator de escala float nPointScaleB = 1.0f; g_device->SetRenderState(D3DRS_POINTSCALE_B, *((DWORD*) &nPointScaleB)); // Aciona iluminação automática g_device->SetRenderState(D3DRS_LIGHTING, false); // Desliga uso do z buffer g_device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); // Configuração de alpha blending g_device->SetRenderState(D3DRS_ALPHABLENDENABLE, true); g_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); g_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO); // Configura o formato de vértice g_device->SetFVF( CustomVertex_PointSprite_Format); // Elaboração do vertexbuffer g_device->CreateVertexBuffer(sizeof( g_Pontos), D3DUSAGE_POINTS | D3DUSAGE_WRITEONLY, CustomVertex_PointSprite_Format, D3DPOOL_MANAGED, &g_pVertexbuffer, NULL); // Tranca o vertexbuffer para inicializar o ponteiro de dados g_pVertexbuffer->Lock(0, 0, &g_pDados, 0); // Transfere os dados para o vertexbuffer memcpy(g_pDados, g_Pontos, sizeof(g_Pontos) ); // Destranca o vertexbuffer g_pVertexbuffer->Unlock(); // Carrega a textura D3DXCreateTextureFromFile(g_device, "particula.png", &g_pTex); } // inicializar_Pointsprite().fim void renderizar_Pointsprite() { // Configura transformação do objeto Pointsprite D3DXMatrixRotationZ(&g_mtxRot, g_angulo ); D3DXMatrixTranslation(&g_mtxPos, 0.0f, 0.0f, 0.0f); g_device->SetTransform(D3DTS_WORLD, &( g_mtxRot * g_mtxPos ) ); // Declara a textura e o vertexbuffer g_device->SetTexture(0, g_pTex); g_device->SetStreamSource(0, g_pVertexbuffer, 0, sizeof( CustomVertex_PointSprite) ); // Desenha o objeto pointsprite g_device->DrawPrimitive(D3DPT_POINTLIST, 0, 4); // Atualiza ângulo para a próxima renderização g_angulo += 0.10f; } // renderizar_Pointsprite().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.0f, 0.0f, 700.0f); // Para aonde a câmera está apontada ou olhando? Alvo da câmera D3DXVECTOR3 cam_alvo (0.0f, 0.0f, 0); // A câmera está de cabeça pra baixo? - orientação da câmera D3DXVECTOR3 cam_vetorcima (0.0f, 1.0f, 0.0f); // 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 // Pega o tamanho da área cliente RECT area_cliente; GetWindowRect (hJanela, &area_cliente); g_xtela = area_cliente.right; g_ytela = area_cliente.bottom; // aspecto dos gráficos float aspecto = (float) g_xtela / g_ytela; // campo de visão float campo_visao = 0.785398f; // 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 Renderizar() { // Fundo preto para combinar com o fundo da textura do pontosprite const DWORD dwPreto = 0; // 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 | D3DCLEAR_ZBUFFER, dwPreto, 1.0f, 0); // Começa a cena if( SUCCEEDED( g_device->BeginScene() ) ) { renderizar_Pointsprite(); // 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 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(); // Libera a textura if(g_pTex != NULL ) g_pTex->Release(); // Libera o vertexbuffer if(g_pVertexbuffer != NULL) g_pVertexbuffer->Release(); // Limpeza dos ponteiros g_device = NULL; g_Direct3d = NULL; g_pTex = NULL; g_pVertexbuffer = NULL; } // Limpar().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 // fim do arquivo: motor.cpp
// ----------------------------------------------------------------------------- // Projeto: prj_PointSprite - arquivo: entrada.cpp // Esta aplicação mostra como renderizar partículas com pontosprites // 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; // alça da janela HWND hJanela; int WINAPI WinMain (HINSTANCE app_instancia, HINSTANCE app_anterior, LPSTR sComando,int nExibir) { // 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_Pointsprite"; 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 // fim do arquivo: entrada.cpp

index << >>
1.1 Visão geral
1.2 Estrutura principal da aplicação
2.1 Aspectos globais: arquivo motor.h
2.2 Aspectos globais: arquivo motor.cpp
2.3 initGfx()                 -  Inicialização do motor gráfico (Direct3D)
2.4 inicializar_Pointsprite() - Inicialização das partículas
2.5 renderizar_Pointsprite()  - Renderização das partículas
2.6 Renderizar()              - Renderização da cena
Anx. Código fonte do projeto de exemplo: prj_Pointsprite

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