Š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=
=𝐢(a2b3a3b2)+𝐣(a3b1a1b3)+𝐤(a1b2a2b1)=
=(a2b3a3b2;a3b1a1b3;a1b2a2b1)=
=𝐢𝐧𝐍𝐨𝐫𝐦𝐚𝐥=AB×AC=|𝐢𝐣𝐤333666|=|3366|𝐢|3366|𝐣+|3366|𝐤=
=(3636;(3636);3636)=(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=
=𝐢(a2b3a3b2)+𝐣(a3b1a1b3)+𝐤(a1b2a2b1)=
=(a2b3a3b2;a3b1a1b3;a1b2a2b1)=
=𝐢𝐧𝐍𝐨𝐫𝐦𝐚𝐥=AB×AC=|𝐢𝐣𝐤7912124|=|91224|𝐢|71214|𝐣+|7912|𝐤=
=(9(4)212;[7(4)(1)12];72(1)9)=
=(3624;[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=|𝐢𝐣𝐤584601623|=|841623|𝐢|546023|𝐣+|586016|𝐤=
=(823164;[523(60)4];516(60)8)=
=(18464;[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=|𝐢𝐣𝐤2471112601623|=|711121623|𝐢|241126023|𝐣+|24716016|𝐤=
=(712316112;[2423(60)112];2416(60)(71))=
=(16331792;[552+6720];3844260)=(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.780720060.2416212817+0.390360030.34733059=
=0,44212164158+0,188638581546+0,13558398=0,117899080034.
Randame sinusą
sine = sqrt(1 - cosine * cosine) =
=1(0,117899080034)2=10,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