| Introducción¿ Quien no   ha    oído   hablar       de    Pixar?, ¿ Quien   no ha visto Toy Story?. Pixar Animation Studios
se dedica desde hace mucho tiempo a la animación por ordenador.
Luxo Jr. (1986) fue  la primera película en 3D realizada
por ordenador  nominada al Oscar, además ganó más
de 20 premios en festivales de cine internacionales.
      En 1987, Red's Dream ganó varios premios en el Festival
 Mundial de Animación en Zagreb  y en el Festival Internacional
 de Cine de San Francisco. 
 
La primera animación que  ganó un  Oscar fue Tin  Toy
(1988),     Pixar realizó un  modelo    para  la cara de un
bebé definiendo más de 40 músculos que controlaba
el animador.
 
     
En 1989 sacaron Knick Knack, es la historia de un muñeco
de  nieve que vive  en una bola.  La película se realizó
inicialmente para  verla  en  3D  aunque también  sacaron   una
versión normal.
 
 Después de  esto vendrían muchos más exitos como
 la reciente película  Toy
 Story. Este es  uno de los primeros  largometrajes realizados
 íntegramente  por  ordenador.  En    la página  de   Pixar    podéis      encontrar
 más  cosas interesantes, como Toy Story  2 que esperan sacarla
 en 1999.
  Pixar desarrolló  el interface   RenderMan para separar   y
mantener independientes los  "modeladores" y los  "renderizadores". Un
modelador  es   una herramienta  que  se  usa  para  dibujar  escenas,
diseñar animaciones   etc., mientras   que un renderizador   lo
único que hace  es coger esa descripción y representarla
con sombras, luces, texturas, etc.
 
 RenderMan permite a los modeladores especificar que es lo que hay que
 renderizar pero  no  cómo hacerlo, es   decir, un modelador no
 debería   preocuparse en absoluto   del rendering.   Del mismo
 modo,  un renderizador  que cumpla las  especificaciones del estandar
 RenderMan puede   usar Z-buffer, scan-line,  ray-tracing, radiosity o
 cualquier otro método para   "dibujar" los objetos, y  esto es
 independiente de RenderMan. Podemos  ver el interface RenderMan  como
 un formato    de descripción de  escenas  del   mismo modo que
 PostScript      es  un      formato  de      descripción    de
 páginas. Este standard es independiente  de arquitecturas y de
 sistemas operativos.
            The RenderMan@ Interface Procedures and RIB Protocol are: Copyright 1988, 1989, Pixar.
 All Rights Reserved.
 RenderMan@ is a registered trademark of Pixar
 En  este artículo  trataremos de  introducirnos  un poco  en
RenderMan,               para       ello     usaremos               Blue       Moon
Rendering Tools,  escrito   íntegramente por  Larry  Gritz.
Este   paquete   es  un   renderizador   de libre  distribución
(sólo ejecutables y para  uso personal), existen versiones para
muchas máquinas  entre las que se encuntra  Linux (de hecho fue
una de las primeras implementaciones), utiliza ray-tracing y radiosity
y no tiene  nada que envidiar   a Photorealistic RenderMan  (PRMan) el
producto comercial de Pixar.
 En  un principio el  sistema de  coordenadas del  mundo y  el de la
cámara coinciden, son  sistemas de coordenadas levógiros
(exactamente igual que el del Pov-Ray), con el  origen en el centro de
la pantalla, el eje X hacia la derecha, el Y hacia arriba y el Z hacia
"dentro" de la  pantalla.  En  la siguiente   figura podemos ver    la
cámara que se usa por  defecto (el eje X  es rojo, el Y verde y
el  Z  azul,  para     ver  el código   fuente  pincha    en la
imagen).  Un sistema dextrógiro es igual pero con el eje Z
cambiado de signo.
 
   En Pov-Ray, el sistema de coordenadas del mundo  es fijo, es decir,
podemos mover   la  cámara por el mundo   y  poner los  objetos
mediate transformaciones, en RenderMan,  ocurre justo lo contrario, la
cámara  es fija y lo que  se  transforma para obtener distintos
puntos de vista es  el sistema de  coordenadas del mundo. Todo esto lo
veremos más adelante cuando "desmiguemos" un ejemplo.
 RenderMan   contempla  muchísimas   primitivas,   tanto   de
definición de  objetos como    de  luces y   demás.    A
continuación   veremos, como  ejemplo,    el formato    de  las
cuádricas  que  son las   más   famosas, aunque  existen
más (como parches bezier, polígonos, etc.).
 
 
|  |  |  
| Disk    height    radius   
thetamax     Disk     5           
10            300  | Cone    height   
radius    thetamax     Cone    15           
10            300  |  
|  |  |  
| Cylinder    radius    zmin   
zmax    thetamax     Cylinder    10           
-5        10       
300  | Sphere    radius    zmin   
zmax    thetamax     Sphere     10       
-4            8           
300  |  
|  |  |  
| Torus    major rad    min rad   
phimin    phimax    thetamax     Torus    10                   
4               
90            320           
300  | Paraboloid    radius    zmin   
zmax    thetamax     Paraboloid     10           
4            15       
300  |  
|  |  
| Hyperboloid    point1           
point2        thetamax     Hyperboloid    0 10 -5       
10 5 15        300  |  
Podemos observar que el  formato de algunas de  estas primitivas no es
demasiado  sencillo, pero  teniendo en cuenta  que el   fichero  RIB lo   debe
proporcionar un modelador como salida,  este formato es el  más
adecuado, tanto por sencillez como por potencia.
 
 
InstalaciónAntes  de  nada  debemos   ir    a   la página   de     Blue      Moon    Rendering Tools y
bajarnos  el programa. En  estos momentos la versión más
reciente  es la  2.3.6 y  para descomprimirlo  se procede  de la forma
normal:
rabit:~/$ gzip -d BMRT2.3.6.linux.tar.gz
rabit:~/$ tar xvf BMRT2.3.6.linux.tar
   Una vez   descomprimido   y desempaquetado nos  creará  un
directorio llamado BMRT2.3.6, en él tenemos los ejecutables (en
bin/),    los  ejemplos     (en    examples/)   y     la
documentación  en  postcript    y  HTML    (en    doc/),
también hay un     README en el  que,  además  de
información  útil sobre el  programa y demás, hay
un apartado de instalación. Es muy sencillo y no debería
dar problemas a nadie.
 
 
Primeros PasosPara familiarizarnos con  la especificación, veremos un fichero
típico Renderman (../../common/May1998/disptest.rib).  La
imagen se genera con rendrib -v ../../common/May1998/disptest.rib (pinchando en la
imagen la veremos a 1024x768 y con anti-aliasing 2x2).Este es  uno de los  muchos ejemplos que encontraréis  en el
directorio  examples/ de BMRT (Blue   Moon Rendering Tools) y
como  podéis ver el  fichero  que lo  produce  no es  muy largo
(cuando   hagamos animaciones veremos como   el  fichero crece de
forma considerable).
 
   Cómo habréis   podido  observar, en    el  directorio
bin/   hay       varios     ejecutables:    rendrib,
rendribv y rgl.  Rendrib es el renderizador
con todas las de la ley, rendribv es igual, pero renderiza en
modo  wire-frame,   es     decir, con     líneas,    por
último, rgl renderiza  en modo polígonos. Estos
últimos renderizadores  son para hacer previews  de posiciones,
animaciones   etc.,   el     rendering final   debemos   hacerlo   con
rendrib.
  El formato de los ficheros RIB (Renderman Interface ByteStream) es
bastante sencillo, aunque no por ello menos potente, y son ficheros de
texto plano (igualito, igualito que  Pov-Ray). Un fichero RIB correcto
contiene lo siguiente:
 
El estado  gráfico  contiene  toda la   información para
renderizar una  primitiva.  Se divide en   dos partes: una  global que
permanece constante  de primitiva en  primitiva y un estado actual que
cambia con cada primitiva.   Los parámetros en el estado global
se   llaman    opciones   y   los      del    estado     actual
atributos.
Opciones que son constantes para todos los frames
(resolución, anti-aliasing, etc.).
FrameBegin
Inicialización de las opciones del estado
gráfico para este frame (como el nombre del fichero de salida,
nivel de detalle etc.)
Atributos del   estado gráfico  para  este  frame  (como
luces, tipo de proyección, etc.).
WorldBegin
Modificación de   los  atributos del estado    gráfico y
declaraciones de geometría para el frame actual.
WorldEnd. Lo cual provoca: el frame
actual se renderiza y se salva. Toda la geometría y las luces declaradas
en (6) se destruyen. El estado gráfico vuelve al que había
antes de (5).
FrameEnd. Esto hace que el estado gráfico
vuelva a como estaba antes de (2).
Si hay mas frames se repiten los pasos (2)
a (8). Para comprender mejor todo esto y para  introducirnos un poco en la
manera de  especificar escenas con RenderMan, vamos   a ver el ejemplo
anterior línea por línea. Con esto  nos haremos una idea
de lo que se puede hacer y de cómo hacerlo.
 1.-  ##RenderMan RIB-Structure 1.0   
 2.-  version 3.03   
 3.-   
 4.-  ###########################################################################   
 5.-  #   
 6.-  # This RIB file demonstrates some more complex procedural textures.   
 7.-  # Two spheres show the use of "stucco" and "dented" displacement shaders.   
 8.-  # The floor shows the gmarbtile_polish shader, which is polised green   
 9.-  # marble tiles.  Note that the reflection is accomplished by the shader   
 10.- # actually calling the trace() function, rather than reflection mapping.   
 11.- #   
 12.- ###########################################################################   
 13.-   
 14.- Option "searchpath" "shader" [".:../shaders:&"]   
 15.- Display "balls2.tif" "file" "rgb"   
 16.- Format 400 300 -1   
 17.- PixelSamples 1 1   
 18.-   
 19.- Declare "prmanspecular" "integer"   
 20.- Option "render" "prmanspecular" [0]   
 21.- Projection "perspective" "fov" 35   
 22.- Translate 0 -0.55 8   
 23.- Rotate -110 1 0 0   
 24.-   
 25.-   
 26.- WorldBegin   
 27.-   
 28.- LightSource "ambientlight" 1 "intensity" 0.02   
 29.-   
 30.- Declare "shadows" "string"   
 31.- Attribute "light" "shadows" "on"   
 32.- LightSource "distantlight" 1 "from" [0 1.5 4] "to" [0 0 0] "intensity" 0.6   
 33.-   
 34.- AttributeBegin   
 35.-   Declare "txtscale" "float"   
 36.-   Declare "Kr" "float"   
 37.-   Declare "darkcolor" "color"   
 38.-   Declare "lightcolor" "color"   
 39.-   Declare "veincolor" "color"   
 40.-   Surface "gmarbtile_polish" "Ka" 1 "txtscale" 0.5 "Kr" .25 "Kd" 0.3 "Ks" 0.2 "roughness" 0.02   
 41.-   Patch "bilinear" "P"  [ -5 -5 0 5 -5 0 -5 5 0 5 5 0  ]   
 42.- AttributeEnd   
 43.-   
 44.- AttributeBegin   
 45.-   Color  [ .6 .6 .6 ]   
 46.-   Translate -1.5 0 1   
 47.-   Surface "matte"   
 48.-   Declare "frequency" "float"   
 49.-   Declare "Km" "float"   
 50.-   Displacement "stucco" "frequency" 20 "Km" 0.3   
 51.-   Sphere 1 -1 1 360   
 52.- AttributeEnd   
 53.-   
 54.- AttributeBegin   
 55.-   Translate 1.5 0 1   
 56.-   Color 1 .45 .05   
 57.-   Declare "Kr" "float"   
 58.-   Declare "Km" "float"   
 59.-   Surface "shiny" "Kd" 0 "Kr" 0.25 "roughness" 0.15 "specularcolor" [1 .5 .06]   
 60.-   Displacement "dented" "Km" 0.5   
 61.-   Sphere 1 -1 1 360   
 62.- AttributeEnd   
 63.-   
 64.- WorldEnd   
 Como podemos ver en  la línea 1 y de  la línea 4 a la
12, el símbolo  # se usa  para los comentarios, pueden estar en
cualquier lugar del fichero  y ocupan una  linea (como los comentarios
de  C++ //). Los comentarios los  usaremos  más que nada cuando
editemos estos ficheros a mano ya que ayudan  bastante a comprender el
funcionamiento de la escena.
  En la línea 2  está la directiva version. Nos
dice qué versión del interface se está usando (la
3.03), la versión más actual  es la 3.1 de septiembre de
1989  (si, de 1989, no me  he equivocado),  aunque tiene revisiones de
Mayo del 95.
 
La linea 14 define con  la directiva searchpath y shader
el   path de   los  "sombreadores",  los   sombreadores le  dicen   al
renderizador de qué  forma  un objeto debe  renderizarse  (como
plástico, transparente, etc.), esta   es una de las  cosas  que
hacen potente al interface, ya que las texturas de los objetos son una
especie de  Plug-Ins,  por tanto podemos implementar  nuevas texturas,
efectos etc. sin tener  que  esperar a una versión   más
potente del renderizador.  Normalmente existe una  variable de entorno
(SHADER)  que indica donde están  estos ficheros, por lo que no
se suele declarar en el fichero.
 La opción Display  está en la línea 15,
con      ella   declaramos el   nombre    del     fichero  de   salida
"balls2.tiff" y su tipo "file" "rgb",  es decir, de tipo
fichero RGB.  
 En  la   línea  16,   con la   opción Display,
definimos   la  resolución   del    rendering,  es   decir,  el
tamaño de la imagen, que en este caso será de 400x300 el
-1 define  el aspect ratio   del ancho y alto   del pixel (en realidad
debería ser un +1, no sé por qué ponen -1)
  A continuación  tenemos el sampleado horizontal  y vertical
de  cada  pixel,  es  decir,   el número   de  rayos  que    se
lanzarán para renderizar un pixel,  con PixelSamples 2 2
tendremos que por cada pixel lanzaremos 4 rayos,  lo que se traduce en
una mejor calidad de la imagen (esto es el anti-aliasing), pero
por  contra un mayor tiempo de  renderización,  en nuestro caso
tendremos únicamente un rayo por pixel (1x1=1).
 La línea 19 es  una declaración y en ella simplemente
decimos que prmanspecular en un  integer, en realidad lo
que   hacemos  es definir el   token  prmanspecular y cuando el
renderizador se encuentre con este token,  lo siguiente será un
entero.
 
Seguidamente, en la línea 21, tenemos la declaración
de  la proyección, con "perspective"   le decimos que la
proyección que queremos    es  perspectiva,  y   con   "fov"
35   (field of view o  campo de visión) ponemos
un ángulo de visión de 35 grados.
  Las siguientes líneas, 22 y  23, definen la posición
de la cámara.  Primero tenemos   una traslación y  luego
una  rotación, pero debido a que  todas las transformaciones se
realizan introduciéndolas primero   en la pila y  calculando al
final    (cuando encuentra el   WorldBegin  en  este caso), las
transformaciones se "ejecutan" al revés,  es decir, primero  se
realiza la rotación de -110 grados en el eje X (para hacerla en
el  eje  Y     se haría  Rotate   45   0  1   0),    y a
continuación la traslación de -0.55 unidades en el eje Y
y 8 en el eje Z. Hay que tener en cuenta que lo que se gira y traslada
no  es la cámara, es el  origen de coordenadas del mundo. 
En las siguientes figuras podéis  ver las dos transformaciones,
el  estado inicial, la  rotación  y luego la  traslación.
 
       En  este    punto empieza  la  escena   en   sí.  Una escena
(declaración de  las   luces,  de los  objetos,  etc.)  empieza
siempre  con  WorldBegin   y   acaba  con   WorldEnd
(líneas 26 y  64   respectivamente).  Seguidamente  tenemos  la
declaración de las luces (líneas 28 a 32), la primera es
luz    ambiente, es  la  número uno   (cada  luz  debe tener un
número, y en teoría deben ser distintos) y tiene 0.02 de
intensidad  luminosa.  A  continuación  vemos  que  se  declara
shadows  como una  cadena de   caracteres (string) y
activamos la  opción de  las  luces para que  hagan sombra.  La
siguiente línea es una luz  de tipo distantlight (como
la del sol por ejemplo) con el número uno aunque debería
ser otro (por ejemplo el  dos) esto funciona debido  a que BMRT parece
que ignora estos números,  pero para guardar la  compatibilidad
(por    ejemplo con  PRMan de  Pixar)   debemos  ser  estrictos con el
interface.   La intensidad se  declara igual  que  en la otra  luz(son
atributos  comunes)  y   el  vector  dirección de    la luz con
from y to, esta  luz lanza rayos paralelos, es  como
si estuviera en el infinito.
 A  partir de  aquí  tenemos los  tres objetos  que forman la
escena,     cada  objeto    está    encerrado   en    un    par
AttributeBegin, AttributeEnd,  ya que cada uno tiene
sus propias  características, tanto de posición  como de
apariencia,  si lo único  que cambiaramos  de  un objeto a otro
fuera su posición, podríamos declarar la textura fuera y
a continuación  definir los objetos con TransformBegin
y   TransformEnd.  El primer  objeto (lineas  34 a  42) es un
parche, los parches pueden ser: uniformes o no-uniformes, racionales o
no-racionales y bilineares o  bicúbicos, con esto se  consiguen
parches   Bezier,  BSplines  etc.   (un  libro sobre
gráficos  por  ordenador  ayudaría bastante a comprender
esto). En este  caso  tenemos un parche  bilinear  con cuatro  puntos,
estos se definen  con "P" y  luego  se ponen las  coordenadas
(x,y,z) de los puntos que queramos. La  textura del objeto se
consigue con la directiva Surface, el  primer argumento es un
fichero shader, las siguientes son específicas de cada
shader. En la  imagen siguiente tenemos  como queda la escena
al        añadir    este       cuadrado.
   El siguiente objeto va  de la línea 44  a la 52, se trata de
una esfera (línea 51)  y el color se  lo proporcionamos  con la
directiva Color [R G  B]. A continuación la ponemos en
el sitio  con Translate y  le decimos que clase de superficie
tiene,  en  este   caso  matte   que   no tiene    más
parámetros.   Después tenemos la   característica
más    importante    de      BMRT,  los   shaders   de
desplazamiento. Estos shaders  son como  los bump-maps
de Pov-Ray,  con la diferencia que los  "bultos" no son simulados, son
reales. Con esto conseguimos que una esfera con bump-mapping no
se vea redonda por los bordes y  se vea abollada. Los shaders
de   desplazamiento  son iguales que los   de   textura, un  nombre de
shader   y   sus  parámetros.   El   formato   de
especificación  de   esferas  es   un  poco  raro:   el  primer
parámetro es   el  radio,    el  segundo  y   el   tercero  son
zmin y zmax respectivamente y recortan la esfera por
esos valores  (zmin=-1  y zmax=1  la  dejan  entera,
zmin=0 y    zmax=1 la parten    por la   mitad),  el
último valor son los grados que cubre la  esfera, 360 toda, 180
la  mitad etc. La   imagen  siguiente es la   escena  con  la  primera
bola:
   El siguiente  objeto   es igual que    el primero  pero con   otras
características de  textura y desplazamiento,   por  lo que  no
seremos pesados y lo dejaremos  correr.  Como antes, veremos como
queda la escena en  la imagen  siguiente:
 
   Con esto se acaba el  fichero. Como podéis ver el desarrollo
de escenas no es  muy complejo, pero con  una escena complicada o  con
una animación  el  fichero se complica bastante.  Para evitarlo
basta usar un modelador que soporte RenderMan (cualquier modelador que
se     precie  debería   exportar     RIB's)  o    programar la
animación  en C. Con  la distribución de BMRT vienen los
includes   y   las   librerias  necesarias.  Son  simplemente
funciones que  sacan  por  la  salida  estandard  el  fichero  RIB. La
correspondencia entre las dos formas  es total: WorldBegin en
un fichero    RIB se corresponde   con  RiWorldBegin()  en un
programa C    (para  más  información  sobre  esto  leer
RenderMan  for   Poets  que  se   encuentra  en  el  directorio
doc/).
 
ConclusionesEl inteface  RenderMan es muy potente y  de hecho Toy Story esta hecho
así (con un modelador que se  llama marionet).   En
www.toystory.com hay    algunos
números sobre la película y algunas cosillas más.
La especificación   del  interface la  podéis  encontrar
en                                                             giga.cps.unizar.es.
Además de la especificación  hay un manual de PRMan  (el
renderizador     de    Pixar)  y       algunos   trabajos     de    giga
hechos con RenderMan. En  el   próximo artículo intentaremos   modelar  un
monigote,   lo  modelaremos     en   C  para      animarlo  más
fácilmente   después   y para   familiarizarnos  con  la
librería.  El monigote puede ser  el  pinguino de Linux o  Bill
Gate$  (o los  dos   y  hacemos que  el    pinguino lo fría   a
mamporros).
 |