10.4 Modelo texturizado
1.1 Visão geral
A aplicação deste exemplo vai mostrar como renderizar um modelo
texturizado com hlsl. O programa hlsl vai mostrar duas técnicas: uma
que vai retornar a textura original do objeto e outra técnica que
vai retornar a textura com um simples efeito visual aplicado.Ainda, o
programa hlsl vai mostrar uma forma alternativa de declarar os
argumentos de entrada e saída das funções.
A base desta aplicação é o projeto prj_Modelo3d do tópico 4.3. Essa
aplicação original foi modificada para ter o modelo 3d renderizado
com o efeito hlsl que foi aplicado duas vezes na função
renderizar_Geometria() com seleção de técnicas diferentes que
produziu um visual diferente para o mesmo modelo 3d carregado.
1.2 Estrutura principal da aplicação
Arquivo: motor.cpp
Aspectos globais
Declaração de ponteiros globais para:
o objeto 3d da interface ID3DXMesh ( g_objeto3d )
o objeto efeito produzido pela interface ID3DXEffect ( g_efeito )
Declaração de dois handles globais para as técnicas:
technique texturaOriginal ( htech_texturaOriginal )
technique texturaNegativa ( htech_texturaNegativa )
inicializarEfeito()
inicializa os argumentos da função que produz o objeto efeito
produz o objeto efeito com a função D3DXCreateEffectFromFile()
que carrega o arquivo com o código hlsl, compila-o e produz o
objeto efeito da interface ID3DXEffect.
carrega cada técnica para seu próprio handle
initGfx()
Configura a ocorrência do processamento de vértices no hardware.
chama inicializar_Camera() para configuração inicial da câmera.
chama inicializarEfeito() para carregar o programa hlsl do disco
e inicializar o objeto efeito ( g_efeito ).
carrega o modelo 3d na função CarregarModelo()
desenharObjeto()
Esta função vai renderizar na tela o objeto da interface ID3DXMesh .
Isso envolve a configuração das matrizes parciais de rotação, posição
e escala; produzir a matriz de mundo final com as matrizes parciais.
Atualiza as variáveis para produzir variação de movimento e cor
Produz a matriz final de câmera combinada com a matriz final do objeto.
Introjeta as variáveis atualizadas na linha programável do
dispositivo gráfico.
configura textura e material no dispositivo renderizador
Renderiza o modelo 3d
renderizar_Geometria()
Inicializa o processo de renderização com o objeto efeito
aplica a técnica htech_texturaOriginal
Chama desenharObjeto() para renderizar o objeto
Finaliza o processo de renderização com o objeto efeito
Inicializa o processo de renderização com o objeto efeito
aplica a técnica htech_texturaNegativa
Chama desenharObjeto() para renderizar o objeto
Finaliza o processo de renderização com o objeto efeito
2.1.1 Aspectos globais - Arquivo: motor.h
// Projeto: prj_HLSL03 - Arquivo: motor.h
// Esta aplicação ilustra como renderizar um
// modelo 3d texturizado com técnicas diferentes
// By www.gameprog.com.br
#ifndef motor_h
#define motor_h
// Inclui as bibliotecas do Direct3D
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
// Desliga aviso de 'função insegura' devido ao uso das
// funções de string ( strcat etc. . . )
#pragma warning( disable:4996 )
// Estrutura posição e rotação do objeto 3d
struct Propriedades3d
{
D3DXVECTOR3 pos;
D3DXVECTOR3 rot;
};
// 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();
// Renderiza o modelo 3d duas vezes com o objeto efeito
void renderizar_Geometria (void);
// Inicializa as matrizes da câmera
void inicializar_Camera(void);
// Inicializa o objeto efeito
void inicializarEfeito(void);
// Desenha o objeto 3d
void desenharObjeto ( ID3DXMesh *obj3d, Propriedades3d *props);
// Carrega o modelo 3d
void CarregarModelo( char *diretorioBase, char *arquivo);
// Declaração da função que atende as mensagens da janela
LRESULT CALLBACK processaJanela (HWND hJanela, UINT mensagem,
WPARAM wParam, LPARAM lParam);
#endif
2.1.2 Aspectos globais - Aqrquivo: motor.cpp
// Representa o objeto efeito
ID3DXEffect *g_efeito = NULL;
D3DXHANDLE htech_texturaOriginal = NULL;
D3DXHANDLE htech_texturaNegativa = NULL;
// Variáveis para provocar mudanças de cor e movimento
float nMovimento = 0.0f;
float nVelocidade = 0.01f;
float g_angulo = 0.01f;
// Interface do objeto 3d
ID3DXMesh *g_objeto3d = NULL;
// Recipiente de materiais do mesh
DWORD g_mtlQtd = 0;
D3DMATERIAL9 *g_meshMtl = NULL;
// Recipiente de texturas do mesh
IDirect3DTexture9 **g_meshTex = NULL;
// Recipiente de cor, rotação e posição do objeto
Propriedades3d g_props;
D3DXHANDLE htech_texturaOriginal = NULL;
D3DXHANDLE htech_texturaNegativa = NULL;
Estes handles para as técnicas estão no espaço global pois precisam
ser vistos na função inicializarEfeito() aonde são inicializados e
na função renderizar_Geometria() aonde são utilizados efetivamente.
2.2 Inicialização do motor gráfico
// 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 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) );
// A aplicação vai ter janela
pps.Windowed = TRUE;
// Vamos ativar o buffer de profundidade
pps.EnableAutoDepthStencil = true;
pps.AutoDepthStencilFormat = D3DFMT_D16;
// Esse método transfere 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_HARDWARE_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
// Carrega o modelo 3d
CarregarModelo("\\gameprog\\gdkmedia\\Modelos\\Tiny\\", "tiny.x");
// Inicializa o objeto efeito
inicializarEfeito();
// Inicializa a configuração de câmera
inicializar_Camera();
return S_OK;
} // initGfx().fim
2.3 Renderização dos modelos 3d com técnicas diferentes
void renderizar_Geometria()
{
// Número de passos do efeito
UINT numPasses = 0;
// Renderiza o quadrado usando o efeito
g_efeito->SetTechnique(htech_texturaOriginal);
g_efeito->Begin(&numPasses, 0);
for(UINT ncx = 0; ncx < numPasses; ncx++)
{
// Renderiza uma etapa no VertexShader
g_efeito->BeginPass (ncx);
// Renderização efetiva dos vértices
g_props.rot = D3DXVECTOR3 (0.0f, 0.0f, 0.0f);
g_props.pos = D3DXVECTOR3 (-150.0f, 40.0f, -20.0f);
desenharObjeto(g_objeto3d, &g_props);
// Fim do passo
g_efeito->EndPass ();
} // endfor
// Fim do efeito
g_efeito->End ();
// Renderiza o quadrado usando o efeito
g_efeito->SetTechnique(htech_texturaNegativa);
g_efeito->Begin(&numPasses, 0);
for(UINT ncx = 0; ncx < numPasses; ncx++)
{
// Renderiza uma etapa no VertexShader
g_efeito->BeginPass (ncx);
// Renderização efetiva dos vértices
g_props.rot = D3DXVECTOR3 (0.0f, 0.0f, 0.0f);
g_props.pos = D3DXVECTOR3 (100.0f, 0.2f, -20.0f);
desenharObjeto(g_objeto3d, &g_props);
// Fim do passo
g_efeito->EndPass ();
} // endfor
// Fim do efeito
g_efeito->End ();
} // renderizar_Geometria().fim
g_efeito->SetTechnique(htech_texturaOriginal);
g_efeito->Begin(&numPasses, 0);
for(UINT ncx = 0; ncx < numPasses; ncx++) {
g_efeito->BeginPass (ncx);
// (...)
desenharObjeto(g_objeto3d, &g_props);
g_efeito->EndPass ();
} // endfor
g_efeito->End ();
O aspecto importante para considerar aqui é que a técnica deve ser
configurada antes de entrar em g_efeito->Begin() e somente pode ser
reconfigurada depois de g_efeito->End() como aconteceu nesta função
renderizar_Geometria().
g_efeito->SetTechnique(htech_texturaNegativa);
g_efeito->Begin(&numPasses, 0);
for(UINT ncx = 0; ncx < numPasses; ncx++) {
g_efeito->BeginPass (ncx);
// (...)
desenharObjeto(g_objeto3d, &g_props);
g_efeito->EndPass ();
} // endfor
g_efeito->End ();
2.4 Inicialização do efeito
void inicializarEfeito()
{
// Nome do arquivo de efeito
char fx_arquivo[] = "\\gameprog\\gdkmedia\\shader\\mesh-texturizado.fx";
// Flag de configuração
DWORD create_flags = D3DXSHADER_DEBUG;
// Buffer para receber informação em caso de erro
ID3DXBuffer *txtErro = NULL;
// Gera o efeito a partir do arquivo carregado
g_hr = D3DXCreateEffectFromFile( g_device, fx_arquivo,
0, 0, create_flags, 0, &g_efeito, &txtErro);
if (FAILED(g_hr))
{
MessageBox(NULL, "falha: D3DXCreateEffectFromFile()",
"inicializarEfeito", MB_OK);
MessageBox(NULL, (char*) txtErro->GetBufferPointer(),
"inicializarEfeito", MB_OK);
txtErro->Release ();
return;
} // endif
// Carrega cada técnica em seu próprio handle
htech_texturaOriginal = g_efeito->GetTechniqueByName ("texturaOriginal");
htech_texturaNegativa = g_efeito->GetTechniqueByName ("texturaNegativa");
// Libera o buffer de erros
if (txtErro != NULL) txtErro->Release();
} // inicializarEfeito().fim
htech_texturaOriginal = g_efeito->GetTechniqueByName ("texturaOriginal");
htech_texturaNegativa = g_efeito->GetTechniqueByName ("texturaNegativa");
Aqui cada técnica foi carregada para seu próprio handle podendo assim
cada uma ser selecionada e aplicada no melhor momento decidido pela
aplicação.
2.5 Renderização do modelo 3d
void desenharObjeto ( ID3DXMesh *obj3d, Propriedades3d *props)
{
// Matrizes para controlar posição e rotação do objeto 3d
D3DXMATRIX obj_rot;
D3DXMATRIX obj_pos;
D3DXMATRIX camera;
// Handle para a variáveis do shader
D3DXHANDLE hMov = NULL;
D3DXHANDLE hCam = NULL;
// Vamos inicializar as matrizes para um valor neutro
D3DXMatrixIdentity( &obj_rot );
D3DXMatrixIdentity( &obj_pos );
D3DXMatrixIdentity( &camera );
// Atualiza ângulo de rotação
g_angulo += 0.01f;
// Configura rotação do objeto 3d
D3DXMatrixRotationYawPitchRoll(&obj_rot,
props->rot.y,
props->rot.x + g_angulo,
props->rot.z);
// Ajusta posição do objeto 3d;
D3DXMatrixTranslation(&obj_pos,
props->pos.x, props->pos.y, props->pos.z);
// Tranfere posição e rotação para o g_mtxMundo
D3DXMatrixMultiply (&g_mtxMundo, &obj_rot, &obj_pos);
// Atualiza cor
nMovimento += nVelocidade;
if (nMovimento >= 1.0f) nVelocidade *= -1;
if (nMovimento <= 0.0f) nVelocidade *= -1;
// Atualiza a câmera
camera = g_mtxMundo * g_mtxVisao * g_mtxProj;
// Obtém acesso às variáveis do shader
hMov = g_efeito->GetParameterByName (0, "nMovimento");
hCam = g_efeito->GetParameterByName (0, "Camera");
// Atualiza variáveis no shader
g_efeito->SetValue (hMov, &nMovimento, sizeof(nMovimento) );
g_efeito->SetValue (hCam, &camera, sizeof(camera) );
// Renderiza o mesh
if (g_mtlQtd > 0)
for (DWORD ncx=0; ncx < g_mtlQtd; ncx++)
{
g_device->SetMaterial(&g_meshMtl[ncx] );
g_device->SetTexture(0, g_meshTex[ncx] );
obj3d->DrawSubset(ncx);
} // endfor
} // desenharObjeto().fim
3.0 Código hlsl para renderização do modelo 3d texturizado: mesh-texturizado.fx
3.1 Variáveis globais do shader
// Variáveis globais de camera, textura, estruturas de entrada e saída.
float4x4 Camera : WORLDVIEWPROJECTION;
sampler textura;
// Dados de saída: posição e coordenada de textura
struct vsSaida
{
float4 pos : POSITION;
float2 texCoord : TEXCOORD0;
};
// Dados de entrada: posição e coordenada de textura
struct vsEntrada
{
float4 pos : POSITION;
float2 texCoord : TEXCOORD0;
};
sampler textura;
Dentro do shader as texturas são acessadas e configuradas através de
variáveis do tipo sampler. A variável textura vai permitir o acesso
aos dados de cor da textura enviados ao shader pela aplicação.
// Dados de saída: posição e coordenada de textura
struct vsSaida
{
float4 pos : POSITION;
float2 texCoord : TEXCOORD0;
};
A novidade presente na estrutura de entrada e saída que serão
utilizadas pelo Shader é a variável texCoord do tipo float2. Este
tipo possui como subelementos x e y visto que a textura é uma
superfície 2D.A semântica TEXCOORD0 serve para indicar que a variável
será utilizada para a manipulação de coordenadas de textura. É muito
comum em trabalhos com coordenadas de textura pensar em termos de
(u, v) em correspondência com os elementos (x, y) de uma imagem 2D.
3.2 VertexShader: vs_Main()
// Retorna posição e coordenadas de textura
vsSaida vs_Main ( vsEntrada entrada )
{
// Declara estrutura de saída
vsSaida saida = (vsSaida) 0;
// Transforma posição para espaço de mundo
saida.pos = mul(entrada.pos, Camera);
// Repassa para a saida as coordenadas de textura
saida.texCoord = entrada.texCoord;
// Retorna posição transformada e coordenadas originais
// de textura
return saida;
}
vsSaida vs_Main ( vsEntrada entrada )
Com esta assinatura através das estruturas declaradas, esta função do
vertexshader que denominamos vs_Main() recebe posicionamento de
vértices e coordenadas de textura. E retorna na estrutura de saída
a posição transformada e as coordenadas de textura do jeito que
entraram. Na sequência deste shader mostramos uma outra forma de
declarar valores de entrada e de saída da função.
// Transforma posição para espaço de mundo
saida.pos = mul(entrada.pos, Camera);
Esta linha simplesmente devolve a posição 3d transformada em
espaço de mundo. Em aplicações mais sofisticadas é comum antes deste
trecho a posição 3d sofrer outras transformações em seus subelementos
xyz que ocasionam efeitos especiais ou animações particulares sobre
os vértices.
// Repassa para a saida as coordenadas de textura
saida.texCoord = entrada.texCoord;
Esta linha passa adiante as coordenadas de textura com os valores
originais intactos. É comum antes deste trecho modificar estas
coordenadas para criar através disso efeitos especiais com texturas
animadas.
return saida;
Esta linha retorna a posição transformada e coordenadas originais de
textura que estão assinaladas dentro desta estrutura saida.
Vamos ver abaixo que o apontamento antecipado da variável pela
instrução out dispensa depois o uso da instrução return.
3.3 Retornando a textura original
float4 ps_TexturaOriginal( float2 texCoord : TEXCOORD0,
float4 cor_difusa : COLOR0 ) : COLOR0
{
// Pega a cor do pixel da textura
cor_difusa = tex2D(textura, texCoord);
// Retorna cor da textura sem modificações
return cor_difusa;
};
float4 ps_TexturaOriginal( float2 texCoord : TEXCOORD0,
float4 cor_difusa : COLOR0 ) : COLOR0
Esta aqui é a primeira função do nosso pixelshader.Conforme assinatura
essa função retorna uma cor. Na entrada de argumentos, ela recebe as
coordenadas de textura e uma cor difusa para ser trabalhada. Na
recepção de um modelo com textura, a função de pixelshader deve ter
esta assinatura.
// Pega a cor do pixel da textura
cor_difusa = tex2D(textura, texCoord);
A função tex2D() recebe dados de textura como cor e coordenada, faz
uma pesquisa utilizando essa entrada e retorna a cor correspondente
ao ponto examinado.
// Retorna sem modificações
return cor_difusa;
Aqui ocorre o retorno da cor para a aplicação. É comum antes disso
aplicar alterações na cor, em seus componentes rgba, para obtenção
de efeitos visuais na imagem final; faremos isso na próxima função
de pixelshader.
3.4 Aplicando textura original
Finalmente a seleção desta técnica na aplicação ocasiona o retorno
da textura original do objeto com seus vértices transformados para
espaço de mundo.
technique texturaOriginal
{
pass P0
{
// Aplicando textura original
VertexShader = compile vs_1_1 vs_Main();
PixelShader = compile ps_2_0 ps_TexturaOriginal();
}
}
3.5 PixelShader: Retornando cor negativa
// --------------------- Estrutura da segunda técnica -------------------------
// Testando instruções in e out
void ps_TexturaNegativa( in float2 texCoord : TEXCOORD0,
out float4 cor_difusa : COLOR0 )
{
// Pega a cor do pixel da textura
cor_difusa = tex2D(textura, texCoord);
// Modifica a cor original
cor_difusa.r = 1.0f - cor_difusa.r;
cor_difusa.g = 1.0f - cor_difusa.g;
cor_difusa.b = 1.0f - cor_difusa.b;
}
// --------------------- Estrutura da segunda técnica -------------------------
// Testando instruções in e out
void ps_TexturaNegativa( in float2 texCoord : TEXCOORD0,
out float4 cor_difusa : COLOR0 )
Esta assinatura traz uma forma diferente de declarar os argumentos de
entrada e saida. Os argumentos de entrada são declarados com a
instrução in enquanto os argumentos de saída são declarados com a
instrução out e a função é assinalada como void.
// Pega a cor do pixel da textura
cor_difusa = tex2D(textura, texCoord);
Pegamos aqui a cor da textura e vamos modificá-la abaixo.
// Modifica a cor original
cor_difusa.r = 1.0f - cor_difusa.r;
cor_difusa.g = 1.0f - cor_difusa.g;
cor_difusa.b = 1.0f - cor_difusa.b;
Com essa subtração produz-se o efeito de cor negativa. Através da
manipulação destes três canais da cor pode ser produzido dezenas
de efeitos visuais. Esta função retorna então a cor do pixel com
essa modificação.
3.6 Aplicando textura negativa
A seleção desta técnica retorna então para a aplicação a textura
modificada do objeto e com seus vértices transformados para espaço de
mundo.
technique texturaNegativa
{
pass P0
{
// Aplicando textura negativa
VertexShader = compile vs_1_1 vs_Main();
PixelShader = compile ps_2_0 ps_TexturaNegativa();
}
}
3.7 Código fonte do programa hlsl de exemplo:mesh_texturizado.fx
// prj_HLSL03: Renderizando mesh texturizado com hlsl
// Arquivo: mesh_texturizado.fx
// Produzido por www.gameprog.com.br
// Variáveis globais de camera, textura, e estruturas de entrada e saída
float4x4 Camera : WORLDVIEWPROJECTION;
sampler textura;
// Dados de saída: posição e coordenada de textura
struct vsSaida
{
float4 pos : POSITION;
float2 texCoord : TEXCOORD0;
};
// Dados de entrada: posição e coordenada de textura
struct vsEntrada
{
float4 pos : POSITION;
float2 texCoord : TEXCOORD0;
};
// Retorna posição e coordenadas de textura
vsSaida vs_Main ( vsEntrada entrada )
{
// Declara estrutura de saída
vsSaida saida = (vsSaida) 0;
// Transforma posição para espaço de mundo
saida.pos = mul(entrada.pos, Camera);
// Repassa para a saida as coordenadas de textura
saida.texCoord = entrada.texCoord;
// Retorna posição transformada e coordenadas originais
// de textura
return saida;
}
float4 ps_TexturaOriginal( float2 texCoord : TEXCOORD0,
float4 cor_difusa : COLOR0) : COLOR0
{
// Pega a cor do pixel da textura
cor_difusa = tex2D(textura, texCoord);
// Retorna sem modificações
return cor_difusa;
};
technique texturaOriginal
{
pass P0
{
// Aplicando textura original
VertexShader = compile vs_1_1 vs_Main();
PixelShader = compile ps_2_0 ps_TexturaOriginal();
}
}
// --------------------- Estrutura da segunda técnica -------------------------
// Testando instruções in e out
void ps_TexturaNegativa( in float2 texCoord : TEXCOORD0,
out float4 cor_difusa : COLOR0 )
{
// Pega a cor do pixel da textura
cor_difusa = tex2D(textura, texCoord);
// Modifica a cor original
cor_difusa.r = 1.0f - cor_difusa.r;
cor_difusa.g = 1.0f - cor_difusa.g;
cor_difusa.b = 1.0f - cor_difusa.b;
}
technique texturaNegativa
{
pass P0
{
// Aplicando textura negativa
VertexShader = compile vs_1_1 vs_Main();
PixelShader = compile ps_2_0 ps_TexturaNegativa();
}
}
4.0 Código fonte do projeto de exemplo: prj_HLSL03
// Projeto: prj_HLSL03 - Arquivo: motor.h
// Esta aplicação ilustra como renderizar um
// modelo 3d texturizado com técnicas diferentes
// By www.gameprog.com.br
#ifndef motor_h
#define motor_h
// Inclui as bibliotecas do Direct3D
#pragma comment(lib,
"d3d9.lib")
#pragma comment(lib,
"d3dx9.lib")
// Desliga aviso de 'função insegura' devido ao uso das
// funções de string ( strcat etc. . . )
#pragma warning( disable:4996 )
// Estrutura posição e rotação do objeto 3d
struct Propriedades3d
{
D3DXVECTOR3 pos;
D3DXVECTOR3 rot;
};
// 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();
// Renderiza o modelo 3d duas vezes com o objeto efeito
void renderizar_Geometria (
void);
// Inicializa as matrizes da câmera
void inicializar_Camera(
void);
// Inicializa o objeto efeito
void inicializarEfeito(
void);
// Desenha o objeto 3d
void desenharObjeto (
ID3DXMesh *obj3d,
Propriedades3d *props);
// Carrega o modelo 3d
void CarregarModelo(
char *diretorioBase,
char *arquivo);
// 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_HLSL03 - arquivo: motor.cpp
// Esta aplicação ilustra como renderizar um
// modelo 3d texturizado com técnicas diferentes
// By www.gameprog.com.br
// -----------------------------------------------------------------------------
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <stdio.h>
#include <string.h>
#include "motor.h"
// Variáveis globais
// Representa o dispositivo Direct3D
LPDIRECT3D9 g_Direct3d = NULL;
// Representa o dispositivo Renderizador
IDirect3DDevice9* g_device = NULL;
// Representa o objeto efeito
ID3DXEffect *g_efeito = NULL;
D3DXHANDLE htech_texturaOriginal = NULL;
D3DXHANDLE htech_texturaNegativa = NULL;
// Variáveis para provocar mudanças de cor e movimento
float nMovimento = 0.0f;
float nVelocidade = 0.01f;
float g_angulo = 0.01f;
// Interface do objeto 3d
ID3DXMesh *g_objeto3d = NULL;
// Recipiente de materiais do mesh
DWORD g_mtlQtd = 0;
D3DMATERIAL9 *g_meshMtl = NULL;
// Recipiente de texturas do mesh
IDirect3DTexture9 **g_meshTex = NULL;
// Recipiente de cor, rotação e posição do objeto
Propriedades3d g_props;
// 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 verde = 0xFF008000;
// Matrizes de configuração da câmera
D3DXMATRIX g_mtxMundo;
D3DXMATRIX g_mtxVisao;
D3DXMATRIX g_mtxProj;
// 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 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) );
// A aplicação vai ter janela
pps.Windowed = TRUE;
// Vamos ativar o buffer de profundidade
pps.EnableAutoDepthStencil = true;
pps.AutoDepthStencilFormat = D3DFMT_D16;
// Esse método transfere 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_HARDWARE_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
// Carrega o modelo 3d
CarregarModelo("\\gameprog\\gdkmedia\\Modelos\\Tiny\\", "tiny.x");
// Inicializa o objeto efeito
inicializarEfeito();
// Inicializa a configuração de câmera
inicializar_Camera();
return S_OK;
} // initGfx().fim
void renderizar_Geometria()
{
// Número de passos do efeito
UINT numPasses = 0;
// Renderiza o quadrado usando o efeito
g_efeito->SetTechnique(htech_texturaOriginal);
g_efeito->Begin(&numPasses, 0);
for(UINT ncx = 0; ncx < numPasses; ncx++)
{
// Renderiza uma etapa no VertexShader
g_efeito->BeginPass (ncx);
// Renderização efetiva dos vértices
g_props.rot = D3DXVECTOR3 (0.0f, 0.0f, 0.0f);
g_props.pos = D3DXVECTOR3 (-150.0f, 40.0f, -20.0f);
desenharObjeto(g_objeto3d, &g_props);
// Fim do passo
g_efeito->EndPass ();
} // endfor
// Fim do efeito
g_efeito->End ();
// Renderiza o quadrado usando o efeito
g_efeito->SetTechnique(htech_texturaNegativa);
g_efeito->Begin(&numPasses, 0);
for(UINT ncx = 0; ncx < numPasses; ncx++)
{
// Renderiza uma etapa no VertexShader
g_efeito->BeginPass (ncx);
// Renderização efetiva dos vértices
g_props.rot = D3DXVECTOR3 (0.0f, 0.0f, 0.0f);
g_props.pos = D3DXVECTOR3 (100.0f, 0.2f, -20.0f);
desenharObjeto(g_objeto3d, &g_props);
// Fim do passo
g_efeito->EndPass ();
} // endfor
// Fim do efeito
g_efeito->End ();
} // 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 as texturas que estejam presentes no modelo
if (g_mtlQtd > 0)
{
for (DWORD ncx=0; ncx < g_mtlQtd; ncx++)
if (g_meshTex[ncx] != NULL) g_meshTex[ncx]->Release();
} // endif
// Libera o buffer de vértices
if( g_objeto3d != NULL) g_objeto3d->Release();
if (g_efeito != NULL) g_efeito->Release();
// 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
// -----------------------------------------------------------------------------
// 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 | D3DCLEAR_ZBUFFER, verde, 1.0f, 0);
// Começa a cena
if( SUCCEEDED( g_device->BeginScene() ) )
{
// Vamos renderizar a geometria
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 inicializar_Camera(void)
{
// ***************************************************************************
// Inicializa todas as matrizes para elemento neutro
D3DXMatrixIdentity( &g_mtxMundo );
D3DXMatrixIdentity( &g_mtxVisao );
D3DXMatrixIdentity( &g_mtxProj );
// ***************************************************************************
// 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 );
// ***************************************************************************
// 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_g_mtxVisao = 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_g_mtxVisao, aspecto,
corte_perto, corte_longe);
} // inicializar_Camera().fim
void inicializarEfeito()
{
// Nome do arquivo de efeito
char fx_arquivo[] = "\\gameprog\\gdkmedia\\shader\\mesh-texturizado.fx";
// Flag de configuração
DWORD create_flags = D3DXSHADER_DEBUG;
// Buffer para receber informação em caso de erro
ID3DXBuffer *txtErro = NULL;
// Gera o efeito a partir do arquivo carregado
g_hr = D3DXCreateEffectFromFile( g_device, fx_arquivo,
0, 0, create_flags, 0, &g_efeito, &txtErro);
if (FAILED(g_hr))
{
MessageBox(NULL, "falha: D3DXCreateEffectFromFile()",
"inicializarEfeito", MB_OK);
MessageBox(NULL, (char*) txtErro->GetBufferPointer(),
"inicializarEfeito", MB_OK);
txtErro->Release ();
return;
} // endif
// Carrega cada técnica em seu próprio handle
htech_texturaOriginal = g_efeito->GetTechniqueByName ("texturaOriginal");
htech_texturaNegativa = g_efeito->GetTechniqueByName ("texturaNegativa");
// Libera o buffer de erros
if (txtErro != NULL) txtErro->Release();
} // inicializarEfeito().fim
void desenharObjeto ( ID3DXMesh *obj3d, Propriedades3d *props)
{
// Matrizes para controlar posição e rotação do objeto 3d
D3DXMATRIX obj_rot;
D3DXMATRIX obj_pos;
D3DXMATRIX camera;
// Handle para a variáveis do shader
D3DXHANDLE hMov = NULL;
D3DXHANDLE hCam = NULL;
// Vamos inicializar as matrizes para um valor neutro
D3DXMatrixIdentity( &obj_rot );
D3DXMatrixIdentity( &obj_pos );
D3DXMatrixIdentity( &camera );
// Atualiza ângulo de rotação
g_angulo += 0.01f;
// Configura rotação do objeto 3d
D3DXMatrixRotationYawPitchRoll(&obj_rot,
props->rot.y,
props->rot.x + g_angulo,
props->rot.z);
// Ajusta posição do objeto 3d;
D3DXMatrixTranslation(&obj_pos,
props->pos.x, props->pos.y, props->pos.z);
// Tranfere posição e rotação para o g_mtxMundo
D3DXMatrixMultiply (&g_mtxMundo, &obj_rot, &obj_pos);
// Atualiza cor
nMovimento += nVelocidade;
if (nMovimento >= 1.0f) nVelocidade *= -1;
if (nMovimento <= 0.0f) nVelocidade *= -1;
// Atualiza a câmera
camera = g_mtxMundo * g_mtxVisao * g_mtxProj;
// Obtém acesso às variáveis do shader
hMov = g_efeito->GetParameterByName (0, "nMovimento");
hCam = g_efeito->GetParameterByName (0, "Camera");
// Atualiza variáveis no shader
g_efeito->SetValue (hMov, &nMovimento, sizeof(nMovimento) );
g_efeito->SetValue (hCam, &camera, sizeof(camera) );
// Renderiza o mesh
if (g_mtlQtd > 0)
for (DWORD ncx=0; ncx < g_mtlQtd; ncx++)
{
g_device->SetMaterial(&g_meshMtl[ncx] );
g_device->SetTexture(0, g_meshTex[ncx] );
obj3d->DrawSubset(ncx);
} // endfor
} // desenharObjeto().fim
void CarregarModelo( char *diretorioBase, char *arquivo)
{
// Composição do nome final do arquivo do modelo 3d
// caminhoFinal = diretorioBase + arquivo
char caminhoFinal[255] = "\0";
strcat (caminhoFinal, diretorioBase);
strcat (caminhoFinal, arquivo);
// Buffer para o pacote de materiais e texturas do modelo 3d
ID3DXBuffer *mtlPack;
// Recebe nome do arquivo de textura sendo carregado
char *arquivo_textura = NULL;
// Carrega modelo 3d com suas texturas e materiais
g_hr = D3DXLoadMeshFromX(caminhoFinal, D3DXMESH_SYSTEMMEM,
g_device, NULL, &mtlPack, NULL, &g_mtlQtd, &g_objeto3d );
// Verifica falha no carregamento do modelo 3d
if(FAILED (g_hr) )
{
MessageBox (NULL,
"Falha no carregamento do modelo", "CarregarModelo()", MB_OK);
return;
} // endif
// Pacote de materiais da biblioteca auxiliar d3dx
D3DXMATERIAL* xMtl = (D3DXMATERIAL*) mtlPack->GetBufferPointer();
// Inicializa as variáveis arrays de materiais e texturas
g_meshMtl = new D3DMATERIAL9[g_mtlQtd];
g_meshTex = new IDirect3DTexture9* [g_mtlQtd];
// Carrega texturas e materiais
for (DWORD ncx = 0; ncx < g_mtlQtd; ncx++)
{
// Copia o material
g_meshMtl[ncx] = xMtl[ncx].MatD3D;
// Configura a cor ambiente do material
g_meshMtl[ncx].Ambient = g_meshMtl[ncx].Diffuse;
// Cria a textura se ela existir
g_meshTex[ncx] = NULL;
ZeroMemory(caminhoFinal, sizeof(caminhoFinal));
strcat(caminhoFinal,diretorioBase);
arquivo_textura = strcat(caminhoFinal, xMtl[ncx].pTextureFilename);
if (arquivo_textura != NULL) g_hr = D3DXCreateTextureFromFile(g_device,
arquivo_textura, &g_meshTex[ncx]);
// Verifica falha no carregamento da textura
if(FAILED (g_hr) )
{
MessageBox (NULL,
"Falha na criação da textura", "CarregarModelo()", MB_OK);
mtlPack->Release();
return;
} // endif
} // endfor
// Libera o buffer do pacote de materiais
mtlPack->Release();
} // CarregarModelo().fim
//-----------------------------------------------------------------------------
// Projeto: prj_HLSL03 - arquivo: entrada.cpp
// Esta aplicação ilustra como renderizar um
// modelo 3d texturizado com técnicas diferentes
// 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_HLSL03";
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