Primeros pasos con WebGL

Informática Gráfica  

José Ribelles

Departamento de Lenguajes y Sistemas Informáticos

Universitat Jaume I

En esta práctica vas a realizar tus primeros pasos con WebGL. Es una práctica de introducción en la que vas a conocer el entorno de trabajo, ejecutarás algunas demos que muestran las posibilidades de WebGL, y crearás una página Web con tu primer programa en JavaScript y WebGL que mostrará nada más y nada menos que un triángulo!

Última revisión: 7/9/2016

Aplicación WebGL

Incluir una aplicación WebGL en una página Web requiere de dos pasos previos: crear un Canvas y obtener un contexto WebGL.

Como ya sabes, HTML es el lenguaje que se utiliza para el desarrollo de páginas Web. Su última versión es HTML5 y entre sus nuevos elementos destaca el denominado Canvas. Se trata de un elemento rectangular que define el área en la que se visualizará la aplicación WebGL. Además, es el propio canvas el que nos va a proporcionar un contexto WebGL, objeto JavaScript a través del cual se accede a toda la funcionalidad de WebGL.

Prueba de WebGL

Enciende tu equipo, selecciona un sistema operativo y después ejecuta tu navegador preferido. A continuación accede a la siguiente página Web:

http://get.webgl.org/

¿Ha funcionado? Si es así deberías ver un cubo dando vueltas sobre sí mismo como el de la figura de la izquierda.

Si no te ha funcionado prueba con otro navegador que haya instalado. Y si te funcionó, hazlo también para conocer qué navegadores te ofrecen soporte para WebGL. Recuerda que si en alguno no funciona, es muy posible que simplemente requiera una actualización.

(placeholder)

Ejercicio 2

Accede a la siguiente página Web para recabar información acerca de las características soportadas en tu navegador preferido.

http://webglreport.com/

Obtendrás una página similar a la que se muestra en la figura de la derecha.

Observa la información que te aparece como resultado de la consulta. Aunque muchos términos te van a resultar extraños poco a poco los irás conociendo. De momento, trata de contestar a las siguientes preguntas:

¿Cuál es la versión de WebGL que soporta tu navegador?

¿Cuántos bits utiliza para codificar el color de un pixel?

(placeholder)

Ejercicio 3

Ahora vas a probar algunas demos que tratan de mostrar las bondades de WebGL. Si realizas una búsqueda a través de la WWW encontrarás bastantes páginas que te ofrecen una selección de ejemplos y páginas donde los desarrolladores cuelgan sus propios trabajos. Aquí tienes una selección personal, pruébalas y coméntalas con tus compañeros.

(placeholder)

  <!DOCTYPE html>

  <html>

    <head>

      <meta charset="utf-8">

      <title> Informática Gráfica </title>

      <style type="text/css">

      canvas {border: 1px solid black;}

      </style>

    </head>


    <body>

      <canvas id="myCanvas" width="800" height="600">

        El navegador no soporta HTML5

      </canvas>

    </body>

  </html>

(placeholder)

  function getWebGLContext() {

  

    var canvas = document.getElementById("myCanvas");

  

    var names = ["webgl", "experimental-webgl",

                 "webkit-3d", "moz-webgl"];

  

    for (var i = 0; i < names.length; ++i) {

      try {

        return canvas.getContext(names[i]);

      }

      catch(e) {

      }

    }

  

    return null;

  

  }


  function initWebGL() {

  

    var gl = getWebGLContext();

  

    if (!gl) {

      alert("WebGL no está disponible");

    } else {

      alert("WebGL disponible");

    }

  

  }


  initWebGL();

(placeholder)

Ejercicio 6

Descarga minimoPrograma.js y observa que se ha modificado la función initWebGL() tal y como se muestra abajo. Modifica el archivo html para que ahora se llame a este nuevo script (en lugar de a contexto.js) y recarga la página correspondiente. ¿Qué observas?

Veamos el nuevo código que se ha incluido en dicha función. Después de obtener el contexto WebGL, esta función especifica un color de borrado, o color de fondo, utilizando el método clearColor, y ordena que borre el contenido del canvas con la orden clear y el parámetro COLOR_BUFFER_BIT. Es un código sumamente sencillo. Prueba a modificar las componentes RGBA y practica un poco con ellas. ¿Sabrías hacer que el color de fondo sea el amarillo? ¿Qué ocurre si intercambias el orden de clear y clearColor? ¿Por qué?

Por último, señalar que aunque el programa que terminas de probar contiene la mínima expresión de código que utiliza WebGL, su estructura no se corresponde aún con la estructura habitual de una aplicación. Pero tranquilo, más tarde en esta misma práctica encontrarás un ejemplo.

  function initWebGL() {


    gl = getWebGLContext();


    if (!gl) {

      alert("WebGL no está disponible");

      return;

    }


    // especifica en RGBA el color de fondo (4 valores entre 0 y 1)

    gl.clearColor(1.0,0.0,0.0,1.0);


    // rellena el buffer de color utilizando ...?

    gl.clear(gl.COLOR_BUFFER_BIT);     

  }

(placeholder)

Shaders en WebGL

El Pipeline de WebGL

El funcionamiento básico del pipeline se representa en el diagrama simplificado que se muestra justo aquí arriba. Las etapas de procesado del vértice y del fragmento son programables. El programador debe escribir los shaders que desea que sean ejecutados en cada una de ellas.

El procesador de vértices acepta vértices como entrada, los procesa utilizando el shader de vértices y envía el resultado a la etapa denominada Procesado de la Primitiva. En esta etapa, los vértices se reagrupan dependiendo de qué primitiva geométrica se está procesando (punto, línea o triángulo). También se realizan otras operaciones que de momento vamos a omitir. La primitiva pasa por una etapa de conversión al raster que básicamente consiste en generar pequeños trozos denominados Fragmentos que todos juntos cubren la superficie de la primitiva.

El procesador de fragmentos determina el color definitivo utilizando el shader de fragmentos, que ejecuta el shader correspondiente para cada fragmento recibido. El resultado se envía al framebuffer no sin antes atravesar algunas etapas más que se han omitido por cuestión de claridad.

El lenguaje GLSL

Como has podido comprobar, en los ejemplos anteriores se ha combinado HTML y JavaScript. Ahora, con WebGL se añade un tercer elemento, el lenguaje GLSL ES que es el que utilizarás para crear tus propios shaders.

El lenguaje GLSL forma parte de WebGL, y permite al programador escribir el código que desea ejecutar en los procesadores programables de la GPU. En la actualidad hay cinco tipos de procesadores: vértices, control de teselación, evaluación de teselación, geometría y fragmentos; por lo que también decimos que hay cinco tipos de shaders, uno por cada tipo de procesador. Sin embargo, WebGL 1.0 solo soporta dos tipos de shaders, el de vértices y el de fragmentos, por lo que solo podremos escribir código para sus dos respectivos procesadores.

GLSL es un lenguaje de alto nivel, parecido al C, aunque también toma prestadas algunas características del C++. Su sintaxis se basa en el ANSI C. Constantes, identificadores, operadores, expresiones y sentencias son básicamente las mismas que en C. El control de flujo con bucles, la sentencias condicionales if-then-else y las llamadas a funciones son idénticas al C.

Pero GLSL también añade características no disponibles en C, entre otras se destacan las siguientes:

- Tipos vector: vec2, vec3, vec4

- Tipos matriz: mat2, mat3, mat4

- Tipos sampler para el acceso a texturas: sampler1D, sampler2D, sampler3D, samplerCube

- Tipos para comunicarse entre shaders y con la aplicación: uniforms, varyings

- Acceso a componentes de un vector mediante: .xyzw .rgba .stpq

- Operaciones vector-matriz, por ejemplo: vec4 a = b * c, siendo b de tipo vec4 y c de tipo mat4

- Variables predefinidas que almacenan estados de WebGL

GLSL también dispone de funciones propias como, por ejemplo, trigonométricas (sin, cos, tan, etc.), exponenciales (pow, exp, sqrt, etc.), comunes (abs, floor, mod, etc.), geométricas (length, cross,  normalize, etc.), matriciales (transpose, inverse, etc.) y operaciones relacionales con vectores (equal, lessThan, any, etc). Consulta la especificación del lenguaje para conocer el listado completo.

Y también hay características del C no soportadas en OpenGL como es el uso de punteros, los tipos: byte, char, short, long int; y la conversión implícita de tipos está muy limitada.

Del C++, GLSL copia la sobrecarga y el concepto de constructor.

En el siguiente listado se muestra el código HTML que incluye un ejemplo de shader, el más simple posible. Los scripts identificados como myVertexShader y myFragmentShader contienen los fuentes de los shaders de vértices y de fragmentos respectivamente. Cuando desde la aplicación se ordene dibujar, cada vértice producirá la ejecución del shader de vértices, que en este caso genera como salida la posición del vértice que se almacena en la variable predefinida en gl_Position. El resultado de procesar cada vértice atraviesa el pipeline, se agrupan dependiendo del tipo de primitiva a dibujar, y en la etapa de conversión al raster la posición del vértice (y también de sus atributos en el caso de haberlos) es interpolada generando los fragmentos y produciendo, cada uno de ellos, la ejecución del shader de fragmentos en el procesador correspondiente. El objetivo de este último shader es determinar el color definitivo del fragmento. Siguiendo con el ejemplo, todos los fragmentos son puestos a color verde (especificado en formato RGBA) utilizando la variable predefinida gl_FragColor.

  <script id=”myVertexShader” type=”x−shader /x−vertex”>

  

    // Shader de vértices


    // Declaración del atributo posición

    attribute vec3 VertexPosition;


    void main() {


     // se asigna la posició́n del vértice a

     // la variable predefinida gl_Position

     gl_Position = vec4(VertexPosition,1.0);


    }


  </script>


  <script id=”myFragmentShader” type=”x−shader /x−fragment”>

    

    // Shader de fragmentos


    void main() {


      // se asigna el color verde a cada fragmento

      gl_FragColor = vec4(0.0,1.0,0.0,1.0);

  

    }


  </script>

Compilación y enlazado

Has leído bien, el título no contiene ningún error. Los shaders han de ser compilados y enlazados antes de poder ser ejecutados en una GPU. Incluso también ahora que estás utilizando JavaScript.

El compilador de GLSL está integrado en el propio driver de OpenGL instalado en tu máquina (ordenador, teléfono, tableta, etc.) . Esto implica que la aplicación en tiempo de ejecución será quien envíe el código fuente del shader al driver para que sea compilado y enlazado, creando un ejecutable que puede ser instalado en los procesadores correspondientes. Tres son los pasos a realizar:

1.     Crear y compilar los objetos shader.

2.     Crear un programa y añadirle los objetos compilados.

3.     Enlazar el programa creando un ejecutable.

El siguiente listado muestra un ejemplo de todo el proceso.

function initShader() {


    // paso 1

    var vertexShader = gl.createShader(gl.VERTEX_SHADER);

    gl.shaderSource(vertexShader,

                    document.getElementById('myVertexShader').text);

    gl.compileShader(vertexShader);


    var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);

    gl.shaderSource(fragmentShader,

                    document.getElementById('myFragmentShader').text);

    gl.compileShader(fragmentShader);


    // paso 2

    var program = gl.createProgram();

    gl.attachShader(program, vertexShader);

    gl.attachShader(program, fragmentShader);


    // paso 3

    gl.linkProgram(program);


    gl.useProgram(program);


    return program;


  }

Ejercicio 7

Observa detenidamente la función initShader() de la sección anterior e identifica en el código cada una de las tres etapas. Utiliza la especificación de WebGL para conocer más a fondo cada una de las órdenes que aparecen en el ejemplo. Por último, para que el programa ejecutable sea instalado en la GPU, es necesario indicarlo con la orden glUseProgram que como parámetro debe recibir el identificador del programa que se desea utilizar. La carga de un ejecutable siempre supone el desalojo automático del que hubiera con anterioridad.

Ejercicio 1

Si en ocasiones trabajas con otro sistema operativo diferente del que terminas de utilizar, y está instalado en tu equipo, reinicia la máquina con dicho sistema y haz las mismas pruebas.

También, si dispones de un dispositivo móvil (telefóno, tableta, portátil, etc.) prueba a chequear el soporte de WebGL en los diferentes navegadores que dispongas.

Después de las diferentes pruebas, ¿cuál es tu opinión respecto al estado de soporte de WebGL en los diferentes navegadores ? ¿crees que es suficiente o que por contra tendremos que esperar aún más a que aparezcan nuevas versiones? ¿tienes claro qué navegador vas a utilizar en la asignatura? ¿piensas que los ejercicios que hagas vas a tener que probarlos en diferentes navegadores y sistemas con el fin de comprobar si se obtiene el mismo resultado?

(placeholder)

Ejercicio 4

El siguiente código HTML crea un canvas de tamaño 800x600:

(placeholder)

Ejercicio 5

Observa el siguiente código que trata de obtener un contexto WebGL y así averiguar su disponibilidad en el navegador. Consulta las dudas a tu profesor.

a) Escríbelo y guárdalo como contexto.js (o descárgalo).

b) Edita el html creado en el ejercicio anterior y añade el script justo antes de cerrar el cuerpo de la página Web:

<script src = "contexto.js"></script>

c) Refresca la página que muestra el canvas y comprueba el resultado. ¿Tienes soporte para WebGL?

a) Utiliza un editor para escribirlo (o descárgalo) y ábrelo con el navegador que hayas elegido para trabajar.

b) Examínalo y pregunta las dudas a tu profesor.

c) Prueba a cambiar algunos de los parámetros como el tamaño, el tipo de borde, o su color. Realmente que el marco sea visible no es necesario, pero de momento lo necesitamos para ver claramente cuál es el área de dibujo establecida.

(placeholder)

Ejercicio 8

Ahora, descarga miPrimerTrianguloConWebGL.zip y descomprímelo.

Observa el código y comprueba que se han añadido los fuentes del shader en el archivo .html y la función initShader en el .js. De momento no te preocupes por entender las funciones initBuffers y draw que las trataremos en la siguiente práctica.

Cárgalo en el navegador y comprueba que obtienes una salida similar a la que se muestra en la siguiente figura.

(placeholder)

Ejercicio 9

Modifica el color de relleno del triángulo por otro que tu elijas. Recuerda que el color de cada fragmento se establece en el shader de fragmentos cuyo fuente está en el .html.

Ejercicio 10

Aunque en la siguiente práctica trataremos el dibujado de geometría a fondo, prueba ahora a modificar las coordenadas de los vértices del triángulo definido en la variable exampleTriangle. Por ejemplo, trata de obtener el triángulo simétrico respecto a un eje horizontal. Prueba también a especificar coordenadas de magnitud mayor que uno, e incluso a utilizar valores distintos de cero en la componente Z. Haz todas las pruebas que se te ocurran, es la mejor manera de aprender. Si el resultado que obtienes no es el que esperas, pregunta a tu profesor para que pueda ayudarte a comprender lo que ha ocurrido.

(placeholder)
(placeholder)