SmVR_CGeometricObject *Mao, *Polegar;Para inserir um novo filho no objeto Mao, pode-se usar o trecho a seguir:
Mao = new SmVR_CGeometricObject("Mao", DesenhaMao);
Polegar = new SmVR_CGeometricObject("Polegar", DesenhaPolegar);
Mao->AddChild(Polegar); // cria a relação entre os objetos
SmVR_CGeometricObject *Indicador;A criação destas relações fará com que qualquer transformação geométrica aplicada ao objeto Mao tenha reflexos sobre todos os obejtos que são seus filhos, no caso, os objetos Polegar e Indicador. Entre os objetos Indicador e Polegar há uma relação de irmão.
Indicador = new SmVR_CGeometricObject("Indicador", DesenhaIndicador);
Mao->AddChild(Indicador);
Graficamente poderíamos representar o grafo construído acima através do seguinte desenho:
Figura - Exemplo de um grafo de cena
A partir deste momento, quaisquer dos objetos do grafo pode receber novos objetos como filhos, da mesma forma como foi feito com os objetos do exemplo acima.
Para exibir um objeto o programador deve evocar o método Render do objeto em questão. Neste momento, além do objeto, todos os seus filhos serão exibidos. No caso, o comando de exibição da mão seria:
Mao->Render();
Podemos definir a geometria dos objetos basicamente de 2 formas. A primeira, criando funções para desenhar o objeto em OpenGL e a segunda lendo os objetos de um arquivo no formato Wavefront OBJ. Nas seções a seguir são apresentadas essas duas alternativas.
Juntamente a SmallVR, é
disponibilizada
a classe "SmVR_COBJLoader" que carrega objetos do Alias
Wavefront (.obj),
criada como uma classe derivada da SmVR_CObjFromFile.
O uso desta classe é feito conforme
o exemplo abaixo.
As informações para obtenção das faces, vértices e outras informações do objeto estão disponiveis aqui.
// Cria o objeto SmallVR
SmVR_CGeometricObject *Bola;
// Cria um objeto para carregar o modelo de arquivo
SmVR_COBJLoader *obj1 = new SmVR_COBJLoader();
// Executa a carga do objeto
obj1->Load("objetos3d/bola.obj");
// Associa o objeto ligo de arquivo com o objeto SmallVR
// Isto é feito passando o objeto "obj1" na construtora da classe
// do objeto SmallVR
Bola = new SmVR_CGeometricObject("bola1", obj1);
// Adiciona o objeto recém criado ao grafo de cena
RootObject->AddChild();
SmVR_CGeometricObject
*obj1;
obj1 = new
SmVR_CGeometricObject("Teste",
DesenhaTeste);
Depois isto é necessário adicionar o objeto ao grafo de cena da SmallVR, através do método AddChild. Lembre-se que a raiz do grafo de cena em nosso exemplos se chama RootObject.
RootObject->AddChild(obj1);
Abaixo temos um exemplo mais completo que mostra como isto é feito.
// função que desenha um objeto com comando OpenGLNeste exemplo cria-se um objeto da classe SmVR_CGeometricObject cujo nome é "Teste".
int DesenhaTeste(void *p) {
glBegin (GL_QUADS);
// Front Face
glVertex3f(-0.5,-0.5, 0.5);
glVertex3f( 0.5,-0.5, 0.5);
glVertex3f( 0.5, 0.5, 0.5);
glVertex3f(-0.5, 0.5, 0.5);
// Complete o cubo com as faces que faltam.
glEnd();
}int main(int argc, char **argv) {
// Inicialização da GLUT
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(800, 600);
glutCreateWindow("Teste");// Inicializaçõa da SmallVR
RootObject = SmVR_Init(NULL);
// criacao do cubo e adicao dele como filho do RootObject
SmVR_CGeometricObject *obj1 = new SmVR_CGeometricObject("Teste", desenhaCubo);
// Inclusão
RootObject->AddChild(obj1);
glutDisplayFunc(RenderScene); // Especifica a função de desenho
glutMainLoop();
return 0;
}
IMPORTANTE:
Não faça nenhuma utilização dos objetos da
classe SmVR_CGeometricObject dentro da rotina que exibe o
objeto.
A título de exemplo, podemos
sugerir
o uso deste parâmetro para a definição a cor de um
objeto. No trecho de código a seguir é passado para o
método
SetRenderFunctionData(void
*d) um vetor que contém os valores R, G, e B da cor do
objeto.
Note que é necessário
aplicar
um type cast sobre os dados passados como parâmetro, a
fim
de adequar os tipos de dados.
IMPORTANTE:
A SmallVR não armazena uma cópia dos dados informados
pelo
método SetRenderFunctionData. Armazena-se apenas um
apontador
para a área de memória onde está o dado a ser
utilizado.
Assim,a fim de que o dado passado como parâmetro possa ser de
fato
utilizado na função de exbição, a
variável
passada como parâmetro para o método SetRenderFunctionData
deve ser global.
int DesenhaTeste(void *p)
{
if(p) // verifica se há algum parâmetro válido
glColor3fv((GLfloat*)p); // Se houver, seta cor do objeto
// Usa o type cast para GLfloat*glBegin (GL_QUADS);
glVertex3f(-0.5,-0.5, 0.5);
glVertex3f( 0.5,-0.5, 0.5);
glVertex3f( 0.5, 0.5, 0.5);
glVertex3f(-0.5, 0.5, 0.5);
...
glEnd();
}
void main ()
{
..........
........
..........
GLfloat azul[3] = { 0, 0, 1};SmVR_CGeometricObject *obj1 = new SmVR_CGeometricObject("Teste", DesenhaTeste);
obj1->SetRenderFunctionData(azul); // define o parâmetro da ser usado na
// rotina de exibição do objetoRootObject->AddChild(obj1);
}
void display(void) {O método Render desenha o objeto e todos seus filhos. Portanto se for utilizado um objeto 'root', pai de todos outros objetos, ao chamar o Render desse objeto todo cenário será exibido. Note-se que esta rotina display é a rotian de exibição de objetos definida na GLUT/OpenGL, através da função glutDisplayFunc.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
PosicUser();
glMatrixMode(GL_MODELVIEW);
RootObject->Render();
glutSwapBuffers();
}....
....
glutDisplayFunc ( display );
....
....
Para inicializar a biblioteca SmallVR deve-se chamar a função SmVR_Init. Esta função pode receber como parâmetro o nome de um arquivo com a descrição de uma cena. Na versão atual a leitura das cenas de arquivos ainda não é considerada estável, portanto não deve ser usada. Em face disto, deve-ser passar como parâmetro a constante NULL no parâmetro da função.
Como retorno esta função devolve uma referência (ponteiro) para um objeto que irá representar toda a cena a ser exibida. Em nosso exemplo este objeto será chamado de RootObject. Este objeto representará um apontador para a raiz ou nodo inicial a partir do qual o grafo de cena pode ser percorrido.
SmVR_CGeometricObject *RootObject;Todos os demais objetos da cena serão criados como filhos deste RootObject. Assim, a exibição da cena pode ser feita simplesmente chamando o método Render deste objeto, desta forma:
RootObject = SmVR_Init(NULL);
RootObject->Render();O exemplo a seguir inicializa a SmallVR e desenha um quadrado na tela. No exemplo estão sendo omitidos os detalhes relativos à posicionamento de câmera e à inicialização de outros parâmetros de OpenGL.
Exercício
1:
Carregando objetos de arquivo
Conforme foi dito na seção 2.1, a SmallVR permite que
sejam carregados objetos no formato Wavefront
OBJ. Para testar
esta característica, copie o arquivo LoadObj.cpp, grave-o no
sub-diretório TestFiles,
que se encontra no diretório onde você descompactou a SmallVR (se você tiver objetos
em outros formatos, como 3DS, VRML, DXF, entre outros, sugerimos usar
um conversor como o AccuTrans
3D e converter os objetos para Wavefront OBJ).
Adicione o arquivo LoadObj.cpp
ao projeto.
Extinguisher.obj |
Mesa1.obj |
Plant.obj |
Piso.obj |
Soccerball.obj |
Sistema de
Coordenadas OpenGL/SmallVR
Lembre-se
que o sistema de coordenadas de OpenGL e pro conseqüência,
da SmallVR, tem a
configuração apresentada na figura abaixo.
O trecho de código a seguir, por exemplo, permite obter um apontador para o objeto de nome "Test Object", se este for filho do objeto RootObject.
SmVR_CGeometricObject *temp = RootObject->FindChildObject("Test Object");
(a) aplicação de rotações e escalas no sistema de coordenadas local de um objeto;
(b) aplicação de translações no sistema de coordenadas do pai do objeto;
(c) aplicação de transformações no sistema de coordenadas de um outro objeto.
Figura - Exemplo de uma
rotação
no Sistema de Coordenadas Local (SCL) de um Objeto
Para efetuar este tipo de
transformação
geométrica, a classe SmVR_CGeometricObject possui os
apresentados
na tabela a seguir.
|
|
ScaleBy(float ex, float ey, float ez) | aplica uma escala (ex,ey,ez) no objeto usando o SCL do objeto |
ScaleBy(SmVR_CPoint p) | aplica uma escala no objeto usando o SCL do objeto. As componentes X,Y,Z do ponto 'p' definem os fatores de escala a serem aplicados |
RotateBy(float angle, float ax, float ay, float az) | aplica uma rotação de "angle" graus ao redor do vetor definido por (ax,ay,az), no SCL do objeto |
RotateBy(float angle, SmVR_CPoint p) | aplica uma rotação de "angle" graus ao redor do vetor definido por p, no SCL do objeto |
As translações, por sua
vez,
são sempre aplicadas no sistema de coordenadas do pai do objeto,
conforme a tabela abaixo.
|
|
TranslateBy(float tx, float ty, float tz) | aplica uma translação(tx,ty,tz) no objeto usando como referência o sistema de coodenadas do pai do objeto |
TranslateBy(SmVR_CPoint p) | aplica uma translação no objeto usando como referência o sistema de coodenadas do pai do objeto. O ponto P funciona como um vetor que define a translação |
Exercício
3: Copie o arquivo CenarioExerc3.cpp para o sub-diretório TestFiles, e adicione o arquivo ao
projeto.
A seguir, altere o programa de maneira a modelar uma sala semelhante a
da figura abaixo. Procure inserir seu código dentro da rotina CriaCenario().
O trecho de código a seguir exemplifica o posicionamento do
sofá e do piso.
Se as transformações geométricas tomarem como base sistema de coordenadas de um outro objeto o resultado é diferente daquele obtido com transformações no Sistema de Coordenadas do Objeto. Na figura abaixo, por exemplo, pode-se observar a rotação ao retângulo ao redor do eixo Y, do objeto vermelho que aparece na figura.
|
|
TranslateByOnOBJCS(float tx, float ty, float tz, SmVR_CGeometricObject *OCS) | aplica uma translação(tx,ty,tz) no objeto usando o Sistema de Coordenadas do objeto OCS como referência |
TranslateByOnOBJCS(SmVR_CPoint p, SmVR_CGeometricObject *OCS) | aplica uma translação usando o o Sistema de Coordenadas do objeto 'OCS' como referência. O ponto P funciona como um vetor que define a translação |
ScaleByOnOBJCS(float ex, float ey, float ez, SmVR_CGeometricObject *OCS) | aplica uma escala (ex,ey,ez) no objeto, usando o Sistema de Coordenadas do objeto 'OCS' como referência |
ScaleByOnOBJCS(SmVR_CPoint p, SmVR_CGeometricObject *OCS) | aplica uma escala no objeto, usando o Sistema de Coordenadas do objeto 'OCS' como referência. As componentes X,Y,Z do ponto 'p' definem os fatores de escala a serem aplicados |
RotateByOnOBJCS(float angle, float ax, float ay, float az, SmVR_CGeometricObject *OCS) | aplica uma rotação de "angle" graus ao redor do vetor definido por (ax,ay,az), no Sistema de Coordenadas do objeto 'OCS' |
RotateByOnOBJCS(SmVR_CPoint p, SmVR_CGeometricObject *OCS) | aplica uma rotação de "angle" graus ao redor do vetor definido por 'p', no Sistema de Coordenadas do objeto 'OCS' |
void
SmVR_CGeometricObject::TranslateToOnOBJCS(float
x, float y, float z, SmVR_CGeometricObject *OCS);
void
SmVR_CGeometricObject::TranslateToOnOBJCS(SmVR_CPoint
p, SmVR_CGeometricObject *OCS);
Este método permite que se mova um objeto O para uma posição X,Y,Z definida no sistema de coordenadas de um objeto OCS, independente da posição corrente de O.
Para obter as coordenadas de um ponto no sistema de coordenadas de um outro objeto deve-se usar o método
void SmVR_CGeometricObject::GetPointInOCS (SmVR_CPoint *in, SmVR_CPoint *out, SmVR_CGeometricObject *OCS).
Este método recebe como primeiro parâmetro (in) o ponto que se deseja obter, no sistema de coordenadas do objeto usado para evocar o método. O segundo parâmetro (out) receberá o resultado da conversão. O terceiro parâmetro (OCS) especifica o objeto do qual será usado o sistema de coordenadas para obter as coordenadas do ponto in.
O trecho a seguir, por exemplo, obtém as coordenadas do ponto (0,0,0) do objeto TestObject, no sistema de referência da raiz do grafo da cena. Isto serve, por exemplo, para saber a posição do objeto no sistema de coordenadas global.
void keyboard(unsigned char key, int x, int y) {
SmVR_CGeometricObject *temp1;
SmVR_CPoint Zero(0,0,0), GlobalPoint;temp1 = RootObject->FindChildObject("Teste");
switch(key) {
case 27:
exit(0);
break;case 'p': // get Point
temp1->GetPointInOCS(&Zero, &GlobalPoint, RootObject);
printf("X = %f, Y = %f, Z = %f", GlobalPoint.X, GlobalPoint.Y, GlobalPoint.Z);
break;}
}
void main(int argc, char** argv) {
SmVR_CGeometricObject *obj1;
......
......// initialize the library
RootObject = SmVR_Init(NULL);// criacao do cubo e adicao dele como filho do RootObject
TestObject = new SmVR_CGeometricObject("Teste", desenhaCubo);// Add the object to the scene
RootObject->AddChild(TestObject);TestObject->TranslateBy(0,0,8); // apply a translation on TestObject
.......
.......
}
|
|
void SetVisibility(int status) | define se um objeto deve ou não ser exibido. O parâmetro status pode receber os valores 0 (invisível) ou 1 (visível) |
void SetName(char *name); | define um novo nome para o objeto |
Exemplo de uso:
SmVR_CPoint User(0,6,10); // cria um ponto de coordenadas X = 0; Y = 6, Z = 10Os campos X,Y e Z desta classe, por questões de eficiência, são declarados como public, podendo desta forma serem acessados diretamente, por exemplo:
printf("X = %f, Y = %f, Z = %f", User.X, User.Y, User.Z);