我正在尝试创建景深后期处理,但不知道从哪里开始(渲染深度图除外,我目前正在使用它)。它的所有教程要么是针对 XNA3.1,实际上不给你解释,要么是一本书的一部分。
那么,您能否详细介绍一下如何渲染 DOF 的分步过程?
这里描述了如何使用 XNA 在 Reach 配置文件中提供的“开箱即用”功能来实现它的基本近似。
一旦你了解了如何在 C# 中使用内置的东西来实现它,在 HLSL 中实现它希望会更加明显。
此外,如果您希望为 Windows Phone 7 制作游戏,您可以从哪里开始(因为 Windows Phone 7 目前不支持自定义着色器)。
首先,我们将定义一些实例级变量来保存我们需要生成外观的点点滴滴:
BasicEffect effect;
List<Matrix> projections;
List<RenderTarget2D> renderTargets;
SpriteBatch spriteBatch;
接下来,在 LoadContent() 方法中,我们将开始加载它们。从我们将用于渲染最终场景的 SpriteBatch 开始:
spriteBatch = new SpriteBatch(GraphicsDevice);
后面是 BasicEffect 的一个实例:
effect = new BasicEffect(GraphicsDevice);
effect.EnableDefaultLighting();
effect.DiffuseColor = Color.White.ToVector3();
effect.View = Matrix.CreateLookAt(
Vector3.Backward * 9 + Vector3.Up * 9,
Vector3.Zero,
Vector3.Up);
effect.World = Matrix.Identity;
effect.Texture = Content.Load<Texture2D>("block");
effect.TextureEnabled = true;
effect.EnableDefaultLighting();
基本效果如何配置的细节在这里并不重要。仅仅是我们有一个效果来渲染。
接下来我们将需要一些投影矩阵:
projections = new List<Matrix>() {
Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(60f),
GraphicsDevice.Viewport.AspectRatio,
9f,
200f),
Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(60f),
GraphicsDevice.Viewport.AspectRatio,
7f,
10f),
Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(60f),
GraphicsDevice.Viewport.AspectRatio,
0.2f,
8f)};
如果您检查每个投影的最后两个参数,您会注意到我们在这里有效地做的是将世界分割成“块”,每个块覆盖与相机不同的距离范围。
例如,超过 9 个单位的所有内容,距离相机 7 和 10 个单位之间的任何内容,最后是接近 8 个单位的任何内容。
(您需要根据场景调整这些距离。请注意少量重叠)
接下来我们将创建一些渲染目标:
var pp = GraphicsDevice.PresentationParameters;
renderTargets = new List<RenderTarget2D>()
{
new RenderTarget2D(GraphicsDevice,
GraphicsDevice.Viewport.Width / 8,
GraphicsDevice.Viewport.Height / 8,
false, pp.BackBufferFormat, pp.DepthStencilFormat),
new RenderTarget2D(GraphicsDevice,
GraphicsDevice.Viewport.Width / 4,
GraphicsDevice.Viewport.Height / 4,
false, pp.BackBufferFormat, pp.DepthStencilFormat),
new RenderTarget2D(GraphicsDevice,
GraphicsDevice.Viewport.Width,
GraphicsDevice.Viewport.Height,
false, pp.BackBufferFormat, pp.DepthStencilFormat),
};
每个渲染目标对应于前面提到的“块”。为了实现真正简单的模糊效果,每个渲染目标都设置为不同的分辨率,“最远”的块是低分辨率,最近的块是高分辨率。
跳转到 Draw() 方法,我们可以渲染我们的场景块:(确保不要在每个块中渲染背景)
effect.Projection = projections[0];
GraphicsDevice.SetRenderTarget(renderTargets[0]);
GraphicsDevice.Clear(Color.Transparent);
// render scene here
effect.Projection = projections[1];
GraphicsDevice.SetRenderTarget(renderTargets[1]);
GraphicsDevice.Clear(Color.Transparent);
// render scene here
effect.Projection = projections[2];
GraphicsDevice.SetRenderTarget(renderTargets[2]);
GraphicsDevice.Clear(Color.Transparent);
// render scene here
GraphicsDevice.SetRenderTarget(null);
所以现在我们已经有了我们的场景,被距离分解和模糊,剩下的就是将它重新组合在一起以获得我们的最终图像。
第一步,渲染(很棒的)背景:
GraphicsDevice.Clear(Color.CornflowerBlue);
接下来渲染每个块,从更远到最近:
spriteBatch.Begin(
SpriteSortMode.Deferred,
BlendState.AlphaBlend,
SamplerState.AnisotropicClamp,
null, null);
spriteBatch.Draw(renderTargets[0], GraphicsDevice.Viewport.Bounds, Color.White);
spriteBatch.Draw(renderTargets[1], GraphicsDevice.Viewport.Bounds, Color.White);
spriteBatch.Draw(renderTargets[2], GraphicsDevice.Viewport.Bounds, Color.White);
spriteBatch.End();
还有中提琴!尽管在众所周知的边缘有点粗糙,但我们有一个景深的近似值。
现在,如果您打算保持在 Reach 配置文件的范围内,您可以通过以多种分辨率渲染每个块并使用 Additive BlendState 之类的东西将生成的图像组合在一起来改善模糊效果。
另一方面,如果您计划在 HiDef 配置文件中编写自定义着色器,则概念大致相同,只是执行方法发生了变化。
例如,将低分辨率渲染换成更真实的高斯风格模糊……或者……放弃粗粒度的块概念,转向基于深度图的相对细粒度的模糊方法。