Šviesos laužimas

Iš testwiki.
Pereiti į navigaciją Jump to search

Šviesos laužimo shader'is:

float4x4 view_proj_matrix;
float4 view_position;
struct VS_OUTPUT
{
float4 Pos: POSITION;
float2 TexCoord: TEXCOORD0;
float3 Refract: TEXCOORD1;
};
VS_OUTPUT vs_main(float4 inPos: POSITION, float3 inNormal: NORMAL,
float2 inTxr: TEXCOORD0)
{
VS_OUTPUT Out;
// Compute the projected position and send out the texture coordinates
Out.Pos = mul(view_proj_matrix, inPos);
Out.TexCoord = inTxr;
float3 viewVec = normalize(view_position - inPos);
// Compute the reflection vector using Snell’s Law
// the refract HLSL function does not always work properly
// n_i * sin(theta_i) = n_r * sin(theta_r)
// sin(theta_i) : Determine the sine of the incident vector 
float cosine = dot(viewVec, inNormal);
float sine = sqrt(1 - cosine * cosine);
// sin(theta_r) : Determine cosine of the refracted vector
// Note that the saturate(x) function is equivalent to
// using clamp(0,1,x). Also, 1.14 is the IOR for this
// shader.
float sine2 = saturate(1.14 * sine);
float cosine2 = sqrt(1 - sine2 * sine2);
// Determine the refraction vector be using the normal and tangent
// vectors as basis to determine the refraction direction
float3 x = -inNormal;
float3 y = normalize(cross(cross(viewVec, inNormal), inNormal));
Out.Refract = x * cosine2 + y * sine2;
return Out;
}
Iš pixel'ių shader'ių pusės viskas ko reikia, tai su'sample'inti environment map ir išgauti spalvą kaip sekantis kodas daro:
sampler Wood;
sampler EnvMap;
float4 ps_main(float2 inTxr: TEXCOORD0,float3 inRefract: TEXCOORD1) : COLOR
{
// Output texture color with reflection map
return texCUBE(EnvMap,inRefract);
}


Šita funkcija:
cross(viewVec, inNormal)
duoda vektorinę vektorių sandaugą iš dviejų vektorių. Padarius vektorinę vektorių sandaugą tarp dviejų trimačių vektorių gaunamas vektorius sudarantis 90 laipsnių kampą tiek su viewVec, tiek su inNormal. Tarkim, g=cross(viewVec, inNormal), tada g vektorius sudaro 90 laipsnių kampą su viewVec vektoriumi ir 90 laipsnių kampą su inNormal vektoriumi. Vektorius g lygiagretus trikampio plokštumai.
Vektorius inNormal yra plokščio trikampio (sudaryto iš 3 vertex'ų) normalė (normalė visada sudaro 90 laipsnių kampą su plokštuma).
Kadangi, spėju, kad vektorius inNormal normalizuotas (visos vektoriaus koordinatės gali būti tik nuo −1 iki 1) ir viewVec vektorius normalizuotas, tai shader'yje šito cross(cross(viewVec, inNormal), inNormal) normalizuoti greičiausiai nereikėjo (nebūtina).
y = normalize(cross(cross(viewVec, inNormal), inNormal)) = cross(cross(viewVec, inNormal), inNormal) = cross(g, inNormal).
Vektoriui y priešingos krypties vektorius yra vektorius h:
h = -y = -cross(g, inNormal).
Vektoriaus h kiekviena koordinatė turi priešingą ženklą (+ arba -) negu vektoriaus y. Vektorius h yra lygaigretus trikampio plokštumai (vektorius h guli ant trikampio plokštumos kaip ir vektorius g). Vektorius h su vektoriumi g sudaro 90 laipsnių kampą ant trikampio plokštumos (vektorius y taip pat sudaro 90 laipsnių kampą su vektoriumi g).
VEKTORIUS h YRA PROJEKCIJA VEKTORIAUS viewVec ANT TRIKAMPIO PLOKŠTUMOS. Vektoriaus projekcija ant plokštumos yra trumpiausias atstumas nuo vektoriaus galo iki plokštumos.


Pavyzdžiai

  • Duotas trikampis, kurio taškai (viršūnės) yra A(3; 4; 5), B(6; 7; 8), C(9; 10; 11). Rasime vektorius AB ir AC.
AB={6-3; 7-4; 8-5}={3; 3; 3};
AC={9-3; 10-4; 11-5}={6; 6; 6}.
Sudauginę vektorius AB ir AC vektorine vektorių sandauga (cross product) gausime vektorių inNormal (gausime trikampio normalės vektorių).
𝐧=𝐚×𝐛=|𝐢𝐣𝐤a1a2a3b1b2b3|=|a2a3b2b3|𝐢−|a1a3b1b3|𝐣+|a1a2b1b2|𝐤=
=𝐢a2b3+𝐣a3b1+𝐤a1b2−𝐢a3b2−𝐣a1b3−𝐤a2b1=
=𝐢(a2b3−a3b2)+𝐣(a3b1−a1b3)+𝐤(a1b2−a2b1)=
=(a2b3−a3b2;a3b1−a1b3;a1b2−a2b1)=
=𝐢𝐧𝐍𝐨𝐫𝐦𝐚𝐥=AB→×AC→=|𝐢𝐣𝐤333666|=|3366|𝐢−|3366|𝐣+|3366|𝐤=
=(3⋅6−3⋅6;−(3⋅6−3⋅6);3⋅6−3⋅6)=(0;0;0).
Blogas pavyzdis, nes vektoriai AB ir AC lygiagretūs (normalizavus gaunasi tas pats vektorius). Visi trys taškai guli ant vienos linijos.


  • Duotas trikampis, kurio taškai (viršūnės) yra A(3; 4; 5), B(10; 13; 17), C(2; 6; 1). Rasime vektorius AB ir AC.
AB={10-3; 13-4; 17-5}={7; 9; 12};
AC={2-3; 6-4; 1-5}={-1; 2; -4}.
Sudauginę vektorius AB ir AC vektorine vektorių sandauga (cross product) gausime vektorių inNormal (gausime trikampio normalės vektorių).
𝐧=𝐚×𝐛=|𝐢𝐣𝐤a1a2a3b1b2b3|=|a2a3b2b3|𝐢−|a1a3b1b3|𝐣+|a1a2b1b2|𝐤=
=𝐢a2b3+𝐣a3b1+𝐤a1b2−𝐢a3b2−𝐣a1b3−𝐤a2b1=
=𝐢(a2b3−a3b2)+𝐣(a3b1−a1b3)+𝐤(a1b2−a2b1)=
=(a2b3−a3b2;a3b1−a1b3;a1b2−a2b1)=
=𝐢𝐧𝐍𝐨𝐫𝐦𝐚𝐥=AB→×AC→=|𝐢𝐣𝐤7912−12−4|=|9122−4|𝐢−|712−1−4|𝐣+|79−12|𝐤=
=(9⋅(−4)−2⋅12;−[7⋅(−4)−(−1)⋅12];7⋅2−(−1)⋅9)=
=(−36−24;−[−28+12];14+9)=(−60;16;23).
Vektorius viewVec yra viewVec={5; 8; 4}. Rasime vektorių g (vektorius g guli ant trikampio ABC plokštumos, nes vektorius inNormal yra status trikampio plokštumai).
g=cross(viewVec, inNormal)=
=𝐠=viewVec→×inNormal→=|𝐢𝐣𝐤584−601623|=|841623|𝐢−|54−6023|𝐣+|58−6016|𝐤=
=(8⋅23−16⋅4;−[5⋅23−(−60)⋅4];5⋅16−(−60)⋅8)=
=(184−64;−[115+240];80+480)=(120;−355;560).
Suprastinus vektorius g lygus g={24; -71; 112}.
Toliau rasime vektorių y.
y=cross(g, inNormal)=
=𝐲=g→×inNormal→=|𝐢𝐣𝐤24−71112−601623|=|−711121623|𝐢−|24112−6023|𝐣+|24−71−6016|𝐤=
=(−71⋅23−16⋅112;−[24⋅23−(−60)⋅112];24⋅16−(−60)⋅(−71))=
=(−1633−1792;−[552+6720];384−4260)=(−3425;−7272;−3876).
Net iš normalizuotų vektorių vektorinė vektorių sandauga neduoda normalizuoto vektoriaus (jei duoti normalizuoti vektoriai a={0.8; 0.6; 0} ir b={-0.8; 0.6; 0}, tai z koordinatė vektoriaus c=cross(a, b) lygi k(0.8*0.6-(-0.8)*0.6)=k(0.48+0.48)=0.96 k, kas ne lygu 1 k). Todėl reikia normalizuoti vektorių y.
Normalizuosime vektorių viewVec={5; 8; 4}.
‖viewVec‖=52+82+42=25+64+16=105=10.246950766;
viewVec→={510.24695;810.24695;410.24695}={0.4879500;0.78072006;0.39036003}.
Toliau normalizuosime vektorių inNormal={-60; 16; 23}.
‖inNormal‖=(−60)2+162+232=3600+256+529=4385=66.21933252457;
inNormal→={−6066.2193325;1666.2193325;2366.2193325}={−0.9060798065;0.2416212817;0.34733059}.
Padarę skaliarinę vektorių sandaugą gausimę kosinusą kampo tarp vektoriaus viewVec ir vektoriaus inNormal.
cosine = dot(viewVec, inNormal)=
=cosine=𝐯𝐢𝐞𝐰𝐕𝐞𝐜⋅𝐢𝐧𝐍𝐨𝐫𝐦𝐚𝐥=0.4879500⋅(−0.9060798065)+0.78072006⋅0.2416212817+0.39036003⋅0.34733059=
=−0,44212164158+0,188638581546+0,13558398=−0,117899080034.
Randame sinusą
sine = sqrt(1 - cosine * cosine) =
=1−(−0,117899080034)2=1−0,01390019307=0,986099806927
Jei kampas tarp dviejų vektorių 0 laipsnių, tai kosinusas lygus 1, o sinusas lygus 0. O jei kampas tarp dviejų vektorių lygus 90 laipsnių, tai kosinusas lygus 0, o sinusas lygus 1.
Funkcija saturate(x) yra ekvivalenti funkcijai clamp(0, 1, x). Funkcija clamp(0, 1, x) duoda reikšmes tik nuo 0 iki 1. Jei x daugiau už 1, tada vis tiek funkcija clamp(0, 1, x) grąžins 1.

Ir jeigu x mažiau už 0, tai vis tiek bus 0. Funkcija saturate duoda reikšmes intervale nuo 0 iki 1. O didesnias arba mažesnes reikšmes paverčia į 1 arba 0.

// Note that the saturate(x) function is equivalent to
// using clamp(0,1,x).
Jei šitą kodą
float3 x = -inNormal;
float3 y = normalize(cross(cross(viewVec, inNormal), inNormal));
Out.Refract = x * cosine2 + y * sine2;
pakeisti tokiu kodu
float3 x = -inNormal;
float3 y = normalize(cross(cross(viewVec, inNormal), inNormal));
Out.Refract = x * cosine + y * sine;
tai tada bus gautas viewVec arba -viewVec vektorius (sunku pasakyti ar reikalingas minusas ar ne). Tai yra
\\ Out.Refract = x * cosine + y * sine = viewVec
arba
\\ Out.Refract = x * cosine + y * sine = -viewVec
Vektorius x = -inNormal. O vektorius y yra projekcija vektoriaus viewVec (arba vektoriaus -viewVec, neaišku ar reikia to minuso) ant trikampio plokštumos.
Normalizuosime vektorių y=(−3425;−7272;−3876).
‖y‖=(−3425)2+(−7272)2+(−3876)2=11730625+52881984+15023376=79635985=8923,899652058;
y→={−342579635985;−727279635985;−387679635985}={−0,383800819545;−0,8148903824;−0,434339263229}.
Patikrinsime ar x * cosine + y * sine = viewVec.
x * cosine + y * sine =
=−0,117899080034⋅(−{−0,9060798065;0,2416212817;0,34733059})+0,986099806927⋅{−0,383800819545;−0,8148903824;−0,434339263229}=
=−0,117899080034⋅{0,9060798065;−0,2416212817;−0,34733059}+0,986099806927⋅{−0,383800819545;−0,8148903824;−0,434339263229}=
={−0,1068259756;0,02848692683;0,040949957}+{−0,3784659140517;−0,8035632487513;−0,4283018636109}=
={−0,4852918896517;−0,7750763219213;−0,3873519066109}.
Gavosi apytiksli -viewVec reikšmė. Tikroji viewVec reikšmė yra tokia viewVec→={0,4879500;0,78072006;0,39036003}. Vektorius x*cosine+y*sine yra beveik normalizuotas:
(−0,4852918896517)2+(−0,7750763219213)2+(−0,3873519066109)2=0,9862930225198678.


High_Level_Shading_Language