9. Tworzenie cieni płaskich

Transkrypt

9. Tworzenie cieni płaskich
Tworzenie cieni płaskich
Pod pojęciem cieni płaskich będziemy rozumieć cienie dwuwymiarowe, to znaczy rzucane na
płaskie powierzchnie, ewentualnie na kilka płaskich powierzchni. Opisana poniżej metoda nie
nadaje się do tworzenia cieni rzucanych na inne rodzaje powierzchni, np. na sferę, walec itp.
Cień płaski można utworzyć poprzez odpowiednią trnasformację świata. Poniżej znajduje się
scena wykorzystująca tę metodę:
Cień został uzyskany porzez "spłaszczenie" przedmiotu.
Stworzymy teraz macierz dokonującą takiej transformacji.
.
Powyższy rysunek przedstawia odpowiednie rzutowanie. Żólty punkt L to pozycja światła w
przestrzeni (lx, ly, lz), czrwony P - to rzutowany funkt (px, py, pz) na płaszczyznę, zaś różowy
S to ponkt cienia (sx, sy, sz) odpowiadający zrzutowaniu punktu P.
Jak widać punkt p musi być odpowiednio przesunięty wzdłuż różowego wektora. Określimy
teraz kierunke i zwrot w jakim to przesunięcie ma być wykonane.
Możemy określić współrzędne wektora żółtego biegnącego od pozycji światła do punktu
rzutowanego:
LP = (px = lx, py - ly, pz - lz)
Jeśli jakiś wektor pomnożymy przez dowolna liczbę rzeczywistą nieujemną i różną od zera to
otrzymany nowy wektor ma taki sam zwrot i kierunek jak wektor poprzedni, lecz inną
długość.
Zatem nasz punkt P musimy przesunąć o wektor * LP, gdzie  to pewna dodatnia liczba
rzeczywista różna od zera.
Czyli możemy tak zapisać wektorowo transformację:
S = P + * LP
Rozpisując to wzdłuż poszczególnych osi otrzymamy trzy równania skalarne:
sx = px + * lpx
1)
sy = py + * lpy
2)
sz = pz + * lpz
3)
Dodatkowo wiemy, że punkt cienia (sx, sy, sz) leży na znanej nam płaszczyźnie o równaniu:
Ax + By + Cz + D = 0, czyli spełnia to równanie
Asx + Bsy + Csz + D=0
4)
Podstawmy równania 1), 2), 3) do 4)
A(px + * lpx)+ B(py + * lpy) + C(pz + * lpz) + D=0
Wyliczmy stąd wpółczynnik alfa:
 Apx  Bpy  Cpz  D

Apx  Alx  Bpy  Bly  Cpz  Clz
Podstawiając go do 1), 2), 3) otrzymamy równianie transformacji:
sx 
px * ( B * ly  C * lz  D)  py * ( B * lx )  pz * ( C * lx )  D * lx
px * (  A)  py * ( B )  pz * ( C )  A * lx  B * ly  C * lz
sy 
px * (  A * ly )  py * ( A * lx  C * lz  D )  pz * ( C * ly )  D * ly
px * (  A)  py * ( B)  pz * ( C)  A * lx  B * ly  C * lz
sy 
px * (  A * lz )  py * ( B * lz )  pz * ( A * lx  B * ly  D)  D * lz
px * (  A)  py * (  B)  pz * ( C )  A * lx  B * ly  C * lz
Jak widać powyższa transformacja jest nieliniowa (mam na mysli fakt, ze mianownik zależy
od współrzędnych punktu P(px, py, pz).
Macierz skonstruujemy w następujący sposób - jako sx wpiszemy licznik sx, jako sy
wpiszemy licznik sy, jako sz wpiszemy licznik sz. Natowmiast mianownik będzie
potraktowany jako współczynnik skalowania. Jeśli jest on równy 1, to nie wnosi nic nowego
do transformacji (punkt ukaże się dokładnie pod takimi wpółrzędnymi jakie wyszły z
transformacji). Jednak gdzy jest on różny od zera, to każda współrzędna jest przez niego
dzielona i dopiero jest rysowany punkt (sx/w. sy/w. sz/w) - czyli to, co nas teraz interesuje.
Poniżej przedstawiłem procedurę tworzącą macierz płaskiego cienia (w trochę bardziej
zwięzłej postaci). Przyjmuje ona macierz, która będzie modyfikowana, pozycję światła jako
wektor i trzy punkty (jako wektory) należące do płaszczyzny, na którą jest rzucany cień.
Public Sub MakeShadowMatrix(ByRef DestMat As D3DMATRIX, l As D3DVECTOR, p()
As D3DVECTOR)
Dim normal As D3DVECTOR 'wektor normalny płaszczyzny, na którą jest rzucany cień
Dim D As Single
Dim dot As Single
'iloczyn skalarny wektora normalnego płaszczyzny i
'pozycji światła
normal = CalcNormal(p(0), p(1), p(2))
D = -(normal.x * p(2).x + normal.y * p(2).y + normal.z * p(2).z)
dot = DX.VectorDotProduct(normal, l) + D
With DestMat
.rc11 = dot - normal.x * l.x
.rc21 = -normal.y * l.x
.rc31 = -normal.z * l.x
.rc41 = -D * l.x
.rc12 = -normal.x * l.y
.rc22 = dot - normal.y * l.y
.rc32 = -normal.z * l.y
.rc42 = -D * l.y
.rc13 = -normal.x * l.z
.rc23 = -normal.y * l.z
.rc33 = dot - normal.z * l.z
.rc43 = -D * l.z
.rc14 = -normal.x
.rc24 = -normal.y
.rc34 = -normal.z
.rc44 = dot - D
End With
End Sub