Hogar Mapa Indice Busqueda Noticias Arca Enlaces Sobre LF
[Top bar]
[Bottom bar]
[Foto del Autor]
por Carlos Calzada Grau

Sobre el Author:

Soy licenciado en inform�tica y desde que me regalaron un Spectrum me han gustado los gr�ficos por ordenador. Soy muy aficionado a Linux, a su filosof�a de desarrollo y a todo lo que no tiene que ver con micro$oft. Los bons�is y los acuarios son mis aficiones no relacionadas con los aparatitos, estos con pantalla y teclado.

Contenidos:

  1. Introducci�n
  2. Escena simple:
  3. Movimiento rectil�neo:
  4. Movimiento parab�lico:
  5. Referencias

Renderman III

[Ilustracion]

Resumen:

En este tercer art�culo de la serie sobre Renderman (III) trataremos uno de los aspectos m�s importantes: la posibilidad de modelar y animar una escena utilizando "C" o "C++".



 

Introducci�n

Como hemos podido ver en los dos art�culos anteriores, crear una escena o una animaci�n escribiendo directamente en un fichero de texto es una tarea tediosa. �Te imaginas hacer un fichero ".rib" con el movimiento de una pelota botando?. Para hacernos la vida un poco m�s f�cil tenemos la posibilidad de escribir en "C" o "C++" el modelo de la escena o animaci�n con una serie de funciones que sacan por la salida est�ndar los comandos Renderman que queramos. Esta salida la podemos pasar a trav�s de un tubo (pipe) a otro proceso (como rendrib, rendribv o rgl) o redireccionarla directamente hacia un fichero .rib.

Cuando instalamos Blue Moon Rendering Tools, nos aparecen dos directorios llamados lib e include. En �stos encontramos cuatro ficheros de los cuales dos son los que nos interesan: ri.h y libribout.a que son las declaraciones y la librer�a de funciones respectivamente. Debemos copiar ri.h a /usr/local/include y libribout.a a /usr/local/lib (tambi�n se pueden poner en otro sitio pero este es un lugar adecuado) y ya est�, estamos listos para nuestro primer programa.

 

Escena simple:

En este primer programa veremos lo b�sico de la programaci�n con Renderman. Como en cualquier programa C, debemos incluir el correspondiente .h antes de utilizar una librer�a, en nuestro caso ser� ri.h. Adem�s deberemos enlazar (link) el programa con la librer�a, para ello deberemos hacer lo siguiente:

gcc miprograma.c -o miprograma -lribout -lm
      

Nosotros utilizaremos un Makefile para ahorrarnos algo de trabajo a la hora de teclear:
LIBS = -lm -lribout
PROGNAME = primero
	 
all: $(PROGNAME)
	
$(PROGNAME).o: $(PROGNAME).c
	gcc -c $(PROGNAME).c
	
$(PROGNAME): $(PROGNAME).o 
	gcc -o $(PROGNAME) $(PROGNAME).o $(LIBS)

 

El primer programa que haremos consistir� en unos ejes y una pelota en el centro, lo llamaremos primero.c (�que original!) y es el siguiente:
 1 #include <stdio.h>
 2 #include <math.h>
 3 #include <ri.h>
 4
 5 void main(void)
 6 {
 7  int i;
 8  int x,y,z;
 9  int nf;
10  float slopex,slopey,slopez;
11
12  RtColor Rojo={1,0,0};
13  RtColor Verde={0,1,0};
14  RtColor Azul={0,0,1};
15  RtColor Blanco={1,1,1};
16
17  RtPoint p1={30,0,10}; /* Posicicion inicial de la pelota */
18  RtPoint p2={0,20,10}; /*   Posicion final de la pelota   */
19		
20  RtPoint from={0,100,100}; /*   Direccion de la luz       */
21  RtPoint to={0,0,0};
22
23  char name[]="primero.tif";
24  RtFloat fov=45;
25  RtFloat intensity1=0.1;
26  RtFloat intensity2=1.5;
27  RtInt init=0,end=1;
28		
29  RiBegin(RI_NULL);
30    RiFormat(320,240,1);
31    RiPixelSamples(2,2);	
32    RiShutter(0,1);
33    RiFrameBegin(1);
34     RiDisplay(name,"file","rgb",RI_NULL);
35     name[7]++;
36     RiProjection("perspective","fov",&fov,RI_NULL);
37     RiTranslate(0,-5,60);
38     RiRotate(-120,1,0,0);
39     RiRotate(25,0,0,1);
40     RiWorldBegin();
41       RiLightSource("ambientlight","intensity",&intensity1,RI_NULL);
42       RiLightSource("distantlight","intensity",&intensity2,"from",from,"to",to,RI_NULL);
43       RiColor(Azul);
44       RiTransformBegin();
45         RiCylinder(1,0,20,360,RI_NULL);
46         RiTranslate(0,0,20);
47         RiCone(2,2,360,RI_NULL);
48       RiTransformEnd();
49       RiColor(Verde);
50       RiTransformBegin();
51         RiRotate(-90,1,0,0);
52 	   RiCylinder(1,0,20,360,RI_NULL);
53 	   RiTranslate(0,0,20);
54 	   RiCone(2,2,360,RI_NULL);
55       RiTransformEnd();
56       RiColor(Rojo);
57       RiTransformBegin();
58 	   RiRotate(90,0,1,0);
59 	   RiCylinder(1,0,20,360,RI_NULL);
60 	   RiTranslate(0,0,20);
61 	   RiCone(2,2,360,RI_NULL);
62       RiTransformEnd();
63       RiColor(Blanco);
64       RiSphere(5,-5,5,360,RI_NULL);
65     RiWorldEnd();
66    RiFrameEnd();
67  RiEnd();
68 };

En las tres primeras lineas tenemos una serie de #includes entre los que est� ri.h que es el que tiene los prototipos de las funciones. Cada llamada de Renderman tiene su funci�n equivalente en ri.h, as� pues, TransformBegin se corresponde con la funci�n RiTransformBegin(), etc. Haciendo make generamos el fichero ejecutable primero. Si lo ejecutamos tendremos por la salida est�ndar una serie de comandos Renderman, �stos los podemos redireccionar a un fichero (primero > primero.rib) o redireccionarlo a otro proceso (primero | rendrib). Si optamos por la �ltima forma, rendrib generar� el fichero renderizado primero.tif:

Antes de poder utilizar cualquiera de las llamadas en un programa debemos hacer una llamada a RiBegin(RI_NULL) y al acabar un llamada a RiEnd(). El par�metro que le pasamos a RiBegin es t�picamente RI_NULL. Para evitar el env�o de RIB's hacia la salida est�ndar podemos poner en este argumento el nombre de un fichero ("mifichero.rib") e incluso el nombre de un proceso (como rendrib) y de esta forma pas�rselo a un programa sin necesidad de crear un fichero RIB intermedio.

En el listado podemos ver, adem�s de las cosas t�picas de C, algunos tipos y funciones propios del interface de Renderman: tenemos el tipo RtColor que es un vector de tres reales indicando la cantidad de rojo, verde y azul (con valores entre 0.0 y 1.0), vemos tambi�n el tipo RtPoint que indica posiciones en el espacio y RtFloat y RtInt que son el tipo real y entero respectivamente.

En la l�nea 29 tenemos la llamada RiBegin(RI_NULL) que como hemos dicho antes es la primera que debemos usar. A partir de aqu� tenemos m�s o menos lo que escribir�amos en un fichero RIB. Esto lo podemos comprobar ejecutando el programa y redireccion�ndolo a un fichero (./primero > primero.rib), obtendremos lo siguiente:
##RenderMan RIB-Structure 1.0
version 3.03
Format 320 240 1
PixelSamples 2 2
Shutter 0 1
FrameBegin 1
Display "camara.tif" "file" "rgb"
Projection "perspective" "fov" [45 ]
Translate 0 -5 60 
Rotate -120 1 0 0 
Rotate 25 0 0 1 
WorldBegin
LightSource "ambientlight" 1 "intensity" [0.1 ]
LightSource "distantlight" 2 "intensity" [1.5 ] "from" [0 100 100] "to" [0 0 0]
Color [0 0 1]
TransformBegin
Cylinder 1 0 20 360
Translate 0 0 20 
Cone 2 2 360
TransformEnd
Color [0 1 0]
TransformBegin
Rotate -90 1 0 0 
Cylinder 1 0 20 360
Translate 0 0 20 
Cone 2 2 360
TransformEnd
Color [1 0 0]
TransformBegin
Rotate 90 0 1 0 
Cylinder 1 0 20 360
Translate 0 0 20 
Cone 2 2 360
TransformEnd
Color [1 1 1]
Sphere 5 -5 5 360
WorldEnd
FrameEnd

Viendo esto podemos pensar que generar escenas de esta forma es m�s costoso ya que tenemos que hacer exactamente lo mismo, definir todas las cosas y posicionarlas en la escena, pero la verdadera potencia de la librer�a estriba en las animaciones. Este ejemplo consta s�lo de un frame as� que a continuaci�n haremos que la pelota se mueva.

 

Movimiento rectil�neo:

En este segundo programa usaremos exactamente la misma escena pero haremos que la pelota se desplace desde la posici�n (30,0,10) a la posici�n (0,20,10) que es m�s o menos desde la derecha de la pantalla hasta la izquierda. Estas dos posiciones las definiremos como RtPoint (lineas 18 y 19). El n�mero de frames o im�genes de las que constar� nuestra animaci�n lo definimos con la variable nf. A partir de este n�mero y de las posiciones inicial y final obtenemos el paso por frame en los tres ejes (slopex, slopey y slopez). Con todo esto, lo �nico que nos falta es variar la posici�n de la pelota en funci�n del n�mero de frame en que nos encontremos. Esto lo hacemos en las lineas 75 a 78, donde un TransformBegin/TransformEnd se encarga de definir la posici�n de la bola. La posici�n la calculamos de una forma muy simple como podemos ver en la l�nea 76.

 1 #include <stdio.h>
 2 #include <math.h>
 3 #include <ri.h>
 4 #include "filename.h"
 5
 6 void main(void)
 7 {
 8  int i;
 9  int x,y,z;
10  int nf;
11  float slopex,slopey,slopez;  
12
13  RtColor Rojo={1,0,0};
14  RtColor Verde={0,1,0};
15  RtColor Azul={0,0,1};
16  RtColor Blanco={1,1,1};
17
18  RtPoint p1={30,0,10}; /* Posicicion inicial de la pelota */
19  RtPoint p2={0,20,10}; /*   Posicion final de la pelota   */
20	
21  RtPoint from={0,100,100}; /*      Direccion de la luz        */
22  RtPoint to={0,0,0};
23
24  char base[]="camara_";
25  char ext[]="tif";
26  char name[50];
27  RtFloat fov=45;
28  RtFloat intensity1=0.1;
29  RtFloat intensity2=1.5;
30  RtInt init=0,end=1;
31	
32  nf=100; /*        Numero de frames         */
33  slopex=(p2[0]-p1[0])/nf;
34  slopey=(p2[1]-p1[1])/nf;
35  slopez=(p2[2]-p1[2])/nf;
36
37  RiBegin(RI_NULL);
38    RiFormat(320,240,1);
39    RiPixelSamples(2,2);	
40    RiShutter(0,1);
41    for (i=1;i <= nf;i++)
42 	{
43 	RiFrameBegin(i);
44	  filename(base,ext,sizeof(base)+4,i-1,name);
45	  RiDisplay(name,"file","rgb",RI_NULL);
46	  name[7]++;
47	  RiProjection("perspective","fov",&fov,RI_NULL);
48	  RiTranslate(0,-5,60);
49	  RiRotate(-120,1,0,0);
50	  RiRotate(25,0,0,1);
51	  RiWorldBegin();
52	    RiLightSource("ambientlight","intensity",&intensity1,RI_NULL);
53	    RiLightSource("distantlight","intensity",&intensity2,"from",from,"to",to,RI_NULL);
54	    RiColor(Azul);
55	    RiTransformBegin();
56	    	RiCylinder(1,0,20,360,RI_NULL);
57	  	RiTranslate(0,0,20);
58	  	RiCone(2,2,360,RI_NULL);
59	    RiTransformEnd();
60	    RiColor(Verde);
61	    RiTransformBegin();
62		RiRotate(-90,1,0,0);
63		RiCylinder(1,0,20,360,RI_NULL);
64		RiTranslate(0,0,20);
65		RiCone(2,2,360,RI_NULL);
66	    RiTransformEnd();
67	    RiColor(Rojo);
68	    RiTransformBegin();
69		RiRotate(90,0,1,0);
70		RiCylinder(1,0,20,360,RI_NULL);
71		RiTranslate(0,0,20);
72		RiCone(2,2,360,RI_NULL);
73	    RiTransformEnd();
74	    RiColor(Blanco);
75	    RiTransformBegin();
76		RiTranslate(p1[0]+slopex*(i-1),p1[1]+slopey*(i-1),p1[2]+slopez*(i-1));
77		RiSphere(5,-5,5,360,RI_NULL);
78	    RiTransformEnd();
79	  RiWorldEnd();
80	RiFrameEnd();
81	}
82  RiEnd();
83 };

Podemos pasar ahora a probar nuestro programa, para ello procederemos de la misma forma que en el programa anterior: lo compilamos y lo ejecutamos redireccion�ndolo, por ejemplo, a rendribv. Podemos de esta forma ver como queda nuestra animaci�n de forma r�pida y a una velocidad aceptable. Para ver el fichero rib que se genera no tienes m�s que redireccionar la salida hacia un fichero. Podr�s comprobar que el fichero es bastante grande (segundo.rib ocupa 70kb) ya que tenemos repetido la definici�n de la escena 100 veces (una por cada frame).

En las siguientes figuras podemos ver una serie de im�genes de la animaci�n:

Por supuesto podemos animar cualquier cosa que se nos ocurra: la posici�n de los objetos, su tama�o, la intensidad de la luz, la c�mara, hacer que aparezcan o desaparezcan cosas, etc.

 

Movimiento parab�lico:

En este �ltimo ejemplo veremos como hacer que la pelota bote. Para ello definimos una funci�n rebote() a la cual le pasamos tres par�metros: el n�mero de frame actual, el n�mero total de frames por rebote y la m�xima altura a la que queremos rebotar. A continuaci�n podemos ver la implementaci�n:

float rebote (int i, int nframes, int max)
{
  float min, z;

  while (i > nframes) i-=nframes;

  min=sqrt(max);

  z=i-((float)nframes/2.0);
  z=(z*min)/((float)nframes/2.0);
  z=(float)max - (z*z);
  return(z);
}

Con unos sencillos c�lculos transformamos la t�pica funci�n de par�bola (y=x^2) para que se ajuste al n�mero de frames y a la altura que deseamos. En las siguientes figuras tenemos un parte de las im�genes que se generan para cada rebote en el programa tercero.c:

Para ver las animaciones hemos creado unos GIF's animados de las escenas aunque van un poco lentos (por lo menos con el Netscape) aunque con xanim funcionan a una velocidad aceptable:

Movimiento rectil�neo: segundo_anim.gif

Movimiento parab�lico: tercero_anim.gif

Con esto acabamos con los aspectos b�sicos del interface de Renderman y su programaci�n. La parte m�s avanzada y tambi�n la m�s espectacular es la programaci�n de shaders. Con esto conseguimos un control total sobre el proceso de rendering y sobre el aspecto final de la escena ya que podemos controlar texturas, iluminaci�n, etc.

 

Referencias


Contactar con el equipo de LinuFocus
© Carlos Calzada Grau
LinuxFocus 1999

1999-07-02, generated by lfparser version 0.6