C#/XNA/HLSL - 如何创建景深

本文关键字:创建 何创建 XNA HLSL | 更新日期: 2023-09-27 18:30:16

我正在尝试创建一个景深后期处理,但不知道从哪里开始(除了我目前所在的渲染深度图)。它的所有教程要么是针对XNA3.1的,实际上并没有给你解释,要么是一本书的一部分。

那么,您能否详细介绍一下如何呈现自由度?

C#/XNA/HLSL - 如何创建景深

以下是有关如何使用 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 配置文件中编写自定义着色器,则概念大致相同,只是执行方法发生了变化。

例如,将低分辨率渲染换成更真实的高斯风格模糊......或。。。抛弃了块的路线粒度概念,转向基于深度图的相对细粒度的模糊方法。