Projeto Virtual Worlds

Computação Gráfica 3D em C

Manipulação da câmera (viewpoint).

Existe uma maneira simples de lidar com a analogia da câmera, em OpenGL. Na biblioteca GLU (OpenGL Utilities) existe a função gluLookAt, que toma 3 vetores:

void gluLookAt(float eyeX, float eyeY, float eyeZ,
               float centerX, float centerY, float centerZ,
               float upX, float upY, float upZ);

O problema é que os vetores eye e up tem que ser perpendiculares.

Mas, se mudarmos o ponto de visão (o vetor “eye”), o vetor “up”, com toda certeza, não será mais perpendicular ao primeiro. E como não temos o terceiro vetor perpendicular como referência, não podemos usar um produto vetorial para calcular o novo vetor “up”. Poderíamos colocar um quarto vetor na jogada (além do vetor “eye” − que dá o ponto para onde estamos olhando; o vetor “center” − que nos dá a posição no espaço da câmera; e do vetor “up” − que nos diz onde é que nossa câmera interpreta “para cima”), mas isso só iria causar mais complicações e diminuiria a performance, já que teríamos que lidar com mais um vetor. Existe um jeito mais fácil.

Dado um vetor “eye” e um vetor “up”, não perpendicular, podemos simplesmente calcular a projeção do vetor “up” num vetor unitário baseado em “eye” e subtrair do vetor “up” essa projeção, lembrando de normalizar o vetor “up” no fim das contas. “Projeção” é “produto escalar”. A coisa fica assim:

static void RecalcUpVector(float *up, const float *eye)
{
  float w[3], v[4];

  /* w = normalize(eye); */
  Vector3Normalize(w, eye);

  /* up = up - (w . up)w */
  Vector3Scale(v, w, Vector3Dot(w, up));
  Vector3Sub(up, up, v);
  Vector3Normalize2(up);
}

Todo vetor tem 3 componentes. Para facilitar o entendimento eis como funciona com vetores 2D: Todo vetor 2D tem componentes X e Y. Ao projetar o vetor “up”, não perpendicular, sobre o vetor unitário colinear ao vetor “eye” temos um vetor apenas com o tamanho X de “up”. Sabendo que \vec{v}_{up} é dado por:

\vec{v}_{up} = \vec{v}_{up_x} + \vec{v}_{up_y}

vector

Para obter o vetor \vec{v}_{up_y}, que é perpendicular ao vetor unitário \vec{w} basta subtrair o vetor \vec{v}_{up_x} (a projeção de \vec{v}_{up} sobre \vec{w}) do próprio \vec{v}_{up}.

Ok, toda essa história de “projeção” e “normalização” pode ser resumida assim: A rotina acima substrai o componente do vetor “up” da parte que se encontra “sobre” o vetor “eye” e certifica-se que o novo vetor “up” tem tamnho igual a 1.

Se nossa câmera é definida somente com esses 3 vetores (eye, center e up), então o código para ajustar a matriz de transformação do sistema de coordenadas VIEW fica:

void SetupViewspaceMatrix(struct camera_s *camera)
{
  RecalcUpVector(camera->up, camera->eye);

  gluLookAt(camera->eye[0], camera->eye[1], camera->eye[2],
            camera->center[0], camera->center[1], camera->center[2],
            camera->up[0], camera->up[1], camera->up[2]);
}

Simples assim…

Para mover a cãmera, basta atualizar o vetor “center” (que é uma coordenada). Para rotacionar a câmera podemos usar a função Vector3RotateAroundAxis() e depois recalcular o vetor “up”. É claro que temos que ter cuidado para que os vetores “eye” e “up” não sejam colineares!

Anúncios

Deixe um comentário

Faça o login usando um destes métodos para comentar:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s