Introducción al curso de VRML
Atención, si quieres este curso en ZIP y mejorado para su impresión, mira al final de esta página o en la incial (pincha en el logo)

Si ya trabajas con VRML, esto no te servirá de gran cosa. Este apartado no intenta ser un curso completo de VRML, tan solo es una introducción al fascinante mundo de las ballenas !!## @@ ??!! ...., esto..., no las ballenas no, queria decir del VRML, es por los documentales sabes, me los trago todos y luego pasa lo que pasa. En fin, a lo que vamos, que si no lo conoces, pero tienes unas mínimas nociones de programación y HTML, después de ver este apartado podrás hacer tus primeros pinitos con VRML, y si ya eres un experto en el tema, puedes pasarte a verlo, no me ha quedado mal del todo.

La configuración más recomendable para seguir este curso, es un 486-66/ Pentium con 8Mb, y con una resolucción mínima de 800x600. En cuanto al color, si puedes disponer de 16 o 24 bits, la cosa mejorará muchísimo (no existe paleta de color en esos modos).

De todas formas, si la paleta se te modifica al entrar en un modelo 3D, cuando salgas de él, debes minimizar el navegador para que se restaure la paleta original.

Todo lo que se explique en este curso, va referido al estandard VRML 1.0, y para poder ver los resultados debes tener Netscape 3.0, o un plug-in como en tu navegador como Live3D o CosmoPlayer. 


Uso del navegador en 3D
Para no volverte loco cuando entres en modo 3D, voy ha daros unos pocos consejos, siempre suponiendo que usais Netscape 3.0 o el plug-in Live3D.

Una vez entramos en la pantalla de navegación, manteniendo pulsado el botón izquierdo del ratón sobre ella, teneis dos opciones: mover el ratón de arriba a abajo, con lo que lograreis acercaros o alejaros de la escena, o moverlo lateralmente, que intenta crear el efecto de girar la cabeza a uno y otro lado. Si en lugar del botón izquierdo pulsais el derecho, el efecto que lograis es de rotación; lo mejor es que lo experimenteis.

Existe un menú accesible al pinchar con el botón derecho sobre la pantalla, en el cual podeis configurar multitud de parámetros, como el tipo de representación: alámbrica, nube de puntos o sólida.

En ese menú, existen dos opciones interesantes en el apartado Navigation, que son Animate to clicked point, que nos permite avanzar automaticamente hacia el punto de un objeto sobre el que pinchemos, y Collision detection que como su nombre indica, detecta cuando chocamos con un objeto, impidiendonos atravesarlo.

Por último, daré un truco, para cuando esteis perdidos en la escena y no sepais volver al origen: la primera opción del menú View points, sirve para almacenar puntos de vista, pero si no habeis almacenado ninguno, tiene el Entry view, con lo que conseguireis volver al punto de vista inicial. 


¿Que son las 3D?
Si no estás familarizado con la jerga, te diré que generalmente, cuando hablamos de 3D, nos estamos refiriendo al hecho de representar objetos que en el mundo real tienen 3 dimensiones (anchura altura y profundidad) en una pantalla de ordenador con solo 2 de las dimensiones (anchura y altura). Para poder representar estos objetos, se recurre, como en casi todo, a las matamaticas. Con ellas, se les añade la dimensión que falta. A partir de aquí, usaremos el nombre que se usa universalmente para las dimensiones, esto es, los ejes X, Y, Z, tal y como vemos en el dibujo :
Ejes

Cualquier punto en el espacio, viene definido por sus coordenas (x,y,z). 


Objetos en 3D
Para poder representar objetos reales por medio de un ordenador, debemos tener alguna manera de almacenarlos en la memoria, de manera que podamos manejarlos comodamente. Esto se consigue generalmente (existen muchas otras formas de representación) reduciendo el objeto a una serie de puntos en el espacio, de manera que podamos almacenar esos puntos como un conjunto de tres numeros para cada uno de ellos, es decir, sus coordenadas X, Y, Z. Estos puntos formarian una "nube de puntos", que incorporará casi toda la información que podemos necesitar sobre el objeto.
Nube de puntos
Nube de puntos representando un cubo

Pero un objeto representado solo por unos puntos, no seria muy real, por lo que en primera instancia, se recurre a la representación alámbrica, que no es otra cosa que unir parejas de puntos con una linea, de manera que nos de una idea más clara del objeto que representamos. Aunque mejora mucho, todavia no es muy buena representación puesto que se pueden producir ambiguedades, al no saber exactamente que lado del objeto miramos, por ser este transparente.

Alámbrica
El cubo anterior en versión alámbrica
mostrando la ambiguedad

Por último, vamos ha hacer una mejora sustancial de nuestra representación, al añadir caras sólidas al objeto, que ya no deja ver a traves de ellas, con lo que el problema de ambiguedad en la interpretación del objeto se acaba. En total, para representar al objeto, necesitamos tener información sobre que puntos del espacio lo representan y en que orden deben unirse para formar las caras (opcionalmente puede almacenarse la información de las aristas, pero no es obligado).

Sólida
Versión sólida del cubo
sin ambiguedades


Primeros pasos en VRML
Un fichero VRML es un texto ASCII normal y corriente, que puede ser escrito y modificado con cualquier editor de textos normal, como podria ser el Notepad de Windows o EDIT de MS-DOS. Cualquier texto que pretenda ser un fichero VRML, debe comenzar con el texto:
#VRML V1.0 ascii
Es obligatorio, anuque cualquier linea que comienza con "#" se interpreta como un comentario.

Muy muy IMPORTANTE, VRML es case sensitive, que en cristiano significa que, al contrario que HTML, él si diferencia entre mayúsculas y minúsculas.

Este es un lenguaje en el que no se usan muchos caracteres extraños, tan solo necesitareis para este curso los corchetes"[ ]" y las llaves "{ }", o sea que si pretendeis escribir algo, ya podeis localizarlas en vuestro teclado. Tampoco tendreis estructuras de control como en los lenguajes de programación tradicionales, de hecho VRML no es un lenguaje normal, tan solo es un lenguaje para definir la apariencia de un mundo virtual, creado por vosotros. Esto se ve claro si extendemos sus siglas Virtual Reality Modeling Lenguage, con lo que queda claro, que en su versión 1.0 que es la que nos interesa, es un lenguaje para Modelar, no para Programar en el sentido tradicional.

Nodos
Cada orden de VRML se denomina nodo y viene seguida por una serie de parámetros entre llaves, como por ejemplo Sphere{}, que crea una esfera como veremos en los ejemplos de primitivas.

Superposición
Una característica importante de VRML es la superposición de objetos. En esencia tiene el mismo efecto que una suma booleana, pero solo aparentemente, puesto que esta no se realiza en realidad. Lo único que pasa es que se superponen varios objetos y se visualizan las partes de estos que sobresalen dando al exterior respecto de los otros. No tiene ningún nodo asociado, simplemente debemos situar los objetos en los lugares correspondientes y comprobar que el resultado es el esperado.

Situación en el navegador
Cuando por primera vez entramos al visualizador VRML, los ejes están dispuestos con la componente Y apuntando hacia arriba, la X hacia la derecha y la Z hacia el observador, siendo el origen de coordenadas el centro de la pantalla. Esto es importante para que se puedan comprender las transformaciones realizadas en los ejemplos. Además, todas las primitivas se insertan respecto de estos ejes situándose centradas sobre ellos, por lo que si insertamos un cilindro de altura dos en el origen y queremos situarnos en su parte superior, deberemos realizar una traslación respecto del eje Y de una, y no dos unidades. 


Primitivas básicas y textos en 3D
Primitivas
Las Primitivas, no son Wilma ni Betty, las de los Picapiedra, son la primera y bastante potente herramienta que nos brinda VRML para crear nuestro mundo. Las prinitivas, en son figuras básicas que ponen a nuestra disposición para que las usemos y combinemos a nuestro antojo. En VRML nos ofrecen cuatro, que son:
Cubo.
Cilindro.
Cono.
Esfera.
Todos los parámetros que definen estas primitivas, pueden ser definidos por nosotros, pero si no especificamos ninguno, el navegador da unas dimensiones por defecto.

Cada uno de los nodos que nos premite crear una primitiva tiene unos parámetros diferentes:

        Cube {
        width  (anchura)
        height (altura)
        depth  (profundidad)
        }

        Sphere {
        radius (radio)
        }

        Cone {
        parts  ALL|SIDES|BOTTOM
        bottomRadius (radio)
        height (altura)
        }

        Cylinder {
        parts  ALL|SIDES|BOTTOM|TOP
        radius (radio)
        height (altura)
        }
#VRML V1.0 ascii

     Cube {}
Con este sencillo ejemplo, cramos un Cubo con las dimensiones por defecto que le de el navegador. 
#VRML V1.0 ascii

     Cylinder {}
En este, cramos un Cilindro.
#VRML V1.0 ascii

     Cone {}
Un Cono. 
#VRML V1.0 ascii

     Sphere {}
Y ahora una Esfera
Los parámetros en mayúsculas del cono y el cilindro, especifican que partes de ellos son visibles:
ALL
Todas las partes del cono o cilindro serán visibles.
SIDES
Se verán los laterales del cono o cilindro.
BOTTOM
Se verá la base del cono o cilindro.
TOP
Se verá la parte superior del cilindro.
Pueden combinarse varias de ellas con la barra vertical | como si se tratarse de un OR lógico, pero en este caso, deberán ir entre paréntesis, como por ejemplo (SIDES|TOP). De todas formas, no os asusteis si no funciona, algunos visualizadores o Plug-ins (Live3D de NetScape 3.0 entre ellos) no entienden la especificación de varias partes del objeto, solo admiten una de ellas o todas. En el ejemplo del siguiente código, se generará un cilindro con sus laterales solamente:
#VRML V1.0 ascii
        Cylinder {
        parts SIDES
        radius 5
        height 10
        }
Si os desplazais por el cilindro, comprobareis que se han retirado las tapas, pero también comprobareis probablemente que las caras posteriores del cilindro no se pueden ver hasta que no le damos totalmente la vuelta. No hay ningún error, es un método de acelerar el Render del objeto en pantalla denominado Backface Culling, por el que las caras que no son visibles no se dibujan y vuestro navegador no se ha percatado de que ahora sí que debe dibujar esas caras, puesto que hemos retirado las tapas del cilindro. Algunos se dan cuenta de esto y las dibujan, pero otros no.

Textos

AsciiText{}
Además de estas primitivas, también podemos introducir texto en 3D, para lo tendremos que usar el nodo AsciiText{} que aparece a continuación:

AsciiText {
        string "cadena"
        spacing 1
        justification LEFT|CENTER|RIGHT
        width 0
        }
Este nodo permite introducir texto del juego de caracteres ASCII mediante su parámetro string (siempre entre comillas) y permite ralizar ajustes al mismo, en función de los valores que demos a sus parámetros. Con spacing indicaremos al visualizador que las sucesivas cadenas que se escriban serán separadas con uns distancia definida por el producto size*spacing. Para ver el significado de size debereis mirar en los parámetros del nodo FontStile{}. La justificación del texto respecto de su punto de inserción la indica el parámetro justification, ya os podeis imaginar cual es el significado de sus valores. En cuanto al parámetro width, nos permite sugerir al visualizador la anchura que deseamos para cada cadena. A continuación podeis ver un sencillo ejemplo. de lo que decia.
#VRML V1.0 ascii

     AsciiText { 
     string  "Esto es un texto en 3D"
        }
Además de todo esto, podeis situar el texto como si se tratara de un objeto más del entorno, cambiarle el color e incluso aplicarle texturas.

FontStyle{}
Con este nodo se puede seleccionar el tipo de fuente que deseamos para nuestros textos en 3D y su sistaxis es:

FontStyle {
        size 1
        family SERIF|SANS|TYPEWRITER
        style NONE|BOLD|ITALIC
        }
Con el parámetro size podemos determinar la altura y el espaciado vertical de las lineas de texto adyacentes. Mediante family podemos elegir el tipo de fuente entre las tres disponibles que son SERIF (similar a TimesRoman), SANS (como Helvetica) y TYPEWRITER con espaciado constante como Courier. Por último podemos indicar el estilo de la fuente con style escribiendo BOLD para el texto en negrita e ITALIC para texto en itálica. Si el navegador lo soporta, podremos combinar estos últimos para especificar texto en negrita e itálica como en el caso de las partes de una primitiva. 
Añadiendo colores al diseño
Podemos especificar colores distintos para cada uno de los objetos de la escena y también para el fondo de la pantalla. Veamos el ejemplo siguiente: 
#VRML V1.0 ascii
    DEF BackgroundColor Info {string "0.15 0.6 0.7"}
    Material {
            #ambientColor    0 0 0
            diffuseColor     1 0 0
            #specularColor   0 0 0
            #emissiveColor   0 0 0
            #shininess       0
            #transparency    0
        }
     Sphere {}
Colores del objeto
En el ejemplo anterior, hemos definido el color del objeto mediante el nodo Material{} en la linea diffusseColor que en principio es la que nos interesa puesto que las otras las he añadido como comentarios solo para que veais que existen muchas posibilidades más avanzadas.

Todos los valores numéricos son en coma flotante dentro del rango de 0 a 1. Para entenderlos, sería de gran utilidad conocer el modelo de iluminación de Phong, puesto que excepto transparency que indica el grado de transparencia del objeto y emissiveColor que especifica el color con que va a brillar en la oscuridad , los otros parámetros son similares a los de dicho modelo. En concreto, ambientColor, nos permite indicar el color del objeto frente a la luz ambiental de la escena por lo que va a actuar sobre las partes de dicho objeto no iluminadas directamente por luces, pero solo en el caso de que especifiquemos alguna luz distinta de la que sale por defecto y que está situada sobre la cabeza del observador aproximadamente. Con diffuseColor, especificamos lo que definiríamos como el color normal del objeto (reflexión difusa) y con specularColor podemos especificar el color de la luz reflejada por él (reflexión especular). El parámetro shininess sirve para indicar el nivel de brillo de la superficie. Cuando nos metamos con el tema del posicionamiento de luces, volveremos sobre esto. Por supuesto, no es necesario especificar todos los parámetros del nodo Material{}, lo normal será usar solo ambientColor y diffuseColor. Si usáis transparency, tened en cuenta que algunos visualizadores antiguos no lo implementan, por lo que no afectará al resultado final.

Formato RGB
Los colores se especifican en formato RGB, es decir, mediante sus componentes de color rojo (Red), verde (Green) y azul (Blue). En VRML, se escriben con tres números reales con un rango entre 0 y 1 ambos inclusive (el intervalo cerrado [0..1] para los más matemáticos). Es posible que en algún sitio hayais visto este mismo método, pero usando numeros enteros con el rango de 0 a 255 (un BYTE por componente de color en TrueColor), para poder convertir esos colores al formato VRML, tan solo teneis que dividir cada componente por 256.

Los campos del nodo Material{} que sirven para especificar un color, tienen tres apartados cada uno como podeis ver en el ejemplo superior. Cada apartado sirve para especificar un color básico o componente del color final en el orden RGB, o sea, primero especificaremos el rojo, luego el verde y por último el azul. 

Color de fondo
Para especificar el color de fondo, hemos usado la expresión DEF BackgroundColor Info {string "0.15 0.6 0.7"}. El color viene indicado por la cadena que aparece dentro del nodo Info{}, 0.15 para el rojo, 0.6 para el verde y 0.7 para el azul. Por ahora, con esto hay bastante. El significado del nodo Info{} el operador DEF y el resto de cosas nuevas ya se verá más adelante. 


Nodo de agrupamiento Separator{}
Esta sencilla palabra, nos brinda la oprtunidad de agrupar objetos para asignarles unas características comunes, o darles un tratamiento idéntico. Solo los objetos del interior de una sentencia Separator, se ven afectador por las propiedades o modificaciones que se realizen entre la apertura de sus llaves y el cierre de las mismas. De hecho, el visulaizador VRML guarda el estado de los parámetros como orientación, colores, etc, antes de entrar a evaluar el contenido de un nodo Separator{} y tras evaluarlo y salir de él, restaura de nuevo el estado guardado para que las siguientes acciones u objetos, no se vean afectadas por lo realizado en su interior. La sintaxis es:
Separator { definición de objetos y propiedades }
En el ejemplo de las traslaciones, podreis ver más en detalle como actua este nodo independizando cada una de las esferas del ejemplo de las otras.

Por supuesto, pueden anidarse (ponerse unos dentro de otros) varios nodos Separator{} sin ningún problema.

Ademas de este, existen otros nodos de agrupamiento como Group{}, pero no tienen tanta importancia como este y por ahora pasaré de incluirlos en el curso, cuando tenga un rato ya los añadiré. 


Transformaciones en el espacio 3D
Supongamos que queremos modelar un cucurucho de helado. Tenemos las piezas básicas, que son la bola de helado y el cucurucho, las cuales serán modeladas por una esfera y un cono respectivamente. Pero existe un pequeño problema, ¿como le decimos al navegador, que la bola va encima del cucurucho?, bueno pues para eso están las transformaciones, que nos permiten modificar la posición y geometria de un objeto existente.

En cualquier entorno de programación 3D, existen tres transformaciones básica, que son:

Translación.
Rotación.
Escalado.
La translación, nos permite mover o trasladar un objeto por el espacio 3D. La rotación por su parte, nos permite rotar el objeto respecto de los ejes X, Y o Z un determinado número de radianes (radianes = grados *2*3.1416 /360). Por último, el escalado, nos permite introducir un factor de escala en cada uno de los ejes X, Y, Z, para estirar o encoger el objeto respecto de esos ejes independientemente uno de otro. 

Traslaciones
En este ejemplo veremos una esfera gris que está en el origen de coordenadas (0,0,0) y tres más que son esa misma esfera pero translada en alguno de los ejes:

#VRML V1.0 ascii
Separator{
        Material {emissiveColor    0.7 0.7 0.7}
        Translation {translation 0 0 0}
        Sphere {}
        }
Separator{
        Material {emissiveColor    1 0 0}
        Translation {translation 5 0 0}
        Sphere {}
        }
Separator{
        Material {emissiveColor    0 1 0}
        Translation {translation -5 0 0}
        Sphere {}
        }
Separator{
        Material {emissiveColor    0 0 1}
        Translation {translation 0 5 0}
        Sphere {}
        }
Para especificar la translación, hemos usado Translation{translation X Y Z }, donde se observa claramente que las traslaciones en cada uno de los ejes deben especificarse respectivamente en la X, Y o Z, pudiendo, por supuesto, especificar varios ejes a la vez.

Rotaciones
El caso de las rotaciones es un poco más complicado de comprender y de explicar, pero no mucho más. Las rotaciones, se especifican respecto de un eje formado por el origen de coordenadas (0, 0, 0) y una posición (X, Y, Z) en el espacio 3D, entre las que se establece un vector que será el eje de rotación anteriormente comentado. El metodo básico es muy simple: se usa la instrucción Rotation{rotation X Y Z rad } donde los valores X, Y o Z pueden ser cualquier número real y el valor de rad corresponde al ángulo en radianes que deseemos rotar. Si deseamos realizar la rotación respecto de uno de los ejes de coordenadas X, Y o Z, nos bastará con poner en su posición un valor numérico cualquiera y dejar los correspondientes a los otros dos ejes a 0. Lo veremos más claro con un ejemplo:

#VRML V1.0 ascii
Separator{
        Material {emissiveColor    0.7 0.7 0.7}
        Translation {translation -4.5 0 0}
        Rotation {rotation 0 0 0 0}
        Cube {}
        }
Separator{
        Material {emissiveColor    1 0 0}
        Translation {translation -1.5 0 0}
        Rotation {rotation 1 0 0 1.57}
        Cube {}
        }
Separator{
        Material {emissiveColor    0 1 0}
        Translation {translation 1.5 0 0}
        Rotation {rotation 0 1 0 1.57}
        Cube {}
        }
Separator{
        Material {emissiveColor    0 0 1}
        Translation {translation 4.5 0 0}
        Rotation {rotation 0 0 1 1.57}
        Cube {}
        }
Este ejemplo, se ha complicado un poco, pero es muy interesante porque en el se combinan dos transformaciones, la traslación y la rotación. Antes de rotar cada uno de los cubos, lo movemos para que no se amontonen unos encima de otros como podeis comprobar si eliminais las translaciones. Pero lo más curioso es que no da lo mismo transladar primero y luego rotar que al reves. La explicación es sencilla: las translaciones y rotaciones, se realizan sobre unos ejes, y existen unos ejes para cada objeto, es decir, cuando trasladamos una esfera, la trasladamos respecto de ella misma, de su posicion anterior. Cuando transladamos un objeto lo trasladamos a él y a sus ejes particulares. Lo mismo pero más grave, ocurre con las rotaciones, cuando rotamos un objeto, lo rotamos respecto de sus ejes actuales, pero también rotamos sus ejes. Esto último podeis comprobarlo si rotais primero y transladais después en el ejemplo.

Escalados
El escalado no tiene muchas complicaciones. Se trata de estirar o encoger un objeto por cada uno de sus ejes. Se consigue con la orden Scale{ scaleFactor X Y Z }, donde X, Y y Z son valores mayores que 0. Estos valores, multiplican las coordenadas correspondientes de los puntos del objeto, por lo que un valor de 0.5 reducirá a la mitad el objeto en el eje al que se aplique y un valor de 1.5 lo aumentara en un 50%. Pueden aplicarse a la vez todos los escalados sin ningún tipo de problema. En el ejemplo siguiente, veremos esto con más claridad:

#VRML V1.0 ascii
Separator{
        Material {emissiveColor    0.7 0.7 0.7}
        Translation {translation -4.5 0 0}
        Scale {scalefactor 1 1 1}
        Cylinder {}
        }
Separator{
        Material {emissiveColor    1 0 0}
        Translation {translation -1.5 0 0}
        Scale {scalefactor 1 1 1.5}
        Cylinder {}
        }
Separator{
        Material {emissiveColor    0 1 0}
        Translation {translation 1.5 0 0}
        Scale {scalefactor 1 0.5 1}
        Cylinder {}
        }
Separator{
        Material {emissiveColor    0 0 1}
        Translation {translation 4.5 0 0}
        Scale {scalefactor 1.5 1 0.5}
        Cylinder {}
        }

El nodo Transform{}
Este nuevo nodo, como podreis deducir por su nombre, está directamnete relacionado con las transformaciones. En su interior podemos agrupar varias de ellas sin necesidad de poner el nodo asociado a cada una. Además, sirve también para especificar cualquier transformación, poniendo siempre este nodo en lugar del propio de la transformación, con lo que se simplifica bastante la escritura del codigo VRML.
Translation {translation 1.5 0 0}
Transform {translation 1.5 0 0}

Scale {scaleFactor 1.5 1 1}
Trasnform {scaleFactor 1.5 1 1}
En este caso, los dos pares de expresiones son equivalentes, ambas especifican una traslación o un escalado en el eje X de 1.5 . 
Transform
        {
        translation 4.5 0 0
        rotation 1 1 0 3.14
        translation 0 0 1
        }
Ahora, lo que hemos hecho es agrupar dentro de un solo nodo Transform{} varias transformaciones. 

Iluminación de la escena
Ahora que ya hemos visto como poder aplicar a los objetos características como color, transparencia y brillos, vamos a ver como podemos aplicar luces a la escena para poder realzarla.
Básicamente existen tres tipos de luces, las cuales podemos encontrar en cualquier programa de diseño 3D y que son las siguientes:
Infinitas o direccionales, cuyo foco emisor se supone que se encuentra a una distancia lo suficientemente alejada de la escena que ilumina como para suponer que esta en el infinito. Con esto se consigue una simplificación, que es la de poder considerar todos los rayos de luz incidentes como paralelos entre si. Un claro ejemplo de este tipo de luces es la del sol que incide sobre la tierra, cuyos rayos son prácticamente paralelos entre si. Solo necesitan un vector para caracterizarlas, expresado normalmente con un punto respecto del origen de coordenadas.
Puntuales, las cuales vienen caracterizadas por un punto del espacio en el cual se sitúan y desde el que emiten luz en todas direcciones. Un ejemplo de este tipo de luces sería una bombilla, la cual está en un lugar determinado de la escena y emite su luz desde ese lugar hacia toda la escena. En el límite, si situásemos una luz de este tipo a una distancia lo suficientemente alejada de la escena, podríamos considerarla como una luz infinita.
Focales, con las que podremos crear efectos como los de enfocar una fuente de luz sobre un objeto determinado. Este tipo de luces viene caracterizado por dos puntos en el espacio en lugar de uno solo como en las dos anteriores. El primero de ellos indica la posición en la que se encuentra situada la fuente de luz y el segundo determina la dirección y el sentido de la luz o dicho de otra forma, hacia donde esta enfocada. Puede considerarse este tipo de luz como algo similar a una linterna que permite dirigir la luz hacia un lugar determinado de la escena.
Para poder usar estos tres tipos de luces, VRML incorpora tres nuevos nodos:
DirectionalLight{}, mediante el que podemos especificar luces infinitas usando el parámetro direction, que contiene las coordenadas de un punto, el cual junto con el origen actual de coordenadas define un vector mediante el que especificaremos el sentido de todos los rayos de luz emitidos por esta luz.
DirectionalLight
        {
        on TRUE
        intensity  1
        color  1 1 1
        direction  0 0 -1
        }
PointLight{}, que nos va a permitir modelar las luces de tipo puntual, situándolas en el lugar del espacio especificado por medio del parámetro location y que emitirá sus rayos en todas direcciones a partir de él, por lo que no necesita mas parámetros.
PointLight
        {
        on TRUE
        intensity 1
        color 1 1 1
         location 0 0 1
        }
SpotLight{}, el cual nos proporciona el nodo más complejo de todos para poder modelar una luz de tipo focal. En este tipo de luces, tenemos dos puntos a definir, los cuales definirán un vector que apuntara hacia el objeto o parte de la escena a iluminar. Mediante el parámetro location, especificamos la posición de la luz en la escena y mediante el parámetro direction lo que especificamos es hacia donde enfocamos la luz que hemos situado mediante el anterior parámetro. Podéis comprobar que este nodo es un poco más complejo que los otros, al aparecer dos parámetros nuevos que son cutOffAngle mediante el que podemos especificar la amplitud del cono de iluminación de este tipo de luces (imaginad una linterna) y dropOffRate que nos va ha permitir definir mediante un número real la velocidad de caída de la luz hacia los bordes de su cono de iluminación.
SpotLight
        {
        on TRUE
        intensity 1
        color 1 1 1
        location  0 0 1
        direction 0 0 -1
        dropOffRate 0
        cutOffAngle 0.785398
        }
Además de los parámetros comentados, podréis ver tres más que no he mencionado que son comunes a los tres nodos y son on, que es booleano y por tanto puede tomar los valores de TRUE o FALSE para poder desactivar una luz sin necesidad de eliminar su código de la escena. Tambiién tenemos intensity, que mediante un numero real con un rango entre 0.0 y 1.0 nos va ha permitir especificar la intensidad de la luz a la que pertenezca y por último y no por ello miserablemente despreciado, encontramos color, el cual nos va a permitir especificar en formato RGB el color de la luz emitida por nuestra fuente de la misma manera que en el número pasado especificábamos el color de un objeto.
Debéis tener en cuenta que las luces se ven afectadas por la transformación acumulada actual (debéis tener en cuenta las rotaciones y traslaciones realizadas) y también se ve afectada por los Separator{} , puesto que una luz que se encuentre en el interior de uno de ellos solo iluminara los objetos que se encuentren a su vez dentro de ese Separator{} siendo ignorada por los objetos exteriores a él, aunque no todos los visualizadores soportan esto último ni todos los tipos de luz definidos en el estándar. De hecho muchos de ellos solo soportan el nodo DirectionalLight{} y algunos no permiten especificar luces más que de color blanco.
#VRML V1.0 ascii
Separator
        {
        DirectionalLight {
                on TRUE
                intensity 0.8
                direction 0 -1 0
                }
        Material{diffuseColor 1 0 0}
        Transform{translation 0 1.5 0}
        Sphere{}
        }
Separator
        {
        DirectionalLight {
                on FALSE
                intensity 0.8
                direction -1 1 0
                }
        Material{diffuseColor 0 1 0}
        Transform{translation 1.5 -1.5 0}
        Sphere{}
        }
Separator
        {
        DirectionalLight {
                on TRUE
                intensity 0.8
                direction 1 1 0
                }
        Material{diffuseColor 0 0 1}
        Transform{translation -1.5 -1.5 0}
        Sphere{}
        }
En la imagen del ejemplo, podemos comprobar que una de las tres luces está desactivada y según el visualizador usado vereis individualizada o no la luz de cada nodo Separator{} con su esfera. Probad a encender y apagar las luces con el parámetro on, pero no intentéis probar muchas más cosas porque en el momento de escribir esta parte del curso no funcionan sobre Cosmo Player ni sobre Live3D que son los PlugIn's más comunes. 

Aplicación de texturas
Hasta ahora, solo hemos visto objetos sólidos de colores, pero al fin y al cabo no todo es del mismo color, y podemos querer simular objetos de marmol, papel, metal, etc. Las texturas nos ayudan en eso. Al nivel del VRML, consideraremos una textura como un fichero de dibujo en un formato comprendido por el visualizador que usemos, no existe un estandard a este respecto (en VRML 1.0 por lo menos), JPEG, GIF o BMP son formatos posibles, aunque algunos visualizadores antiguos solo entienden el formato RGB de Sun. El caso es que dicha textura contiene un dibujo de un pedazo de algo, y lo que nosotros queremos es recubrir el objeto con ese algo. Es muy sencillo aplicar una textura a un objeto en VRML, se realiza de la siguiente manera con el nodo Texture2{}:

#VRML V1.0 ascii
Separator {
        Texture2 {
         filename "textura1.jpg"
         #image    0 0 0
         #wrapS    REPEAT
         #wrapT    REPEAT
         }
        Sphere{}
         }
Textura JPEG
textura1.jpg
En el ejemplo anterior, le hemos aplicado el fichero textura1.jpg, que contiene la textura del dibujo de arriba, a una esfera, lo que nos da un resultado bastante vistoso.

El parámetro filename es el que contiene el nombre de la textura, el cual puede ser desde luego una URL. El siguiente parámetro que encontramos es image, que nos permitirá crearnos una trama de bits para usarla como textura, pero como no es muy útil, simplemete la ignoraré. Después de estos, encontramos wrapS y wrapT los cuales hacen referencia a la manera de extender la textura en sus dos ejes por la superficie del objeto. Para comprenderlos mejor se debería conocer realmente como se produce el mapeo de una textura sobre una superficie, cosa que se escapa al interés y espacio de este curso (los Kbytes son los Kbytes...). Los valores que pueden tomar estos parámetros son:

REPEAT, que permite repetir la textura fuera del rango de coordenadas de textura normal entre 0 y 1. Dejad normalmente esta opción o no las especifiquéis.
CLAMP, que fuerza a que las coordenadas de la textura entren en el rango de 0 a 1. Estas coordenadas representan las dos dimensiones del gráfico a mapear sobre las tres del objeto VRML.
Ahora, vamos a ver como se extiende una textura sobre cada una de las primitivas que conocemos:
Cube{}- Sobre esta, la textura se extiende de manera plana en cada una de las caras del paralelepípedo, la proyección usada es una planar normal y corriente.
Cone{}- En este caso cambian las proyecciones, en la base se extiende de una manera similar a como lo realizaba sobre el cubo, pero sobre las caras laterales lo hace "enrollándose", o más técnicamente, mediante una proyección cilíndrica.
Cylinder{}- Es muy similar a la anterior, en las dos tapas del cilindro se realiza una proyección plana de la textura y en las caras laterales se vuelve a proyectar de manera cilíndrica, pero en este caso el resultado no distorsiona tanto el gráfico como en el caso del cono.
Sphere{}- Para la esfera, se usa la proyección esférica (que original...), que consiste en recubrir esta como si juntásemos el borde superior de la textura en el polo superior de la esfera, el inferior en el polo inferior y después tratásemos de cubrir la esfera estirando la textura. Veremos más claro todo esto en los ejemplos.
En el caso de la proyección esférica, es conveniente dejar unos ribetes en los bordes superior e inferior sin dibujo en el gráfico de textura para evitar distorsiones al aplicarla.

Para mayor claridad, la textura que se va a utilizar es una foto y no una autorrepetitiva, con lo que se apreciarán mejor los tipos de proyección y los efectos o deformaciones que provocan las proyecciones sobre la imagen.

#VRML V1.0 ascii
Separator {
        Texture2 {
         filename "Xw-Tie.jpg"
         }
       Cube{}
       Cylinder{}
       Cone{}
       Sphere{}
         }
Textura JPEG
Xw-Tie.jpg
Ajuste de texturas

Texture2Transform{}- Mediante este nodo podemos asociar una serie de transformaciones a una textura de la misma manera que hacíamos sobre un objeto 3D, pero teniendo en cuenta que en este caso, la imagen es una superficie con solo dos dimensiones, por lo que solo usaremos dos valores en cada transformación, uno para cada eje de coordenadas de textura.

Texture2Transform {
 	translation  	0 0
  	rotation     	0 
  	scaleFactor 	1 1
  	center      	0 0 
  	}
Como podéis ver, tenemos básicamente las mismas transformaciones que en el caso del nodo Transform{} pero sobre dos ejes. Las traslaciones se asocian al parámetro translation, las rotaciones al parámetro rotation (en radianes, claro...) y el escalado no uniforme al parámetro scaleFactor. Los casos del escalado y la rotación, deben realizarse respecto de un punto de la textura, el cual viene determinado por el último de los parámetros, center , que especifica el punto del mapa de textura sobre el que se realizarán dichas transformaciones. Los valores van en el rango de 0 a 1 como todos los referidos a las texturas, puesto que se asume que tanto el eje horizontal denominado S como el vertical denominado T, tienen una dimensión de una unidad, independientemente del tamaño en pixels de la textura. Como en otros nodos, pueden omitirse los parámetros que no deseemos usar.

De la misma forma que en el nodo Transform{}, las diversas transformaciones se acumulan sucesivamente en una única matriz de transformación, en nuestro caso también se obtiene una única matriz, la cual se aplicará sucesivamente a todos lo objetos que queden dentro de su radio de acción (refrescad el uso del nodo Separator{}). El orden en que se evalúan las transformaciones a acumular en la matriz es: escalado-> rotación-> traslación en el caso de que se especifiquen todas.

#VRML V1.0 ascii
Separator {
        Texture2Trasform {
       sin transformar
       translation 0.5 0
       rotation 0.785
       scaleFactor 1.5 1
         }
       Texture2 {
       filename"caballo.jpg"
         }
       Cube{}
         }
Textura JPEG
Selecciona una de las tres transformaciones a aplicar a esta textura sobre un cubo

TextureCoordinate2{}- Existe un segundo nodo asociado a estos menesteres que es el que da nombre a este apartado. Define una serie de coordenadas que se usarán para mapear texturas en los objetos definidos mediante los nodos PointSet{}, IndexedLineSet{} o IndexedFaceSet{}, mediante el que se reemplazan los vértices actuales del objeto definido a efectos de texturado y que tiene el siguiente formato:


TextureCoordinate2 {
	point  0 0 
	}
Las coordenadas de textura que podemos introducir en él, nos permitirán crear algunos efectos interesantes, pero para ver esto, necesitaremos primero saber como funcionan los tres nodos anteriores, que son los que nos van a permitir explotar las verdaderas capacidades del VRML, puesto que hasta ahora nos habíamos limitado a crear objetos predefinidos mediante las primitivas que proporciona el lenguaje, lo cual es a todas luces muy limitado. Con estos nuevos nodos podremos crear cualquier escena que se nos ocurra (tampoco os paseis...), y si tenemos el programa adecuado, importar diseños de 3D Studio o similares a formato VRML

Para aplicar texturas a objetos creados mediante la enumeración de sus caras y/o vértices en nodos como IndexedFaceSet{}, se presentan problemas más complejos que los vistos hasta ahora, pero primero tendremos que ver la manera de usar estos nuevos nodos para definir nuestros objetos en la siguiente entrega de este manual, que estoy realizando en mis ratos libres. 


THE END
Autor: Vicente Luis Villagrasa Blanco - mailto:[email protected]

Si teneis alguna aportación constructiva al curso, quereis preguntarme algo, o pedirme que me extienda más en alguna cosa, no os corteis y decidlo.

Ya que habeis leido el curso de VRML, no olvideis pasar por mi Museo virtual.

Si quereis una versión en ZIP para verlo tranquilamente desconectados y que además esté preparada para ser imprimida, pinchad aquí, solo son 56KB.

Para que esteis al día de las actualizaciones del curso, mandadme un correo indicando que quereis que os avise de los cambios y mejoras. 


Página anterior
Página inicial.
Hosted by www.Geocities.ws

1