SmallVR - Virtual Reality Toolkit
Prof. Márcio Sarroglia Pinho

Exibição de Cenários em Múltiplas Telas


1.Introdução

Diversas aplicações de realidade virtual necessitam exibir cenários em um conjunto de telas colocadas lado a lado. Este é o caso das CAVEs e dos Workbenches. Um exemplode uma cena exibida em várias telas é apresentada na Figura 1.1
Figura 1.1 – Cena em Múltiplas telas
Em OpenGL, para gerar este tipo de imagem usa-se a função glFrustum que define o View Frustum ou “volume de visualização” a ser usado para projetar uma cena da tela. Na Figura 1.2 pode-se observar o “volume de visualização” e sua relação com a posição do observador e do alvo.

Figura 1.2 – Volume de Visualização

Na Figura 1.3 este mesmo “volume de visualização” é apresentado com suas respectivas dimensões.

Figura 1.3 – Volume de Visualização (com dimensões)

Na figura, os valores DF e DN são, respectivamente as distâncias máximas e mínimas do volume visível pelo observador e L (de Left) e R (de Right) definem o quanto o observador vê à esquerda e à direita de seu ponto central de visão, exatamente na distância do plano NEAR. Para definir um volume de visualização é necessário ainda definir os limites verticais (inferior e superior) da visão do observador na distância do plano NEAR. Para efeito de exemplo estas medidas serão chamadas B (de Bottom) e T (de Top), respectivamente.

Os valores de NEAR e FAR são fornecidos, em geral, pela aplicação. Os valores de L e R podem ser calculados a partir do ângulo de visão pelas fórmulas:

L = -Near * tan(ViewAngleRad/2)

R = Near * tan(ViewAngleRad/2)

Se considerarmos o Plano NEAR como um quadrado, teremos B igual a L e T igual a R.

A partir destes valores é possível definir o volume de visualização, através da função glFrustum. O código da Figura 1.4 apresenta um exemplo deste procedimento. 

1.1 Dividindo o View Frustum em Múltiplas Telas

Para exibir uma cena em múltiplas telas, deve-se dividir o “volume de visualização”de forma que cada janela exiba uma parte dele. Na Figura 1.5 pode-se observar 3 volumes de visualização distintos.
// ****************************************************************
//  void SetViewFrustum()
//
//
// ****************************************************************
void SetViewFrustum()
{
float Near, Left, Right, Bottom, Top; 
float ViewAngleRad;

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

ViewAngleRad = ViewAngle * 3.14f/180;

Near = 1; // definido na aplicação 

Far = 100; // definido na aplicação 

// Calcula os limites horizontais do View Frustum 

Left = -Near * tan(ViewAngleRad/2);

Right = Near * tan(ViewAngleRad/2);

// Calcula os limites verticais do View Frustum 

Bottom = -Near * tan(ViewAngleRad/2);

Top = Near * tan(ViewAngleRad/2);

// Seta o Frustum

glFrustum(Left, Right, Bottom, Top, Near, Far);

glMatrixMode(GL_MODELVIEW); 

SetObs(); // posiciona o observador 

Figura 1.4 – Setando o Volume de Visualização

Figura 1.5 – Dividindo o Volume de Visualização 

Em OpenGL, para recalcular o View Frustum, toma-se o ângulo de visão e divide-se pelo número de janelas nas quais se deseja exibir a imagem. Note que se deve dividir separadamente o volume na horizontal e na vertical pois o número de telas nestas duas direções pode ser diferente. 

No código apresentado na Figura 1.6 pode-se observar um exemplo que um “volume de visualização” é dividido horizontalmente em 3 janelas e verticalmente em duas.

// **************************************************************
// void SetViewFrustum()
//
// **************************************************************
void SetViewFrustum()
{
float Near, Left, Bottom, Top, Right, TileWidth, TileHeight;
float ViewAngleRad;
glMatrixMode(GL_PROJECTION); glLoadIdentity();
Near = 1; // definido na aplicação
Far = 100; // definido na aplicação
// Calcula os limites horizontais do View Frustum
Left = -Near * tan(ViewAngleRad/2);
Right = Near * tan(ViewAngleRad/2);
// Calcula os limites verticais do View Frustum
Bottom = -Near * tan(ViewAngleRad/2);
Top = Near * tan(ViewAngleRad/2);
// Calcula a largura e a altura de cada janela
TileWidth =(Right - Left)/3;
TileHeight = (Top - Bottom)/2;
// Seta o Frustum de cada janela
if (glutGetWindow() == jan1) // Inferior Esquerda
    glFrustum(Left, Left+TileWidth,
    Bottom, Bottom+TileHeight,Near, Far);
if (glutGetWindow() == jan2) // Inferior Central
    glFrustum(Left+TileWidth, Left+TileWidth*2,
    Bottom, Bottom+TileHeight, Near, Far);
if (glutGetWindow() == jan3) // Inferior Direita
    glFrustum(Left+TileWidth*2, Left+TileWidth*3,
    Bottom, Bottom+TileHeight, Near, Far);
if (glutGetWindow() == jan4) // Superior Esquerda
    glFrustum(Left, Left+TileWidth,
    Bottom+TileHeight, Top, Near, Far);
if (glutGetWindow() == jan5) // Superior Central
    glFrustum(Left+TileWidth, Left+TileWidth*2,
    Bottom+TileHeight, Top, Near, Far);
if (glutGetWindow() == jan6) // Superior Direita
    glFrustum(Left+TileWidth*2, Left+TileWidth*3,
    Bottom+TileHeight, Top, Near, 100);
glMatrixMode(GL_MODELVIEW);
SetObs();
}
Figura 1.6  – Código de Divisão do View Frustum

A Figura 1.7 apresenta o resultado visual deste programa. Clique aqui para copiá-lo.
 

Figura 1.7 – “Telão 3 x 2”