Sin embargo, esto todavía es poco. Queremos modificar la posición de la cámara de manera interactiva y así poder observar la escena desde cualquier ángulo sin tener que ir realizando modificaciones en el código. Por ejemplo, es habitual modificar la posición de la cámara simplemente desplazando el ratón mientras se mantiene presionado su botón izquierdo. Y que la misma acción pero con la tecla Shift pulsada nos permita por ejemplo acercar o alejar la cámara de la escena. Y por qué no, también vamos a querer poder modificar el ángulo de visión, conocido por el nombre de fovy, por ejemplo utilizando la combinación de teclas Shift+Alt mientras se desplaza el ratón pulsando al mismo tiempo su botón izquierdo.

Cámara Virtual Interactiva

Para añadir una cámara que nos permita obtener diferentes vistas de nuestra escena hemos de obtener, en primer lugar, la matriz de transformación de la cámara y la matriz de proyección. La librería glMatrix nos proporciona la función mat4.lookAt que construye la matriz de transformación de la cámara. También nos proporciona la función mat4.perspective que construye la matriz que transforma la pirámide truncada, correspondiente al volumen de la vista de una proyección perspectiva, al volumen canónico de la vista que establece OpenGL.

Una vez obtenidas ambas matrices, calcularemos el resultado de operar la matriz de la cámara con la matriz de transformación del modelo, y llamaremos a la matriz resultante matriz del modelo vista. Esta matriz y la matriz de proyección se las pasaremos al shader de vértices antes de ordenar el dibujado de la primitiva. De esta manera, el shader de vértices nos quedaría así (fíjate en el orden de las operaciones):

Mueve la Cámara

Informática Gráfica

José Ribelles

Departamento de Lenguajes y Sistemas Informáticos

Universitat Jaume I

Al igual que en el mundo real se utiliza una cámara para conseguir fotografías, en nuestro mundo virtual tambien es necesario definir un modelo de cámara que permita obtener vistas 2D de nuestro mundo 3D. En esta práctica vas a añadir una camara virtual interactiva, establecer un volumen de la vista correspondiente a una proyección perspectiva, y resolver el problema de la eliminación de partes ocultas.

Última revisión: 4/10/2016

  uniform   mat4 projectionMatrix;  // perspectiva o paralela

  uniform   mat4 modelViewMatrix;   // resultado de cameraMatrix * modelMatrix


  attribute vec3 VertexPosition;

     

  void main()  {


    gl_Position = projectionMatrix * modelViewMatrix * vec4(VertexPosition,1.0);


  }

Ejercicio 2

Observa los resultados que se muestran en las figuras de abajo. Crea una escena que produzca la misma salida. En primer lugar modela la escena en el papel (este punto no es negociable), da medidas a las primitivas e impleméntalo. De momento olvídate de la posibilidad de que giren los aros, eso lo harás después. Los aros se han modelado utilizando toros, el fichero primitivas.js incluye una rutina que te permite crearlos con las dimensiones que quieras. Nota: para poder atender dudas y problemas de este ejercicio es necesario que hayas realizado el correspondiente diseño en papel.

Ejercicio 3

Ahora vas a añadir mayor interacción con el fin de que el usuario pueda girar cada aro por separado al pulsar diferentes teclas. Es necesario añadir un manejador de eventos que dispare la ejecución de una función cada vez que se produzca una pulsación en el teclado. Dicha función será la encargada de comprobar qué acción realizó el usuario y actuar así en consecuencia. El siguiente código muestra cómo atender el evento producido al pulsar una tecla. Al producirse el evento, se ejecuta la función especificada como parámetro que, en este caso, se encarga de incrementar el ángulo de giro de cada aro dependiendo de la tecla pulsada.

document.addEventListener("keydown",

    function (event) {

      switch (event.keyCode) {

        case 65: outerAngle  += 0.03; break; // 'a'

        case 66: middleAngle += 0.02; break; // 'b'

        case 67: innerAngle  += 0.01; break; // 'c'

      }

      requestAnimationFrame(drawScene);

    },

    false);

Modifica ahora tu programa para añadir interacción con el teclado.  Añade el fragmento de código anterior a la función initHandlers. Declara las tres variables globales que almacenan los ángulos de giro de cada uno de los aros. Añade las transformaciones geométricas a los diferentes aros para que respondan según las acciones del usuario. Quizá esta sea la parte más complicada de la práctica ya que has de conseguir que tu objeto no se autodestruya cuando giren los aros.

Ejercicio 4

Por último, modifica el shader de fragmentos tal y como se explicó en la práctica 2 para poder dibujar cada primitiva de un color diferente. De momento utiliza colores que contrasten bien entre sí, y haz que cada primitiva aparezca de un color diferente. Cuando lo tengas terminado, ¿observas algún problema en la visualización de tu escena? Con toda seguridad deberías tener una visualización errónea como la que se puede apreciar en la siguiente figura.

Observa que el problema de la visibilidad no está resuelto y que, por ejemplo, el soporte más alejado en la escena aparece pintado por encima del resto de primitvas. Por supuesto hay muchos más errores en esta imagen, los encuentras ¿verdad?

Por suerte, sabemos que la solución a este problema lo implementa la funcionalidad fija del sistema gráfico y que solo hay que decirle que lo haga llamando a gl.enable(gl.DEPTH_TEST). Esta llamada hay que realizarla una única vez, ¿dónde la pondrías en tú código?

Además, cada vez que se dibuja una nueva vista de la escena, es necesario borrar el contenido del buffer de profundidad para que la visibilidad de la nueva vista se calcule de forma correcta. Aprovecha el borrado del buffer de color para borrar también el de profundidad:

   gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

Ejercicio 1

Descárgate mueveLaCamara.zip y descomprímelo. Carga en tu navegador preferido mueveLaCamara.html y realiza diferentes pruebas, por ejemplo modifica la posición de la cámara a partir del desplazamiento del ratón, y utiliza las teclas shift y alt para modificar la distancia de la cámara a la escena así como el parámetro fovy. Comprueba por ejemplo que no es lo mismo acercar y alejar la cámara a la escena que modificar el fovy, ¿qué diferencias encuentras?

Edita mueveLaCamara.js y estudia la función getCameraMatrix que devuelve la matriz de transformación de la cámara, ¿cuál es el punto de interés establecido? Estudia también la función setProjection, ¿qué tipo de proyección se utiliza? ¿qué cambios harías para utilizar el otro tipo de proyección que ya conoces?

En los ejercicios que realizaste en la práctica anterior, la matriz de transformación del modelo era diferente para cada una de las primitivas que forman parte de la composición del objeto. ¿Ocurre lo mismo con las matrices de transformación de la cámara y de proyección? ¿son diferentes para cada primitiva de la escena?

(placeholder)
(placeholder)
(placeholder)
(placeholder)