Renderman III

ArticleCategory: [Artikel Kategorie]

Graphics

AuthorImage:[Bild des Autors]

[foto van de Auteur]

TranslationInfo:[Author and translation history]

original in es Carlos Calzada Grau

es to en Miguel A. Sepulveda

en to nl Guus Snijders

AboutTheAuthor:[Über den Autor]

Afgestudeerd in computer wetenschappen en heb plezier met computer graphics sinds mijn eerste Spectrum. Ik ben erg enthousiast over Linux, de ontwikkelings-filosofie en alles dat niets te maken heeft met micro$oft. Andere niet-scherm gerelateerde hobbies zijn bonsais en aquaria.

Abstract:[Zusammenfassung]

Dit is het derde artikel in een serie over Renderman. (I, II), Deze keer gaan we het hebben over twee belangrijke onderwerpen: de mogelijkheid van het modelleren en animeren van een scene met "C" of "C++".

ArticleIllustration:[Titelbild des Artikels]

[Ilustratie]

ArticleBody:[Der eigentliche Artikel]

Introductie

In de vorige twee artikelen is het duidelijk geworden dat, hoewel het mogelijk is om een scene direct te schrijven door een tekst bestand te typen, het erg omslachtig is. Neem bijvoorbeeld het schrijven van een ".rib" bestand om de beweging van een stuiterende bal te beschrijven! Om het leven gemakkelijker te maken, kunnen we "C" of "C++" applicaties schrijven die de scene modelleren en animeren in gebruiker-gedinieerde functies en vervolgens een ".rib" script naar de standaar uitvoer (stdout) sturen. Met behulp van UNIX pipes kunnen we dan de gegenereerde Renderman commando's direct naar een ander proces (zoals rendrib, rendribv, rgl) sturen of omleiden (redirect) naar een ".rib" bestand.

Onze vorige installatie van Blue Moon Rendering Tools creëerde twee nieuwe directories, lib en include. Deze bevatten vier bestanden, waarvan er op dit moment twee voor ons van belang zijn: ri.h, een header bestand, en libribout.a de library met functies. Het header bestand kun je het beste kopiëren naar /usr/local/include en de libribout.a naar /usr/local/lib (de ervaren lezer zou voor een andere locatie kunnen kiezen). Na de installatie van de library zijn we klaar voor ons eerste voorbeeld programma.

Eenvoudige Scene:

Ons eerste voorbeel demonstreert de basis van Renderman programmering. Zoals in alle C code, moeten we eerst de nodige header bestanden "includen" alvorens de library te gebruiken. In ons geval dus ri.h. Verder moeten we ons programma linken met de library, dat gaat als volgt:

gcc myprogram.c -o myprogram -lribout -lm
      

Hier is een voorbeeld Makefile die je tijd bespaart bij het typen op de console:
LIBS = -lm -lribout
PROGNAME = primero
	 
all: $(PROGNAME)
	
$(PROGNAME).o: $(PROGNAME).c
	gcc -c $(PROGNAME).c
	
$(PROGNAME): $(PROGNAME).o 
	gcc -o $(PROGNAME) $(PROGNAME).o $(LIBS)

 

Ons eerste voorbeeld bouwt enkele assen van coördinaten en een bal in het midden. We noemen het primero.c. Hier is de broncode:
 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 };

De eerste drie regels zijn include bestanden, waaronder de ri.h header van prototypes voor de Renderman library. Iedere Renderman call heeft zijn overeenkomende C-stijl call in ri.h, zo komt TransformBegin overeen met de functie RiTransformBegin(), enz. Creëer de executable primero met make. Ons voorbeeld kan uitgevoerd worden om een input bestand te maken via omleiding (primero > primero.rib) of door de uitvoer direct naar een ander proces te sturen (primero | rendrib). In het laatste geval zorgt rendrib voor het genereren van het gerenderde bestand primero.tif:

De functie calls van de library moeten worden opgenomen tussen RiBegin(RI_NULL) en RiEnd() calls. De parameter die aan RiBegin wordt gegeven is meestal een RI_NULL. Om de uitvoer van de RIB's naar de standaard uitvoer (stdout) te voorkomen, kunnen we een bestandsnaam * ("myfile.rib") of zelfs de naam van proces (zoals rendrib) opgeven voor de uitvoer, de executable zal dan de renderman commando's naar de renderer sturen, zonder tussenopslag in een RIB bestand.

De broncode voor ons eerste voorbeeld heeft typische C instructies plus types en functies specifiek voor de Renderman interface: het type RtColor is een vector van drie echte componenten voor de waarde van rood, groen en blauw (bereik van 0.0 tot 1.0), dan bevat RtPoint een positie in de ruimte en RtFloat en RtInt zijn respectievelijk de echte (real) en integer types.

Regel 29 bevat een aanroep naar RiBegin(RI_NULL), die zoals we eerder een beschreven, een initialisatie call is voor de Renderman interface. Vanaf dit punt volgen de gebruikelijke commando functies die men anders zou invoeren in een typisch RIB bestand. Probeer de code uit te voeren en de uitvoer naar een bestand om te leiden (./primero > primero.rib), de uitvoer zou zijn:
##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

Ons eerste voorbeeld is niet erg bruikbaar. Om een andere scene te genereren moeten we een nieuw programma schrijven dat vergelijkbare operaties uitvoert. De kracht van de library zit echt in het genereren van animaties. In het eerste voorbeeld werd slechts een frame gegenereerd, nu gaan we de bal laten bewegen.

Horizontale Beweging:

In het tweede voorbeeld bestaat onze scene weer uit drie assen op drie coördinaten en een bal, maar deze keer beweegt de bal van de coördinaten (30,0,10) naar (0,20,10), dat is: van rechts naar links op het scherm. Beide locaties worden gedefinieerd met RtPoint structuren (regels 18 en 19). Het aantal frames of afbeeldingen van de animatie is gedefinieerd in de variabele nf. Met dit nummer en de begin- en eindposities kan men de te nemen stap per frame berekenen in de drie richtingen (slopex, slopey en slopex). Dit is alle informatie die nodig is om de positie van de bal te veranderen als een functie van het framenummer. Tussen de regels 75 tot 78 zorgt een set van TransformBegin/TransformEnd voor het definiëren van de locatie van de bal. De nieuwe positie voor iedere stap wordt erg eenvoudig berekend in regel 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 };

Laten we het tweede voorbeeld ook uitproberen: compileer het en start het met de uitvoer omgeleid naar bijvoorbeeld rendribv. Dit is een eenvoudige methode om onze animatie snel te bekijken en op een aanvaardbare snelheid. Om de rib uitvoer te bekijken, kun je de standaard uitvoer (stdout) gewoon naar een bestand omleiden. Zoals je kunt zien, is het gegenereerde bestand vrij groot (segundo.rib is 70 kb), daar dezelfde scene 100 keer gedefinieerd is (een per frame).

Het volgende figuur laat enkele frames uit de animatie zien:

Natuurlijk kunnen we alles animeren wat we willen: de positie van de objecten, hun grootte, de licht-intensiteit, de camera, dingen laten verschijnen en verdwijnen, enz.

Parabolische Beweging:

In het laatste voorbeeld zien we hoe je de bal kunt laten stuiteren op de vloer. Eerst definiëren we de functie rebote() (stuiter), welke drie parameters neemt: het huidige frame, het totale aantal frames per stuiter en de maximale hoogte die de bal bereikt. Hier is de implementatie:

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);
}

Met enkele simpele calculaties kan men de typische parabool-curve (y=x^2) naar het aantal frames mappen en de de gewenste maximale hoogte. De volgende figuren enkele van de afbeeldingen per bounce zien, gegenereerd door het programma tercero.c:

Ik heb een paar geanimeerde GIF bestanden bijgevoegd om de animaties weer te geven, deze lopen echter nogal langzaam (onder Netscape tenminste), xanim zou deze op een acceptabele snelheid moeten weergeven:

Horizontale Beweging: segundo_anim.gif

Parabolische Beweging: tercero_anim.gif

Met dit laatste voorbeeld beëindigen we onze presentatie van de basis van de C interface voor Renderman en het programmeren hiervan. Het gevanceerdste en meest spectaculaire onderwerp, is het hoofdstuk van de shaders. Deze geven een ultieme controle over de uiteindelijke rendering vna de scene daar ze de volledige controle geven over texturen, belichting, enz..

Referenties



Translated by Miguel A Sepulveda