Curso completo de DirectX 9 com C\C++
Gameprog - Escola de programação de jogos digitais
Contato: gameprog.br@gmail.com
Fase 03-1
03.1 Triângulo iluminado
1.1 Visão geral
Na computação gráfica de forma geral o processo de aplicação de luz
necessita de um ponto de apoio que indique o local de entrada da luz
na superfície a ser iluminada. Esse ponto de apoio é chamado de
normal e matematicamente é representado por um vetor 3d, geralmente
desenhado como um raio perpendicular entrando ou saindo da superfície.
Formato de vértice
Vamos utilizar na aplicação de exemplo o formato de vértice que
permite inserir a posição da normal para cada vértice. Na ilustração
acima todos os pontos p0, p1, p2 recebem o ponto g_normal que
indica a posição da normal utilizada na iluminação do triângulo. A
posição g_normal está localizada perto de um ponto paralelo ou
perpendicular ao ponto central da face triângulo.
Geralmente as aplicações de modelagem 3d já exportam junto com a
geometria do modelo 3d as coordenadas das normais dos vértices, mas
na ausência dessa informação o directx tem uma função para calculá-la.
Materiais
A iluminação básica da cena é uma combinação de dois fatores: a luz
em contato com o material da superfície a ser iluminada. O directx
geralmente possui uma coleção de luzes pré-existentes guardadas em
uma array de 6 a 8 luzes conforme os limites variáveis das diversas
placas de vídeo. Essas luzes são configuradas através da alteração
das propriedades contidas na estrutura D3DLIGHT9 que depois é passada
para o dispositivo renderizador. A aplicação de materiais na cena é
realizada de forma semelhante através da configuração das propriedades
da estrutura D3DMATERIAL9.
Formato de cor
A composição da cor utilizada na configuração de luzes e materiais é
feita através do preenchimento da estrutura D3DCOLORVALUE na qual
os componentes rgba são expressos em percentuais entre 0.0f e 1.0f.
Certamente que depois, em algum processo interno, estes percentuais
são multiplicados pelo valor 255 para se chegar no valor real do
componente de cor.
Ajuda visual
Criamos uma função para colocar uma esfera dentro de um ponto 3d com
uma cor especificada como argumento. Isso é para ajudar na percepção
concreta do posicionamento dos vértices no espaço 3d. Utilizamos essa
função para assinalar aproximadamente a posição aonde a luz foi
colocada com uma esfera amarela e utilizamos uma esfera verde para
indicar a posição da normal (g_normal) que foi projetada na frente do
triângulo.
Tipo de luz
Luz difusa: esse tipo de luz viaja numa direção particular e quando
atinge uma superfície se reflete igualmente para todas as direções.
Devido ao fato dessa luz ser refletida para todas as direções é
certeza que ela atinge o olho do espectador local não importando o
seu ponto de vista. Com esse contexto, a implementação desse tipo de
luz não leva em consideração a posição do espectador, considerando
apenas a direção da luz e as propriedades da superfície atingida que
vão impactar na quantidade, intensidade e direção dos raios refletidos.
Geralmente a luz difusa representa o maior volume primário de luz
emitido por uma fonte de luz.
Luz ambiente:
Esse tipo representa o tipo secundário de iluminação e consiste no
uso dos raios refletidos da luz primária por outras superfícies
para iluminar a cena de maneira geral. Geralmente, objetos ou partes
de objetos ainda que não estejam em contato direto com a fonte
de luz primária são iluminados por esta luz secundária cujos raios
vieram rebatidos por outras superfícies.
Luz especular:
Esse tipo de luz surge quando uma determinada parte de uma superfície
reflete para uma mesma direção os raios de uma fonte de luz causando
um clarão ou um brilho muito intenso na região. A percepção desse
tipo de luz ocorre apenas dentro de um certo ponto de vista do
espectador com relação ao objeto e a fonte de luz. Esse brilho
é comum aparecer em superfícies esféricas bem polidas como bolas
de boliche, metal polido, bolinhas de natal etc.
Tipos de fonte de luz
O directx simula a iluminação da cena através de 3 tipos de fontes de
luz:
- Luz apontada (PointLight)
Essa fonte de luz representa a luz que se espalha para todas as
direções. Geralmente, aquela lâmpada doméstica em forma de pêra, é um
bom exemplo de luz que se irradia para todas as direções.
- Luz direcionada (DirectionalLight)
Essa luz tem direção mas não tem posição no espaço. Um exemplo de
emanação dessa luz é o sol cuja direção da luz se modifica ao passar
das horas. É claro que o sol tem uma posição relativa no espaço
mas dentro de uma grande região iluminada é a direção tomada
pelo raio de luz que mais importa.
- Holofote (SpotLight)
Esse tipo de fonte de luz simula um holofote que ilumina fortemente
uma região circular da cena.
Todos esses três tipos de fonte de luz são obtidos através da
configuração particular dos elementos da estrutura D3DLIGHT9. A
aplicação desse tópico vai mostrar um exemplo com o tipo de luz
apontada (PointLight) mas ao longo do curso você vai ver amostras
de uso da luz ambiente e de luz direcionada que aumenta a beleza
visual da cena.
1.2 Estrutura principal da aplicação
Arquivo: motor.cpp
criarMaterial()
limpa a estrutura de material recebida ( D3DMATERIAL9 )
configura cor difusa e ambiente com a cor recebida ( D3DCOLORVALUE )
colocar_PointLight()
prepara uma estrutura de luz ( D3DLIGHT9 )
configura tipo da luz para pointlight ( D3DLIGHT_POINT )
configura posição da luz com posição recebida ( D3DXVECTOR3 )
configura cor da luz com a cor recebida ( D3DCOLORVALUE )
configura fator de atenuação e faixa de alcance da luz
Instala a luz configurada no dispositivo
Liga a luz.
calcularNormal()
Recebe 3 vértices e projeta na frente deles um vértice perpendicular
montar_Geometria()
calcula a normal para os vértices com calcularNormal()
configura posição dos vértices
initGfx()
chama montar_Geometria() para configurar os vértices
chama inicializar_Camera() para configurar a câmera
cria um material vermelho para o triângulo com criarMaterial()
coloca uma luz branca na cena com colocar_PointLight()
ajuda_visual()
Renderiza um esfera com a cor e posição especificadas
Isso envolve:
criar material para o objeto com criarMaterial()
criar uma matriz de mundo particular para posicionar a esfera
criar um objeto mesh do tipo ID3DXMesh
posicionar o objeto no mundo 3d com D3DXMatrixTranslation()
renderizar o objeto no mundo 3d com ID3DXMesh->DrawSubset(0)
liberar o objeto ID3DXMesh utilizado
renderizar_Geometria()
Declara o formato de vértice utilizado: CustomVertex_PositionNormal_Format
Renderiza os vértices com g_device->DrawPrimitiveUP()
desenha esfera de ajuda visual para identificação espacial de posicionamento
atualizar_Camera()
atualiza ângulo de rotação
atualiza matriz mundial com ângulo de rotação
joga matriz mundial no dispositivo renderizador
configurar_cenaEstados()
Habilita o uso de iluminação própria da aplicação
configura alguns estados referentes à iluminação
configura o material vermelho no dispositivo
Renderizar()
configura alguns estados do dispositivo com configurar_cenaEstados()
chama atualizar_Camera() para girar o triângulo 3d
chama renderizar_Geometria() para desenhar o triângulo
2.1.1 Aspectos globais - motor.h
// Projeto: prj_Luz - Arquivo: motor.h
// Esta aplicação ilustra como iluminar um triângulo
// 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);
// Configura alguns estados de renderização
void configurar_cenaEstados(void);
// Cria um material
void criarMaterial(D3DMATERIAL9 *mtl, D3DCOLORVALUE cvCor);
// Configura e coloca uma luz pointlight na cena
void colocar_PointLight(D3DXVECTOR3 pos, D3DCOLORVALUE cvCor);
// Faz o cálculo da normal para iluminar o triângulo
void calcularNormal(D3DXVECTOR3* p0, D3DXVECTOR3* p1,
D3DXVECTOR3* p2, D3DXVECTOR3* pSaida);
// Ajuda a visualizar a localização do ponto 3d
void ajuda_visual(D3DXVECTOR3 pos, D3DCOLORVALUE cvCor);
// Declaração da função que atende as mensagens da janela
LRESULT CALLBACK processaJanela (HWND hJanela, UINT mensagem,
WPARAM wParam, LPARAM lParam);
#endif
void configurar_cenaEstados(void);
Essa função configura os estados do dispositivo renderizador, tais
como o culling, material e estados ligados com a iluminação da cena.
void criarMaterial(D3DMATERIAL9 *mtl, D3DCOLORVALUE cvCor);
Essa função realiza o trabalho simples de limpar e configurar uma
estrutura de material.
void colocar_PointLight(D3DXVECTOR3 pos, D3DCOLORVALUE cvCor);
Essa função configura e coloca uma luz do tipo pointlight na cena.
void calcularNormal(D3DXVECTOR3* p0, D3DXVECTOR3* p1,
D3DXVECTOR3* p2, D3DXVECTOR3* pSaida);
Essa função realiza o cálculo da normal. É utilizada para configurar
o vetor 3d g_normal que na sequência é adicionado a cada vértice do
triângulo.
void ajuda_visual(D3DXVECTOR3 pos, D3DCOLORVALUE cvCor);
Essa função renderiza uma esfera colorida em um ponto 3d dando assim
um aspecto concreto e visual desse ponto na tela. Isso facilita
o entendimento de localizações no espaço 3d. É usada para marcar o
local de colocação do ponto g_normal e do ponto aproximado de
colocação da luz.
2.1.2 Aspectos globais - Arquivo: motor.cpp
// Constante para cores
const DWORD azul = 0xFF0000FF;
// Constante para cores com rgba expressado como float's
const D3DCOLORVALUE cvBranco = { 1.0f, 1.0f, 1.0f, 1.0f };
const D3DCOLORVALUE cvVermelho = { 1.0f, 0.0f, 0.0f, 1.0f };
const D3DCOLORVALUE cvAmarelo = { 1.0f, 1.0f, 0.0f, 1.0f };
const D3DCOLORVALUE cvVerde = { 0.0f, 1.0f, 0.0f, 1.0f };
// Variável para o material
D3DMATERIAL9 g_mtlVermelho;
// Indicação de entrada de luz
D3DXVECTOR3 g_normal;
// Definição do formato de vértice utilizado pela aplicação
#define CustomVertex_PositionNormal_Format( D3DFVF_XYZ | D3DFVF_NORMAL)
// Definição da estrutura de vértice customizado
struct CustomVertex_PositionNormal
{
float x, y, z;
float nx, ny, nz;
// Construtor default
CustomVertex_PositionNormal() {}
// Construtor com inicialização
CustomVertex_PositionNormal( float _x, float _y, float _z,
float _nx, float _ny, float _nz)
{
// entrada da posição
x = _x;
y = _y;
z = _z;
// entrada da Normal
nx = _nx;
ny = _ny;
nz = _nz;
} // fim do construtor
}; // fim da estrutura CustomVertex_PositionNormal
// Declaração dos vértices para o triângulo
CustomVertex_PositionNormal g_Vertices[3 ];
D3DXVECTOR3 g_normal;
Este aqui é o vetor 3d para a normal que apoia a iluminação do
triângulo.
const D3DCOLORVALUE cvBranco = { 1.0f, 1.0f, 1.0f, 1.0f };
Esta é uma outra maneira de definir uma cor dentro do directx através
do uso da estrutura D3DCOLORVALUE cujos elementos são todos do tipo
float e devem estar na faixa de valor entre 0.0f até 1.0f. Estes
valores representam percentuais do componente final da cor. Esta forma
de expressão de cor está muito ligada com as teorias científicas da
cor e da interação da luz com os materiais.
D3DMATERIAL9 g_mtlVermelho;
Aqui definimos uma instância da estrutura D3DMATERIAL9 para produzir
um material vermelho para colorir o triângulo. Esta estrutura está
definida desta forma dentro do arquivo d3d9types.h:
typedef struct _D3DMATERIAL9 {
D3DCOLORVALUE Diffuse; // Cor difusa ARGB
D3DCOLORVALUE Ambient; // Cor ambiente ARGB
D3DCOLORVALUE Specular; // Brilho especular ARGB
D3DCOLORVALUE Emissive; // Cor de emissão ARGG
float Power; // Taxa de definição (sharpness) do brilho especular
} D3DMATERIAL9;
Diffuse - Representa a cor normal do objeto diante da luz principal
Ambient - Cor que o objeto emite na presença da luz ambiente. A luz
ambiente é uma luz secundária formada pelos raios da luz principal
que foram refletidos por outros objetos da cena. Geralmente esses
dois elementos são configurados com a mesma cor.
Power - Fator que controla a definição visual do brilho especular.
Specular - Brilho especular. É aquela bolinha brilhante que fica sobre
uma bola de boliche ou de uma superfície redonda bem polida.
Emissive - É utilizada para simular superfícies auto-iluminadas como
neon, lâmpadas etc.
#define CustomVertex_PositionNormal_Format( D3DFVF_XYZ | D3DFVF_NORMAL )
Esta linha é a definição do formato de vértice que comporta posição
e o vetor 3d normal. Veja abaixo a estrutura de implementação:
// Definição da estrutura de vértice customizado
struct CustomVertex_PositionNormal
{
float x, y, z;
float nx, ny, nz;
// Construtor default
CustomVertex_PositionNormal() {}
// Construtor com inicialização
CustomVertex_PositionNormal( float _x, float _y, float _z,
float _nx, float _ny, float _nz)
{
// entrada da posição
x = _x;
y = _y;
z = _z;
// entrada da Normal
nx = _nx;
ny = _ny;
nz = _nz;
} // fim do construtor
}; // fim da estrutura CustomVertex_PositionNormal
CustomVertex_PositionNormal g_Vertices[3];
Aqui declaramos 3 vértices para produzir o triângulo iluminado.
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 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();
// Cria um material vermelho para o triângulo
criarMaterial(&g_mtlVermelho, cvVermelho);
// Configura e coloca uma luz na cena
D3DXVECTOR3 pos(2.0f, 1.0f, -4.0f);
colocar_PointLight (pos, cvBranco);
return S_OK;
} // initGfx().fim
montar_Geometria();
Antes de montar o triângulo esta função chama calcularNormal() para
obter um valor adequado para o vetor 3d g_normal.
criarMaterial(&g_mtlVermelho, cvVermelho);
Cria um material vermelho para o triângulo. Isto envolve simplesmente
limpar a estrutura do material e configurar os elementos Diffuse e
Ambient para cvVermelho.
D3DXVECTOR3 pos(2.0f, 1.0f, -4.0f);
Definimos aqui a posição da luz. Utilizamos a função ajuda_visual()
para dar uma noção aproximada mas concreta da localização deste ponto
na tela.
colocar_PointLight (pos, cvBranco);
Esta função configura e coloca uma luz do tipo pointlight na cena.
2.3 Configuração da luz do tipo pointlight
void colocar_PointLight(D3DXVECTOR3 pos, D3DCOLORVALUE cvCor)
{
// Declara a estrutura
D3DLIGHT9 luz;
// Limpa a estrutura
ZeroMemory( &luz, sizeof(D3DLIGHT9) );
// Configura tipo
luz.Type = D3DLIGHT_POINT;
// Configura cor
luz.Diffuse = cvCor;
// Configura posição
luz.Position = pos;
// Configura fator de atenuação
luz.Attenuation0 = 0.2f;
// Configura faixa de alcance
luz.Range = 100.0f;
// Instalação e acionamento da luz no dispositivo renderizador
g_device->SetLight( 0, &luz );
g_device->LightEnable( 0, TRUE);
} // colocar_PointLight().fim
// Declara a estrutura
D3DLIGHT9 luz;
Aqui declaramos a estrutura utilizada na criação da fonte de luz.
ZeroMemory( &luz, sizeof(D3DLIGHT9) );
Aqui é o processo rotineiro de limpar a estrutura que vai ser
utilizada.
luz.Type = D3DLIGHT_POINT;
Aqui o tipo de luz pointlight é estabelecido.
// Configura cor
luz.Diffuse = cvCor;
// Configura posição
luz.Position = pos;
Aqui ocorre a configuração da cor e da posição da luz pointlight.
// Configura fator de atenuação
luz.Attenuation0 = 0.2f;
Essa linha configura o primeiro fator de atenuação da luz em função
da distância percorrida. Esse elemento junto com os outros dois
similares é utilizado para simular o esmaecimento da intensidade da
luz à medida em que o raio de luz está mais longe da fonte de emissão.
// Configura faixa de alcance
luz.Range = 100.0f;
Este elemento configura a faixa de alcance da luz. Depois dessa
distância a luz não tem mais efeito.
// Instalação e acionamento da luz no dispositivo renderizador
g_device->SetLight( 0, &luz );
Esta linha instala a luz no dispositivo. Você pode ter centenas de
luzes pré-configuradas mas pode ter apenas algumas luzes ativas
simultâneamente cujo número vai depender do limite dado pela placa de
vídeo. É comum este número máximo ficar abaixo de 8 luzes. A
iluminação deve ser usada sabiamente pois é um recurso que demanda
bastante tempo para ser calculado.
g_device->LightEnable( 0, TRUE);
Aqui a luz é ligada. Desligue a luz quando for fazer algum trabalho
de reconfiguração de algum aspecto da luz.
2.4 Elaboração de materiais
void criarMaterial(D3DMATERIAL9 *mtl, D3DCOLORVALUE cvCor )
{
// Limpa a estrutura
ZeroMemory( mtl, sizeof(D3DMATERIAL9) );
// Configura cor ambiente e difusa
mtl->Ambient = cvCor;
mtl->Diffuse = cvCor;
} // criarMaterial().fim
// Configura cor ambiente e difusa
mtl->Ambient = cvCor;
mtl->Diffuse = cvCor;
Essa função configura apenas os elementos Diffuse e Ambient do
material para a cor especificada. Uma dica legal é escrever uma cópia
dessa função configurando os outros elementos do material.
2.5 Ajuda visual
void ajuda_visual(D3DXVECTOR3 pos, D3DCOLORVALUE cvCor)
{
// Variável de controle do objeto 3d
ID3DXMesh* obj3d;
// Matriz mundo para posicionamento do objeto 3d
D3DXMATRIX mtxMundo;
D3DXMatrixIdentity( &mtxMundo );
// Configuração do material do objeto 3d
D3DMATERIAL9 mtl;
criarMaterial(&mtl, cvCor);
// Cria o objeto 3d
float nRaio = 0.2f;
UINT nSegs = 16;
D3DXCreateSphere(g_device, nRaio, nSegs, nSegs, &obj3d, 0);
// Configura posição do objeto no mundo 3d
D3DXMatrixTranslation(&mtxMundo, pos.x, pos.y, pos.z);
g_device->SetTransform(D3DTS_WORLD, &mtxMundo);
// Configura material
g_device->SetMaterial (&mtl);
// Renderiza o objeto
obj3d->DrawSubset(0);
// Libera o objeto utilizado
obj3d->Release();
} // void ajuda_visual().fim
// Variável de controle do objeto 3d
ID3DXMesh* obj3d;
Esta é a interface do directx para lidar com objetos 3d ou modelos 3d
mais elaborados. Geralmente o modelo 3d é chamado de mesh que pode
ser traduzido como malha em língua portuguesa. O ponteiro obj3d vai
ser usado para receber a geometria de uma esfera 3d.
// Matriz mundo para posicionamento do objeto 3d
D3DXMATRIX mtxMundo;
D3DXMatrixIdentity( &mtxMundo );
Aqui definimos uma matriz de mundo para posicionar a esfera na tela.
// Configuração do material do objeto 3d
D3DMATERIAL9 mtl;
criarMaterial(&mtl, cvCor);
Aqui é o código que aplica o material colorido na esfera.
// Cria o objeto 3d
float nRaio = 0.2f;
UINT nSegs = 16;
D3DXCreateSphere(g_device, nRaio, nSegs, nSegs, &obj3d, 0);
Este bloco de código faz a criação da esfera 3d com as definições de
raio ( nRaio ) e de segmentação horizontal e vertical ( nSegs ) que
passamos.
// Configura posição do objeto no mundo 3d
D3DXMatrixTranslation(&mtxMundo, pos.x, pos.y, pos.z);
g_device->SetTransform(D3DTS_WORLD, &mtxMundo);
Aqui é um bom exemplo de uso da função D3DXMatrixTranslation() que
posiciona a esfera no ponto 3d especificado.
// Configura material
g_device->SetMaterial (&mtl);
Configuramos aqui a esfera com um material colorido.
// Renderiza o objeto
obj3d->DrawSubset(0);
A esfera e os modelos 3d em geral são renderizados com o método
DrawSubset() e o número da peça do modelo (0) a ser renderizada. Cada
parte de um modelo 3d é chamada de subset dentro do directx. Os
objetos formados de uma só parte, como é o caso da esfera, são
renderizados com zero (0) em DrawSubset().
// Libera o objeto utilizado
obj3d->Release();
Depois da esfera renderizada liberamos o objeto no final da função.
2.6 Cálculo da normal
void calcularNormal(D3DXVECTOR3* p0, D3DXVECTOR3* p1,
D3DXVECTOR3* p2, D3DXVECTOR3* pSaida)
{
D3DXVECTOR3 u = *p1 - *p0;
D3DXVECTOR3 v = *p2 - *p0;
D3DXVec3Cross(pSaida, &u, &v);
D3DXVec3Normalize(pSaida, pSaida);
} // calcularNormal().fim
O aspecto mais importante a saber dessa função é que ela recebe 3
vértices (p0, p1, p2) e retorna um vértice perpendicular (pSaida)
aos vértices fornecidos.
Poderíamos ter fornecido diretamente o valor da normal sem a presença
dessa função, mas consideramos que esta função pode ser útil em
outros contextos dentro da programação de jogos para localizar ou
projetar pontos na frente de uma superfície.
Não vamos discutir os aspectos de matemática envolvidos para não
avolumar este tópico. Vamos deixar apenas recomendações de pesquisa
com as palavras chaves em inglês e português. A temática envolvida
está toda dentro de vetores matemáticos.
D3DXVECTOR3 u = *p1 - *p0;
D3DXVECTOR3 v = *p2 - *p0;
Pesquise por subtração de vetores ou vector subtraction
D3DXVec3Cross(pSaida, &u, &v);
Pesquise por produto cruzado de vetores ou vector cross product
D3DXVec3Normalize(pSaida, pSaida);
Pesquise por normalização de vetores ou normalizing vectors.
2.7 Configuração de estados do dispositivo renderizador
void configurar_cenaEstados(void)
{
// Mostra a parte interna do polígono
g_device->SetRenderState (D3DRS_CULLMODE, D3DCULL_NONE);
// Habilita iluminação
g_device->SetRenderState (D3DRS_LIGHTING, true);
// Aplica o material no dispositivo renderizador
g_device->SetMaterial(&g_mtlVermelho);
// Corrige as normais
g_device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
// Desabilita cálculo de luz especular
g_device->SetRenderState(D3DRS_SPECULARENABLE, false);
} // configurar_cenaEstados().fim
g_device->SetRenderState (D3DRS_LIGHTING, true);
Depois que uma luz foi colocada na cena é necessário habilitar a
iluminação configurando esse estado para true.
g_device->SetMaterial(&g_mtlVermelho);
Esta linha configura o material no dispositivo. Depois dessa linha
tudo que for renderizado ganha a aplicação desse material.
g_device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
Essa linha indica ao directx fazer uma correção nas normais que podem
perder a sintonia com os vértices durante as transformações.
g_device->SetRenderState(D3DRS_SPECULARENABLE, false);
O cálculo de luz especular é dispendioso. Esta linha desliga a
aplicação de luz especular na cena. Habilite este estado para true
quando for usar o efeito de brilho especular que também deve estar
presente na configuração de luz e do material.
2.8 Montagem do triângulo iluminado
void montar_Geometria(void)
{
// Posicionamento de profundidade
float zpos = 0.0f;
// Faz o cálculo da normal para configurar os vértices
calcularNormal (&D3DXVECTOR3(0.0f, 1.0f, zpos),
&D3DXVECTOR3(-1.0f, -1.0f, zpos),
&D3DXVECTOR3(1.0f, -1.0f, zpos), &g_normal);
// p0 - primeiro vértice
g_Vertices[0] = CustomVertex_PositionNormal( 0.0f, 1.0f, zpos,
g_normal.x, g_normal.y, g_normal.z);
// p1 - segundo vértice
g_Vertices[1] = CustomVertex_PositionNormal( -1.0f, -1.0f, zpos,
g_normal.x, g_normal.y, g_normal.z);
// p2 - terceiro vértice
g_Vertices[2] = CustomVertex_PositionNormal( 1.0f, -1.0f, zpos,
g_normal.x, g_normal.y, g_normal.z);
} // montar_Geometria().fim
calcularNormal (&D3DXVECTOR3(0.0f, 1.0f, zpos),
&D3DXVECTOR3(-1.0f, -1.0f, zpos), &D3DXVECTOR3(1.0f, -1.0f, zpos), &g_normal);
Aqui a função calcularNormal() utilizando os valores de [x,y,z]
presentes nos vértices calcula o valor adequado para o vértice 3d
g_normal.
// (...)
// p2 - terceiro vértice
g_Vertices[2] = CustomVertex_PositionNormal( 1.0f, -1.0f, zpos,
g_normal.x, g_normal.y, g_normal.z);
Na sequência os vértices são configurados adequadamente com a
coordenada [x,y,z] de posição e com a coordenada [x,y,z] da normal.
2.9 Renderização do triângulovoid renderizar_Geometria()
{
// Configura formato de vértice no dispositivo
g_device->SetFVF( CustomVertex_PositionNormal_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_PositionNormal);
// Desenha forma geométrica
g_device->DrawPrimitiveUP( D3DPT_TRIANGLELIST, nContagem, &g_Vertices, nPasso);
// Mostra localização aproximada da luz
ajuda_visual( D3DXVECTOR3(1.5f, 0.5f, -3.5f), cvAmarelo);
// Mostra posição da normal
ajuda_visual( g_normal, cvVerde);
} // renderizar_Geometria().fim
// Configura formato de vértice no dispositivo
g_device->SetFVF( CustomVertex_PositionNormal_Format);
// Tamanho do passo para achar o próximo vértice
UINT nPasso = sizeof(CustomVertex_PositionNormal);
Repare que a cada mudança no formato de vértice essa função é
reajustada para se adequar ao formato de vértice utilizado na
configuração dos vértices.
// Mostra localização aproximada da luz
ajuda_visual( D3DXVECTOR3(1.5f, 0.5f, -3.5f), cvAmarelo);
// Mostra posição da normal
ajuda_visual( g_normal, cvVerde);
A maior novidade dessa função é a função auxiliar ajuda_visual() que
grafa na tela a posição aproximada da colocação da luz e a posição
da normal. O espaçamento dos pontos no mundo 3d se modifica quando se
muda o tamanho do frustrum da câmera. Então para se acostumar com um
padrão de espaçamento é necessário fixar um tamanho padrão para a
área do frustrum.
2.10 Renderização da cena
A função Renderizar() está bem modularizada com o destaque da função
configurar_cenaEstados() que configura os estados do dispositivo
renderizador interessantes para a aplicação.
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, azul, 1.0f, 0);
// Configure estados de renderização
configurar_cenaEstados();
// 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
3. Código fonte do projeto de exemplo: prj_Luz
// Projeto: prj_Luz - Arquivo: motor.h
// Esta aplicação ilustra como iluminar um triângulo
// 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);
// Configura alguns estados de renderização
void configurar_cenaEstados(
void);
// Cria um material
void criarMaterial(
D3DMATERIAL9 *mtl,
D3DCOLORVALUE cvCor);
// Configura e coloca uma luz pointlight na cena
void colocar_PointLight(
D3DXVECTOR3 pos,
D3DCOLORVALUE cvCor);
// Faz o cálculo da normal para iluminar o triângulo
void calcularNormal(
D3DXVECTOR3* p0,
D3DXVECTOR3* p1,
D3DXVECTOR3* p2,
D3DXVECTOR3* pSaida);
// Ajuda a visualizar a localização do ponto 3d
void ajuda_visual(
D3DXVECTOR3 pos,
D3DCOLORVALUE cvCor);
// 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_Luz - arquivo: motor.cpp
// Esta aplicação ilustra como iluminar um triângulo
// 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;
float nVelocidade = 0.1f;
// 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 azul = 0xFF0000FF;
// Constante para cores com rgba expressado como float's
const D3DCOLORVALUE cvBranco = { 1.0f, 1.0f, 1.0f, 1.0f };
const D3DCOLORVALUE cvVermelho = { 1.0f, 0.0f, 0.0f, 1.0f };
const D3DCOLORVALUE cvAmarelo = { 1.0f, 1.0f, 0.0f, 1.0f };
const D3DCOLORVALUE cvVerde = { 0.0f, 1.0f, 0.0f, 1.0f };
// Variável para o material
D3DMATERIAL9 g_mtlVermelho;
// Indicação de entrada de luz
D3DXVECTOR3 g_normal;
// Definição do formato de vértice utilizado pela aplicação
#define CustomVertex_PositionNormal_Format(D3DFVF_XYZ | D3DFVF_NORMAL)
// Definição da estrutura de vértice customizado
struct CustomVertex_PositionNormal
{
float x, y, z;
float nx, ny, nz;
// Construtor default
CustomVertex_PositionNormal() {}
// Construtor com inicialização
CustomVertex_PositionNormal( float _x, float _y, float _z,
float _nx, float _ny, float _nz)
{
// entrada da posição
x = _x;
y = _y;
z = _z;
// entrada da Normal
nx = _nx;
ny = _ny;
nz = _nz;
} // fim do construtor
}; // fim da estrutura CustomVertex_PositionNormal
// Declaração dos vértices para o triângulo
CustomVertex_PositionNormal 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();
// Cria um material vermelho para o triângulo
criarMaterial(&g_mtlVermelho, cvVermelho);
// Configura e coloca uma luz na cena
D3DXVECTOR3 pos(2.0f, 1.0f, -4.0f);
colocar_PointLight (pos, cvBranco);
return S_OK;
} // initGfx().fim
void colocar_PointLight(D3DXVECTOR3 pos, D3DCOLORVALUE cvCor)
{
// Declara a estrutura
D3DLIGHT9 luz;
// Limpa a estrutura
ZeroMemory( &luz, sizeof(D3DLIGHT9) );
// Configura tipo
luz.Type = D3DLIGHT_POINT;
// Configura cor
luz.Diffuse = cvCor;
// Configura posição
luz.Position = pos;
// Configura fator de atenuação
luz.Attenuation0 = 0.2f;
// Configura faixa de alcance
luz.Range = 100.0f;
// Instalação e acionamento da luz no dispositivo renderizador
g_device->SetLight( 0, &luz );
g_device->LightEnable( 0, TRUE);
} // colocar_PointLight().fim
void criarMaterial(D3DMATERIAL9 *mtl, D3DCOLORVALUE cvCor )
{
// Limpa a estrutura
ZeroMemory( mtl, sizeof(D3DMATERIAL9) );
// Configura cor ambiente e difusa
mtl->Ambient = cvCor;
mtl->Diffuse = cvCor;
} // criarMaterial().fim
void ajuda_visual(D3DXVECTOR3 pos, D3DCOLORVALUE cvCor)
{
// Variável de controle do objeto 3d
ID3DXMesh* obj3d;
// Matriz mundo para posicionamento do objeto 3d
D3DXMATRIX mtxMundo;
D3DXMatrixIdentity( &mtxMundo );
// Configuração do material do objeto 3d
D3DMATERIAL9 mtl;
criarMaterial(&mtl, cvCor);
// Cria o objeto 3d
float nRaio = 0.2f;
UINT nSegs = 16;
D3DXCreateSphere(g_device, nRaio, nSegs, nSegs, &obj3d, 0);
// Configura posição do objeto no mundo 3d
D3DXMatrixTranslation(&mtxMundo, pos.x, pos.y, pos.z);
g_device->SetTransform(D3DTS_WORLD, &mtxMundo);
// Configura material
g_device->SetMaterial (&mtl);
// Renderiza o objeto
obj3d->DrawSubset(0);
// Libera o objeto utilizado
obj3d->Release();
} // void ajuda_visual().fim
void calcularNormal(D3DXVECTOR3* p0, D3DXVECTOR3* p1,
D3DXVECTOR3* p2, D3DXVECTOR3* pSaida)
{
D3DXVECTOR3 u = *p1 - *p0;
D3DXVECTOR3 v = *p2 - *p0;
D3DXVec3Cross(pSaida, &u, &v);
D3DXVec3Normalize(pSaida, pSaida);
} // calcularNormal().fim
void configurar_cenaEstados(void)
{
// Mostra a parte interna do polígono
g_device->SetRenderState (D3DRS_CULLMODE, D3DCULL_NONE);
// Habilita iluminação
g_device->SetRenderState (D3DRS_LIGHTING, true);
// Aplica o material no dispositivo renderizador
g_device->SetMaterial(&g_mtlVermelho);
// Corrige as normais
g_device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
// Desabilita cálculo de luz especular
g_device->SetRenderState(D3DRS_SPECULARENABLE, false);
} // configurar_cenaEstados().fim
void montar_Geometria(void)
{
// Posicionamento de profundidade
float zpos = 0.0f;
// Faz o cálculo da normal para configurar os vértices
calcularNormal (&D3DXVECTOR3(0.0f, 1.0f, zpos),
&D3DXVECTOR3(-1.0f, -1.0f, zpos),
&D3DXVECTOR3(1.0f, -1.0f, zpos), &g_normal);
// p0 - primeiro vértice
g_Vertices[0] = CustomVertex_PositionNormal( 0.0f, 1.0f, zpos,
g_normal.x, g_normal.y, g_normal.z);
// p1 - segundo vértice
g_Vertices[1] = CustomVertex_PositionNormal( -1.0f, -1.0f, zpos,
g_normal.x, g_normal.y, g_normal.z);
// p2 - terceiro vértice
g_Vertices[2] = CustomVertex_PositionNormal( 1.0f, -1.0f, zpos,
g_normal.x, g_normal.y, g_normal.z);
} // montar_Geometria().fim
void renderizar_Geometria()
{
// Configura formato de vértice no dispositivo
g_device->SetFVF( CustomVertex_PositionNormal_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_PositionNormal);
// Desenha forma geométrica
g_device->DrawPrimitiveUP( D3DPT_TRIANGLELIST, nContagem, &g_Vertices, nPasso);
// Mostra localização aproximada da luz
ajuda_visual( D3DXVECTOR3(1.5f, 0.5f, -3.5f), cvAmarelo);
// Mostra posição da normal
ajuda_visual( g_normal, cvVerde);
} // renderizar_Geometria().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, 5.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
// 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)
{
// Variável para receber o ângulo final
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
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, azul, 1.0f, 0);
// Configure estados de renderização
configurar_cenaEstados();
// 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
// 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_Luz - arquivo: entrada.cpp
// Esta aplicação ilustra como iluminar um triângulo
// 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_Luz";
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