background image

grafika 3d

34

lipiec 2004

Wspaniały świat 

POV-Raya

Krzysztof Garus

T

en artykuł pokazuje, czym jest 
POV-Ray  –  jeden  z  bardziej 
znanych  programów  do  two-
rzenia  grafiki  trójwymiaro-

wej metodą śledzenia promieni (ang. ray 
tracing
).  Jest  to  ciekawa  propozycja  dla 
tych, którzy mają dużo czasu, lubią pracę 
twórczą i mają odrobinę wyobraźni.

Praca  z  POV-Rayem  przypomi-

na  programowanie:  opisujemy  w  spe-
cjalnym  języku  świat,  który  ma 
zostać  pokazany,  a  następnie  odpa-
lamy  program,  który  czyta  zapisany
w  pliku  opis,  wykonuje  ray  tracing 
i  “wypluwa”  grafikę.  Na  samo  hasło 
"specjalny  język"  wiele  osób  krzywi  się. 
Nic  dziwnego  –  wiele  rzeczy  można 
zrobić  szybciej  i  lepiej  w  takich  pro-
gramach,  jak  Blender,  gdzie  widać  na 
bieżąco  to,  co  się  tworzy.  Bawiąc  się
programem POV-Ray (pomijam stosowa-
nie  Kpovmodeller,  o  którym  później), 
używa się wyobraźni i papieru w kratkę.

Podstawy

Cały świat, który widzimy (zwany sceną), 
składa się z takich elementów, jak obiekty, 
światła, kamera (określa, jak i skąd na coś 
patrzymy) oraz efekty atmosferyczne.

Zajmijmy  się  obiektami.  W  wielu 

innych programach są one zbudowane po 
prostu  z  wielu  trójkącików.  POV-Ray  jest 
bardziej wyrafinowany – może korzystać 
z prawdziwych brył geometrycznych.

Obiekt  posiada  przede  wszystkim 

kształt. Aby go stworzyć, mamy do dyspo-
zycji podstawowe bryły (ang. primitives),
takie  jak  kula,  torus,  płaszczyzna  itd. 
oraz  zestaw  operacji  CSG,  które  można 
na  nich  wykonywać.  Te  operacje  to: 
łączenie  (union),  scalenie  (merge),  część 
wspólna (intersection) oraz odejmowanie 
(difference).

Przykładowo, nasz ołówek (Listing 1 

i Rysunek 1) to cylinder, od którego odjęto 
duże  sfery  (każda  sfera  na  jedno  "stru-
gnięcie"). Jeśli chcemy mieć ołówek "kan-
ciaty", odejmujemy od niego kilka płasz-
czyzn.  To  jest  najczęstsze  wykorzysta-
nie  prymitywów  nieograniczonych  typu 
plane (płaszczyzna) czy poly (powierzch-
nia określona wielomianem n-tego stop-
nia). Co ciekawe, te obiekty mają swoje 
"wnętrze",  np: 

plane  {y,  0}

  jest  płasz-

czyzną skierowaną "do góry" i wszystko 
poniżej jest w jej wnętrzu – warto o tym 
pamiętać, gdy robimy część wspólną.

Wygląd

Sam kształt obiektu to za mało. Będzie on 
zrobiony z jakiegoś materiału (material), 
który określa "skórkę" (texture), a jeśli jest 
ona chociaż miejscami przeźroczysta, to 
warto określić wnętrze (interior).

Tekstur może być kilka np.:

texture{T_metal}
texture{T_lakier}
texture{T_kurz}

Ma  to  sens,  o  ile  pigmenty  tych  tek-
stur  mają  przeźroczystości.  W  powyż-
szym  przykładzie  tekstura  T_kurz  jest 
niemal  całkowicie  przeźroczysta  czy 

O autorze

Autor pracuje jako administrator 

na Uniwersytecie Łódzkim. Linuk-

sem zajmuje się od 5 lat, a pro-

gramem POV-Ray jeszcze dłużej. 

Kontakt z autorem: 

autorzy@linux.com.pl.

Na płycie CD/DVD

Na płycie CD/DVD znajdują się 

pakiety źródłowe i binarne POV-

Raya, jak również przykład oma-

wiany w artykule. Aby wygene-

rować ołówki, należy skopiować 

katalog Linux+/Grafika/povray/

olowek na dysk twardy i wykonać 

w nim 

make.

 Bezpośrednio uży-

wając POV-Raya: 

povray +io-

lowek.pov +FN +oolowek.png 

+D +w320 +h240 +Q8 +a0.2 

+am2 +j0.3 +r3

, gdzie 

+i 

- plik 

z opisem sceny, 

+o

 - plik wyj-

ściowy, 

+FN

 - format: PNG, 

+D

 

– pokazuje rendering, 

+w +h

 

- rozmiar rysunku, 

+a +am +j +r

 

- opcje polepszające jakość.

CD/DVD

Po uruchomieniu dystrybu-

cji Linux+ Live CD/DVD można 

korzystać z POV-Raya.

Rysunek 1. 

Przykładowa scenka – ołówki

background image

35

grafika 3d

pov-ray

www.lpmagazine.org

półprzeźroczysta,  a  gdzieniegdzie  jest 
widoczna  jakaś  kropka.  Pod  spodem 
będzie  T_lakier  –  niemal  jednolity,  ale 
miejscami  z  przeźroczystymi  zadra-
paniami.  Spod  niego  wyłania  się  goły 
metal.

Sama  tekstura  ma  kilka  elemen-

tów:  pigment  (kolor+przeźroczystość), 
finish (sposób odbijania światła, lśnienie, 
połysk, odbijanie) oraz normal (symula-
cja nierówności).

Tekstury  nie  muszą  być  jednolite. 

Mogą się (tak jak pigment/normal/finish
zmieniać w przestrzeni z jednej na drugą. 
Do  tego  może  posłużyć  wzór  (pattern). 
Prostym wzorem jest szachownica (chec-
ker
). Dzieli ona przestrzeń na sześciany, 
które mają naprzemiennie raz jedną, raz 
drugą  teksturę  (pigment/normal/finish), 
np.:

texture { checker texture{T_Wood_3A},

S

   texture{Stone12} }

Dużo  ciekawsze  są  wzory,  które  każ-
demu  punktowi  w  przestrzeni  przypo-
rządkowują  liczbę  od  0  do  1.  W  przy-
kładowej  scenie  z  ołówkami  użyłem 
wzoru  cylindrical,  który  punktom  na 
osi  Y  przypisuje  wartość  1.0,  a  dalej, 
w  miarę  oddalania  się  od  tej  osi,  war-
tość  maleje  równomiernie  aż  do  0.0 
w odległości 1 od tej osi. Jeszcze dalej, 
pozostaje 0. Wykorzystałem to do usta-
lenia koloru rysika:

   pigment {
      cylindrical
      color_map {
         [0 Clear]
         [.5 Clear]
         [.5 Black]
         [1 Black]
      }
   }

Clear  to  brak  barwy  –  przeźroczystość. 
Zauważmy,  że  od  przeźroczystego  do 
czarnego  mamy  zerowy  przedział,  więc 
granica  między  nimi  jest  ostra.    Dzięki 
wykorzystaniu  tego  wzoru  ołówek  jest 
w  środku  czarny,  a  dalej  przeźroczysty 
– prześwituje spod niego poprzednia tek-
stura: drewno.

Domyślnie  materiał  to  czarny  pla-

stik z pustym wnętrzem. Na początek nie 
musimy  wszystkiego  określać  –  wystar-
czy  sam  pigment.  Nie  trzeba  też  pisać 
wszystkich szczebli całej struktury:

Listing 1. 

Przykładowa scenka z ołówkami

#

include 

"colors.inc"

#

include 

"textures.inc"

camera 

{

   

location 

<-

4, 6.2, 

-

9

>

   

look_at y

*

2

}

light_source 

{

y

*

400, 

White

}

light_source 

{

<-

1, 4, 

-

2

>*

100, 

White

}

light_source 

{

<

3, 2, 

-

3

>*

100, 

White

}

sky_sphere 

{

   

pigment 

{

      

gradient y

      

color_map 

{

         

[

0 .4  

color Black color Brown

]

         

[.

4    

color Brown

]

         

[.

45   

color Orange

]

         

[.

58 1  

color LightBlue color Blue

]

      

}

      

translate 

-

y/

2

      

scale 

<

1,2,1

>

      

turbulence 

0.03

   

}

}

plane 

{

   

y, 

0

   

pigment 

{

      

bumps

      

color_map 

{

         

[

0  

Brown

]

         

[.

Gray

]

         

[

1  

DarkGreen

]

      

}

   

}

   

finish 

{

diffuse 

0.4

}

}

#declare T_rysik = texture {
   

pigment 

{

      

cylindrical

      

color_map 

{

         

[

Clear

]

         

[.

Clear

]

         

[.

Black

]

         

[

Black

]

      

}

   

}

   

finish 

{

      

reflection 

0.1

      

phong 

0.2

   

}

}

;

#macro T_lakier(kolor)
      

pigment 

{

kolor

}

      

finish 

{

/*specular 0.2*/ 

      

reflection 

0.03

}

#end

#macro olowek(kolor, s)
   #local wys=6;
   

difference 

{

      

cylinder 

{

       

0, 

// punkt 0,0,0 - "dół" ołówka

       

y

*

wys  

// <0,6,0> - "góra ołówka

       

// średnica 

         //(przed obskrobaniem)

      

}

      

// strugamy czubek

      
      #local c=0;
      #while (c<1)
        

sphere 

{

          

y

*

wys,

          

wys

          

rotate x

*

75

          

translate y

*(

wys

+

0.2

*

rand

(

s

))

          

rotate y

*(

c

*

360 

S

            

+ (

rand

(

s

)-

0.5

) * 

20

)

         

}

         #declare c = c+1/6;
      #

end

   

texture 

{

White_Wood scale .

       

translate y

*

rand

(

s

)

}

      

texture 

{

T_rysik

}

   

}

#end

#macro olowek_kanciaty(kolor, s)
   

difference 

{

      

olowek

(

kolor, s

)

      

// obcinamy boczki

      #declare c=0;
      #while (c<1)
         

plane 

{

z, 

-

0.8 

texture 

S

           

{

T_lakier

(

kolor

)

S

            

rotate c

*

y

*

360

}

         #declare c = c+1/6;
      #end
   

}

#end

object 

{

olowek_kanciaty

(

Red, 

S

   seed

(

1

))

 

translate x

*-

2

}

object 

{

olowek_kanciaty

(

Yellow,

S

 

   

seed

(

2

)) 

translate x

*

0

}

object 

{

olowek_kanciaty

(

Green,

S

   

seed

(

3

)) 

translate x

*

2

}

object 

{

olowek_kanciaty

(

Gray, 

S

   

seed

(

4

)) 

translate x

*

4

}

background image

36

grafika 3d

lipiec 2004

sphere {
   0,1
   material {texture {pigment{ color

S

 

Yellow}}}

}

bo można to uprościć do:

sphere {
   0,1
   pigment{ Yellow }
}

Inne elementy

Musimy określić kamerę (camera), czyli 
podać  informację,  z  którego  miejsca 
i w które miejsce (lub w jakim kierun-
ku)  patrzymy.  Podajemy  tu  też  pro-
porcje  ekranu.  Co  ciekawe,  rozmiar 
wynikowego  pliku  graficznego,  który 
przy  kwadratowych  pikselach  defi-
niuje  nam  te  proporcje,  wskazujemy 
w  wywołaniu  programu  opcjami 

+w

 

+h

.
Aby  było  cokolwiek  widać,  potrzeb-

ne  jest  oświetlenie  – 

light_source

  (nie 

licząc  samoświecenia  obiektów,  określa-
nego w 

finish

).

Dyrektywy

Wszystko, co zaczyna się od 

#

 w kodzie 

źródłowym,  jest  dyrektywą  –  odpo-
wiednik 

dyrektywy 

preprocesora 

w  języku  C.  Za  pomocą  dyrekty-
wy 

declare

  możemy  zadeklarować 

sobie  zmienną  rzeczywistą,  wektor, 
obiekt  czy  teksturę,  a  potem  się 
nim  wygodnie  posługiwać,  np.  dekla-
rujemy  pod  nazwą  Pionek  figurę  sza-
chową,  a  potem  używamy  jej  wielo-
krotnie:

object{ Pionek translate jakieś_miejsce }
object{ Pionek translate

S

   jakieś_inne_miejsce }

Powyższy  sposób  jest  dobry  do  obiek-
tów identycznych, ale nie nadaje się, jeśli 
zadeklarowany  obiekt  może  różnić  się 
jakimś  szczegółem,  np.  kolorem  emalii 
w  kredce.  Wtedy  przydaje  się  makro 
– może ono mieć parametry, które przy 
wywołaniu  zostaną  wstawione  w  miej-
sce  swoich  nazw.  Trzeba  na  to  uważać, 
np. mamy makro do obliczania długości 
przeciwprostokątnej:

#macro przeciwp(a,b) sqrt(a*a + b*b) #end

które  przy  wywołaniu 

przeciwp(1,3+4)

 

rozwinie się do 

sqrt(1*1 + 3+4*3+4)

.

Prawidłowo zdefiniowane makro ma 

postać:

#macro przeciwp(a,b) sqrt((a)*(a) + 

S

(b)*(b)) #end

To  makro  rozwija  się  w  wyrażenie 
–  możemy  go  używać  jak  funkcji.  Inne 
makra mogą rozwijać się w obiekty czy 
tekstury, tak jak w przykładzie.

Przy  okazji,  cenna  rada  dotycząca 

deklarowania obiektów: powinien on się 
znajdować  w  środku  układu  współrzęd-
nych,  a  dopiero  potem  w  trakcie  korzy-
stania  z  obiektu  możemy  go  sobie  prze-
sunąć. Przykładowo, mamy lampę wiszą-
cą u sufitu. Nie deklarujmy jej od razu jako 

wiszącej wysoko – niech jej zaczep będzie 
w punkcie <0,0,0>. Dopiero potem można 
ją sobie wygodnie "powiesić":

object {lampa translate y*wys_pokoju}

Co  więcej,  jeśli  chcemy  ją  rozbujać 
(a  obroty  są  zawsze  wokół  początku 
układu współrzędnych), to wystarczy:

object {lampa rotate z*bujniecie 

S

   

translate y*wys_pokoju}

Dyrektywa 

#include

 powoduje włączenie 

w  to  miejsce  innego  pliku  źródłowego 
– dzięki temu możemy sobie dzielić duży 
plik na mniejsze lub tworzyć pliki wyko-
rzystywane  wielokrotnie  (biblioteki). 
Warto  się  zainteresować  standardowy-
mi plikami bibliotecznymi – można tam 
znaleźć dużo gotowych rzeczy do wyko-
rzystania.  Te  pliki  są  dokładnie  opisane 
w dokumentacji.

Listing 2. 

Skrypt tworzący plik Makefile 

dla renderingu równoległego

#!/bin/bash

num=$1
srcfiles='test.pov'
povopts="+itest.pov +oframe.png 

S

+w400 +h300 +kfi1 +kff$num"
anim=

"anim: "

echo all: anim
echo "

POV=povray $povopts"

for n in $(seq -w 1 

$num); 

do

   

anim="$anim frame$n.png

"

   echo -e "frame

$n.png: 

S

   $srcfiles\n\t\$(POV) +sf$n +ef$n\n"

done

echo 

$anim

Rysunek 3. 

Plik POV-Raya w edytorze VIM

Rysunek 2. 

POV-Ray Modeler

background image

37

grafika 3d

pov-ray

www.lpmagazine.org

Animacje

Program  nie  tworzy  plików  Avi/Mpeg, 
natomiast  generuje  sekwencje  obra-
zów.  Ruch  na  tych  obrazach  tworzy  się 
w bardzo prosty sposób: mamy do dys-
pozycji  zmienną 

clock

,  która  dla  każdej 

klatki ma inną wartość: zaczyna (domyśl-
nie)  od  zera,  a  kończy  na  jedynce.  Ma 
znaczenie,  czy  robimy  animację  zwykłą 
czy cykliczną (parametr 

+KC

). Dla 5 klatek 

animacji zwykłej zmienna clock przyjmie 
kolejno wartości: 0 0.25 0.5 0.75 1, a przy 
cyklicznej: 0 0.2 0.4 0.6 0.8.

Zmienną clock można wykorzystać w 

dowolny sposób – jesteśmy tylko ograni-
czeni pomysłowością i znajomością mate-
matyki. Prosty obrót obiektu robimy tak:

rotate y*clock

a przesunięcie z punktu A do punktu B 
tak:

translate A+(B-A)*clock

Zdecydowanie  odradzam  posługiwanie 
się  “gołą”  zmienną  clock  –  wygodniej 
jest tworzyć makra z parametrem "faza", 
który zawsze będzie miał zmieniać się od 
0 do 1, np.:

// 0 - odchylenie w jedną
// 0.5 - odchylenie w drugą

// 1 - to co 1
#macro hustawka(faza)
...
#end

Jeśli  nagle  postanowimy,  że  nasza  huś-
tawka będzie wahać się nie raz, a 3 razy, 
to wystarczy zmienić 

hustawka(clock)

 na 

hustawka(3*clock)

.

Losowość

Powtarzalność  i  regularność  nie  wyglą-
da  zbyt  naturalnie  (jak  słoje  drewna 
w naszych ołówkach), więc warto wpro-
wadzić  odrobinę  chaosu,  np.  samą  tek-
sturę  można  przesunąć  wzdłuż  ołówka 
o pewną wartość – wtedy wygląd będzie 
odmienny.

Dodatkowo, na Rysunku 1 widać, że 

kredki nie są zaostrzone równo, a każde 
"machnięcie  nożem"  jest  w  jakiś  sposób 
losowe.

Do losowania służą dwie funkcje, sto-

sowane w taki sposób:

#declare s = seed(1234);
#declare v1 = rand(s);
#declare v2 = rand(s);
#declare v3 = rand(s);
#declare v4 = rand(s);

Funkcji  seed()  przekazujemy  zarodek 
losowania. Z tego samego zarodka kolej-
ne  wylosowane  wartości  od  v1  do  v4 
(z  przedziału  0.0  -  1.0)  będą  te  same. 
Ta  cecha  jest  przydatna  w  animacjach, 
np. dziury w serze niech będą porozpra-
szane, ale ich układ nie może się zmieniać 
z klatki na klatkę.

Obliczenia równoległe

Pracę  polegającą  na  wyrenderowaniu 
obrazka  czy  całej  animacji  łatwo  jest 
podzielić  na  kawałki  i  liczyć  równole-
gle. Każdą klatkę można wyrenderować 
niezależnie  –  nawet  jedną  scenę  można 
podzielić na kawałki, wyrenderować i na 
końcu je posklejać.

Program  jest  uruchamiany  z  linii 

poleceń (wszelkie ustawienia wpisujemy 
w  parametry),  więc  dosyć  łatwo  można 
to  “uskryptowić”.  Na  komputerze  wielo-
procesorowym lub na klastrze można by 
odpalić  wiele  programów  na  raz,  każdy 
liczący  jedną  klatkę.  Gdy  jeden  z  nich 
skończy  pracę,  to  odpalamy  następny, 
który  liczy  kolejną  klatkę.  Można  sko-
rzystać  z  programu  make  i  jego  opcji 

-j

 mówiącej, ile zadań może uruchomić 

jednocześnie.  Potrzebny  mu  plik  Make-
file
  można  wygenerować  przy  pomocy 
skryptu  mkmake.sh  (Listing  2),  podając 
liczbę klatek animacji:

./mkmake.sh 40 >Makefile

Wtedy,  mając  do  dyspozycji  4  proceso-
ry (np. 2 x Xeon), spokojnie odpalamy 6 
zadań na raz: 

$ make -j6

.

Słowo na koniec

Zamieściłem  tutaj  krótki  przegląd  tego, 
co oferuje POV-Ray. Polecam jego doku-
mentację, która jest ładnie usystematyzo-
wana  i  nie  trzeba  od  razu  wszystkiego 
czytać – można potem w razie potrzeby 
łatwo znaleźć interesujący fragment. 

Ciekawostki

Dla  tych,  którzy  nie  lubią  plików  teksto-
wych, powstał program POV-Ray Mode-
ler (Rysunek 2). Program pokazuje to, co 
się  stworzyło  –  mamy  okienko  z  całym 
"drzewem  sceny":  obiekty  zrobione 
z podobiektów, z nałożonymi teksturami, 
które składają się z prostszych elemen-
tów  itd.  Osobiście  nie  korzystam  z  tego 
typu  narzędzi,  ponieważ  efekty  osiąga 
się  na  ogół  wolniej  (tak,  tak,  przy  odro-
binie  wprawy  sceny  w  POV-Rayu  pisze 
się  całkiem  sprawnie),  nie  ma  skompli-
kowanej elastycznej parametryzacji oraz 
animacji. 

Istnieje  projekt  o  nazwie  Internet

Movie  Project  –  grupa  osób  postanowi-
ła  stworzyć  pełnometrażowy  film  ani-
mowany  używając  do  tego  programu
POV-Raya,  a  animacje  renderować 
w  sposób  rozproszony  w  Internecie  (na 
podobieństwo projektu Seti@Home).

Jeśli  Czytelnik  nabierze  odrobiny 

sprawności  w  posługiwaniu  sie  progra-
mem, a do tego ma trochę talentu i pomy-
słowości, może wziąć udział w konkursie 
dla amatorów na stronie www.irtc.org. Są 
dwie  konkurencje:  na  najlepszą  grafikę 
oraz animację. Prace wykonane w POV-
Rayu pokazują się tam dosyć często.

W Internecie:

•   Oficjalna strona programu POV-Ray:
   http://www.povray.org/ 
•   Grupy dyskusyjne na temat POV-

Raya (w tym international, na której 
można pisać po polsku):

   http://news.povray.org/groups/
•   Konkurs grafiki 3D dla amatorów:
   http://www.irtc.org/

Rysunek 4. 

Strona projektu Internet Movie 

Project

Rysunek 5. 

Strona główna programu