Portal Chamar Táxi

Biblioteca Gráfica OpenGl

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Transformações Geométricas Hierárquicas em OpenGL
Representando Transformações Geométricas por Matrizes
As transformações geométricas aplicadas usando comandos OpenGL do tipo glTranslate, glRotate ou glScale, são sempre armazenadas em uma matriz chamada MODELVIEW.
A cada chamada de uma destas funções OpenGL cria uma matriz de transformação específica para a função e a seguir multiplica esta matrix pela matriz MODELVIEW atual.

Por exemplo, na chamada da função glTranslatef(-3, 2, -8)é criada a seguinte matriz:

1.00 0.00 0.00 0.00
0.00 1.00 0.00 0.00
0.00 0.00 1.00 0.00
-3.00 2.00 -8.00 1.00

Note que na última linha da matriz são colocados os valores passados como parâmetros para a função.

No momento de exibir um objeto o que OpenGL faz é a multiplicação desta matriz pelo vértices do objeto, obtendo assim a posição final do objeto. Por exemplo, no caso de exibir o ponto (10, 15, 20) seria obtido o ponto (7,17, 12) da seguinte forma:

Equacao.PNG


Caso seja desejável ou necessário, é possivel setar "à mão" esta matriz de transformação. Esta operação manual pode ser feita de tres formas:
- usando a função glLoadIdentity(): com esta função a matriz de transformação converte-se na matriz identidade;
- usando a função glLoadMatrixf(matrix): com esta função é possível definir uma nova matriz de transformação destruindo-se a matrix anterior.
- usando a função glMultMatrixf(matrix): com esta função é possível multiplicar a matriz de transformação atual por uma segunda matriz.
 

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Aplicando novas Matrizes de Transformação
Caso se tenha uma nova transformação (também representada em forma de matriz) é possivel aplicá-la a matriz atual, bastando multiplicar a matriz atual pela nova matriz.
Por exemplo, caso tenhamos a matriz de transformação para uma translação (5, 7, 2) a equação a seguir calcula a nova matriz.


image7ER.JPG


Obtendo a Matriz de Transformação Corrente
Para obter a matriz de transformação geométrica atual em OpenGL usa-se a função glGetFloatv da seguinte forma:

GLfloat Matriz[4][4];
glGetFloatv(GL_MODELVIEW_MATRIX, &Matriz[0][0]);

Armazenando as Transformações de um objeto em uma matriz
Para armazenar as transformações geométricas de um objeto em uma matriz deve-se chamar a função glGetFloatv imediatamente após terem sido setadas todas estas transformações do objeto.

Por exemplo:

// **********************************************************************
// void RecalculaMatrizObjeto()
// **********************************************************************
void RecalculaMatrizObjeto()
{
glPushMatrix();
glLoadIdentity();
glTranslatef (PosObj.X, PosObj.Y, PosObj.Z);
// guarda a matriz de transformação do objeto para um futuro uso
glGetFloatv(GL_MODELVIEW_MATRIX, &MatObj[0][0]);
glPopMatrix();
}


 

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Alterando a Matriz de Transformação antes de desenhar um objeto
Uma vez que se tem a matriz de transformações de um objeto é possível aplicar estas transformações multiplicando-se esta matriz pela matriz atual. Isto é feito da seguunte forma:

// **********************************************************************
// void DesenhaObjeto()
// **********************************************************************
void DesenhaObjeto()
{
glColor3f(0.0f,0.0f,0.6f);
glPushMatrix();
glMultMatrixf(&MatObj[0][0]);
DesenhaCubo();
glPopMatrix();
}


Montando Transformações Hierárquicas
A montagem de uma hierarquia de trnasfomações serve para que se possa definir um objeto como filho de outro.
Neste caso, o objeto filho sofrerá todas as transformações geométrica aplicadas a seu pai. Para tanto deve-se apenas desenhar o objeto logo após o desenho de seu. O exemplo a seguir ilustra este procediemnto.

// **********************************************************************
// void DesenhaPAI()
// **********************************************************************
void DesenhaPAI()
{
glColor3f(0.7f,0.7f,0.0f);

glPushMatrix();
glMultMatrixf(&Mat_Pai[0][0]); // aplica as transformações do pai
DesenhaCubo();
if (TemFilho)
DesenhaObjeto(); // desenha Filho
glPopMatrix();
}

Neste caso, entretato, no instante em que se torna um objeto filho de outro, este filho irá sofrer as transformações geométricas de seu pai adicionadas às suas. Por exemplo, se o pai tem uma translação em X igual a 40 e o filho outra igual a 30, então o objeto filho irá ser transladado de 70 unidades. Isto irá ocorrer no momento em que o objeto filho for desenhado pela primeira vez após o pai, causando uma translação indesejada.
 

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Montando o vínculo de hierarquia
Para contornar este efeito colateral é ncessário que no momento do estabelecimento da relação pai-filho, a matriz do filho desfaça as transformações existentes no pai naquele momento. Para tanto deve-se multiplicar a matriz do filho pela inversa da matriz do pai, conforme o exemplo a seguir.

// **********************************************************************
// void CriaVinculoPai_Filho()
// **********************************************************************
void CriaVinculoPai_Filho()
{
GLfloat MatInv[4][4];

TemFilho = TRUE;

// calcula a inversa da matriz do Pai
CopyMatrix(MatInv_Pai, Mat_Pai);
M_invert(MatInv_Pai);
// Multiplica a Matriz do filho pela inversa da matriz do pai
M_mult(MatObj, MatInv_Pai); // MatObj = MatObj * MatInv_Pai
}


Note que isto deve ser feito somente no instante em que se estabelece o vínculo entre pai e filho. Isto porque só deve-se desfazer as transformações do pai que existem no momento do estabelecimento do vínculo. A partir deste momento, se uma nova transformaçõa for aplicada ao pai, ela deverá ser também aplicada ao filho.

Desfazendo o vínculo de hierarquia
Para desfazer o vínculo de hierarquia e deixar o objeto no mesmo lugar deve-se multiplicar sua matriz pela matriz atual de seu pai. Se isto não for feito ocorrerá uma translação indesejada no objeto filho pois este deixará de sofrer as translações do pai (após o término do vínculo).

// **********************************************************************
// void DesfazVinculoPai_Filho()
// **********************************************************************
void DesfazVinculoPai_Filho()
{
TemFilho = FALSE;
M_mult(MatObj, MatPai); // MatObj = MatObj * Mat_Pai
}


A partir deste momento o objeto filho não mais deverá ser desenhado após o pai.



Exemplos
 

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Geração de Imgens Estereoscópicas em OpenGL
A idéia básica de criação de imagens estereoscópicas em OpenGL é geração de imagem diferente para cada olho a partir da mudança da posição do observador.

No caso do uso de um Óculos do tipo I-Glasses, a separação entre a imagem do olho esquerdo e do olho direito é feita pelo hardware do óculos que põe no visor do olho direito as imagens das linhas pares da tela, e no visor do olho esquerdo a imagem das linhas ímpres.

Para fazer a separação das iamgens na tela, usa-se o stencil buffer, com o seguinte algoritmo:

Bloqueia-se, através do stencil buffer, a exibição das imagens nas linhas impares;
Exibe-se a imagem referente ao olho direito;
Libera-se, através do stencil buffer, a exibição das imagens nas linhas impares;
Bloqueia-se, através do stencil buffer, a exibição das imagens nas linhas pares;
Exibe-se a imagem referente ao olho esquerdo
// **********************************************************************
//
// **********************************************************************
void display( void )
{

// Limpa a tela
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

DefineLuz();

PosicUser(ESQUERDO); // posiciona o observador no olho esquerdo
DesabilitaDesenhoNoStencil();
DesenhaCena();

PosicUser(DIREITO); // posiciona o observador no olho direito
HabilitaDesenhoNoStencil();
DesenhaCena();

glutSwapBuffers();

}
 

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Posicionamento do Observador

// **********************************************************************
// void PosicUser()
// esta função define a posicã0 de cada um dos olhos do observador
//
// **********************************************************************
void PosicUser(int Olho)
{
// Set the clipping volume
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(80,ratio,0.01,200);

switch (Olho)
{
case ESQUERDO:
gluLookAt(-DistOlhos/2, 0, 5, 0, 0, 0, 0.0f,1.0f,0.0f);
break;
case DIREITO:
gluLookAt(DistOlhos/2, 0, 5, 0, 0, 0, 0.0f,1.0f,0.0f);
break;
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

}
 

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Marcação do Stencil
Para permitir o bloqueio e desbloqueio das imagens no stencil, deve-se desenhar linhas horizontais na linhas pares


// **********************************************************************
// void DesenhaFundo()
// Inicializa o stencil com 1 nas linhas pares
//
// **********************************************************************
void DesenhaFundo(int Largura, int Altura )
{

glMatrixMode(GL_PROJECTION); //
glLoadIdentity ();
gluOrtho2D(0, Largura, 0, Altura);

glMatrixMode(GL_MODELVIEW);

glBegin(GL_LINES);
// inicializa apenas as linhas pares no stencil
for (int y= 0; y < Altura; y += 2)
{
DrawLine(0,y, Largura, y);
}
glEnd();
// volta à matriz de objetos
//glMatrixMode(GL_MODELVIEW);

}

// **********************************************************************
// void DrawStencil()
//
//
// **********************************************************************
void DrawStencil(int Largura, int Altura )
{
// Habilita o uso do Stencil
glEnable(GL_STENCIL_TEST);

// Define que "0" será usado para limpar o Stencil
glClearStencil(0);
// limpa o Stencil
glClear(GL_STENCIL_BUFFER_BIT);

glStencilFunc(GL_ALWAYS, 1, 1);
glStencilOp(GL_REPLACE,GL_REPLACE,GL_REPLACE);

DesenhaFundo(Largura,Altura);

}


Faça o download de um exemplo clicando aqui.
 

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Cálculo das Equações que Definem os Planos Limitantes de um Volume de Visualização
O objetivo dos cálculos apresentados a seguir é a determinação das coordenadas dos pontos verdes da figura abaixo.
A partir deste pontos são calculadas as equações dos planos limitantes do volume de visualização.


DadosIniciais1.jpg




Dados Iniciais
Para que se possa calcular os pontos deve-se ter em mãos os seguintes dados:

OBS: posição do observador
ALVO: Posição para onde se está olhando
NEAR: Distância entre o OBS e o plano Near
FAR: Distância entre o OBS e o plano Far
RIGHT: Distância do centro do Plano near até sua lateral direita



DadosIniciais2.jpg



DadosIniciais3.jpg
 

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Cálculo dos Pontos Extremos do Plano NEAR
O cálculo dos pontos verdes é feito calculando-se um "caminho de vetores" do OBS até cada um dos pontos.
O cálculo do ponto verde no canto superior-direito do plano Near pode ser obtido conforme o caminho apresentado na figura a seguir.



VetoresParaP1.jpg


Inicialmente calcula-se o vetor unitário que representa o vetor de visão (VV).
VV = ALVO - OBS

VV = VV / Módulo (VV)
Cria-se um vetor que vai do OBS ao plano Near. Chamemos este vetor de V1.
V1 = VV * NEAR
Obtém-se o ponto onde V1 toca o plano Near, somando V1 a OBS. Charemos este ponto de PCentroNear.
PCentroNear = V1 + OBS
Obtém-se um vetor na direção de VDIR fazendo o produto vetorial de V1 por UP = (0,1,0).

VDIR = V1 x UP
Transforma-se VDIR em unitário

VDIR = VDIR / Módulo (VDIR)
Altera-se o tamanho de VDIR para RIGHT

VDIR = VDIR * Right
Calcula-se o ponto DireitaNear (na borda do plano NEAR) somando-se VDIR ao CentroNear
DireitaNear = VDIR + CentroNear
Obtém-se um vetor na direção de VUpDir fazendo o produto vetorial de VDIR por V1.

VUPDIR = VDIR x V1
Transforma-se VUpDir em unitário


VUPDIR = VUPDIR / Módulo (VUPDIR)
Altera-se o tamanho de VUPDIR para TOP

VUPDIR = VUPDIR * Top
Obtém-se o ponto final, no canto superior direito do plano Near, somando-se o VUPDIR ao ponto DireitaNear

CantoSuperiorDireito = DireitaNear + VUPDIR


 

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Transparências em OpenGL
Para exibir objetos transparentes em OpenGL, deve-se utilizar as Funções de Blend (ou de mistura). Estas funções misturam a cor do objeto que JÁ está na tela com cor do objeto que está sendo desenhado num dado momento.

Assim, como OpenGL trata sempre sobre a imagem que JÁ FOI GERADA, é importante que os objeto transparentes sejam EXIBIDOS DEPOIS de todos os demais.

Configurando OpenGL para usar Transparências
Em primeiro lugar é necessário ativar as funções de BLEND. Para tanto, em OpenGL usa-se:
glEnable(GL_BLEND);

Quando for necessário desenhar um objeto quen não é transparente deve-se desativar o BLEND:
glEnable(GL_BLEND);

Definição do nível de Transparência de um Objeto
Para definir o nível de transparência de um objeto é necessário especificar o ALFA de sua cor. PAra tanto usa-se um quarto parâmetro na função glColor.

glColor4f(1,1,1,alfa);

Este quarto parâmetro alfa pode variar entre 0 e 1, sendo 0 um objeto totalmente transparente e 1 um objeto opaco.
 

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Definição das Funções de Mistura
As funçoes de BLEND definem como é feita a mistura entre as cores do objeto que está sendo desenhado e as imagens que já estão na tela. Esta mistura é feita a partir de uma média ponderada entre o ponto da tela e o ponto do objeto que está sendo desenhado. A função OpenGl para definir este pesos é "glBlendFunc".

Esta função recebe dois parâmetro: o primeiro define o peso da cor do novo ponto e o segundo o peso da cor do ponto que já está na tela. Este pesos, em OpenGL, srão sempre uma função do nível de transparência do objeto, ou seja, de seu alfa.

Por exemplo, a chamada:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

define que a nova cor do ponto na tela será:

NovaCorNaTela = CorDoObjeto * AlfaDoObjeto + CorAntigaNaTele * (1-AlfaDoObjeto);

Neste caso, as contantes tem o seguinte sifnificado:
- GL_SRC_ALPHA: define que o peso da cor do objeto que está sendo desenhado é o próprio alfa de sua cor;
- GL_ONE_MINUS_SRC_ALPHA: define que o peso da cor que já está na tela é de (1 - Alfa), onde alfa é o nível de transparência do objeto que está sendo desenhado.
 

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Exemplo
Veja o exemplo a seguir com objeto transparente e outro opaco:

// **********************************************************************
// void display( void )
// **********************************************************************
void display( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

// Desbilita o BLEND par ao primeiro objeto
glDisable(GL_BLEND);
glPushMatrix();
glTranslatef(0,0,-1);
glRotatef ( xrot, 1.0, 0.0, 0.0 );
glRotatef ( yrot, 0.0, 1.0, 0.0 );
glRotatef ( zrot, 0.0, 0.0, 1.0 );

// habilita remoção de faces traseiras
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
DrawCube(0.5);
glPopMatrix();

// Habilita o BLEND para ao segundo objeto
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

// NovaCorNaTela = CorDoObjeto * AlfaDoObjeto + CorAntigaNaTele * (1-AlfaDoObjeto)

DesenhaVidro(AlfaVidro);

xrot+=0.3f;
yrot+=0.2f;
zrot+=0.4f;
glutSwapBuffers();
}
 

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Exercícios
Compile e rode este programa. Um objeto transparente.
// **********************************************************************
// FirstTransp.cpp -- Exemplo de Transparências
//
//
// **********************************************************************

#include <windows.h>
#include <stdio.h>
#include <gl\gl.h>
#include <gl\glu.h>


#ifndef __GNUC__
#include <glut.h>
#endif

#ifdef __GNUC__
#include "glut.h"
#endif


float xrot;
float yrot;
float zrot;
float ratio;
float AlfaVidro=0.5f;

// **********************************************************************
// void init(void)
// Inicializa os parâmetros globais de OpenGL
//
// **********************************************************************
void init(void)
{
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Black Background

glEnable(GL_COLOR_MATERIAL);

glEnable(GL_DEPTH_TEST); // habilita ZBuffer

}

// **********************************************************************
// void reshape( int w, int h )
// trata o redimensionamento da janela OpenGL
//
// **********************************************************************
void reshape( int w, int h )
{
// Prevent a divide by zero, when window is too short
// (you cant make a window of zero width).
if(h == 0)
h = 1;

ratio = 1.0f * w / h;

glMatrixMode(GL_PROJECTION);
glLoadIdentity();

glViewport(0, 0, w, h);

// Seta o ângulo de visão
gluPerspective(50,ratio,1,200);

// Define a posição do observador
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, 5,
0,0,0,
0.0f,1.0f,0.0f);

}
// **********************************************************************
// void DrawCube()
//
//
// **********************************************************************
void DrawCube(GLfloat alfa)
{

glBegin ( GL_QUADS );
// Front Face
glColor4f(0.7f,0.7f,0, alfa);
glVertex3f(-1.0f, -1.0f, 1.0f);
glVertex3f( 1.0f, -1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
// Back Face
glColor4f(0,0,0.7f, alfa);
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glVertex3f( 1.0f, 1.0f, -1.0f);
glVertex3f( 1.0f, -1.0f, -1.0f);
// Top Face
glColor4f(0.7f,0,0.7f, alfa);
glVertex3f(-1.0f, 1.0f, -1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, -1.0f);
// Bottom Face
glColor4f(0.7f,0.7f,0.7f, alfa);
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f( 1.0f, -1.0f, -1.0f);
glVertex3f( 1.0f, -1.0f, 1.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
// Right face
glColor4f(0,0.5f,0, alfa);
glVertex3f( 1.0f, -1.0f, -1.0f);
glVertex3f( 1.0f, 1.0f, -1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f, -1.0f, 1.0f);
// Left Face
glColor4f(0.7f,0,0, alfa);
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
}

// **********************************************************************
// void DesenhaPlano(GLfloat alfa)
//
//
// **********************************************************************
void DesenhaPlano(GLfloat alfa)
{
glBegin(GL_QUADS);
glVertex3f(-1.0f, -1.0f, 1.0f);
glVertex3f( 1.0f, -1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glEnd();
}

// **********************************************************************
// void DesenhaVidro(GLfloat alfa)
//
//
// **********************************************************************
void DesenhaVidro(GLfloat alfa)
{
static float x= -2;
static float delta = -0.02f;
glPushMatrix();
glTranslatef(x,0,0);
if ((x > 2) || (x < -2))
delta *= -1;
x += delta;
glColor4f(1,1,1,alfa);
DesenhaPlano(1);
glPopMatrix();

}
// **********************************************************************
// void display( void )
// **********************************************************************
void display( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );


// Desbilita o BLEND par ao primeiro objeto
glDisable(GL_BLEND);
glPushMatrix();
glTranslatef(0,0,-1);
glRotatef ( xrot, 1.0, 0.0, 0.0 );
glRotatef ( yrot, 0.0, 1.0, 0.0 );
glRotatef ( zrot, 0.0, 0.0, 1.0 );

// habilita remoção de faces traseiras
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
DrawCube(0.5);
glPopMatrix();

// Habilita o BLEND para ao segundo objeto
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

// NovaCorNaTela = CorDoObjeto * AlfaDoObjeto + CorAntigaNaTele * (1-AlfaDoObjeto)

glPushMatrix();
glTranslatef(0,0,0);
DesenhaVidro(AlfaVidro);
glPopMatrix();

xrot+=0.3f;
yrot+=0.2f;
zrot+=0.4f;
glutSwapBuffers();
}

// **********************************************************************
// void keyboard ( unsigned char key, int x, int y )
//
//
// **********************************************************************
void keyboard ( unsigned char key, int x, int y )
{
switch ( key )
{
case 27:
exit ( 0 );
break;
}
}

// **********************************************************************
// void main ( int argc, char** argv )
//
//
// **********************************************************************
void main ( int argc, char** argv )
{
glutInit ( &argc, argv );
glutInitDisplayMode ( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA );
glutInitWindowPosition (0,0);
glutInitWindowSize ( 700, 500 );
glutCreateWindow ( "Tópicos em Computação Gráfica - Teste (UM) com Transparencias..." );

init ();

glutDisplayFunc ( display );
glutReshapeFunc ( reshape );
glutKeyboardFunc ( keyboard );
glutIdleFunc ( display );
glutMainLoop ( );
}


No caso de usar o DEV CPP, lembre-se de colocar as opções -lopengl32 -lglu32 -lglut32 no projeto


Altere o programa de forma que ele permita a mudança do nível de transparência do objeto que se move. Veja as imagens abaixo.
Faça outra alteração de forma a mover o objeto transparente para frente e para trás.

Transp1.jpg



Texturas com Transparências
Faço o dowload deste programa e teste o uso de transparências e texturas no mesmo programa.
Para compilá-lo, inclua os dois arquivos .CPP no seu projeto.
No caso de usar o DEV CPP, lembre-se de colocar as opções -lopengl32 -lglu32 -lglut32 no projeto.
 

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Mascaramento de regiões em OpenGL
Uso do STENCIL Bufffer


A utilização de áreas de mascaramento telas geradas com programas OpenGL tem o objetivo de criar regiões onde os objetos não podem ser desenhados.
Um exemplo disto são as áreas reservadas a menus e telas de ajuda. Estas, quando presentes na tela, não devem ser afetadas pelos desenhos 3D gerados com comandos OpenGL.
Para dar suporte a este tipo de situação a biblioteca OpenGL possui um recurso chamado de Stencil Buffer.

O Stencil Buffer é uma matriz bidimensional que possui o mesmo tamanho da janela de desenho usada em para exibir os objetos OpenGL. Para criá-la deve-se usar a constante GLUT_STENCIL no comando de inicialização da GLUT:

glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH |GLUT_STENCIL);
Funcionamento do Stencil Buffer
Limpeza do Stencil Buffer
Todas as vezes que a janela desenho de OpenGL for redimensionada, é necessário limpar o Stencil Buffer. Isto é feito da seguinte forma:

// Habilita o uso do Stencil neste programa
glEnable(GL_STENCIL_TEST);
// Define que "0" será usado para limpar o Stencil
glClearStencil(0);
// limpa o Stencil
glClear(GL_STENCIL_BUFFER_BIT);
 

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Inicialização do Stencil Buffer
A seguir, é necessário inicializar o Stencil Buffer. Como foi dito anteriormente o Stencil é uma matriz bidimensional. Nesta matiz devem ser colocados valor que serão posteriormente testados para determinar se é possível, ou não, desenhar numa certa área da tela.

Não há, entretanto, funções que permitam o acesso direto ao Stencil Buffer.

O armazenamento de dados no Stencil é feito desenhando-se sobre a tela OpenGL como normalmente se faz. No caso de se desejar colocar dados no Stencil, entretato, define-se funções de teste que irão colocar (ou não) dados na área do Stencil, dependendo do resiltado dos testes.
Por exemplo,
Referencia = 1;
NovoDado = 1;
glStencilFunc(GL_ALWAYS, Referencia, NovoDado);
glStencilOp(GL_REPLACE,GL_REPLACE,GL_REPLACE);
definem que o valor ''NovoDado" será usado para substituir (GL_REPLACE) o conteúdo do Stencil Buffer sempre (GL_ALWAYS) que um desenho for feito na tela de OpenGL.
A partir disto, então, pode-se desenhar qualquer coisa na tela que o Stencil Buffer irá receber o valor "NovoDado" nos pontos correspondentes aos pontos ocupados pelo desenho.
O trecho de código a seguir, por exemplo, define a janela de OpenGL como uma região com coordenadas lógicas de (0,0) a (10,10) e desenha dentro desta região um retângulo. A área ocupada por este retângulo, no Stencil Buffer, será setada com "NovoDado".

// Define uma área de desenha com coordenadas
// lógicas (0,0)->(10,10)

// Ativa matriz de projeção (necessário para usar a gluOrtho2D)
glMatrixMode(GL_PROJECTION);
glLoadIdentity ();
gluOrtho2D(0, 10, 0, 10); // define coordenadas lógicas de desenho

// Volta para a matrix de transformações geométricas
glMatrixMode(GL_MODELVIEW);

// Desenha um retângulo
glRectf(0,4.5, 10,5.5);
 

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Redimensionamento do Stencil Buffer
Como o Stencil deve ter sempre o mesmo tamanho da janela de exibição dos objetos, então a rotina que trata do redimensionamento da janela deve sempre reinicializar o Stencil Buffer com os comandos apresentados acima.
Desenhando DENTRO da área marcada do Stencil Buffer
Para desenhar na área do Stencil Buffer que foi previamente inicializada com um deve-se habilitar esta operação através dos seguintes comandos:
glStencilFunc(GL_EQUAL, 1, 1);
glStencilOp(GL_KEEP,GL_KEEP, GL_KEEP);
Estas funções fazem com que sempre que o Stencil Buffer tiver valor igual (GL_EQUAL) a 1 então o desenho pode ser exibido na tela. O valor existente no Stencil Buffer, no ponto onde o desenho está sendo realizado deverá, ser mantido como está (GL_KEEP).

O trecho de programa seguir exibe dois retângulos (um verde e outro vermelho) na área do Stencil. Note que se faz uso do comando glDisable(GL_DEPTH_TEST) a fim de desabilitar o teste do ZBUFFER. isto é feito pois neste caso o desenho é 2D, não necessitando do uso de teste de profundidade.
glStencilFunc(GL_EQUAL, 1, 1);
glStencilOp(GL_KEEP,GL_KEEP, GL_KEEP);

// Ativa matriz de projeção (necessário para usar a gluOrtho2D)
glMatrixMode(GL_PROJECTION);
glLoadIdentity ();
// define coordenadas lógicas de desenho
gluOrtho2D(0, 10, 0, 10);

// Volta para a matrix de transformações geométricas
glMatrixMode(GL_MODELVIEW);

glDisable(GL_DEPTH_TEST); // Desabilita o ZBuffer

glColor3f(0,1,0); // Desenha um retângulo verde
glRectf(4.5f, 4.5f, 5.5f, 5.5f);

glColor3f(1,0,0); // Desenha um retângulo vermelho
glRectf(2.0f, 4.7f, 8.0f, 5.3f);

glEnable(GL_DEPTH_TEST); // Habilita o ZBuffer
O código descrito aqui deve ser colocado na roina que trata do redesenho da tela.
 

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Desenhando FORA da área marcada do Stencil Buffer
Para desenhar fora da área do Stencil Buffer que foi previamente inicializada com um deve-se habilitar esta operação através dos seguintes comandos:
glStencilFunc(GL_NOTEQUAL, 1, 1);
glStencilOp(GL_KEEP,GL_KEEP, GL_KEEP);
Estas funções fazem com que sempre que o Stencil Buffer tiver valor diferente (GL_NOTEQUAL) de 1 então o desenho pode ser exibido na tela. O valor existente no Stencil Buffer, no ponto onde o desenho está sendo realizado, deverá ser mantido como está (GL_KEEP).

O trecho de programa seguir exibe dois cubos FORA da área do Stencil.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();
glPushMatrix();
glTranslatef ( 1.0f, 0.0f, 0.0f );
glRotatef(ang,0,1,0);
glColor3f(0.5f,0.3f,0.0f);
DesenhaCubo();
glPopMatrix();

glLoadIdentity ();
glPushMatrix();
glTranslatef ( -1.0f, 0.0f, -5.0f );
glRotatef(45,0,1,0);
glColor3f(0.5f,0.3f,0.0f);
DesenhaCubo();
glPopMatrix();

ang = ang + 2;
Programa Exemplo
para copiar o programa-fonte com o código do exemplo apresentado acima.

// **********************************************************************
// StencilTeste1.cpp
//
// Autor: Márcio Serolli Pinho
// **********************************************************************

#include <windows.h>
#include <stdio.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <glut.h>

GLfloat ratio;
static GLfloat ang = 0;

// **********************************************************************
// void DefineLuz(void)
//
//
// **********************************************************************
void DefineLuz(void)
{
// Define cores para um objeto dourado
GLfloat LuzAmbiente[] = {0.24725f, 0.1995f, 0.07f } ;
GLfloat LuzDifusa[] = {0.75164f, 0.60648f, 0.22648f, 1.0f };
GLfloat LuzEspecular[] = {0.626281f, 0.555802f, 0.366065f, 1.0f };
GLfloat PosicaoLuz0[] = {3.0f, 3.0f, 0.0f, 1.0f };
GLfloat PosicaoLuz1[] = {-3.0f, -3.0f, 0.0f, 1.0f };
GLfloat Especularidade[] = {1.0f, 1.0f, 1.0f, 1.0f };

// **************** Fonte de Luz 0

glEnable ( GL_COLOR_MATERIAL );

// Habilita o uso de iluminação
glEnable(GL_LIGHTING);

// Ativa o uso da luz ambiente
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, LuzAmbiente);
// Define os parametros da Luz número Zero
glLightfv(GL_LIGHT0, GL_AMBIENT, LuzAmbiente);
glLightfv(GL_LIGHT0, GL_DIFFUSE, LuzDifusa );
glLightfv(GL_LIGHT0, GL_SPECULAR, LuzEspecular );
glLightfv(GL_LIGHT0, GL_POSITION, PosicaoLuz0 );
glEnable(GL_LIGHT0);

// Ativa o "Color Tracking"
glEnable(GL_COLOR_MATERIAL);

// Define a reflectancia do material
glMaterialfv(GL_FRONT,GL_SPECULAR, Especularidade);

// Define a concentração do brilho.
// Quanto maior o valor do Segundo parametro, mais
// concentrado será o brilho. (Valores válidos: de 0 a 128)
glMateriali(GL_FRONT,GL_SHININESS,51.2);

// **************** Fonte de Luz 1

// Ativa o uso da luz ambiente
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, LuzAmbiente);
// Define os parametros da Luz número Zero
glLightfv(GL_LIGHT1, GL_AMBIENT, LuzAmbiente);
glLightfv(GL_LIGHT1, GL_DIFFUSE, LuzDifusa );
glLightfv(GL_LIGHT1, GL_SPECULAR, LuzEspecular );
glLightfv(GL_LIGHT1, GL_POSITION, PosicaoLuz1 );
glEnable(GL_LIGHT1);

// Ativa o "Color Tracking"
glEnable(GL_COLOR_MATERIAL);

// Define a reflectancia do material
glMaterialfv(GL_FRONT,GL_SPECULAR, Especularidade);

// Define a concentração do brilho.
// Quanto maior o valor do Segundo parametro, mais
// concentrado será o brilho. (Valores válidos: de 0 a 128)
glMateriali(GL_FRONT,GL_SHININESS,20);

}


// **********************************************************************
// void init(void)
// Inicializa os parâmetros globais de OpenGL
//
// **********************************************************************
void Init(void)
{
glClearColor(1.0f, 1.0f, 0.0f, 1.0f); // Fundo de tela preto

glShadeModel(GL_SMOOTH); // modelo de tonalização
glColorMaterial ( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );

glEnable(GL_DEPTH_TEST); // habilita ZBuffer
glEnable ( GL_CULL_FACE ); // Habilita remoçõa de faces traseiras

}

// **********************************************************************
// void PosicUser()
//
//
// **********************************************************************
void PosicUser()
{
// Set the clipping volume
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(80,ratio,0.01,200);
gluLookAt(0, 0, 5,
0,0,0,
0.0f,1.0f,0.0f);

}


// **********************************************************************
// void DesenhaCubo()
//
//
// **********************************************************************
void DesenhaCubo()
{
glBegin ( GL_QUADS );
// Front Face
glNormal3f(0,0,1);
glVertex3f(-1.0f, -1.0f, 1.0f);
glVertex3f( 1.0f, -1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
// Back Face
glNormal3f(0,0,-1);
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glVertex3f( 1.0f, 1.0f, -1.0f);
glVertex3f( 1.0f, -1.0f, -1.0f);
// Top Face
glNormal3f(0,1,0);
glVertex3f(-1.0f, 1.0f, -1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, -1.0f);
// Bottom Face
glNormal3f(0,-1,0);
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f( 1.0f, -1.0f, -1.0f);
glVertex3f( 1.0f, -1.0f, 1.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
// Right face
glNormal3f(1,0,0);
glVertex3f( 1.0f, -1.0f, -1.0f);
glVertex3f( 1.0f, 1.0f, -1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f, -1.0f, 1.0f);
// Left Face
glNormal3f(-1,0,0);
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
}
// **********************************************************************
// void InicializaStencil()
// Esta função deve ser chamada toda vez que a janela for
// redimensionada.
//
// **********************************************************************
void InicializaStencil()
{
// Habilita o uso do Stencil neste programa
glEnable(GL_STENCIL_TEST);

// Define que "0" será usado para limpar o Stencil
glClearStencil(0);
// limpa o Stencil
glClear(GL_STENCIL_BUFFER_BIT);

// *****************************
// Inicialização do Stencil
// *****************************

// Define que o valor 1 será "operado"
// com o valor do stencil
GLint Referencia = 1;
GLuint NovoValor = 1;

// Define o teste a ser feito entre o valor do
// stencil e o valor de "Referencia".
// Se o teste for verdadeiro então NovoValor será
// usado para operar sobre o valor corrente do Stencil
// GL_ALWAYS = o teste é sempre verdadeiro
// GL_EQUAL = o teste é verdadeiro se Referencia == Stencil
// GL_LEQUAL = o teste é verdadeiro se Referencia <= Stencil
// GL_NOTQUAL = o teste é verdadeiro se Referencia != Stencil
glStencilFunc(GL_ALWAYS, Referencia, NovoValor);

// Define como o NovoValor é colocado no Stencil:
// GL_REPLACE = define que o valor atual
// do stencil será trocado pelo NovoValor
// GL_KEEP = define que o valor atual
// do stencil será mantido
glStencilOp(GL_REPLACE,GL_REPLACE,GL_REPLACE);

// Define uma área de desenha com coordenadas
// lógicas (0,0)->(10,10)

// Ativa matriz de projeção (necessário para usar a gluOrtho2D)
glMatrixMode(GL_PROJECTION);
glLoadIdentity ();
gluOrtho2D(0, 10, 0, 10); // define coordenadas lógicas de desenho

// Volta para a matrix de transformações geométricas
glMatrixMode(GL_MODELVIEW);

// Desenha um retângulo
glRectf(0,4.5, 10,5.5);

}
// **********************************************************************
// void reshape( int w, int h )
// trata o redimensionamento da janela OpenGL.
// Atualiza o stencil buffer
// **********************************************************************
void reshape( int w, int h )
{

// evita uma divisão por 0
if(h == 0)
h = 1;

ratio = 1.0f * w / h;
//
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

// Set the viewport to be the entire window
glViewport(0, 0, w, h);

InicializaStencil();
}
// **********************************************************************
// void DesenhaNoStencil()
//
//
// **********************************************************************
void DesenhaNoStencil()
{

static GLfloat DeltaX = -2;
// *****************************
// Libera o desenho na área em que o
// Stencil tem 1
// *****************************

// Se o conteúdo do Stencil for == 1,
// então
// - desenha na tela
// - opera o conteúdo do stencil com o 1...
//
glStencilFunc(GL_EQUAL, 1, 1);
glStencilOp(GL_KEEP,GL_KEEP, GL_KEEP);

glMatrixMode(GL_PROJECTION);
glLoadIdentity ();
gluOrtho2D(0, 10, 0, 10);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();

glDisable(GL_DEPTH_TEST); // Desabilita o ZBuffer

glColor3f(1,0,0);
glRectf(2.0f, 4.7f, 8.0f, 5.3f);

glTranslatef(DeltaX,0,1);
glColor3f(0,1,0);
glRectf(4.5f, 4.5f, 5.5f, 5.5f);
DeltaX +=0.01f;
if (DeltaX > 2.5f)
DeltaX = -2;
printf("DeltaX : %6.3f\n", DeltaX);
glEnable(GL_DEPTH_TEST); // habilita o ZBuffer

}

// **********************************************************************
// void DesenhaForaDoStencil()
//
//
// **********************************************************************
void DesenhaForaDoStencil()
{


// *****************************
// Libera o desenho no Stencil
// na área em que o Stencil é
// DIFERENTE de 1
// *****************************

// Se o conteúdo do Stencil for <> de 1,
// então
// - desenha na tela
// - opera o conteúdo do stencil com o 1...
//
glStencilFunc(GL_NOTEQUAL, 1, 1);
// ... mantendo o stencil como ele estava
glStencilOp(GL_KEEP,GL_KEEP, GL_KEEP);

// *****************************
// Faz o desenho 3D
// *****************************
glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();
glPushMatrix();
glTranslatef ( 1.0f, 0.0f, 0.0f );
glRotatef(ang,0,1,0);
glColor3f(0.5f,0.3f,0.0f);
DesenhaCubo();
glPopMatrix();

glLoadIdentity ();
glPushMatrix();
glTranslatef ( -1.0f, 0.0f, -5.0f );
glRotatef(45,0,1,0);
glColor3f(0.5f,0.3f,0.0f);
DesenhaCubo();
glPopMatrix();

ang = ang + 2;

}
// **********************************************************************
// void display( void )
//
//
// **********************************************************************
void display( void )
{

// Limpa a tela
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

DefineLuz();

PosicUser();

DesenhaForaDoStencil();

DesenhaNoStencil();

glutSwapBuffers();


}

// **********************************************************************
// void keyboard ( unsigned char key, int x, int y )
//
//
// **********************************************************************
void keyboard ( unsigned char key, int x, int y )
{
switch ( key )
{
case 27: // Termina o programa qdo
exit ( 0 ); // a tecla ESC for pressionada
break;
default:
break;
}
}

// **********************************************************************
// void arrow_keys ( int a_keys, int x, int y )
//
//
// **********************************************************************
void arrow_keys ( int a_keys, int x, int y )
{
switch ( a_keys )
{
case GLUT_KEY_UP:

break;
case GLUT_KEY_DOWN:

break;
default:
break;
}
}

// **********************************************************************
// void main ( int argc, char** argv )
//
//
// **********************************************************************
void main ( int argc, char** argv )
{
glutInit ( &argc, argv );
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_STENCIL);
glutInitWindowPosition (0,0);
glutInitWindowSize ( 500, 500 );
glutCreateWindow ( "Tópicos em Computação Gráfica - Teste com STENCIL Buffer." );

Init ();

glutDisplayFunc ( display );
glutReshapeFunc ( reshape );
glutKeyboardFunc ( keyboard );
glutSpecialFunc ( arrow_keys );
glutIdleFunc ( display );

glutMainLoop ( );
}
 

helldanger1

GForum VIP
Entrou
Ago 1, 2007
Mensagens
29,631
Gostos Recebidos
1
Exercício
A partir do exemplo acima, crie um programa que permita a movimentação de um retângulo no Stencil Buffer, conforme este exemplo. Use as teclas de seta para mover o retângulo verde.

imageFL0.JPG




 
Topo