这是我的要求:使用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是缩小的样子(所有边框都去了哪里?)
答案 0 :(得分:0)
关于多重采样,通常可以将质量保持为0,质量设置通常是不同的“子像素”(又名:样本)模式。 0一般都很好。
如果使用多重采样渲染到纹理,还需要解析资源,多个采样纹理在着色器中绑定为Texture2DMS(而不是Texture2D)。
为此,您需要创建第二个纹理(具有相同的格式/大小),但只需要一个样本。
然后,在完成渲染多重采样纹理后,您需要执行以下调用:
deviceContext.ResolveSubresource(multisampledtexture, 0, nonmultisampledtexture,
0, format);
然后,您可以在后续传递中使用非多重采样纹理的ShaderView。
从我看到你不应该使用深度模板,只要确保你按正确的顺序绘制元素。
关于格式,这是正常的,因为深度有点“特殊”,您需要为资源/视图传递不同的格式。如果你想使用D24_UNorm_S8_UInt(我说的最常见的格式),你需要设置以下内容:
这将允许您构建一个可以读取的深度模板(如果您不需要读取深度缓冲区,只需忽略着色器视图并直接使用深度格式)。
此外,您可以使用mipmap提高质量(这会有很大帮助,特别是在缩小时)。
为此,请在纹理描述中设置以下选项(确保此纹理不是多重采样)
texBufferDesc.OptionFlags |= ResourceOptionFlags.GenerateMipMaps;
texBufferDesc.MipLevels = 0; //0 means "all"
完成渲染后,请致电:
context.GenerateMips
使用刚刚渲染的纹理的着色器资源视图。
关于直接在后面绘制线条,这绝对是可能的,并且肯定会给你最好的质量。
不确定你渲染了多少行,但它看起来并不像一张合理的现代卡片会挣扎。而一些剔除可以很容易地帮助丢弃屏幕外的线条,这样它们就不会被画出来。
你也可以做一些“混合”(缩小时使用纹理,放大时渲染线条的子集),这也不难设置。