正如主体所暗示的那样,当我在其他渲染目标上使用深度缓冲时,我正在失去精度或者没有足够的精度。
目前,我的渲染是这样的:
我不确定,或者更确切地说,我知道我做错了什么但不知道在哪里或如何。
我希望能够在灯光着色器内执行此操作:
但由于精度损失或其他一些问题,我无法与小于0.01的值进行比较。
某些地图的平铺指数范围为0.00001f-1.0f,因此能够在某些地块之间绘制一些灯光非常有用,例如
我能够通过一些rgba-float编码/解码获得更高的精度,但这是超级重的,在较低的设置中它只会混淆一切并且灯光不能以正确的顺序绘制。
这是场景绘制代码:
RenderTarget2D colorRT;
RenderTarget2D depthRT;
RenderTarget2D shadowRT;
RenderTarget2D finalRT;
protected void LoadContent()
{
colorRT = new RenderTarget2D(GraphicsDevice, width, height);
finalRT = new RenderTarget2D(GraphicsDevice, width, height);
depthRT = new RenderTarget2D(GraphicsDevice, width, height, false, SurfaceFormat.Single, DepthFormat.Depth24);
shadowRT = new RenderTarget2D(GraphicsDevice, width, height, false, SurfaceFormat.Single, DepthFormat.None);
}
protected override void Draw()
{
DrawColorMap();
DrawDepthMap();
GenerateShadowMap();
DrawCombinedMaps();
spriteBatch.GraphicsDevice.SetRenderTarget(null);
spriteBatch.GraphicsDevice.Clear(Color.Transparent);
//draw finalRT
}
private void DrawColorMap()
{
spriteBatch.GraphicsDevice.SetRenderTarget(colorRT);
spriteBatch.GraphicsDevice.Clear(Color.Transparent);
spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.None, RasterizerState.CullCounterClockwise, null, map.camera.GetTransformation() * Resolution.getTransformationMatrix());
map.Draw(spriteBatch, mapsTex, scroll, map.camera.GetTransformation());
spriteBatch.End();
}
private void DrawDepthMap()
{
GraphicsDevice.SetRenderTarget(depthRT);
GraphicsDevice.Clear(Color.White);
greyEffect.Parameters["World"].SetValue(map.camera.GetTransformation() * Resolution.getTransformationMatrix());
spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.Opaque, SamplerState.LinearClamp, DepthStencilState.None, RasterizerState.CullCounterClockwise, greyEffect);
map.Draw(spriteBatch, mapsTex, scroll, map.camera.GetTransformation());
spriteBatch.End();
}
private Texture2D GenerateShadowMap()
{
GraphicsDevice.SetRenderTarget(shadowRT);
GraphicsDevice.Clear(new Color(0, 0, 0, 0));
GraphicsDevice.BlendState = BlendState.AlphaBlend;
GraphicsDevice.DepthStencilState = DepthStencilState.None;
foreach (var light in map.lights)
{
if (light != null)
{
if (!light.IsEnabled) continue;
Vertices[0].Position = new Vector3(map.camera.WorldToScreen2(new Vector2(light.Location.X, light.Location.Y) - new Vector2(scroll.X, scroll.Y), map.camera.GetTransformation()), light.Location.Z);
Vertices[1].Position = new Vector3(map.camera.WorldToScreen2(new Vector2(light.Location.X + light.LightDecay, light.Location.Y) - new Vector2(scroll.X, scroll.Y), map.camera.GetTransformation()), light.Location.Z);
Vertices[2].Position = new Vector3(map.camera.WorldToScreen2(new Vector2(light.Location.X, light.Location.Y + light.LightDecay) - new Vector2(scroll.X, scroll.Y), map.camera.GetTransformation()), light.Location.Z);
Vertices[3].Position = new Vector3(map.camera.WorldToScreen2(new Vector2(light.Location.X + light.LightDecay, light.Location.Y + light.LightDecay) - new Vector2(scroll.X, scroll.Y), map.camera.GetTransformation()), light.Location.Z);
VertexBuffer.SetData(Vertices);
spriteBatch.GraphicsDevice.SetVertexBuffer(VertexBuffer);
_lightEffect.CurrentTechnique = _lightEffectTechniquePointLight;
_lightEffect.Parameters["DepthMap"].SetValue(depthRT);
_lightEffect.CurrentTechnique.Passes[0].Apply();
// Add Belding (Black background)
spriteBatch.GraphicsDevice.BlendState = BlendBlack;
spriteBatch.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, Vertices, 0, 2);
}
return shadowRT;
}
private void DrawCombinedMaps()
{
GraphicsDevice.SetRenderTarget(finalRT);
GraphicsDevice.Clear(Color.LightSkyBlue);
_lightCombinedEffectParamColorMap.SetValue(colorRT);
_lightCombinedEffectParamShadowMap.SetValue(shadowRT);
spriteBatch.Begin(0, BlendState.Opaque, null, DepthStencilState.None, RasterizerState.CullCounterClockwise, _lightCombinedEffect);
spriteBatch.Draw(colorRT, new Rectangle(0, 0, viewPortStored.Width, viewPortStored.Height), Color.White);
spriteBatch.End();
}
Depth buffer shader&照明着色器:
/////////////////////////////////////////DEPTH BUFFER SHADER/////////////////////////////////////////
float2 offset;
float scale;
float2 screenSize;
float4x4 World;
struct VertexShaderInput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
float2 Depth : TEXCOORD1;
};
struct PixelShaderOutput
{
half4 Depth : COLOR0;
};
VertexShaderOutput MyVertexShader(VertexShaderInput input)
{
VertexShaderOutput output;
// Half pixel offset for correct texel centering.
input.Position.xy -= 0.5;
// Viewport adjustment.
input.Position.xy = input.Position.xy / screenSize;
input.Position.xy -= offset;
input.Position.xy *= float2(2, -2);
input.Position.xy -= float2(1, -1);
output.Position = input.Position;
output.TexCoord = input.TexCoord;
output.Depth.x = output.Position.z;
output.Depth.y = output.Position.w;
return output;
}
PixelShaderOutput PointLightShader(VertexShaderOutput input)
{
PixelShaderOutput output;
output.Depth = input.Depth.x / input.Depth.y;
return output;
}
/////////////////////////////////////////END DEPTH BUFFER SHADER/////////////////////////////////////////
/////////////////////////////////////////LIGHTING SHADER/////////////////////////////////////////
float screenWidth;
float screenHeight;
float4 ambientColor;
float lightStrength;
float lightDecay;
float3 lightPosition;
float4 lightColor;
float lightRadius;
float lightCenterStrenght;
float3 coneDirection;
float coneAngle;
float coneDecay;
float scale;
float2 offset;
Texture DepthMap;
sampler DepthMapSampler = sampler_state {
texture = <DepthMap>;
AddressU = CLAMP;
AddressV = CLAMP;
};
struct VertexShaderInput
{
float4 Position : POSITION0;
float4 TexCoord : TEXCOORD0;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 TexCoord : TEXCOORD0;
float4 ScreenPosition : TEXCOORD1;
};
VertexShaderOutput MyVertexShader(VertexShaderInput input)
{
VertexShaderOutput output;
// Half pixel offset for correct texel centering.
input.Position.xy -= 0.5;
// Viewport adjustment.
input.Position.xy = input.Position.xy / float2(screenWidth, screenHeight);
input.Position.xy -= offset;
output.ScreenPosition = input.Position;
input.Position.xy *= float2(2, -2);
input.Position.xy -= float2(1, -1);
output.Position = input.Position;
output.TexCoord = (lightDecay * 2 * input.TexCoord) / scale;
//Output.Color = color;
return output;
}
float4 PointLightShader(VertexShaderOutput input) : COLOR0
{
//float2 texCoord = 0.5f * (float2(input.ScreenPosition.x,-input.ScreenPosition.y) + 1);
//texCoord *= lightDecay * 2;
////allign texels to pixels
//texCoord -= 0.5;
//input.ScreenPosition.xy /= input.ScreenPosition.w;
float depth = tex2D(DepthMapSampler, input.ScreenPosition.xy).r;
clip(abs(depth - lightPosition.z) < 0.05 ? 1 : -1);
//float4 position;
//position.xy = input.ScreenPosition.xy;
//position.z = depth;
//position.w = 1;
//position /= position.w;
float coneAttenuation;
float4 shading;
float2 pixelPosition = input.TexCoord.xy;
float2 lightPos = float2(lightDecay, lightDecay) * scale;
float2 lightDirection = (pixelPosition - lightPos) / scale;
//THIS ADDS THE CIRCLE IN THE CENTER OF THE LIGHT.
float distance;
if (lightCenterStrenght > 0)
distance = (1 / length(pixelPosition - lightPos)) * lightStrength;
else
distance = lightStrength;
coneAttenuation = saturate(1.0f - length(lightDirection) / lightDecay);
shading = distance * coneAttenuation * lightColor;
//if (depth >= 1 * 256)
//return float4(255, 255, 255, coneAttenuation * lightStrength);
/*
if (realDepth >= 1)
return float4(255, 255, 255, coneAttenuation * lightStrength);*/
return float4(shading.rgb, coneAttenuation * lightStrength);
}
float4 SpotLightShader2(float2 TexCoord : TEXCOORD0, float2 screenPos : TEXCOORD1) : COLOR0
{
float4 depth = tex2D(DepthMapSampler, screenPos);
float realDepth = 0;
float3 shading = float3(0, 0, 0);
float coneAttenuation;
float lightDepth = lightPosition.z;
if (realDepth < lightDepth)
{
float2 pixelPosition = TexCoord;
float2 lightVector = normalize((pixelPosition - float2(lightDecay, lightDecay) * scale) / scale);
// cosine of the angle between spotdirection and lightvector
float SdL = dot(coneDirection, -lightVector);
if (SdL > coneAngle)
{
float3 lightPos = float3(lightPosition.x, lightPosition.y, lightPosition.z);
float2 lightVector = (pixelPosition - float2(lightDecay, lightDecay) * scale) / scale;
lightVector = normalize(lightVector);
float3 coneDirectionTemp = coneDirection;
//coneDirectionTemp.z = 50.0f;
float spotIntensity = pow(abs(SdL), coneDecay);
float2 lightDirection = (pixelPosition - float2(lightDecay, lightDecay) * scale) / scale;
float3 halfVec = float3(0, 0, 1);
float amount = max(dot(1, lightVector), 0);
coneAttenuation = saturate(1.0f - length(lightDirection) / lightDecay);
float2 reflect = normalize(2 * amount * 1 - lightVector);
float2 r = normalize(2 * dot(lightVector, 1) * 1 - lightVector);
float2 v = normalize(mul(normalize(coneDirectionTemp), 1));
float dotProduct = dot(r, v);
//float4 specular = light.specPower * light.specularColor * max(pow(dotProduct, 10), 0) * length(inColor);
float specular = min(pow(saturate(dot(reflect, halfVec)), 10), 1);
shading = lightColor * lightStrength;
shading += specular * 1;
shading += amount * 0.5;
shading *= coneAttenuation * spotIntensity;
}
}
else
shading = 0;
return float4(shading.r, shading.g, shading.b, coneAttenuation * lightStrength);
}
/////////////////////////////////////////END LIGHTING SHADER/////////////////////////////////////////
相机代码:
public class Camera
{
public Matrix Transform;
public Matrix PositionTransform = Matrix.CreateTranslation(new Vector3(0, 0, 0f));
public Matrix GetTransformation()
{
Transform = Matrix.CreateScale(new Vector3(zoom, zoom, 1)) * PositionTransform;
return Transform;
}
public Vector2 WorldToScreen(Vector2 worldPosition, Matrix m)
{
return Vector2.Transform(worldPosition, Resolution.getTransformationMatrix());
}
public Vector2 WorldToScreen2(Vector2 worldPosition, Matrix m)
{
return Vector2.Transform(worldPosition, m * Resolution.getTransformationMatrix());
}
}
Offset只是一个用作滚动的Vector2。
如果缺少一些重要的代码来帮助我,请告诉我。
总而言之,如果甚至可以将深度贴图值与灯光的深度值进行比较,我希望能够获得与8个小数点一样多的精度。 如果没有,那么在我想要的任何两块瓷砖之间设置灯光的最佳做法是什么?
提前谢谢
答案 0 :(得分:0)
编辑:其实我觉得我看到了这个问题。剪辑操作的容差大于为场景中的对象发布的深度差异。
如果你在考虑,“我的z-buffer只有24位,我看不到z-fighting,那为什么我的32位深度缓冲区?”
答案可能是,因为z缓冲区不是线性的,它们的精度比远处更接近。
请记住,并非所有平台都支持SurfaceFormat.Single,因此您可能希望避免编写依赖它的延迟引擎。
两种通用解决方案是......