Šviesos laužimas
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 iki ) 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ų).
- 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ų).
- 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)=
- Suprastinus vektorius g lygus g={24; -71; 112}.
- Toliau rasime vektorių y.
- y=cross(g, inNormal)=
- 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}.
- Toliau normalizuosime vektorių inNormal={-60; 16; 23}.
- Padarę skaliarinę vektorių sandaugą gausimę kosinusą kampo tarp vektoriaus viewVec ir vektoriaus inNormal.
- cosine = dot(viewVec, inNormal)=
- Randame sinusą
- sine = sqrt(1 - cosine * cosine) =
- 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ų
- Patikrinsime ar x * cosine + y * sine = viewVec.
- x * cosine + y * sine =
- Gavosi apytiksli -viewVec reikšmė. Tikroji viewVec reikšmė yra tokia Vektorius x*cosine+y*sine yra beveik normalizuotas: