DirectX newb - 在广告牌上具有深度的多重采样Texture2D

时间:2014-06-17 17:21:48

标签: directx-11 texture2d

这是我的要求:使用DirectX11(通过SlimDX)我必须下载一系列椎骨并使用它们来创建一个县边界地图的Texture2D。然后我需要对州边界做同样的事情,并将它们绘制在县边界上。然后,我需要采用该纹理并从中创建2个不同的纹理,每个纹理包含独特的雷达数据。然后我想拍摄这些纹理并显示它们,以便用户可以并排查看基本反射率和基本速度。用户应该可以放大和缩小地图的特定区域。

这就是我的工作:我正在创建我的Texture2D,而不是在广告牌上进行多重采样或深度,该广告牌显示在2个单独的视图中。但它看起来很块,如果你放大太远,一些边界开始消失。

以下是我的问题:

1)我不能为我的生活获得任何多重采样质量。我正在使用ATI Radeon HD 5750,所以我知道它必须能够做到,但我尝试过的格式都没有支持质量大于0的格式。

2)我不确定是否需要使用深度模板,因为我将所有这些纹理都绘制在一起。我希望不是因为当我尝试时,ShaderResourceView说,“Puny Human!你不能在ShaderResourceView中使用深度模板格式!Bwa哈哈!” (我正在装饰)

我愿意打赌,如果我只是将基元直接绘制到世界空间中,很多这些问题都会得到解决,但是当我这样做时,渲染时间太长,因为有很多行要渲染。是否有一种方法可以减少所需的时间?

这是我上一个工作版的代码:

using SlimDX;
using SlimDX.D3DCompiler;
using SlimDX.Direct3D11;
using SlimDX.DXGI;
using SlimDX.Windows;
using System;
using System.Windows.Forms;
using System.Collections.Generic;

using Device = SlimDX.Direct3D11.Device;
using Buffer = SlimDX.Direct3D11.Buffer;
using Resource = SlimDX.Direct3D11.Resource;
using Format = SlimDX.DXGI.Format;
using MapFlags = SlimDX.Direct3D11.MapFlags;



namespace Radar
{
abstract public class Renderer
{
    protected static Device mDevice = null;
    protected SwapChain mSwapChain = null;
    protected RenderTargetView RenderTarget { get; set; }

    public static Device Device { get { return mDevice; } protected set { mDevice = value; } }
    public static DeviceContext Context { get { return Device.ImmediateContext; } }
    protected SwapChain SwapChain { get { return mSwapChain; } set { mSwapChain = value; } }

    public Texture2D Texture { get; protected set; }
    protected int RenderTargetIndex { get; set; }
    protected VertexShader VertexShader { get; set; }
    protected PixelShader PixelShader { get; set; }
    protected Buffer VertexBuffer { get; set; }
    protected Buffer MatrixBuffer { get; set; }
    protected InputLayout Layout { get; set; }
    protected ShaderSignature InputSignature { get; set; }
    protected SamplerState SamplerState { get; set; }

    protected Color4 mClearColor = new Color4(0.117f, 0.117f, 0.117f);
    protected Color4 ClearColor { get { return mClearColor; } }



    protected void CreateDevice(IntPtr inHandle)
    {
        if (Device == null)
            Device = new Device(DriverType.Hardware, DeviceCreationFlags.Debug);

        SwapChainDescription chainDescription = new SwapChainDescription()
        {
            BufferCount = 2,
            Usage = Usage.RenderTargetOutput,
            OutputHandle = inHandle,
            IsWindowed = true,
            ModeDescription = new ModeDescription(0, 0, new Rational(60, 1), Format.R8G8B8A8_UNorm),
            SampleDescription = new SampleDescription(8, 0),
            Flags = SwapChainFlags.AllowModeSwitch,
            SwapEffect = SwapEffect.Discard
        };

        SwapChain = new SwapChain(Device.Factory, Device, chainDescription);
    }



    protected void SetupViewport(int inWidth, int inHeight)
    {
        Viewport viewport = new Viewport(0.0f, 0.0f, inWidth, inHeight);
        Context.OutputMerger.SetTargets(RenderTarget);
        Context.Rasterizer.SetViewports(viewport);
    }



    public void Clear()
    {
        Context.ClearRenderTargetView(RenderTarget, ClearColor);
    }



    public void Present()
    {
        SwapChain.Present(0, PresentFlags.None);
    }



    // I do this to ensure the texture is correct
    public void Save()
    {
        Texture2D.ToFile(Context, Texture, ImageFileFormat.Png, "test.png");
    }



    public virtual void Dispose()
    {
        Texture.Dispose();
        SamplerState.Dispose();
        VertexBuffer.Dispose();
        Layout.Dispose();
        InputSignature.Dispose();
        VertexShader.Dispose();
        PixelShader.Dispose();
        RenderTarget.Dispose();
        SwapChain.Dispose();
        Device.Dispose();
    }



    public class RenderTargetParameters
    {
        public int Width { get; set; }
        public int Height { get; set; }
        public IntPtr Handle { get; set; }


        public RenderTargetParameters()
        {
            Width = 0;
            Height = 0;
            Handle = new IntPtr(0);
        }
    }



    public abstract void Render(int inWidth, int inHeight, int inCount = -1);
    public abstract void Prepare(string inShaderName = null);
}



public class TextureRenderer : Renderer
{
    public TextureRenderer(RenderTargetParameters inParms)
    {
        CreateDevice(inParms.Handle);

        Texture2DDescription description = new Texture2DDescription()
        {
            Width = inParms.Width,
            Height = inParms.Height,
            MipLevels = 1,
            ArraySize = 1,
            Format = Format.R8G8B8A8_UNorm,
            SampleDescription = new SampleDescription(8, 0),
            Usage = ResourceUsage.Default,
            BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,
            CpuAccessFlags = CpuAccessFlags.None,
            OptionFlags = ResourceOptionFlags.None
        };

        Texture = new Texture2D(Device, description);

        RenderTarget = new RenderTargetView(Device, Texture);

        SetupViewport(inParms.Width, inParms.Height);

        using (ShaderBytecode bytecode = ShaderBytecode.CompileFromFile("ShaderFX.fx", "VShader", "vs_5_0", ShaderFlags.Debug, EffectFlags.None))
        {
            InputSignature = ShaderSignature.GetInputSignature(bytecode);
            VertexShader = new VertexShader(Device, bytecode);
        }

        // load and compile the pixel shader

        InputElement[] elements = new[] { new InputElement("POSITION", 0, Format.R32G32B32_Float, 0) };

        Layout = new InputLayout(Device, InputSignature, elements);

        Context.InputAssembler.InputLayout = Layout;
        Context.InputAssembler.PrimitiveTopology = PrimitiveTopology.LineStrip;

        Context.VertexShader.Set(VertexShader);
    }



    public override void Prepare(string inShaderName)
    {
        using (ShaderBytecode bytecode = ShaderBytecode.CompileFromFile("ShaderFX.fx", inShaderName, "ps_4_0", ShaderFlags.Debug, EffectFlags.None))
            PixelShader = new PixelShader(Device, bytecode);

        Context.PixelShader.Set(PixelShader);
    }



    public void SetVertices(DataStream inShape)
    {
        VertexBuffer = new Buffer(Device, inShape, (int)inShape.Length, ResourceUsage.Default, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);

        Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(VertexBuffer, 12, 0));
    }



    public override void Render(int inWidth, int inHeight, int inCount = -1)
    {
        Context.Draw(inCount, 0);
    }
}



public class RuntimeRenderer : Renderer
{
    private ShaderResourceView ResourceView { get; set; }



    public RuntimeRenderer(RenderTargetParameters inParms, ref TextureRenderer inTextureRenderer)
    {
        CreateDevice(inParms.Handle);

        Texture = inTextureRenderer.Texture;

        using (Resource resource = Resource.FromSwapChain<Texture2D>(SwapChain, 0))
            RenderTarget = new RenderTargetView(Device, resource);

        //using (var factory = SwapChain.GetParent<Factory>())
            //factory.SetWindowAssociation(inParms.Handle, WindowAssociationFlags.IgnoreAltEnter);
    }



    public void Resize()
    {
        RenderTarget.Dispose();

        SwapChain.ResizeBuffers(2, 0, 0, Format.R8G8B8A8_UNorm, SwapChainFlags.AllowModeSwitch);
        using (SlimDX.Direct3D11.Resource resource = Resource.FromSwapChain<Texture2D>(SwapChain, 0))
            RenderTarget = new RenderTargetView(Device, resource);
    }



    public override void Prepare(string inShaderName)
    {
        using (ShaderBytecode bytecode = ShaderBytecode.CompileFromFile("ShaderFX.fx", "TextureVertexShader", "vs_4_0", ShaderFlags.EnableStrictness, EffectFlags.None))
        {
            InputSignature = ShaderSignature.GetInputSignature(bytecode);
            VertexShader = new VertexShader(Device, bytecode);
        }

        using (ShaderBytecode bytecode = ShaderBytecode.CompileFromFile("ShaderFX.fx", "TexturePixelShader", "ps_4_0", ShaderFlags.EnableStrictness, EffectFlags.None))
            PixelShader = new PixelShader(Device, bytecode);

        InputElement[] elements = new InputElement[2];

        elements[0].SemanticName = "POSITION";
        elements[0].SemanticIndex = 0;
        elements[0].Format = Format.R32G32B32_Float;
        elements[0].Slot = 0;
        elements[0].AlignedByteOffset = 0;
        elements[0].Classification = InputClassification.PerVertexData;
        elements[0].InstanceDataStepRate = 0;

        elements[1].SemanticName = "TEXCOORD";
        elements[1].SemanticIndex = 0;
        elements[1].Format = Format.R32G32_Float;
        elements[1].Slot = 0;
        elements[1].AlignedByteOffset = InputElement.AppendAligned;
        elements[1].Classification = InputClassification.PerVertexData;
        elements[1].InstanceDataStepRate = 0;

        Layout = new InputLayout(Device, InputSignature, elements);

        BufferDescription matrixDescription = new BufferDescription()
        {
            Usage = ResourceUsage.Dynamic,
            SizeInBytes = sizeof(float) * 16 * 4,
            BindFlags = BindFlags.ConstantBuffer,
            CpuAccessFlags = CpuAccessFlags.Write,
            OptionFlags = ResourceOptionFlags.None,
            StructureByteStride = 0
        };

        MatrixBuffer = new Buffer(Device, matrixDescription);

        ShaderResourceViewDescription resourceViewDescription = new ShaderResourceViewDescription()
        {
            Format = Texture.Description.Format,
            Dimension = ShaderResourceViewDimension.Texture2DMultisampled,
            MipLevels = Texture.Description.MipLevels,
            MostDetailedMip = 0,
        };

        //Texture2D.ToFile(Context, Texture, ImageFileFormat.Png, "test.png");

        ResourceView = new ShaderResourceView(Device, Texture, resourceViewDescription);

        SamplerDescription samplerDescription = new SamplerDescription()
        {
            Filter = Filter.MinMagMipLinear,
            AddressU = TextureAddressMode.Wrap,
            AddressV = TextureAddressMode.Wrap,
            AddressW = TextureAddressMode.Wrap,
            MipLodBias = 0.0f,
            MaximumAnisotropy = 1,
            ComparisonFunction = Comparison.Always,
            BorderColor = ClearColor,
            MinimumLod = 0,
            MaximumLod = 99999
        };

        SamplerState = SamplerState.FromDescription(Device, samplerDescription);
    }



    public override void Render(int inWidth, int inHeight, int inCount = -1)
    {
        Clear();
        Billboard.SetVerteces(Device, Texture.Description.Width, Texture.Description.Height, inWidth, inHeight);

        SetupViewport(inWidth, inHeight);

        Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(Billboard.Verteces, 20, 0));
        Context.InputAssembler.SetIndexBuffer(Billboard.Indeces, Format.R32_UInt, 0);
        Context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleStrip;

        Context.InputAssembler.InputLayout = Layout;
        Context.VertexShader.Set(VertexShader);
        Context.PixelShader.Set(PixelShader);
        Context.PixelShader.SetSampler(SamplerState, 0);

        Context.VertexShader.SetConstantBuffer(MatrixBuffer, 0);
        Context.PixelShader.SetConstantBuffer(MatrixBuffer, 0);
        Context.PixelShader.SetShaderResource(ResourceView, 0);

        Context.DrawIndexed(4, 0, 0);
        Present();
    }
}
}

如果我将纹理保存到文件中,图像1就是它的样子(我将它缩小了很多,以便它适合我的帖子)。

图像2是在大约中等距离观看时在运行时的样子(不理想,但不是那么糟糕)

图像3是放大到县里的样子(Eww!Blocky and fuzzy!)

图像4是缩小的样子(所有边框都去了哪里?)

enter image description here enter image description here enter image description here enter image description here

1 个答案:

答案 0 :(得分:0)

关于多重采样,通常可以将质量保持为0,质量设置通常是不同的“子像素”(又名:样本)模式。 0一般都很好。

如果使用多重采样渲染到纹理,还需要解析资源,多个采样纹理在着色器中绑定为Texture2DMS(而不是Texture2D)。

为此,您需要创建第二个纹理(具有相同的格式/大小),但只需要一个样本。

然后,在完成渲染多重采样纹理后,您需要执行以下调用:

deviceContext.ResolveSubresource(multisampledtexture, 0, nonmultisampledtexture,
                0, format);

然后,您可以在后续传递中使用非多重采样纹理的ShaderView。

从我看到你不应该使用深度模板,只要确保你按正确的顺序绘制元素。

关于格式,这是正常的,因为深度有点“特殊”,您需要为资源/视图传递不同的格式。如果你想使用D24_UNorm_S8_UInt(我说的最常见的格式),你需要设置以下内容:

  • 在纹理描述中,格式必须为Format.R24_UNorm_X8_Typeless
  • 在Depth Stencil视图描述中,Format.D24_UNorm_S8_UInt
  • 在着色器视图描述中,Format.R24_UNorm_X8_Typeless

这将允许您构建一个可以读取的深度模板(如果您不需要读取深度缓冲区,只需忽略着色器视图并直接使用深度格式)。

此外,您可以使用mipmap提高质量(这会有很大帮助,特别是在缩小时)。

为此,请在纹理描述中设置以下选项(确保此纹理不是多重采样)

texBufferDesc.OptionFlags |= ResourceOptionFlags.GenerateMipMaps;
texBufferDesc.MipLevels = 0; //0 means "all"

完成渲染后,请致电:

context.GenerateMips

使用刚刚渲染的纹理的着色器资源视图。

关于直接在后面绘制线条,这绝对是可能的,并且肯定会给你最好的质量。

不确定你渲染了多少行,但它看起来并不像一张合理的现代卡片会挣扎。而一些剔除可以很容易地帮助丢弃屏幕外的线条,这样它们就不会被画出来。

你也可以做一些“混合”(缩小时使用纹理,放大时渲染线条的子集),这也不难设置。