Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Cree un efecto de sombra añadiendo pruebas de profundidad a su sombreador de vértices (o de geometría) y a su sombreador de píxeles. Parte 3 de la Guía : Implementar volúmenes de sombras usando búferes de profundidad en Direct3D 11.
Inclusión de la transformación para el frustum ligero
El sombreador de vértices debe calcular la posición del espacio de luz transformado para cada vértice. Proporcione el modelo de espacio de luz, la vista y las matrices de proyección mediante un búfer constante. También puede usar este búfer de constantes para proporcionar la posición de la luz y la normalidad para los cálculos de iluminación. La posición transformada en el espacio de luz se usará durante la prueba de profundidad.
PixelShaderInput main(VertexShaderInput input)
{
PixelShaderInput output;
float4 pos = float4(input.pos, 1.0f);
// Transform the vertex position into projected space.
float4 modelPos = mul(pos, model);
pos = mul(modelPos, view);
pos = mul(pos, projection);
output.pos = pos;
// Transform the vertex position into projected space from the POV of the light.
float4 lightSpacePos = mul(modelPos, lView);
lightSpacePos = mul(lightSpacePos, lProjection);
output.lightSpacePos = lightSpacePos;
// Light ray
float3 lRay = lPos.xyz - modelPos.xyz;
output.lRay = lRay;
// Camera ray
output.view = eyePos.xyz - modelPos.xyz;
// Transform the vertex normal into world space.
float4 norm = float4(input.norm, 1.0f);
norm = mul(norm, model);
output.norm = norm.xyz;
// Pass through the color and texture coordinates without modification.
output.color = input.color;
output.tex = input.tex;
return output;
}
A continuación, el sombreador de píxeles usará la posición de espacio de luz interpolada proporcionada por el sombreador de vértices para probar si el píxel está en sombra.
Prueba de si la posición está en el frustum ligero
Primero, compruebe que el píxel está en el frustum de visión de la luz normalizando las coordenadas X e Y. Si están dentro del intervalo [0, 1] entonces es posible que el píxel esté en sombra. De lo contrario, puede omitir la prueba de profundidad. Un sombreador puede probar esto rápidamente llamando a Saturate y comparando el resultado con el valor original.
// Compute texture coordinates for the current point's location on the shadow map.
float2 shadowTexCoords;
shadowTexCoords.x = 0.5f + (input.lightSpacePos.x / input.lightSpacePos.w * 0.5f);
shadowTexCoords.y = 0.5f - (input.lightSpacePos.y / input.lightSpacePos.w * 0.5f);
float pixelDepth = input.lightSpacePos.z / input.lightSpacePos.w;
float lighting = 1;
// Check if the pixel texture coordinate is in the view frustum of the
// light before doing any shadow work.
if ((saturate(shadowTexCoords.x) == shadowTexCoords.x) &&
(saturate(shadowTexCoords.y) == shadowTexCoords.y) &&
(pixelDepth > 0))
{
Prueba de profundidad en el mapa de sombras
Utilice una función de comparación de muestras (SampleCmp o SampleCmpLevelZero) para probar la profundidad del píxel en el espacio de la luz contra el mapa de profundidad. Calcule el valor de profundidad del espacio de luz normalizado, que es z / w
y pase el valor a la función de comparación. Puesto que usamos una prueba de comparación LessOrEqual para el muestreador, la función intrínseca devuelve cero cuando se supera la prueba de comparación; esto indica que el píxel está en sombra.
// Use an offset value to mitigate shadow artifacts due to imprecise
// floating-point values (shadow acne).
//
// This is an approximation of epsilon * tan(acos(saturate(NdotL))):
float margin = acos(saturate(NdotL));
#ifdef LINEAR
// The offset can be slightly smaller with smoother shadow edges.
float epsilon = 0.0005 / margin;
#else
float epsilon = 0.001 / margin;
#endif
// Clamp epsilon to a fixed range so it doesn't go overboard.
epsilon = clamp(epsilon, 0, 0.1);
// Use the SampleCmpLevelZero Texture2D method (or SampleCmp) to sample from
// the shadow map, just as you would with Direct3D feature level 10_0 and
// higher. Feature level 9_1 only supports LessOrEqual, which returns 0 if
// the pixel is in the shadow.
lighting = float(shadowMap.SampleCmpLevelZero(
shadowSampler,
shadowTexCoords,
pixelDepth + epsilon
)
);
Calcular la iluminación dentro o fuera de la sombra
Si el píxel no está en sombra, el sombreador de píxeles debe calcular la iluminación directa y agregarlo al valor de píxel.
return float4(input.color * (ambient + DplusS(N, L, NdotL, input.view)), 1.f);
float3 DplusS(float3 N, float3 L, float NdotL, float3 view)
{
const float3 Kdiffuse = float3(.5f, .5f, .4f);
const float3 Kspecular = float3(.2f, .2f, .3f);
const float exponent = 3.f;
// Compute the diffuse coefficient.
float diffuseConst = saturate(NdotL);
// Compute the diffuse lighting value.
float3 diffuse = Kdiffuse * diffuseConst;
// Compute the specular highlight.
float3 R = reflect(-L, N);
float3 V = normalize(view);
float3 RdotV = dot(R, V);
float3 specular = Kspecular * pow(saturate(RdotV), exponent);
return (diffuse + specular);
}
De lo contrario, el sombreador de píxeles debe calcular el valor de píxel con iluminación ambiental.
return float4(input.color * ambient, 1.f);
En la siguiente parte de este tutorial, aprenderá a gestionar mapas de sombras en una gama de hardware.