....Esta função deve então ser chamada a cada vez que a tela for ser redesenhada, conforme o exemplo abaixo.
......
// ******************************
// User stuff
// see "PosicUser" function
// on how to use these variables
// ******************************
// User position
SmVR_CPoint pt_user(0,1.6,2);
// Target position
SmVR_CPoint pt_target(0,1.0,0);
// Root Object to represent the entire scene
SmVR_CGeometricObject *RootObject;
// Viewing angle in degrees
float ViewAngle = 90;
// **********************************************************************
// void PosicUser()
//
//
// **********************************************************************
void PosicUser()
{
// Set the clipping volume
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(ViewAngle,WindowRatio,0.01,200);
// Set the user Position
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(pt_user.X,pt_user.Y, pt_user.Z,
pt_target.X,pt_target.Y, pt_target.Z,
0.0f,1.0f,0.0f);
}
// **********************************************************************A partir disto, para mover o observador, pode-se alterar os valores das variáveis pt_user e pt_target através de teclas, conforme o exemplo.
// void display( void )
// Exibe a cena
//
// **********************************************************************
void display( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
PosicUser();
glMatrixMode(GL_MODELVIEW);
RootObject->Render();
glutSwapBuffers();
}
void keyboard ( unsigned char key, int x, int y )
{
switch ( key )
{
case 27: // Encerra o programa
exit(0);
break;
case 'd' : // Move o OBSERVADOR e ALVO para a direita
pt_user.X++;
pt_target.X++;
break;
case 'e' : // Move o OBSERVADOR e ALVO para a esquerda
pt_user.X--;
pt_target.X--;
break;
case 't' : // Move o OBSERVADOR e ALVO para a frente
pt_user.Z++;
pt_target.Z++;
break;
case 'f' : // Move o OBSERVADOR e ALVO para a tras
pt_user.Z--;
pt_target.Z--;
break;
}
glutPostRedisplay();// força o refresh da tela
}
Por outro lado, utilizando-se a
SmallVR,
primeiro devemos criar dois objetos que representarão o usuário
e seu alvo. O usuário deverá ser filho do
objeto
raiz
do grafo de cena e o alvo, filho do objeto que represnta o usuário.
O trecho de código a seguir realiza
esta tarefa:
// Inicializa a bibliotecaEsses objetos devem possuir preferencialmente apenas uma das coordenadas diferentes, para ter o vetor resultante sobre um dos eixos.
SmVR_CGeometricObject *RootObject = SmVR_Init(NULL);
// Cria o objeto "usuário"
user = new SmVR_CGeometricObject("user");
// Posiciona o usuário
user->TranslateBy(0, 30, 0);
// Cria o objeto "alvo"
alvo = new SmVR_CGeometricObject("alvo");
// Posiciona o alvo
alvo->TranslateBy(0, 30, 200);
//Faz o "alvo"ser filho do "usuário"
user->AddChild(alvo);
// Faz o "usuário" ser filho da "raiz" do grafo de cena
RootObject->AddChild(user);
O "alvo" deve ser criado como filho de "user", para sofrer as mesmas transformações.
A partir disto, este objetos servem
como
base para a visualização do cenário. O
posicionamento
de fato continua a ser feito pela função gluLookAt como
antes,
porém, agora seu parâmentros são obtidos a partir
das
posições dos objetos user e da SmallVR.
A rotina PosicUser passa a ter
o seguinte código.
//**********************************************************************Deve-se tomar cuidado na hora de posicionar os objetos user e alvo, porque temos que colocá-los em uma posição que esteja dentro do cenário e que seja permitida a navegação.
// void PosicUser()
//**********************************************************************
void PosicUser() {
SmVR_CPoint Zero(0, 0, 0);glutSetWindow(janela);
// Set the clipping volume
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(angle, WindowRatio, val_near, val_far);glMatrixMode(GL_MODELVIEW);
glLoadIdentity();// Obtém a posição do usuário no sistema de coordenadas da raiz do grafo de cena
user->GetPointInOCS(Zero, &pt_user, RootObject);
// Obtém a posição do alvo no sistema de coordenadas da raiz do grafo de cena
alvo->GetPointInOCS(Zero, &pt_target, RootObject);
gluLookAt(pt_user.X, pt_user.Y, pt_user.Z, // Posicao do observador
pt_target.X, pt_target.Y, pt_target.Z, // Ponto que o observador esta olhando
0.0f, 1.0f, 0.0f); // Define o lado de cima do cenario 3D
}
Para isso temos que adicionar no main a
'glutSpecialFunc(SpecialKeys)', para definir que quem trata as
teclas
especiais é a função 'void SpecialKeys(int key,
int
x, int y) {}'
Para as teclas normais usamos 'glutKeyboardFunc(keyboard)',
para definir que as teclas normais chamam a função 'void
keyboard(unsigned char key, int x, int y) {}' para tratamento.
Nessas funções devemos fazer as transformações em user para realizar a navegação.
Para "andar para frente", devemos mover o usuário na direção para onde este está olhando. Isto pode ser feito deslocando-se o objeto "user" no eixo Z do sistema de coordenadas de seu "alvo", desta forma:
Para permitir que o usuário "olhe" para o lado, basta rotacioná-lo em seu eixo Y, sendo que para as rotações é utilizado o sistema de coordenadas do próprio objeto, da seguinte maneira:case GLUT_KEY_UP: // Anda para frente
// Desloca-se na direção do alvo
user->TranslateByOnOBJCS(0, 0, -1, alvo);
break;
case GLUT_KEY_LEFT: // Gira o corpo para esquerda
Angulo = 10;
UserObject->RotateBy(Angulo, 0,1,0);
break;