En mi pregunta anterior , pregunté si es posible realizar texturas proyectivas con iluminación diferida. Ahora (más de medio año después) tengo un problema con mi implementación de lo mismo. Estoy tratando de aplicar esta técnica en paso ligero. (Mi proyector no afecta al albedo). Tengo este proyector Ver una matriz de proyección:
Matrix projection = Matrix.CreateOrthographicOffCenter(-halfWidth * Scale, halfWidth * Scale, -halfHeight * Scale, halfHeight * Scale, 1, 100000);
Matrix view = Matrix.CreateLookAt(Position, Target, Vector3.Up);
Donde halfWidth
y halfHeight
es la mitad del ancho y la altura de la textura, Position
es la posición target
del proyector y es el objetivo del proyector. Esto parece estar bien. Estoy dibujando quad de pantalla completa con este sombreador:
float4x4 InvViewProjection;
texture2D DepthTexture;
texture2D NormalTexture;
texture2D ProjectorTexture;
float4x4 ProjectorViewProjection;
sampler2D depthSampler = sampler_state {
texture = <DepthTexture>;
minfilter = point;
magfilter = point;
mipfilter = point;
};
sampler2D normalSampler = sampler_state {
texture = <NormalTexture>;
minfilter = point;
magfilter = point;
mipfilter = point;
};
sampler2D projectorSampler = sampler_state {
texture = <ProjectorTexture>;
AddressU = Clamp;
AddressV = Clamp;
};
float viewportWidth;
float viewportHeight;
// Calculate the 2D screen position of a 3D position
float2 postProjToScreen(float4 position) {
float2 screenPos = position.xy / position.w;
return 0.5f * (float2(screenPos.x, -screenPos.y) + 1);
}
// Calculate the size of one half of a pixel, to convert
// between texels and pixels
float2 halfPixel() {
return 0.5f / float2(viewportWidth, viewportHeight);
}
struct VertexShaderInput {
float4 Position : POSITION0;
};
struct VertexShaderOutput {
float4 Position :POSITION0;
float4 PositionCopy : TEXCOORD1;
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input) {
VertexShaderOutput output;
output.Position = input.Position;
output.PositionCopy=output.Position;
return output;
}
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 {
float2 texCoord =postProjToScreen(input.PositionCopy) + halfPixel();
// Extract the depth for this pixel from the depth map
float4 depth = tex2D(depthSampler, texCoord);
//return float4(depth.r,0,0,1);
// Recreate the position with the UV coordinates and depth value
float4 position;
position.x = texCoord.x * 2 - 1;
position.y = (1 - texCoord.y) * 2 - 1;
position.z = depth.r;
position.w = 1.0f;
// Transform position from screen space to world space
position = mul(position, InvViewProjection);
position.xyz /= position.w;
//compute projection
float3 projection=tex2D(projectorSampler,postProjToScreen(mul(position,ProjectorViewProjection)) + halfPixel());
return float4(projection,1);
}
En la primera parte del sombreador de píxeles se recupera la posición del G-buffer (este código lo estoy usando en otros sombreadores sin ningún problema) y luego se transforma en el espacio de proyección de la vista del proyector. El problema es que la proyección no aparece. Aquí hay una imagen de mi situación:
Las líneas verdes son el proyector renderizado. ¿Dónde está escondido mi error? Estoy usando XNA 4. Gracias por los consejos y perdón por mi inglés.
EDITAR:
El sombreador anterior funciona pero la proyección era demasiado pequeña. Cuando cambié la propiedad Escala a un valor grande (por ejemplo, 100), aparece la proyección. Pero cuando la cámara se mueve hacia la proyección, la proyección se expande, como se puede ver en este video de YouTube .