
Si has llegado a este punto significa que entiendes cómo están definidas las distintas primitivas geométricas en el fichero primitivas.js, y que para cada primitiva que necesites utilizar en la composición del objeto habrás de obtener su matriz de transformación, enviársela al shader de vértices y después ordenar el dibujado de la primitiva. Además, en el shader de vértices deberás operar cada vértice con la matriz de transformación correspondiente.
Si es así, estás en condiciones de realizar los ejercicios. Para cada uno actúa de la sigusiente manera, en primer lugar piensa sobre el papel qué transformaciones necesitas aplicar a cada una de las primitivas que forman el objeto que has de construir, y solo después procede con la escritura del código. Vamos allá!

Todas estas operaciones se encuentran ya implementadas en transforma.js, no necesitas escribir el código. Edítalo y observa cómo la función initPrimitives() es la encargada de alojar las diferentes primitivas en la memoria del sistema gráfico. A esta función la llamaremos una única vez desde nuestra aplicación, por ejemplo, tras crear los shaders con initShaders(). Si ordenas dibujar una primitiva sin aplicarle ninguna transfomación geométrica la podrás observar en su posición y orientación original. Puedes comprobarlo y probablemente te sirva para entender mejor cómo se encuentran definidas.
Transformaciones geométricas
Para realizar los ejercicios propuestos en esta práctica necesitas la librería glMatrix que ya está incluida en transforma.zip. Parte del código que se te proporciona para realizar los ejercicios propuestos. Antes de comenzar, observa la función llamada drawScene(). Es en esta función concreta donde vas a trabajar y donde has de ordenar el dibujado de las diferentes primitivas cada una acompañada de sus respectivas transformaciones. Observa también que el shader de vértices (en transforma.html) contiene una variable uniforme de tipo mat4 llamada modelMatrix. Esta matriz es la matriz de transformación del modelo y se multiplica por cada vértice para obtener su posición definitiva antes de ser dibujado. En la funcion drawScene() has de calcular dicha matriz y enviársela al shader antes de dibujar la correspondiente primitiva. A continuación se muestra un ejemplo en el que se dibuja un cono previamente escalado a la mitad de su tamaño. Este ejemplo se corresponde con el aparece en transforma.js, comprueba en tu navegador que obtienes el mismo resultado que el que se muestra en la figura. Observa en la función drawScene() el orden de las operaciones realizadas. Es muy importante que antes de continuar resuelvas con tu profesor todas las dudas que tengas en este momento.
Primitivas geométricas básicas
Para realizar esta práctica descarga el fichero transforma.zip y descomprímelo en tu directorio de trabajo.
El fichero primitivas.js contiene los modelos de las primitivas geométricas plano, cubo, esfera, cono y cilindro. En primer lugar has de conocer cómo se han definido dichas primitivas, dimensión, posición y orientación. A continuación tienes la información que necesitas de cada una de ellas (prueba a dibujarlas en papel siguiendo la descripción):
Plano: es un cuadrado sobre el plano XZ centrado en el origen de coordenadas y lado uno.
Cubo: está centrado en el origen de coordenadas, con sus caras paralelas a los planos de referencia XY, XZ e YZ, y lado uno.
Cono: la base reside en el plano XY, tiene radio uno y está centrada en el origen de coordenadas, el eje del cono coincide con el eje Z y la altura es uno.
Cilindro: igual que el cono.
Esfera: está centrada en el origen de coordenadas y su radio es uno.
El modelo de cada primitiva consta de dos vectores, uno contiene las coordenadas de los vértices y el otro contiene los índices al vector de vértices que de tres en tres describen los triángulos. El índice del primer vértice es el cero. De momento los modelos sólo constan de geometría, es decir, no contienen otros atributos (nomales, color, etc.). A continuación se muestra el modelo propuesto para el cubo.
Composición de Objetos
Informática Gráfica
José Ribelles
Departamento de Lenguajes y Sistemas Informáticos
Universitat Jaume I
Ahora que ya sabes cómo describir y visualizar geometría en WebGL, es el momento de aprender a crear objetos más complejos compuestos de primitivas básicas 3D como la esfera, el cilindro, el cono, etc. Para conseguirlo deberás utilizar las transformaciones geométricas que ya conoces: traslación, escalado y rotación.
Última revisión: 23/9/2016
Recordando lo que trabajaste en la práctica anterior, para poder visualizar cualquier modelo es necesario alojarlo previamente en la memoria del sistema gráfico:
function initBuffers(model) {
model.idBufferVertices = gl.createBuffer ();
gl.bindBuffer (gl.ARRAY_BUFFER, model.idBufferVertices);
gl.bufferData (gl.ARRAY_BUFFER, new Float32Array(model.vertices), gl.STATIC_DRAW);
model.idBufferIndices = gl.createBuffer ();
gl.bindBuffer (gl.ELEMENT_ARRAY_BUFFER, model.idBufferIndices);
gl.bufferData (gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(model.indices), gl.STATIC_DRAW);
}
Como ya sabes, esta operación necesitas realizarla una única vez para cada modelo. Después puedes ordenar el dibujado tantas veces como necesites, ¿recuerdas cómo? Por si acaso no lo recuerdas, a continuación tienes la función que dibuja las aristas de todos los triángulos, revísala y resuelve las dudas:
function draw(model) {
gl.bindBuffer (gl.ARRAY_BUFFER, model.idBufferVertices);
gl.vertexAttribPointer (vertexPositionAttribute, 3, gl.FLOAT, false, 3*4, 0);
gl.bindBuffer (gl.ELEMENT_ARRAY_BUFFER, model.idBufferIndices);
for (var i = 0; i < model.indices.length; i += 3)
gl.drawElements (gl.LINE_LOOP, 3, gl.UNSIGNED_SHORT, i*2);
}
function drawScene() {
gl.clear(gl.COLOR_BUFFER_BIT);
var modelMatrix = mat4.create();
// 1. calcula la matriz de transformación
mat4.identity(modelMatrix);
mat4.scale (modelMatrix, modelMatrix, [0.5,0.5,0.5]);
// 2. envía la matriz calculada al shader de vértices
gl.uniformMatrix4fv(program.modelMatrixIndex,
false, modelMatrix);
// 3. dibuja la primitiva
draw(exampleCone);
}

Ejercicio 1
Observa la escena que se muestra en las figuras de abajo inspirada en la figura de bloques de madera que se muestra a la derecha. Crea una escena que produzca la misma salida utilizando únicamente la primitiva cubo. El cubo central tiene de lado 0'1, y los que están a su lado tienen la misma base pero una altura que va incrementándose en 0'1 a medida que se alejan del central. Utiliza un bucle para pintar los trece cubos. Nota: ambas imágenes muestran la misma escena, pero en la imagen de la derecha se ha girado toda la escena para apreciar mejor que se tratan de primitivas 3D.



Ejercicio 2
En este ejercicio vas a hacer un tanque inspirado en el de la figura que se muestra a la derecha. En las figuras de abajo puedes observar lo que has de conseguir. Los cilindros de las ruedas tienen una altura de 0'8 y un radio de 0'1. Utiliza conos para tapar los cilindros por ambos lados. El cuerpo del tanque es un cubo escalado para ocupar lo mismo que las ruedas, y una altura de 0'2. La torreta del cañón es un cilindro de radio 0'2 y altura 0'8. Observa dónde está situada y haz coinicidir la tuya en la misma posición. Tápalo con un par de conos. Por último añade el cañón, que es un cilindro de longitud 0'8 y radio 0'03.



Ejercicio 3
Crea un reloj como el de la figura. No te doy dimensiones, elígelas tú. Imítalo en la medida de lo posible. Sí que te pido que marque las dos en punto.


Necesito más!
Cuando termines los tres ejercicios anteriores, pregúntate si realmente has comprendido o no el uso de las transformaciones geométricas. Si tienes dudas no las dejes pasar, acláralas con tu profesor en clase o en su horario de tutorías. Si crees que necesitas más ejercicios, Internet es una fuente de inspiración excepcional, utilízala para buscar ejemplos que te sirvan de muestra. Fíjate en los siguientes.



var exampleCube = {
"vertices" : [-0.5,-0.5, 0.5,
0.5,-0.5, 0.5,
0.5, 0.5, 0.5,
-0.5, 0.5, 0.5,
-0.5,-0.5, -0.5,
0.5,-0.5, -0.5,
0.5, 0.5, -0.5,
-0.5, 0.5, -0.5],
"indices" : [0, 1, 2, 0, 2, 3,
1, 5, 6, 1, 6, 2,
3, 2, 5, 3, 6, 7,
4, 6, 5, 4, 7, 6,
0, 7, 4, 0, 3, 7,
0, 5, 1, 0, 4, 5]
};



