4.6. Un materiale con tutte le componenti

5
Il tuo voto: Nessuno Media: 5 (2 voti)

Utilizzando i framenti di codice d'esempio e le equazioni dei precedenti capitoli siamo ora in grado di assemblare il codice di uno shader che permetta il rendering di un materiale completo di tutte le sue componenti. In questo caso è utile anche creare una tecnica di shading (quindi anche un Pixel Shader dedicato) per ogni tipo di materiale secondo le componenti che vengono utilizzate. L'obbiettivo di questa pratica è quello di ottimizzare quanto più possibile la parformance generale. Lascio però questa parte al lettore dato che potrà ricavare tutte le tecniche necessarie eliminando opportunamente parti di codice dalla funzione del Pixel Shader completo presentato di seguito.

  1 // Matrici di trasformazione in ingresso
  2 uniform float4x4 World;
  3 uniform float4x4 WorldView;
  4 uniform float4x4 ViewProj;
  5 
  6 // Posizione della telecamera in World-Space
  7 uniform float4 eyePos;
  8 // Posizione della sorgente luminosa omnidirezionale
  9 uniform float3 lightPos;
 10 
 11 // Colori delle componenti del materiale
 12 uniform float4 ambientColor;
 13 uniform float4 diffuseColor;
 14 uniform float4 specularColor;
 15 uniform float4 emissiveColor;
 16 uniform float4 reflectionColor;
 17 
 18 // Esponenete per definire la forma del riflesso speculare
 19 uniform float specularExponent;
 20 
 21 // Variabile della riflessione di fresnel per angolo = zero
 22 uniform float r0;
 23 
 24 // Textures in ingresso per definire il materiale
 25 texture diffuseTex;
 26 texture specularTex;
 27 texture emissiveTex;
 28 texture normalTex;
 29 texture reflectionTex;
 30 
 31 // Samplers delle textures delle componenti del materiale
 32 sampler2D diffuseSampler : register(s0) = sampler_state
 33 {
 34    Texture = (diffuseTex);
 35    ADDRESSU = WRAP;
 36    ADDRESSV = WRAP;
 37    ADDRESSW = WRAP;
 38    MINFILTER = LINEAR;
 39    MIPFILTER = LINEAR;
 40    MAGFILTER = LINEAR;
 41 };
 42 
 43 sampler2D specularSampler : register(s1) = sampler_state
 44 {
 45    Texture = (specularTex);
 46    ADDRESSU = WRAP;
 47    ADDRESSV = WRAP;
 48    ADDRESSW = WRAP;
 49    MINFILTER = LINEAR;
 50    MAGFILTER = LINEAR;
 51    MIPFILTER = LINEAR;
 52 };
 53 
 54 sampler2D emissiveSampler : register(s2) = sampler_state
 55 {
 56    Texture = (emissiveTex);
 57    ADDRESSU = WRAP;
 58    ADDRESSV = WRAP;
 59    ADDRESSW = WRAP;
 60    MAGFILTER = LINEAR;
 61    MINFILTER = LINEAR;
 62    MIPFILTER = LINEAR;
 63 };
 64 
 65 sampler2D normalSampler : register(s3) = sampler_state
 66 {
 67    Texture = (normalTex);
 68    MIPFILTER = LINEAR;
 69    MINFILTER = LINEAR;
 70    MAGFILTER = LINEAR;
 71    ADDRESSU = WRAP;
 72    ADDRESSV = WRAP;
 73    ADDRESSW = WRAP;
 74 };
 75 
 76 samplerCUBE reflectionSampler : register(s4) = sampler_state
 77 {
 78    Texture = (reflectionTex);
 79    ADDRESSU = CLAMP;
 80    ADDRESSV = CLAMP;
 81    ADDRESSW = CLAMP;
 82    MAGFILTER = LINEAR;
 83    MINFILTER = LINEAR;
 84    MIPFILTER = LINEAR;
 85 };
 86 
 87 // Struttura per gli elementi in uscita dal Vertex Shader
 88 struct VS_OUT
 89 {
 90     float4 oPos : POSITION;
 91     float2 oTexCoords : TEXCOORD0;
 92     float3 oLightVec : TEXCOORD1;
 93     float3 oViewVec : TEXCOORD2;
 94     float3 oWorldNormalVec : TEXCOORD3;
 95     float3 oWorldViewVec : TEXCOORD4;
 96 };
 97 
 98 // Dichiarazione della funzione del Vertex Shader con elementi del vertice
 99 // inseriti direttamente nella lista dei parametri.
100 VS_OUT mainVS(
101     in float3 Pos  : POSITION,
102     in float3 Normal : NORMAL,
103     in float3 Tangent : TANGENT,
104     in float3 Binormal : BINORMAL,
105     in float2 TexCoords : TEXCOORD0)
106 {
107     // Dichiarazione della struttura per i dati in uscita
108     VS_OUT Out;
109 
110     // Trasformazione del vertice da object-space a world-space
111     float4 p = mul(float4(Pos, 1.0), World);
112 
113     // Passaggio della posizione trasformata in screen space...
114     Out.oPos = mul(p, ViewProj);
115     // ...e delle coordinate di texture al Pixel Shader
116     Out.oTexCoords = TexCoords * 2.0;
117 
118     // Calcolo della matrice di rotazione per la trasformazione da
119     // world-space a tangent-space
120     float3x3 objToTangentSpace;
121     objToTangentSpace[0] = mul(float4(Tangent, 0.0), World);
122     objToTangentSpace[1] = mul(float4(Binormal, 0.0), World);
123     objToTangentSpace[2] = mul(float4(Normal, 0.0), World);
124 
125     // Calcolo del vettore normale in world-space
126     Out.oWorldNormalVec = mul(float4(Normal, 0.0), World);
127     // Calcolo del "vettore vista" in world-space
128     Out.oWorldViewVec = p - eyePos;
129 
130     // Calcolo dei vettori che vanno al vertice alla sorgente luminosa e
131     // dal vertice alla posizione della telecamera.
132     // Trasformazione dei vettori in tangent-space.
133     float3 LightVec = lightPos - p;
134     Out.oLightVec = mul(objToTangentSpace, LightVec);
135     Out.oViewVec = mul(objToTangentSpace, Out.oWorldViewVec);
136 
137     return Out;
138 }
139 
140 // Dichiarazione del Pixel Shader per il rendering con illuminazione
141 // da una luce puntiforme posizionata su "lightPos"
142 float4 mainPS(
143     float2 TexCoord : TEXCOORD0,
144     float3 LightVec : TEXCOORD1,
145     float3 ViewVec : TEXCOORD2,
146     float3 WorldNormalVec : TEXCOORD3,
147     float3 WorldViewVec : TEXCOORD4) : COLOR0
148 {
149     // Normalizzazione dei vettori provenienti dal VertexShader
150     LightVec = normalize(LightVec);
151     ViewVec = normalize(ViewVec);
152     WorldNormalVec = normalize(WorldNormalVec);
153     WorldViewVec = normalize(WorldViewVec);
154 
155     // Recupero di tutti i texel delle varie componenti del materiale e
156     // modulazione con i rispettivi colori
157     float4 ambient = tex2D(diffuseSampler, TexCoord) * ambientColor;
158     float4 diffuse = tex2D(diffuseSampler, TexCoord) * diffuseColor;
159     float4 specular = tex2D(specularSampler, TexCoord) * specularColor;
160     float4 emissive = tex2D(emissiveSampler, TexCoord) * emissiveColor;
161     float3 normal = tex2D(normalSampler, TexCoord).xyz;
162 
163     float3 reflVec = reflect(WorldViewVec, WorldNormalVec);
164     float4 reflection = texCUBE(reflectionSampler, reflVec) * reflectionColor;
165 
166     // Espansione della normale recuperata dalla texture dal
167     // range 0.0 ... 1.0 a -1.0 ... 1.0 per poter essere utilizzata
168     // nei calcoli di illuminazione
169     normal = normalize((normal * 2.0f) - 1.0f);
170 
171     // Calcolo della componente di illuminazione diffusa
172     float diff = saturate(dot(normal, LightVec));
173     // Calcolo della componente dell'hot-spot speculare
174     float spec = pow(saturate(dot(reflect(ViewVec, normal), LightVec)), specularExponent);
175     // Calcolo della componente della riflessione Fresnel
176     float fres = r0 + (1.0 - r0) * pow(1.0 - saturate(dot(-ViewVec, normal)), 5);
177 
178     // Calcolo del colore definitivo come somma delle componenti
179     return (ambient + diffuse * diff + specular * spec + emissive + reflection * fres);
180 }
181 
182 // Tecnica per il rendering del materiale
183 technique Materiale
184 {
185     pass Pass0
186     {
187         ZEnable = true;
188         ZWriteEnable = true;
189         AlphaBlendEnable = false;
190         FillMode = solid;
191 
192         VertexShader = compile vs_2_0 mainVS();
193         PixelShader = compile ps_2_0 mainPS();
194     }
195 }

Con questo capitolo abbiamo esaurito la trattazione di ogni caratteristica di un materiale standard proponendo uno shader che sia sufficentemente flessibile da rappresentare un buon numero di differenti materiali utilizzando un'interfaccia unica verso il codice C#.