Všechny dosud uvedené metody fungovaly za dosti přísných omezujících podmínek. Tělesa byla osvětlena pouze jedním zdrojem, zobrazovali jsme nanejvýše dvě tělesa, která se navzájem neovlivňovala buď vůbec, nebo se ovlivňovala velmi málo - např. stín vržený na podložku, průhledná plocha či těleso nad vodorovnou rovinou. Často je však třeba zobrazovat více těles z různých materiálů osvětlených několika světelnými zdroji s různými vlastnostmi, což má za následek vznik nejrůznějších optických jevů. K postižení těchto jevů je třeba použít metody, které neřeší jen jeden optický jev (tedy např. jen zastínění tělesa či lom na rozhraní dvou prostředí), ale metody, které se snaží postihnout co nejvíce vzájemných optických vztahů mezi jednotlivými předměty, které se ve zobrazovaném prostoru - scéně nacházejí. Tyto metody se nazývají globální zobrazovací metody.
Globální zobrazovací metody jsou většinou náročné z hlediska počtu potřebných operací. Proto se při nich ve speciálních případech používají také speciální metody, které jsou rychlejší než metody obecné. Velmi často je třeba vyhodnotit chvání světla na povrchu koule. V následujících kapitolách se tedy budeme zabývat odrazem a lomem světla na tomto povrchu, v této kapitole si všimneme efektivních metod používaných speciálně na texturování kulové plochy.
Víme již, že aplikaci textury na
povrch tělesa provedeme definováním tzv. mapovací funkce , která každému bodu z definičního oboru textury přiřadí
bod
na povrchu
tělesa. Barva tohoto
bodu je pak definována hodnotou textury
. Při programové realizaci většinou postupujeme obráceně: pro
daný bod plochy hledáme na textuře jeho barvu, tj. používáme funkci
, která je inverzní k původnímu mapování
. V každém případě jsme dosud dle parametrizace plochy
procházeli všechny její body (v programové realizaci segmenty), každému jsme
přiřadili barvu a každý pak promítli na výstupní zařízení. Tento postup
nanášení textury múžeme označit jako segmentové texturování. Při něm musíme projít
všechny segmenty plochy, mamapovat je a sestrojit, i když mnohé z nich pak
budou překresleny. Nyní budeme postupovat obráceně: budeme procházíme všechny
pixely na výstupním zařízení a každým z nich vyšleme zpětný promítací
paprsek. Protne-li zobrazovanou plochu, obarvíme pixel barvou, která přísluší
nejbližšímu průsečíku, jinak použijeme barvu pozadí. Hlavní výhodou tohoto
postupu je skutečnost, že každý sestrojovaný pixel bude sestrojen „definitivně“
a nebude již překreslován. „Zbytečné kroky“ tak odpadají a konstrukce je
podstatně rychlejší. Docílíme toho následujícím způsobem:
a)
Každému pixelu výstupního zařízení
přiřadíme bod
použité průmětny.
b) Tímto bodem vyšleme zpětný promítací paprsek směrem k zobrazované ploše.
c)
Hledáme jeho průsečíky se zobrazovanou plochou. Jestliže
průsečík neexistuje, testovaný pixel není průmětem žádného bodu a nebude
sestrojen. Jestliže průsečík existuje, pak ho inverzně mapujeme funkcí na texturu a obarvíme
příslušnou barvou (a event. vystínujeme v závislosti na úhlu normály a směru
dopadajícího světla tak, jak bylo rovněž popsáno). Pokud těchto průsečíků
existuje více, mapujeme pouze bod, který je nejblíže pozorovateli.
ad a) Především musíme danému
pixelu (tedy bodu ve světové
souřadné soustavě
) přiřadit uživatelské souřadnice. Jak jsme se zmínili již v
kpt. 7.3., přepočet souřadnic světových na uživatelské provádějí funkce InvXCoor, InvYCoor
- funkce inverzní k XCoor, YCoor. Tím obdržíme průmět
v uživatelské soustavě
s osami
. Když jsme se začali zabývat prostorovou grafikou,
konstatovali jsme, že je-li v prostoru definována souřadná soustava
s osami
a v průmětně
uživatelská souřadná
soustava
je zobrazení prostoru
na rovinu dáno rovnicemi
kde jsou souřadnice
libovolného bodu (tedy například i bod průmětny
) v soustavě
a
jsou souřadnice jeho
průmětu
v soustavě
.
Nyní ovšem známe průmět v uživatelské soustavě
a potřebujeme určit
souřadnice
odpovídajícího bodu
v soustavě
. Použijeme-li stejnou průmětnu
jako v kpt.Mp6.1., tj.
průmětnu o rovnici
, kde
je vektor definující
směr pohledu do soustavy
, dostáváme pro neznámé souřadnice
bodu
soustavu lineárních
rovnic
Vzhledem k tomu, že celý postup budeme programovat, je výhodné řešit tuto soustavu Crammerovým pravidlem. Je tedy třeba spočítat determinanty
;
;
;
; (1)
a potom je ;
;
.
ad b) Takto získaným bodem vyšleme zpětný
promítací paprsek
směrem ke zpracovávané
ploše. Použijeme-li kolmou axonometrii, jsou všechny tyto paprsky kolmé na
průmětnu. Jejich směrovým vektorem je tudíž vektor
a parametrické rovnice
jsou
(2)
ad c) Dostáváme se k hlavní
potíži tohoto postupu. Ta spočívá v tom, že hledání průsečíku promítacího
paprsku s plochou vede na řešení nelineárních rovnic, které jsou obecně
řešitelné jen numericky, což je nejen značně komplikované, ale především
pomalé. U některých speciálních ploch je však řešení relativně snadné
(například u kvadrik řešíme jen kvadratickou rovnici). Pro kulovou plochu o
rovnici kupříkladu dostáváme
po dosazení výše uvedených parametrických rovnic pro hledaný parametr
kvadratickou rovnici
.
jednoduché úpravě a vzhledem k
tomu, že :
Pro hodnotu parametru tak dostáváme
(3)
přičemž u odmocniny v tomto
případě uvažujeme pouze znaménko plus. Tím jsme získali hodnotu parametru , pro kterou soustava (2) určuje souřadnice průsečíku
promítacího paprsku s mapovanou kulovou plochou. Pro inverzní mapování
potřebujeme zjistit odpovídající hodnoty parametrů z parametrického vyjádření
kulové plochy. Máme tedy
(4)
a to pro
;
;
(5)
Z poslední rovnice výše uvedené
soustavy (4) tak dostáváme pro :
(6)
Vydělíme-li druhou rovnici soustavy
(4) rovnicí první, dostáváme pro :
(7)
K řešení rovnic (6), (7)
potřebujeme invertovat funkce sinus a tangens. To lze, jak známo, provést pouze
na intervalech, na kterých jsou tyto funkce prosté. Rovnici (6) můžeme proto
řešit pro . To je v souladu s podmínkou (5), máme tedy
(8)
Funkce tangens je však prostá na
intervalech délky p,
přičemž funkce arctg implementovaná v programovacích jazycích vrací hodnoty , tj pro
. Abychom splnili podmínku (5), je třeba rovnici (7) řešit i
na intervalu
, tj pro
. Pomocí rovnice (6) máme pro
:
a dosazením do první rovnice
soustavy (4):
tj.
Jmenovatel tohoto výrazu nemůže být záporný, o jeho znaménku tedy rozhoduje znaménko čitatele. To spolu s výše uvedeným znamená, že řešení rovnice (7) je tvaru
(9)
1.
Příklad - Zeměkoule rotující v reálném čase. Úlohu zpracujeme pomocí
rastrového texturování kulové plochy v rovnoběžném promítání, přičemž volíme ,
. Nejdříve nadeklarujeme potřebné proměnné. Všechny potřebné
hodnoty (stíny, normály i mapování) bychom samozřejmě mohli počítat bod po bodu
během konstrukce. To by však běh programu značně zdržovalo. Proto je dobré
všechny hodnoty napočítat pokud možno před vlastní konstrukcí a uložit je do
příslušných polí:
type TInvertMap = record x,y :Integer;end;
var Det,Dx1,Dx2,Dx3:Double; {determinanty dle(1)}
OceanShade,
ContShade:Array
[0..600,0..600] of single;
{paměť
pro hodnoty vlastního stínu - zvlášť pro moře a pevninu}
Normala: Array [0..600,0..600] of
TVector;
{paměť
pro normály v jednotlivých bodech kulové plochy}
InvertMap:Array
[0..600,0..600] of TInvertMap;
{paměť pro hodnoty inverzního
mapování}
Stop: Boolean; {zarážka pro ukončení programu}
Dále sestavíme proceduru, která
počítá hodnotu parametru a tím zároveň normálu
kulové plochy ve vypočteném průsečíku - její souřadnice jsou dány pravými
stranami rovnic (3). Tato normála bude potřeba pro výpočet zastínění daného
bodu:
Procedure NormCalcul(i,j:Integer);
var Xc
:T2DPoint;
XPoint :T3DPoint;
Pom,Dx1,Dx2,Dx3,Diskr:Double;
begin
With
Draw3D do
begin {řádky označené r<číslo řádku> budou
použity i v kpt. při sledování paprsku}
Xc[1]:=InvXCoor(i);Xc[2]:=InvYCoor(j);
{SP - uživatelské souřadnice pixelu r1}
{nastavení determinantů podle (1), determinant D (Det) je
nastaven pro všechny body stejně}
Dx1:=k2-MajorRay[2]*k2*Xc[1]-MajorRay[3]*Xc[2];
{SP - nastav determinant D1 r2}
Dx2:=Xc[1]*k2*MajorRay[1]-MajorRay[3]*i2*Xc[1];
{SP - nastav determinant D2 r3}
Dx3:=Xc[2]*MajorRay[1]+Xc[1]*i2*MajorRay[2]-i2;
{SP - nastav determinant D3 r4}
XPoint[1]:=Dx1/Det; {r5}
XPoint[2]:=Dx2/Det; {r6}
XPoint[3]:=Dx3/Det; {souřadnice v prostorové souřadné
soustavě r7}
Pom:=XPoint[1]*MajorRay[1]+XPoint[2]*MajorRay[2]+XPoint[3]*MajorRay[3]; {r8}
Diskr:=Pom*Pom-XPoint[1]*XPoint[1]-XPoint[2]*XPoint[2]-XPoint[3]*XPoint[3]+1; {r9}
if
Diskr>0 then begin {průsečík nalezen r10}
t:=-Pom+sqrt(Diskr); {r11}
Normala[i,j,1]:=XPoint[1]+t*MajorRay[1]; {r12}
Normala[i,j,2]:=XPoint[2]+t*MajorRay[2]; {r13}
Normala[i,j,3]:=XPoint[3]+t*MajorRay[3]; {r14}
end
else begin {průsečík nenalezen r15}
Normala[i,j,1]:=0; Normala[i,j,2]:=0;Normala[i,j,3]:=0; {r16}
end;
end;
end;
Následuje výpočet zastínění:
Procedure Shading(i,j:Integer);
var Cosinus:Double;
begin
With Draw3D do
begin {jestliže byla pro daný bod předchozí procedurou nastavena nenulová normála,}
if Norm(Normala[i,j])>0
{nacházíme se uvnitř průmětu Zeměkoule a stínujeme}
then begin
Cosinus:=abs(CosAngle(Normala[i,j],DirectOfLight));
{moře se leskne víc, než pevnina, proto jsou použity různé funkce}
ContShade[i,j]:=1.15*exp(1.5*ln(Cosinus));
OceanShade[i,j]:=
arctan(sqrt(1-Cosinus*Cosinus)/Cosinus);
OceanShade[i,j]:=(9*exp(-150*OceanShade[i,j]
*OceanShade[i,j])+1)*exp(0.5*ln(Cosinus));
end
else begin {mimo průmět}
OceanShade[i,j]:=1000;ContShade[i,j]:=1000;
end;
end;
end;
Také mapování lze napočítat
předem. V poli InvertMap budou pro každý fyzický pixel průmětu kulové plochy
uloženy souřadnice InvertMap[i,j].x resp. InvertMap[i,j].y fyzického pixelu
textury,jehož barvou má být
obarven:
Procedure InvertTexturing(i,j:Integer);
var fi,psi:Double;
begin
fi:=arctan(Normala[i,j,3]/sqrt(1-
Normala[i,j,3]*Normala[i,j,3]));
psi:=arctan(Normala[i,j,2]/Normala[i,j,1]);
{hodnoty parametrů
dle (8), (9)}
if Normala[i,j,1]<0 then fi:=fi+pi;
InvertMap[i,j].x:=
Trunc(fi*FormOfTexture.ImageHelp.Width/2/pi);
InvertMap[i,j].y:=
Trunc((psi+pi/2)*FormOfTexture.ImageHelp.Height/pi);
end;
Tělo hlavní kreslící procedury začíná obvyklým nastavením základních parametrů, které zde vynecháme. Dále následuje:
Det:=i1*j2*MajorRay[3]+j1*k2*MajorRay[1]+k1*i2*MajorRay[2]-MajorRay[1]*j2*k1-MajorRay[2]*k2*i1-MajorRay[3]*i2*j1;
{nastavení
determinantu D dle (1)}
With Draw3D do
begin
for i:=0 to
Image.Width-1 do
for j:=0 to Image.Height-1 do NormCalcul(i,j); {normály}
for i:=0 to
Image.Width-1 do
for j:=0 to Image.Height-1 do Shading(i,j); {stínování}
for i:=0 to
Image.Width-1 do
for j:=0 to Image.Height-1 do {inverzní mapování}
if
ContShade[i,j]<1000
then
begin {jsme-li uvnitř průmětu}
InvertMapping(i,j); {výpočet hodnot inverzního mapování}
if
InvertMap[i,j].x>FormOfTexture.ImageHelp.Width
then InvertMap[i,j].x:=InvertMap[i,j].x- {přetečení}
FormOfTexture.ImageHelp.Width;
if InvertMap[i,j].x<0
then {podtečení}
InvertMap[i,j].x:=FormOfTexture.ImageHelp.Width
+InvertMap[i,j].x;
end
else begin {mimo průmět}
InvertMap[i,j].x:=-5000; InvertMap[i,j].y:=-5000;
end;
Origin:=0; {inicializace
počátku textury}
Repeat {procházení
průmětny}
for j:=0 to Image.Height-1 do
begin
SL:=Image.Picture.Bitmap.Scanline[j];
for i:=0 to Image.Width-1 do
if ContShade[i,j]<1000 then
begin
GetTexturePixel {vyzvednutí RGB
složek z textury}
(InvertMap[i,j].x,InvertMap[i,j].y,Red,Green,Blue);
if (Blue<Red) or (Blue<Green) {nepřevažuje-li modrá}
then begin {stínuj kontinent}
RRed:=ContShade[i,j]*Red;
RGreen:=ContShade[i,j]*Green;
RBlue:=ContShade[i,j]*Blue;
end
else begin {jinak stínuj moře}
RRed:=OceanShade[i,j]*Red;
RGreen:=OceanShade[i,j]*Green;
RBlue:=OceanShade[i,j]*Blue;
end;
if RRed>255 {ošetření přetečení a podtečení barev}
then
begin Red:=255;Green:=255;Blue:=255;end
else
begin
if RBlue>255
then begin
Red:=Trunc(255-255/RBlue*188);
Green:=Trunc(255-255/RBlue*60);
Blue:=255;
end
else begin
if RRed<0 then Red:=0
else Red:=abs(Trunc(RRed));
if RGreen<0 then Green:=0
else if RGreen>255
then Green:=255
else
Green:=abs(Trunc(RGreen));
if RBlue<0 then
Blue:=0
else Blue:=abs(Trunc(RBlue));
end;
end; {if RRed...}
Adr:=3*i;SL[Adr]:=Blue;
SL[succ(Adr)]:=Green;
SL[succ(succ(Adr))]:=Red;
end; {for i:=0 to
Image.Width-1 do}
end; {for j:=0 to Image.Height-1 do}
Draw3D.Image.Repaint;
Application.ProcessMessages;
{překreslení
obrazu}{*}
Origin:=Origin+Step; {posunutí počátku textury}
if
Pocatek>FormOfTexture.ImageHelp.Width then
{ošetření přetečení počátku}
Pocatek:=Pocatek-FormOfTexture.ImageHelp.Width;
for
i:=0 to Image.Width-1 do {posunutí textury}
for
j:=0 to Image.Height-1 do
InvertMap[i,j].x:=InvertMap[i,j].x+Step;
until
stop;
{proměnná se nastavuje stiskem tlačítka,událost je
"odchycena" řádkem *}
Na těchto stránkách jsou k dispozici zdrojový i spustitelný kód tohoto příkladu. Příklad lze spustit přímo ze stránek, před svým spuštěním si však do dočasného aadresáře stahuje potřebná data. Pokud by byla v komprimované podobě, bylo by třeba nejdříve stáhnout nějaké dynamicky linkované knihovny (*.dll) a pak teprve příklad spustit. Při tomto spuštění si tedy kód stahuje data ve formátu *.bmp, k jejichž čtení nepotřebuje žádné další knihovny. To je však zaplaceno značnou velikostí příslušných obrázků (celkem cca 15 MB) toto spuštění lze doporučit jen při velmi rychlém připojení
– spustíte zde.
V ostatních případech doporučuji stáhnout a rozbalit
Ten je menší – obsahuje data
v komprimovaném formátu *.png, potřebné knihovny *.dll a dále zdrojové
kódy i kód spustitelný. Po rozbalení tedy můžete soubor spustit ze svého
lokálního disku, popř. pracovat i se zdrojovým kódem
2.
Příklad - Rastrové texturování roviny ve středovém promítání. Ve
středovém promítání je směrový vektor promítacího paprsku určen středem
promítání a promítaným
bodem
, jeho souřadnice jsou tedy
a parametrické
rovnice promítacího paprsku jsou
(10)
srovnej s rovnicemi (2)
Ve středovém promítání zobrazme
obdélník v rovině kolmé na osu . Tento obdélník je určen rovnicemi:
Pro průsečík tohoto obdélníku s promítacím
paprskem dostáváme:
Z poslední rovnice je a po dosazení
do zbývajících rovnic máme:
Rastrové texturování roviny tímto
způsobem je velmi rychlé, polohu texturované roviny lze měnit „taháním“ myší.
Rastrové texturování roviny: zde najdete kompletní
zdrojový kód
a zde spustitelný
kód
Odraz světla
Základními zákony geometrické
optiky, které popisují chování světla na rozhraní dvou optických prostředí,
jsou zákon odrazu a zákon lomu. Zákon odrazu ve stručnosti říká, že odražený
paprsek setrvává v rovině dopadu a úhel odrazu se rovná úhlu dopadu. Při
softwarovém zpracování odrazu světla je třeba především zhjistit směr
odtařeného paprsku. Odraz světla na rozhraní dvou optických prostředí je
schématicky znázorněn na připojeném obrázku. Podle zákona odrazu se rovnají
úhly vektorů a
. Tento úhel označme
. Dále platí, že odražený paprsek zachovává rovinu dopadu,
tj. rovinu určenou vektory
a bodem dopadu. Označme
(1).
Vektor musí být normálou
v bodě dopadu. Předpokládejme dále, že
. Pak
a vzhledem
k tomu, že
, je
(2).
Protože , dostáváme z (2)
, což dosazeno do (1) dává
(3).
Protože však , je
, podosazení do (3)
tedy
(4).
Tento vztah dává jednoduchý
návod, jak ze znalosti směru dopadajícího světla a normály v místě dopadu
zjistit směr odraženého paprsku. Odraz světla nebudeme programovat samostatně,
výše uvedeného výsledku využijeme v následujících kapitolách.
Průhledná a průsvitná tělesa
Abychom objasnili průchod světla
průhlednými objekty, je třeba připomenout některé skutečnosti známé z
geometrické optiky. Optické prostředí můžeme považovat za projektivní prostor,
v jehož každém bodě jsou definovány hodnoty nějakých fyzikálních veličin.
(V optice je nejdůležitější index lomu). Hodnoty těchto veličin určují
optické vlastnosti prostředí. Geometrická optika studuje zákony záření založené
na jeho přímočarém šíření. Tyto zákony jsou použitelné v rozměrech mnohokrát
větších než je vlnová délka použitého světla. Při optickém zobrazování se
snažíme dosáhnout toho, aby zobrazení bylo kolineární a navíc projektivní.
Základními zákony geometrické optiky, které popisují chování světla na rozhraní dvou optických prostředí, jsou zákon odrazu a zákon lomu. Zákon odrazu ve stručnosti říká, že odražený paprsek setrvává v rovině dopadu a úhel odrazu se rovná úhlu dopadu. Podle zákona lomu (opět stručně) zůstává lomený paprsek v rovině dopadu a poměr sinů úhlů dopadu a lomu je roven indexu lomu tohoto optického rozhraní. (oba tyto zákony byly přesně formulovány v kpt. Mp4.2. (viz první a druhý zákon). Při modevání průchodu světelného paprsku tenkou vrstvou dochází vpodstatě jen k nepatrnému posunu tohoto paprsku. V kpt. 8.6. jsme tento posun zanedbali, předpokládali jsme, že ke změně směru nedochází vůbec a celou situaci jsme modelovali pouhým mícháním barev. Chceme-li však modelovat průchod paprsku průhledným tělesem nezanedbatelných rozměrů, je třeba vždy pracovat se zákonem odrazu i se zákonem lomu.
Obraťme nyní pozornost
k tomuto obrázku. Předpokládejme, že do bodu dopadá světelný tok
. Tento paprsek se v bodě
zčásti odrazí podle
zákona odrazu - odražený paprsek nese světelný tok
a zčásti lomí
podle zákona lomu - lomený paprsek nese světelný tok
. Část energie
dopadající do bodu
je pohlcena.
V závislosti na vlastnostech objektu v bodě
jsou různě pohlcovány
různé vlnové délky a proto jak odražený tok
, tak prošlý tok
nesou (každý jiným
způsobem) informaci o barvě bodu
. Zopakujeme-li tuto úvahu pro bod
,
, dostáváme světelné toky
,
,
, z nichž poslední dva nesou analogicky informaci
o barvě bodu
. Světelný tok
však může projít
objektem a dopadnout na další rozhraní v bodě
, kde se opět zčásti odrazí -
a zčásti prochází
do dalšího prostředí -
. Část energie dopadající do bodu
je opět pohlcena.
Odražený tok
i prošlý tok
nesou opět informaci
o barvě bodu
. Při vhodné poloze bodů
,
může odražený tok
dopadnout do bodu
, kde se opět odráží -
a láme -
. Při jisté poloze bodů
,
mohou paprsky
a
splynout. Takový paprsek
pak nese současně informaci jak o bodu
, tak o bodech
,
. Velikosti příspěvků jednotlivých světelných toků pak závisí
jednak na pohlcování určitých složek spektra v jednotlivých bodech, tak na
úbytku vlivem průchodu optickým prostředím.
Při průchodu světla hmotným
prostředím klesá svítivost. Přitom úbytek svítivosti na nekonečně tenké vrstvě
daného prostředí je přímo úměrný aktuální hodnotě této svítivosti, tj. . Konstanta této úměrnosti se nazývá index absorbce. Řešením
této rovnice dostáváme:
Lambertův - Beerův zákon: , kde
je svítivost pro
. Číslo
nazýváme koeficientem
absorbce.
U většiny látek existuje tzv. selektivní absorbce, která se projevuje tím, že látka pohlcuje světlo o různých vlnových délkách různě. U těchto látek dochází i k selektivní reflexi – různému odrazu v závislosti na vlnové délce.
Při algoritmizaci nelze bohužel většinou postihnout celý popsaný fyzikální proces. Jednak pro celkovou složitost a jednak pro nedostupnost potřebných informací. U každého paprsku by totiž bylo třeba propočítat všechny odrazy a lomy a barvy interferujících paprsků míchat. Navíc by bylo třeba započítat další jevy - absorbci, difuzi, dispersi apod. To ovšem lze udělat pouze pro objekt, který lze popsat analyticky a pro jehož každý bod jsou tyto veličiny známy. Nicméně i při modelování jednoduchých případů je třeba sofwarově modelovat lom světla na rozhraní dvou optických prostředí:
Lom světla je schématicky
znázorněn na připojeném obrázku. Světlo se láme tak, že lomený paprsek
zachovává rovinu dopadu, tj. rovinu určenou vektory a bodem dopadu, a dále
(1)
kde , resp.
je úhel dopadu, resp.
lomu a
je relativní index
lomu na rozhraní daných optických prostředí. Vektor
, který definuje směr lomeného paprsku určíme jako lineární
kombinaci vektorů
, tj. platí
(2)
kde jsou neznámé
konstanty. Jestliže známe úhel dopadu
a index lomu
, známe podle (1) i úhel lomu
. Předpokládejme, že
a řešme
:
(3)
(4)
Dosazením těchto hodnot do (2)
tedy obdržíme vektor , který definuje směr lomeného paprsku.
Příklad 1 - Zobrazení silnou spojnou čočkou.
Uvažujme spojnou čočku, která je tvořena kulovou plochou o poloměru a rovinou, která leží
v souřadné rovině
. Pozorovaná předloha je umístěna ve vzdálenosti
od této roviny.
Poloměr čočky označme
. Světelný paprsek vychází z předlohy smětem k výstupnímu
zařízení. Nachází-li se ve vzdálenosti větší než poloměr čočky (měřeno od
optické osy, tedy od souřadné osy
) projde přímo na výstupní zařízení (viz oranžový paprsek).
Nachází-li se ve vzdálenosti menší, musí na cestě k výstupnímu zařízení projít
čočkou (fialový paprsek). Zjistěme, „odkud přišel“ paprsek, který dopadl na
fyzický pixel
výstupního zařízení.
Logický pixel, kam paprsek dopadl, má v uživatelské souřadné soustavě
souřadnice
, v prostoru pak
, kde hodnota
je dána výškou roviny
výstupního zařízení nad rovinou
. Sledujme fialový paprsek zpět do místa jeho vzniku. Jeho
první část - úsečka
má směrový vektor
a rovnici
Bod , ve kterém se láme na kulové ploše, určíme jako průsečík
kulové plochy a přímky
:
(zde bereme pouze
znaménko plus).
Paprsek se v bodě
láme a prochází sklem
po přímce
, jejíž směrový vektor je na obrázku označen
.Podle zákona lomu zůstává lomený paprsek v rovině dopadu.
Jeho směrový vektor
lze tedy napsat
jako lineární kombinaci vektorů
;
. Koeficienty této lineární kombinace určíme ze vztahů (3), (4). Známe-li směrový
vektor
paprsku procházejícího
sklem, pak rovnice tohoto paprsku je
Hledejme průsečík tohoto paprsku s
rovinou
. Dosazením do poslední parametrické rovnice přímky
máme
, tedy
.
Konečně je třeba najít poslední
část paprsku, která vznikne lomem v bodě rovinného rozhraní
sklo - vzduch. Směr tohoto paprsku je určen vektorem
. Normála dopadu v bodě
nechť má souřadnice
, pro úhel dopadu pak platí
. Pro úhel posledního lomu je pak
. Směrový vektor lomeného paprsku
určíme opět jako
lineární kombinaci paprsku dopadajícího a normály dopadu. Postup je analogický, jako u prvního lomu s
jediným rozdílem. K lomu dochází na rozhraní sklo - voda, v příslušné
rovnici je tedy třeba počítat s převrácenou hodnohou indexu lomu skla. Je-li
tedy znám vektor
, můžeme napsat rovnici poslední části světelného paprsku
a najít jeho průsečík s rovinou,
ve které leží naše předloha. Pro dostáváme z poslední
rovnice
, takže pro bod
vychází
. Z tohoto bodu je tedy třeba vzít barvu předlohy a přiřadit
ji zpracovávanému pixelu
výstupního zařízení.
Chceme-li navíc započítat úbytek intenzity světla vlivem jeho průchodu
prostředím (úbytek přitom většinou předpokládáme pouze ve skle), je třeba
každou barevnou složku vynásobit v souladu s Lambertovým-Beerovým zákonem
výrazem
, kde
je koeficient absorbce
a
je velikost úsečky
(délka dráhy paprsku
ve skle).
Zde najdete kompletní zdrojový kód a zde spustitelný kód
Neprochází-li čočkou světlo monochomatické, ale např. světlo bílé, dochází jeho lomem jak známo k rozkladu na spektrální barvy. Tento jev lze modelovat např tak, že každému paprsku nepřiřadíme jeden, ale několik indexů lomu, příslušných několika barvám spektra. Tím odebereme barvu předlohy z několika jejích míst a tyto barvy pak následně sečteme. Tímto způsobem lze modelovat např. barevnou vadu čoček. Výstupy na připojených obrázcích vznikly modelováním bílého světla jako světla skládajícího se z osmi barev, jejichž vlnové délky odpovídají Fraunhofferovým spektrálním čarám.
Zobrazení silnou spojnou čočkou pro bílé světlo:
Zde najdete kompletní zdrojový kód a zde spustitelný kód
Princip těchto metod objasníme na metodě sledování paprsku, která patří k nejpoužívanějším. Nejdříve je však nutno uvést alespoň několik informací o tzv. osvětlovacích modelech.
Pokud by reálné rovinné optické rozhraní mělo mikroskopicky dokonalý povrch, pak by optický odraz a lom zachovával rovnoběžnost. Jinými slovy - pokud by na takové rozhraní dopadal rovnoběžný svazek paprsků, pak by odražený i lomený svazek byl opět rovnoběžný. Dokonale hladký povrch však žádný reálný přemět nemá. Není-li povrch dokonale hladký, pak normály tohoto povrchu mají různý směr, různé směry mají tedy i odražené a lomené paprsky. Nerovnosti povrchu mají fraktální charakter a vlastnosti odraženého i lomeného svazku lze popsat jen velmi přibližně. Funkci, která se tento charakter snaží popsat, nazýváme odrazovou resp. lomovou funkcí. Aplikaci této funkce v konkrétní situaci pak nazýváme osvětlovacím modelem.
K vyhodnocení odrazu a lomu světla lze přistupovat vpodstatě dvojím způsobem:
a) Fyzikální modely: vycházejí z fyzikálních zákonů šíření světla a odraz od nerovného povrchu se snaží popsat pomocí popisu šíření energie. Tyto metody mohou poskytnout téměř dokonalé fotorealistické výstupy. Jsou však značně složité, časově velmi náročné a pro skutečné výpočty použitelné jen s velkými obtížemi.
b) Empirické modely: nemají přímý vztah k fyzikální podstatě šíření světla. Chápou složitý fyzikální děj jako černou skříňku a jeho výsledek se snaží více či méně jednoduše kvantifikovat. Nemohou poskytnout tak přesné a vizuálně přesvědčivé výsledky, jako modely fyzikální, jsou však značně jednodušší a aplikace, které jsou na nich založeny, jsou podstatně rychlejší. Jsou proto často používány.
Při fyzikálním popisu je třeba vyjít z definice propustnosti a odrazivosti povrchu. Je známo, že světelný paprsek dopadající na rozhraní dvou optických prostředí se částečně odráží a částečně láme.
Propustnost a odrazivost: Je-li svítivost dopadajícího
paprsku,
resp.
svítivost lomeného
resp. odraženého paprsku, pak zlomek
nazýváme
propustnos-tí, zlomek
odrazivostí.
Propustnost a odrazivost se někdy
udává v procentech. Ze zákona o zachování energie vyplývá . Pro odrazivost na dielektrickém rozhraní (např.
vzduch-sklo) platí
kde resp.
je úhel dopadu resp.
úhel lomu (odvození lze nalézt např. v ). Pro malé úhly, kdy můžeme klást
, dostáváme
resp.
, neboť zákon lomu přechází pro malé úhly v rovnost
.
Postupuje-li světlo pod malým
úhlem dopadu ze vzduchu () do skla (
), vychází
, tj. 4% světla se odráží a 96% světla se láme.
Obecně velkou odrazivost mají
kovy. Příčinou je fakt, že světlo dopadající na kov uvede do nucených kmitů
volné elektrony a tyto kmity se skládají s dopadajícím vlněním. Procházející
vlna se tak z velké části zruší a téměř všechno světlo se odrazí. Odrazivost
kovu při kolmém dopadu je dána vzorcem , kde
je výše uvedený
koeficient absorbce Pro
dostáváme zřejmě
odrazivost na dielektriku. U kovů se však tento koeficient pohybuje většinou v
rozmezích 2.5 - 4.
Je známo, že index lomu závisí na
vlnové délce světla. Výše uvedená odrazivost tudíž také platí jen pro
monochromatické světlo. V softwarových realizacích je třeba zřejmě znát
odrazivosti (a tedy indexy lomu) pro vlnové délky odpovídající barevným složkám
použitého barevného modelu Red -; Green -
; Blue -
(viz kpt Mp4.4. pozn. 15). Ze známých indexů lomu
,
,
pro vlnové
délky
lze pak určit
index lomu a tím i odrazivost pro libovolnou vlnovou délku
podle vzorce
Známe-li svítivost paprsku dopadajícího na bod
plochy a odrazivost
plochy v tomto bodě, můžeme vyjádřit odraženou
svítivost
jako funkci dopadající svítivosti:
. Je-li uvažovaný
objekt vlastním zářičem, je třeba k celkové zářivosti v daném bodě přičíst
ještě vlastní svítivost
, tj.
. Pokud by byla
plocha dokonale opticky hladká, odražené záření by bylo dokonale směrováno.
Takový odraz se nazývá zrcadlový.
Pokud by naopak měly normály povrchu díky jeho mikronerovnostem statisticky
rovnoměrné rozložení, pak by tato plocha odrážela záření rovnoměrně do celého prostoru
bez ohledu na směr dopadajícího světla (byla by kosinovým zářičem dle kpt. Mp.4.1.1.).
Takový odraz se nazývá difuzní. U reálných ploch není žádný odraz dokonale
zrcadlový, ani dokonale difuzní. Za velmi přesný model zrcadlového odrazu však
může sloužit odraz na vyleštěných kovech, za model difuzního odrazu může
sloužit např. odraz na čerstvě napadlém sněhu nebo bílém papíře.
Nejjednoduší empirické osvětlovací modely vycházejí tedy z toho, že celková
svítivost, přicházející z daného bodu k pozorovateli, je dána součtem zrcadlové
a difuzní složky. Většinou se ještě započítává „rovnoměrný příspěvek okolního
světla“ . Okolí scény je
fyzikálně řečeno kromě specifikovaných světelných zdrojů osvětleno ještě
sférou, jejíž poloměr roste nade všechny meze a která je kosínovým zářičem.
Řečeno jazykem počítačových grafiků - je to složka, která zabraňuje tomu, aby
plochy odvrácené od světelných zdrojů, byly zobrazeny jako zcela černé. Celková
svítivost je pak dána součtem
Phongův model: je historicky prvním a nejjednoduším empirickým osvětlovacím modelem. V tomto modelu je zrcadlová složka definována jako
kde je svítivost
dopadajícího paprsku,
je koeficient
zrcadlového odrazu, který určuje míru zastoupení zrcadlové složky v odraženém
světle. Koeficient
udává „ostrost
zrcadlového odrazu“. Vektor
je normovaný vektor definující
směr pohledu pozorovatele,
pak směr zrcadlového
odrazu, tj. vektor symetrický s dopadajícím světelným paprskem
podle normály
. Podle vztahu (4) kpt. Mp8.3. tedy platí
. Je-li
, nachází se pozorovatel na „odvrácené straně zpacovávané
plochy“ a nemůže odraz vidět. Difuzní složka je dána vztahem:
,
kde je koeficient
difuzního odrazu. V případě, že
je povrch opět
odvrácen od světla a odraz nemůže být vidět.
Celkovou svítivost bodu plochy,
na který dopadá světlo z světelných zdrojů pak
počítáme jako
, kde příspěvek okolního rozptýleného světla (tzv. ambientní
složka) se přičítá jen jednou.
Programová realizace Phongova osvětlovacího modelu je tedy
následující:
function
AmbientComponent : Double; {okolní světlo}
begin
AmbientComponent:= I_A;
end;
function PhongReflex
(N:TVector; {normála povrchu} L:TVector; {směr
dopadu}
V : TVector;{směr pohledu} I_L : Double{intenzita dopadajícího světla} ):Double;
var DiffuseComponent, {difuzní složka}
MirrorComponent:Double {zrcadlová složka}
R :TVector; {směr
zrcadlového odrazu}
NL,VR :Double; {skalární součiny}
begin
NL:=
Draw3D.ScalarProduct(N,L);
if NL > 0 then
DiffuseComponent:= I_L * r_d *NL
else DiffuseComponent:= 0; { povrch je odvrácen od světla}
R[1] := 2*NL*N[1] - L[1];R[2] := 2*NL*N[2] -
L[2];R[3] := 2*NL*N[3] - L[3];
VR :=
Draw3D.ScalarProduct(V,R);
if VR < =0 then
MirrorComponent := 0
else
MirrorComponent := I_L * r_s * exp(ln(VR));
PhongReflex :=
DiffuseComponent + MirrorComponent;
end;
V této implementaci model funguje pro gray scale obraz. Pro barevný obraz je třeba příslušné výpočty provádět pro každou barevnou složku zvlášť a výslednou barvu míchat z takto vypočtených barevných složek.
Sledování paprsku
V reálném světě se světlo šíří ze světelných zdrojů všemi směry. Průchodem optickým prostředím je částečně pohlcováno, na rozhraní dvou prostředí se částečně odráží a částečně láme. Odražený i lomený paprsek pak ovlivňuje další části scény. Informace o scéně pak zprostředkují pouze paprsky, které dopadnou do oka pozorovatele, objektivu fotoaparáfu či kamery nebo jiného snímacího zařízení. Obraz na výstupním zařízení počítače je modelován obarvením bodů zobrazovacího okna. Každý paprsek, který zprostředkuje informaci o zobrazovaných objektech, tak musí projít fyzickým pixelem výstupního zařízení a dopadnout do kamery. Je tedy známa poslední přímka chodu každého paprsku, pomocí níž je třeba zpětně zrekonstruovat jeho předchozí cestu. Podobným způsobem jsme vlastně již postupovali při rastrovém texturování kulové plochy i při modelování spojné čočky. Ve výše uvedených situacích však toto zpětné sledování vypadalo vždycky stejně: V prvním případě paprsek dopadl na kulovou plochu a sledování skončilo. V tomto koncovém bodě bylo třeba zjistit barvu povrchu a úhel normály se směrem světla přicházejícího z jediného světelného zdroje. Ve druhém případě jsme sledovali dva lomy paprsku na rozhraní optických prostředí a po těchto dvou lomech dopadl paprsek na snímanou předlohu. Bylo třeba zjistit barvu předlohy v tomto bodě a (po eventuálním vynásobení koeficientem vyjadřujícím částečné pohlcení) tuto barvu přiřadit příslušnému fyzickému pixelu. V reálném světě však takové zpětné sledování paprsku může dopadnout nejrůznějším způsobem. Některý paprsek projde scénou zcela bez interakce s jakýmkoli objektem a nese tak informaci jen o rozptýleném okolním světle, jiný vznikl ve zdroji světla, dvakrát (třikrát, čtyřikrát...) se odrazil od různých předmětů a teprve pak dopadl do pohledového okna. Jsou -li ve scéně průhledné objekty, původní paprsek se na každém z nich rozdělí na paprsek odražený a lomený a z původního paprsku tak máme paprsky dva (čtyři, osm...).
Základním pojmem metody sledování paprsku je pojem scény. Scénou rozumíme množinu objektů, které se mají zobrazit (reálné objekty), a množinu informací, které lze při tomto zobrazení použít. Přitom tyto informace jsou většinou opět strukturovány jako objekty, které se ovšem nezobrazují (abstraktní objekty).
Scéna tak zahrnuje:
a) kameru - abstraktní objekt (množina informací o pohledové transformaci)
b) světla - abstraktní objekty (informace o poloze a charakteru světelných zdrojů)
c) zobrazované předměty - reálné objekty (informace o objektech, které mají být zobrazeny)
Dále rozlišujeme tři druhy paprsků:
a) paprsek primární - určený pozicí kamery a fyzickým pixelem snímacího zařízení.
b) paprsek sekundární - vzniká odrazem či lomem na povrchu zobrazovaného předmětu.
c) paprsek stínový - spojnice zobrazovaného bodu se světelným zdrojem (slouží ke zjištění, zda je tento bod přímo osvětlen daným světelným zdrojem)
Metoda sledování paprsku spočívá v rekurzivním vyhodnocování všech sekundárních paprsků, které protínají zobrazované předměty ve scéně. Není-li žádný průsečík zjištěn, přiřadí se barva odpovídající barvě pozadí a sledování končí. V praktických situacích by však takové sledování mohlo být velmi dlouhé a dokonce by nemuselo nikdy skončit. Sledování je tedy třeba ukončit nejpozději po předem určeném počtu odrazů či lomů primárního paprsku (toto číslo tak udává maximální hloubku použité rekurze).
Předpokládejme, že se scéna skládá z několika koulí (konstanta NoOfSpheres) a že budeme zpracovávat jen odraz. Celý postup lze popsat např. takto:
Globálně je třeba deklarovat světelný paprsek (Ray), zobrazované koule (Sphere), element scény (Scene_Element) se všemi potřebnými vlastnostmi (fiktivní koncový bod sledovaného paprsku, který s sebou nese všechny potřebné intormace), konstanty nahrazující nulu resp. nekonečno (Like_Zero; Like_Infinity) a hloubku použité rekurze (Level):
Type TRay = record
A,{bod, kterým paprsek
prochází}
s: TVector;{směr paprsku}
end;
TSphere = record
Center
:TPoint;
Radius :Double;
Red,Green,Blue :Byte;
Texture :TBitmap;
Reflex_Component,Diffus_Component,
Red_RefLect,Green_Reflect,
Blue_Reflect :Double;
end;
TScene_Element = record
P:TPoint;
N :TVector;
Red,Green,Blue
:Byte;
Reflex_Component,Diffus_Component,
Red_RefLect,Green_Reflect,
Blue_Reflect:Double;
end;
Const NoOfSpheres=5; Like_Zero = 1e-5;
Like_Infinity=1e5;
Var Ray: TRay;
Sphere: Array
[1..NoOfSpheres] of TSphere;
Scene_Element:TScene_Element;
Level: Byte;
Dále je třeba mít k dispozici funkci, která vrátí paprsek
odražený od zpracovávané plochy známe-li bod a normálu
:
Function Reflected_Ray(Ray:TRay;P:T3DPoint;N:TVector):TRay;
Var Scalar:Double; {pomocná proměnná pro skalární součin}
begin
for i:=1 to 3 do Viewing_Direct[1]:=-Ray.s[1];
Scalar:=Draw3D.ScalarProduct(Viewing_Direct,N);
for i:=1 to 3 do Reflected_Ray.s[i]:=
2*Scalar*N[i]-ViewingDirect[i];
for i:=1 to 3 do
Reflected_Ray.A[i]:=P[i]+Paprsek_Odrazu.s[i];
end;
a funkci, která otestuje existenci průsečíku s danou koulí a v případě, že průsečík existuje, vrátí jeho souřadnice s příslušnou normálou:
Function Sphere_Intersect(Sphere:TSphere;
Ray:TRay,
var Point:TPoint,var Norm:TVector):boolean;
(tuto funkci získáme relativně jednoduchou úpravou procedury NormCalcul. Řádky označené zde r8 - r16 všechny potřebné hodnoty počítají. Je třeba je jen upravit podle požadavků zde uvedené hlavičky funkce Sphere_Intersect)
Poté je třeba sesttrojit proceduru, která zajistí texturování kulové plochy. Tento problém jsme již rovněž řešili (viz opět kpt Mp8.2. - procedura InvertTexturing). Zde proběhnou stejné výpočty, některé mezivýsledky však již máme k dispozici, také hlavička procedury bude jiná. Změn je nyní poněkud více, proto vypíšeme celou proceduru:
Procedure SphereTexturing( Sphere:TSphere;
{plocha, kterou je třeba texturovat}
Normal:Tvector {normála});
var fi,psi :Double;
i,j,Adr:Integer;
SL :PByteArray
begin
With
Sphere do
begin
fi:=arctan(
psi:=arctan(
if
i:=Trunc(fi*Sphere.Texture.Bitmap.Width/2/pi);
Adr:=3*i; {mapování
textury}
j:=Trunc((psi+pi/2)*Sphere.Texture.Bitmap.Height/pi); {hodnotu textury
nyní přečteme}
SL:=Sphere.Texture.Bitmap.ScanLine[j];
{z bitmapy, která je součástí
deklarace koule}
Red:= SL[succ(succ(Adr))];
Green:=
SL[succ(Adr)];
Blue:= SL[Adr];
end;
end;
Dále potřebujeme funkci, která otestuje existenci průsečíku
zpracovávaného paprsku se scénou a v případě, že průsečík existuje, vrátí
průsečík a normálu
příslušné plochy:
Function Scene_Intersect (Ray:TRay;var
P: TPoint;
var N: TVector): boolean;
var NewPoint:TPoint;NewNormal:TVector;
k,i :integer;
begin
for i:=1 to
3 do Point[i]:=Like_Infinity;
Scene_Intersect:= False;
for k := 1 to
NoOfSpheres do
if
Sphere_Intersect(Sphere[k], Ray, NewPoint, NewNormal) then
if
(sqr(Ray.A.[1]-NewPoint[1])
+sqr(Ray.A.[2]-NewPoint[2])
+sqr(Ray.A.[3]-NewPoint[3])) <
(sqr(Ray.A.[1]-Point[1])
+sqr(Ray.A.[2]-Point[2])
+sqr(Ray.A.[3]-Point[3]))
then begin
Point := NewPoint; Normal :=
NewNormal;
Scene_Intersect := True;
With Scene_Element do
begin
P:=Point;N:=Normal;
Reflex_Componet:=Sphere[k].Reflex_Component;
Duffus_Componet:=Sphere[k].Diffus_Component;
Red_Reflect :=Sphere[k].Red_RefLect;
Green_Reflect :=Sphere[k].Green_Reflect;
Blue_Reflect :=Sphere[k].Blue_Reflect
end;
SphereTexturing(Sphere[k],P);
end;
end;
Konečně je pořeba funkci, která bude rekurzivně sledovat hodnotu barevné složky Red, Green nebo Blue (Color_Component) daného paprsku:
function RayTrack (Ray:TRay; Level:integer; Color_Component:byte): byte;
var Point :TPoint; {dopad sledovaného paprsku na kulovou plochu}
Normal:TVector;
{normála kulové
plochy v bodě dopadu}
Shadow_Point:TPoint;Shadow_Normal:TVector;
{stejné
parametry pro stínový paprsek}
Intensity :Double; {Intenzita světla}
Shadow_Ray TRay; {stínový paprsek}
SecColor :Byte; {barva sekundárního paprsku}
begin
if Scene_Intersect(Ray,Point,
then begin
Intensity:=AmbientComponent;
{nastavení
intenzity pozadí - viz předchozí kapitola}
for k:=1 to NoOfLights do {testování přímého osvětlení světelnými zdroji}
begin
for i:=1 to 3 do {nastavení vektoru
stínového paprsku}
Shadow_Ray.s[i]:=Light_Source[k].Position[i]-Point[i];
Value:=Draw3D.Norm(Shadow_Ray.s);
{normování vektoru stínového paprsku}
for i:=1 to
3 do Shadow_Ray.s[i]:=Shadow_Ray.s[i]/Value;
Shadow_Ray.A:=Light[k].Position;
{počáteční bod vektoru stínového paprsku}
ifScene_Intersect(Shadow_Ray,Shadow_Point,Shadow_Normal)
then {stínový paprsek protíná scénu}
if
sqr(Point[1]-Shadow_Point[1])
//průsečík stínového paprsku splývá s bodem dopadu paprsku světelného, tj. bod je přímo
+sqr(Point[2]-Shadow_Point[2]) // osvětlen
+sqr(Point[1]-Shadow_Point[1]))<Like_Zero
then Intensity:=Intensity+ {přičti příspěvek zdroje}
PhongReflex(N,Incident_Light_Dir,Viewing_Direct,
Light[k].Intensity);
end;
case Color_Component of {podle sledované barevné složky}
1:begin {je sledována červená}
Color:=Scene_Element.Red;
Scene_Element.Reflect_Component:=
Scene_Element.Red_Reflect;
end;
2: {analogicky sledování zelené}
3: {analogicky sledování modré}
else Color:=0;
end;
Color:=Round(Color*Intensity);
if Level>0 then
if Scene_Element.Reflect_Component>0 then
begin
SecColor:=Round(RayTrack(Reflected_Ray(Ray,P,N),
Level-1,Color_Component));
if SecColor>0
then Color:=Color-
Round(Scene_Element.Reflect_Component*(Color-SecColor));
end;
end {if
Scene_Intersect}
else Color:=0;
RayTrack:=Color;
end;
Nyní již zbývá jen nastavit všechny potřebné parametry kamery, světel a zobrazovaných těles (procedura setting - zde je vynechána) a pak již můžeme procházet výstupní zařízení pixel po pixelu a sledovat jednotlivé paprsky:
Procedure
TForm1.RayTracing(Sender:TObject);
begin
Setting; {nastavení parametrů kamery, světel a zobrazovaných koulí}
With Draw3D do {nastavení kamery - pohled do scény}
begin
x1:=...;x2:=...;y1:=...;y2:=...;Scale(x1,x2,y1,y2);
{uživatelské
pohledové okno}
AlfaView:=...;BetaView:=...;ObserverDistance:=...;
{pozice kamery}
SetCenterProjection(AlfaView,BetaView,ObserverDistance,ObserverPoint);
Level:=....; {úroveň rekurze}
for i:=0 to Image1.Height-1 do {procházej pohledové okno bod po bodu}
for j:=0 to Image1.Width-1 do
begin
{Určení souřadnic pixelu v prostorové soustavě
odpovídající pozici kamery viz Mp8.2.př.1}
Ray.A:=ObserverPoint; {zdroj primárního
paprsku}
for m:=1 to 3 do
Ray.v[m]:=XPoint[m]-Ray.A[m];
{směr
primárního paprsku}
Red:=SledujPaprsek(Ray,Level,1); {sledování červené
složky}
Green:=SledujPaprsek(Ray,Level,2); {sledování zelené
složky}
Blue:=SledujPaprsek(Ray,Level,3); {sledování modré
složky}
PutPixel(i,j,Red,Green,Blue); {obarvení pixelu}
end;
end;
end;
Zde najdete kompletní zdrojový kód a zde spustitelný kód.