Home Creatief met POVRay Nog meer installatie-gedoe Het uiterlijk der dingen
 

Hoofdzaken

Nadat ik in maar liefst twee lange artikelen heb moeten uitweiden over het op gang krijgen van PovRay, wordt het nu tijd om de cursus echt te beginnen. We gaan het over de belangrijkste ditjes, datjes en weetjes hebben voor het maken van afbeeldingen.

Niet getreuzeld: ik begin gelijk.

Ik kan aannemen dat jullie allemaal wel de tekst hebben bekeken (in een .pov file) van een demonstratieplaatje van PovRay. Je hebt gezien dat er nogal veel getallen gebruikt worden. Dat kan nu helaas niet anders: we moeten de plaats van voorwerpen nu eenmaal in een coördinatenstelsel zetten. We hebben rechts en links, boven en beneden, naar voren en naar achter. De drie assen: de x-as, de y-as en de z-as. Zoals we gewend zijn van school (denk er maar eens aan terug) is de positieve richting van de x-as naar rechts toe, die van de y-as naar boven toe en die van de z-as van ons af.

Maar nu de eenheden. We zijn vrij in onze schaling: als je je voorstelt om een stilleven van asbak en vaasje te maken dan werk je het beste als je een schaal van centimeters in je hoofd gebruikt. Werk je aan een scene die gebouwen bevat, dan kan je het beste in meters denken. Wat betreft nauwkeurigheid hoef je geen zorgen te hebben: intern worden posities in 16 bitjes berekend dus van ongeveer -32.000 tot +32.000.

Een andere zaak die we ook even onder ogen moeten nemen is: draairichtingen. Objecten kan je op diverse manieren van plaats laten veranderen: rotatie is zo'n manier. Hoe geef je nu de richting op? Neem je linker hand en pak (virtueel) de x-as beet. Je duim wijst dan in de positieve richting. Je vingers volgen nu de positieve draairichting. Deze truc kan je met alle drie de assen uithalen. We noemen dit het 'linkerhand coördinatensysteem'. Stel je dit eventjes goed voor want anders blijf je later stuntelen. We geven een voorbeeld: we nemen een kant en klaar object uit de verzameling: een doos. Die heeft drie maten: lengte, breedte en diepte. We schrijven dan:

 box {
      < -1, 0, -1>
      < 1, 0.5, 3>
     }

We geven dan op: de linker benedenhoek (1 eenheid naar links op de x-as, niets naar omhoog en 1 eenheid naar achteren) gevolgd door de rechter bovenhoek (1 eenheid rechts van de nulpositie, 1/2 omhoog en 3 naar achteren). Dat is voldoende. Let op een bijzonderheid: het eerst gedefineerde punt heeft de minimum waarden en het tweede de maximale. Het is wat lastig om de termen 'kleiner' en 'groter' te gebruiken in dit verband. Je ziet ook dat de doos parallel aan de assen ligt. Dat kan je later veranderen.

Verder zie je dat de getallen met behulp van < en > samengenomen worden. 3D-posities geef je zo op. Natuurlijk is het afhankelijk van het soort object wat voor zaken (parameters) je moet opgeven.

Een bol is simpel:

 sphere {
         <0, 1, 2> , 2
        }

Je geeft op wiskundige wijze de plaats door het middelpunt op te geven en vervolgens de straal.

De taal

Het zal je wel zijn opgevallen dat de scene-file vol zit met {{}} krulhaken net zoals de taal C. Helaas is het niet fraai en het is ook lastig want een haakje teveel of te weinig brengt de vertaalmachine van PovRay goed van slag af. Vaak gaat dat dan gepaard met een onzinnige foutmelding waarna PovRay er de brui aan geeft. Waar zit het foutje? Lastig naspeurwerk is nodig. Gelukkig hebben meer mensen dit ervaren, vandaar dat er teksteditors zijn die een optie hebben: 'matching quotes'. Controle vindt plaats of elke { ook een corresponderende } bij zich heeft verderop in de tekst (simpel gezegd: haakjes tellen en zien of ervan allebei de soorten ook evenveel zijn). Sommige teksteditors kan je zo instellen dat ze na het intypen van een { direct een nieuwe tekstregel maken met het sluithaakje } juist geïndenteerd (naar rechts ingesprongen) eral in. Het zal ook iedereen wel opgevallen zijn dat getallen vaak in groepjes van drie voorkomen. Dat heeft twee oorzaken: we werken in drie dimensies en (toevallig) ook met drie basiskleuren.

Verplaatsingen

We hebben al in het voorbeeld met de doos gezien dat we niet direct de doos op de gewenste plaats kunnen zetten. Dat geldt voor meer voorwerpen als je ze aanmaakt. (Meestal is het, als je het voor het uitkiezen hebt, het handigste om het nulpunt als uitgang te nemen. Zet de linker onderhoek b.v. op positie <0,0,0> in dit geval.) Vandaar dat er diverse manieren zijn om zaken te verschuiven naar hun gewenste positie. De eenvoudigste manier om voor te stellen is de translatie: het ding wordt in de ruimte een aantal eenheden verschoven. B.v.

sphere{<10,10,10>,1
       translate <-5, 2, 1>
      }

Vanaf positie <10,10,10> komt het middelpunt terecht op <5,12,11> dus niet op <5,2,1> zoals je in eerste instantie zou kunnen denken. Verschuiving is altijd relatief t.o.v de laatste positie.

Translatie is dus: posities optellen!

We kunnen dingen ook vergroten en verkleinen. We moeten dan opgeven: scale <x,y,z>. Je ziet, in elke richting kunnen we iets anders opgeven. Op die manier kan je voorwerpen uitrekken of inkrimpen in elke gewenste richting. Getallen groter dan 1.0 geven rek, kleiner dan 1.0 geven krimp. In geval van ons voorbeeld van de doos is het niet zo zinnig om de maat te veranderen op deze manier, maar een bol kan je met 'scale' echt een andere vorm geven!

Om een voorwerp op zijn plaats te krijgen is een rotatie vaak noodzakelijk. Geef dit op als b.v .

rotate <0,30,0>

om 30 graden om de y-as te draaien in positieve richting. Je weet toch nog wel welke dat is nietwaar? Terugdraaien om de x-as doe je met

rotate <-20,0,0>

De camera

Wat je ook maakt, de camera moet er een afbeelding van maken. Zeg je niets dan is er een 'default' maar die kan volkomen verkeerd staan. 'Beschrijf dus altijd waar de camera staat', is mijn advies. Bij de versie van PovRay die wij gebruiken is de camera een heel simpele 'camera obscura': er is geen lens maar een klein gaatje waar het licht door valt. Dus geen problemen met scherptediepte, diafragma enz. Ook hoef je je geen zorgen te maken over belichtingstijden, de camera is als het ware een vol-automaat.

camera {
        location < 1, 2, -3 >
        direction < 0, 0, 2 >
        up < 0, 1, 0 >
        right < 1.33, 0, 0 >
        look_at < 0, 1, 2 >
       }

De camera bevindt zich nu 1 eenheid naar rechts, twee omhoog en 3 naar achteren. Er wordt gekeken in de richting van een punt dat boven de y-as ligt, een meter omhoog en twee naar voren. Het look_at punt is het punt waar de aandacht hoofdzakelijk moet liggen als je de afbeelding bekijkt. Een wat vreemde naam is 'direction' die niet betekend wat je zou denken. Je geeft een lijnstuk op (een vector noemen wiskundigen dat) en als die kort is, dan heb je een camera met een wijde zichthoek en maak je hem langer, dan krijg je een telelens effect.

De camera heeft ook een 'aspect ratio', de verhouding tussen horizontale en verticale grootte van het beeld. Gewoonlijk gebruiken we wat van de TV bekend is: 4 op 3. Ook onze monitoren hebben kunnen met deze beeldverhouding een redelijk groot beeld op het scherm zetten. Er is niets op tegen om modern te zijn (of wat daarvoor doorgaat) en een TV-breedbeeld format verhouding te gebruiken. Maar voor geschapen landschappen kan een 'panoramisch' beeld heel mooi zijn.

We doen het met de 'up' en de 'right'. In het bovenstaande voorbeeld opgegeven waarden maken een 4:3 beeldverhouding.

Hoe de beeldverhoudingen uiteindelijk uitpakken ligt ook aan wat je opgeeft in de commandline van PovRay of in de (zie de vorige aflevering van deze cursus) .def file. Met 800 x 600 pixels (+W800 +H600) blijft de 4:3 verhouding behouden. Doe je het anders, dan krijg je vreemd 'uitgerekte' beelden en dat is niet de bedoeling.

Lichtbronnen

In het donker zijn alle katjes zwart. Zo is het in PovRay-scenes ook. Zonder licht zie je geen barst. Wat je dus moet doen is wat lichtbronnen maken. De simpelste is:

light_source { <2, 4, -3>
              color White
             }

twee eenheden naar rechts, 4 omhoog en 3 naar achteren hangt een lichtbron. Dit is eigenlijk een oneindig klein punt dat zelf onzichtbaar is en vanwaaruit in alle richtingen lichtstralen gaan. Het gevolg is dat schaduwen scherpe randen hebben. De kleur van het licht heb je volledig in de hand, je kan wat dimmen door grijstinten te gebruiken of 'donkere kleuren'. Er is niets op tegen om meerdere lichtpunten te plaatsen maar de rekentijd neemt wel toe.

Een puntvormige lichtbron is eigenlijk onnatuurlijk. Vooral de eigenschap dat de hoeveelheid licht die ergens op valt onafhankelijk is van de afstand tot de bron maakt belichting onwezelijk. Vandaar dat er iets beters is en wel een echte schijnwerper:

light_source { <x, y, z>
               color red #, green #, blue #
               spotlight
               point_at <xa, ya, za>
               radius #
               falloff #
               tightness #
              }

Je ziet dat er nogal wat bij komt kijken. De x,y,z geeft aan waar de schijnwerper staat, de xa,ya,za het punt waar de schijnwerper op gericht is (dat lijkt dus wat op look_at bij de camera). De kegel van licht kan je opvatten als bestaande uit twee verschillende kegels. Hoe wijd de centrale kegel zijn lichtbundel werpt wordt met een hoek opgegeven, de 'radius' parameter dient hiervoor. Om de kegel heen zit een ruimere tweede kegel die van binnen naar buiten gaand steeds minder licht werpt. De samenwerking van beide maakt dat het veel lijkt kwa lichteffect op een echte schijnwerper, zolang je tenminste de stralingshoek opgegeven met 'falloff' wat groter maakt dan die van radius. Met 'tightness' geef je aan hoe snel het licht vanaf radius tot niets verloopt als je 'falloff' waarde nadert. Een lage waarde geeft een zachter verloop, een hoge waarde maakt de bundel scherper aan de randen. Om te ontkomen aan het effect van te scherpe schaduwen kan je een lichtbron maken in de vorm van een lichtuitstralende rechthoek: een 'area_light'. Ik kom er later op terug want het gebruik is niet simpel en het vreet erg veel rekentijd. Wil je een puntvormige lichtbron toch zichtbaar maken, dan moet je een looks_like opgeven. Is de lichtbron volledig uit zicht, dan is er geen probleem maar komt de lichtbron in beeld (hij is zelf onzichtbaar), dan zijn schaduwen soms heel 'raar'. Aan de hand van geworpen schaduwen verwacht je een lichtbron maar die 'is er niet'. Vandaar dat je het lichtpunt kan omgeven met een vorm die licht doorlaat. Zo maak je dus lampje met een lampekap eromheen. Ik kom hier ook later op terug.

Include files

Ik heb het gehad over 'color White'. Grijstinten e.d. en een heleboel kleuren zijn al voor je bedacht. Die kan je gebruiken als je aan het begin van de file zet:

#include "colors.inc"

Bekijk de tekst van die file maar eens; er is heel veel beschikbaar. Ook zijn er oppervlaktestructuren (textures) kant en klaar beschikbaar zoals 'sinasappelhuidje' als je

#include "textures.inc"

opgeeft en met

#include "shapes.inc"

krijg je ook nog heel wat handige vormen ter beschikking. Welke kan je zelf in de file nalezen.

Voorwerpen

In het Engels spreken we over 'objects'. We kunnen ze op diverse manieren typeren. Om te beginnen hebben we de simpele eindige massieve vormen (solid finite primitives) in 7 soorten:

sphere { <middelpunt>, straal}

Daar heb ik het in het voorafgaande al over gehad evenals over de

  • box { <hoekpunt1>,<hoekpunt2>}
     
  • cylinder { <end1>,<end2>,radius }
     

spreekt ook voor zich. Ik zei al dat dit een massief voorwerp is. Er zijn dus platte vlakken die de einden afsluiten. Voor de duidelijkheid: die vlakken staan automatisch loodrecht op de asrichting van de cylinder. Aangezien er af en toe ook vraag is naar holle cylinders, kan je door toevoeging van het woordje "open" na de radius (straal) die afsluitingen verwijderen. Je kan dan in de buis naar binnen kijken.

cone { <end1>, radius 1, <end2>, radius2 }

geeft een kegel die op positie end1 begint en eindigt op end2. De maat waarmee de kegel begint is radius1 en als zij eindigt is de afmeting radius2. Zijn beide radiussen (radiï, radia?) gelijk, dan degradeert de boel tot een cylinder.

torus { groot, klein }

De vorm is wat lastig te beschrijven maar een opgepompte binnenband lijkt er veel op. Er zijn maar twee getallen nodig: de straal van het wiel en de straal van de binnenband zelf. Het centrum ligt in het nulpunt en de as recht door het middelpunt heen isde Y-as. De binnenband ligt dus in het x-z vlak. Met schuiven, draaien en scaling kan je de torus op de gewenste manier in de scene plaatsen. Een handige vorm die wat lastig te beschrijven is (ik zal het later in de cursus met wat meer details behandelen) is de 'blob'. Je manipuleert als het ware flexibele bolvormen. Ze trekken aan elkaar of ze duwen met als gevolg dat hun oppervlak in- dan wel uitstulpt.

Als laatste vorm die 'massief' is moeten we de hoogtevelden noemen. Deze 'height fields' zijn wat lastig te maken, zodat ze apart besproken dienen te worden. Er zijn wat gereedschappen extra nodig waarvan het gebruik ook enige toelichting zeker kan gebruiken. Wil je in een landschap hoogteverschillen hebben (bergen b.v.) dan gebruik je 'height fields'. Om bergen en dalen te krijgen moet een kleurentekening gemaakt worden alsof het een tweedimensionale landkaart betreft waarin de kleur de hoogte aangeeft. Iedereen zal wel eens een afbeelding van een 'fractaal' landschap hebben gezien. Programma's die fractals maken kunnen die vaak in kleur opbergen. Op die manier kan je ook heel 'echt' lijkende landschappen maken.

Speciale basisvormen

Natuurlijk kan je met de boven beschreven objecten wel dingen maken maar het blijft beperkt. Vandaar dat er voorzieningen zijn om eigen vormen te creëren. Iemand heeft jaren geleden een theepot opgemeten en zijn meetresultaten zijn te vinden in de folder met voorbeelden onder de naam teapot.pov. Het oppervlak is beschreven met behulp van een groot aantal

triangle { <hoekpunt1>, <hoekp2>, <hoekp3> }

uitdrukkingen. Dit zijn gewone platte driehoekjes. En net zoals je veel pixels op je scherm moet hebben wil een afbeelding een beetje uit de verf komen, zo moeten voorwerpen ook opgebouwd zijn uit erg veel kleine driehoekjes. We moeten dan ook een beetje aan vormvervaging gaan doen om de oppervlakten glad te doen lijken. De meest gebruikte manier is om de driehoekjes om te zetten tot

smooth_triangle { <h1>, n1, <h2>, n2, <h3>, n3 }

Er komen dus drie getallen bij de zgn. 'normals'. Je kan die opvatten als lijntjes loodrecht op het 'gemiddelde' oppervlak op de hoekpunt waar driehoeken bijeenkomen. Het werken met driehoeken is zo arbeidsintensief, dat er speciale gereedschappen zijn om ermee om te gaan. Daarom later meer hierover.

Een andere mogelijkheid is het gebruik van de bicubic_patch. Dit is het driedimensionale equivalent van de Bezier-curve. Speciale software gebruikt de hoekpunten van de driehoekjes om een vloeiend oppervlak te maken. Heel soms heb je behoefte aan iets dat kwa vorm lijkt op een CD. Om zo'n vlak te krijgen (zonder dikte, want anders kan je 'cylinder' gebruiken) zeg je

disc { <centrum>, <normal>, radius, hole_radius }

Ik meld dit voor de volledigheid. Misschien kunnen we deze disk later ergens voor gebruiken.

Grenzeloze vlakken

Er zijn een aantal erg wiskundige dingen die als 'polynomal shapes' bekend staan. De eerste is het vlak dat voldoet aan een lineaire vergelijking, de tweede is een gebogen vlak gebaseerd op een tweedegraads vergelijking. Hierbij kunnen we denken aan cirkels, ellipsen, parabolen, hyperbolen en meer van dat spul.

We kunnen nog een graadje hoger gaan in de vergelijkingen en dan komen we uit op vlakken die beschreven worden door polynomen. Ik ben niet zo thuis in deze dingen. Maar gelukkig hebben mensen veel zaken al eerder gemaakt. Kijk maar eens in de files 'shapes.inc' wat een schat aan vormen daar te vinden is.

Gaan met CSG!

Met alleen maar geometrische vormen kan je in de praktijk weinig beginnen. Vandaar dat er een methode is bedacht om 'massive' voorwerpen met elkaar te combineren: Constructive Solid Geometric. Laat ik als voorbeeld de volgende situatie nemen: ik heb een doos en daarop plaats ik een bol met zijn middelpunt in het centrum van het bovenvlak. Nu kan ik 'logisch' bewerkingen doen met de ruimte die 'van beide is'. Zo kan de bol onzichtbaar blijven en toch een ronde kuil in het bovenvlak van de doos maken. Of, logisch omgekeerd, alleen het deel dat beide gemeenzaam hebben 'wordt gebruikt'. We hebben dan een hangende halve bol. Ook kan je de buiten de doos uitstekende halve bol verlijmen met de doos tot 1 geheel. Denk er even over na en je zal zien dat je met deze werkwijze hapjes uit vormen kan nemen of uitstulpingen eraan kan plakken. Met behulp van de uitdrukking

union { vormbeschrijving1, vormbeschrijving2...}

kan je de boel samennemen en er alles mee doen wat je ook met de basisvormen kan doen. Ik zal later wat voorbeelden geven hoe je slim die toch best wel complexe vormen kunt bouwen.

Achtergrond

Over het algemeen zal je niet willen dat je achtergrond volledig zwart is. Een andere kleur is b.v. mogelijk met

background { color SkyBlue }

Maar het effect is wat gekunsteld. Beter is het om te werken met een echte hemelbol. Maar dat is een hoofdstuk apart.

Bodem

Vaak wil je ook een soort oppervlak hebben waar dingen op staan. Het kan een gewone bodem zijn of een watervlak, een tegelvloer enz. We hebben daar iets handigs voor:

plane { <0, 1, 0>, 2
       pigment {
        checker
         color Red color Blue
       }
}

geeft een oneindig groot vlak en ga ik een lijn rechtop op het vlak zetten (wiskundig heet dat de normaallijn), dan wijst die naar 0,1,0 en met een opgegeven verplaatsing van 2 ligt dat vlak dus evenwijdig aan het vlak van de x-as en de z-as en 2 eenheden daarboven. Verder in dit voorbeeld hebben we niet veel aandacht aan de oppervlaktestructuur gegeven. We hebben een schaakbordpatroon in twee kleuren. Er is niets op tegen om een texture {...} op te geven. De 'vloer' kan zich dus net zo voordoen met zijn oppervlak als objecten dat kunnen. Weerspiegelingen en dergelijke zijn mogelijk.

Textures

In principe zie je in een PovRay afbeelding de belichte oppervlakken van voorwerpen. Er zit dus heel wat in de grabbelton om van alles met oppervlaktestructuren en kleuren te doen. Kijk maar eens om je heen hoeveel verschil er is! De oppervlakte van een voorwerp beschrijven we b.v. met:

sphere { <0, 1,2>, 2
       texture {
                ...hier kan
                van alles staan..
               {
       }

Het eerste wat we opgeven is de kleur. Eigenlijk moet ik wat zorgvuldiger zijn in mijn taalgebruik: een pigment ofwel en 'verfje' bedoel ik.

Er is een file geheten colors.inc met veel kleurtjes. Zo maak je b.v.

pigment { color DarkTan }

Moet het geheel glimmend worden, dan voeg je toe:

finish { Shiny }

Kijk maar eens in textures.inc wat er allemaal is. Meestal zal het door jouw gewenste oppervlak in deze file vinden zijn of iets dat in de buurt daarvan komt en dat je zelf met wat experimenteren kan bijvijlen.

Een belangrijke eigenschap van een oppervlak is zijn ruwheid. Zo is er een heel groot verschil tussen een sinasappel met zijn kleine bobbeltjes en een perzik met zijn haartjes. Ook deze zijn ruim in voorraad. Iets anders zijn patronen op het oppervlak: marmer, hout e.d. Dat wordt heel wat ingewikkelder om te beschrijven maar ook hier weer: in textures.inc kan je zeker 7 verschillende houtsoorten vinden die allemaal kwa nervenstructuur van elkaar verschillen.

Afbeeldingen

Deze keer zijn er bij dit artikel geen afbeeldingen. Het zou wel gekund hebben, maar ik moet bij deze cursusaflevering wat woekeren met de ruimte. Zoveel bladzijden als ik de vorige keer in dit blad heb mogen vullen, krijg ik deze keer niet van de redactie. De volgende keer gaan we aan de hand van een voorbeeld de vele mogelijkheden van PovRay stap voor stap heel precies uitproberen. Ik zal het larderen met tips, trucs en verhelderende uitleg. Enige basiskennis die onontbeerlijk is om het vervolg te kunnen snappen hebt u met deze aflevering tot u genomen.

Tot de volgende keer.

Piet Vogelaar


Copyright © Rein Bakhuizen van den Brink
Last updated on 1 september 1999
Home Creatief met POVRay Nog meer installatie-gedoe Het uiterlijk der dingen