尝试在Windows.Forms.Panels上渲染纹理 [英] Trying to render a texture on Windows.Forms.Panels

查看:104
本文介绍了尝试在Windows.Forms.Panels上渲染纹理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用SlimDX.Windows.RenderForm动态创建美国地图的纹理,将该纹理复制到其他2个纹理,然后在每个纹理上绘制唯一的雷达数据.然后,我将把这2个纹理传递到各自的Windows.Forms.Panel上.这样,用户将能够例如在2个面板中并排查看基本反射率和基本速度.现在,我已成功将我的美国地图生成到纹理上.但是当我尝试将其渲染到面板上时,我会变成黑色(顺便说一句,我的透明色是柔和的灰色,而不是黑色).

Using a SlimDX.Windows.RenderForm, I want to dynamically create a texture of a map of the US, copy that texture to 2 other textures, then draw unique radar data onto each texture. Then I will pass those 2 textures to each be drawn over its own Windows.Forms.Panel. This way, the user will be able to, for example, view base reflectivity and base velocity side by side in the 2 panels. Right now, I've successfully generated my map of the US onto a texture. But when I try to render it to the panels, I get black (and btw, my clear color is a soft grey, not black).

经过一番实验之后,我修改了代码以获取TextureRenderer使用的Texture,将其转换为流,并在RuntimeRenderer的设备下创建一个新的Texture.现在我有一个柔软的灰色正方形,里面有一个黄色正方形(与我用于顶点的-0.9,-0.9 ... 0.9,0.9兼容).我知道新的Texture是正确的,但是正方形仍然是黄色.

After some playing around, I have modified my code to take that Texture that the TextureRenderer is using, turn it to a stream, and create a new Texture under the device of the RuntimeRenderer. Now I have a soft grey square with a yellow square inside it (which is compatible with the -0.9, -0.9... 0.9, 0.9 I use for vertices). I know the new Texture is correct, but the square is still yellow.

这是我的代码:

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 Device mDevice = null;
    protected SwapChain mSwapChain = null;
    protected RenderTargetView RenderTarget { get; set; }

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

    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 void CreateDevice(IntPtr inHandle)
    {
        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(1, 0),
            Flags = SwapChainFlags.AllowModeSwitch,
            SwapEffect = SwapEffect.Discard
        };

        Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.Debug, chainDescription, out mDevice, out mSwapChain);
    }



    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, new Color4(0.117f, 0.117f, 0.117f));
    }



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



    public virtual void 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);
        }
    }



    // the inCount parameter is used in the TextureRenderer, but not in the code I've given
    public abstract void Render(int inCount = -1);
    public abstract void Prepare(string inShaderName = null);

}



// I use this to render the texture. This is working fine
public class TextureRenderer : Renderer
{
    .
    .
    .
}



public class RuntimeRenderer : Renderer
{
    public TextureRenderer TextureRenderer { get; protected set; }



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

        TextureRenderer = inTextureRenderer;

        // I save to a file to make sure the texture is what it should be (and it is)
        TextureRenderer.Save();

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

        SetupViewport(inParms.Width, inParms.Height);

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



    public override void Prepare(string inShaderName)
    {
        DataStream data = new DataStream(12 * 4, true, true);
        data.Write(new Vector3(-0.9f, -0.9f, 0.0f));
        data.Write(new Vector3(-0.9f, 0.9f, 0.0f));
        data.Write(new Vector3(0.9f, -0.9f, 0.0f));
        data.Write(new Vector3(0.9f, 0.9f, 0.0f));
        data.Position = 0;

        DataStream indices = new DataStream(sizeof(int) * 4, true, true);
        indices.Write(0);
        indices.Write(1);
        indices.Write(2);
        indices.Write(3);
        indices.Position = 0;

        VertexBuffer = new Buffer(Device, data, (int)data.Length, ResourceUsage.Default, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
        Buffer indexBuffer = new Buffer(Device, indices, (int)indices.Length, ResourceUsage.Default, BindFlags.IndexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);

        Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(VertexBuffer, 12, 0));
        Context.InputAssembler.SetIndexBuffer(indexBuffer, Format.R32_UInt, 0);
        Context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleStrip;

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

        using (ShaderBytecode bytecode = ShaderBytecode.CompileFromFile("ShaderFX.fx", "SimplePixelShader", "ps_5_0", ShaderFlags.Debug, EffectFlags.None))
            PixelShader = new PixelShader(Device, bytecode);

        InputElement[] inputEl = new InputElement[2];
        inputEl[0].SemanticName = "POSITION";
        inputEl[0].SemanticIndex = 0;
        inputEl[0].Format = Format.R32G32B32_Float;
        inputEl[0].Slot = 0;
        inputEl[0].AlignedByteOffset = 0;
        inputEl[0].Classification = InputClassification.PerVertexData;
        inputEl[0].InstanceDataStepRate = 0;

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

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

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

        MatrixBuffer = new Buffer(Device, matrixDescription);

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

        ShaderResourceView resourceView = new ShaderResourceView(Device, TextureRenderer.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 = new Color4(0, 0, 0, 0),
            MinimumLod = 0,
            MaximumLod = 99999
        };

        SamplerState = SamplerState.FromDescription(Device, samplerDescription);

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

        Vector3 position = new Vector3(0.0f, 0.0f, 10.0f);
        Vector3 target = new Vector3(0.0f, 0.0f, 0.0f);
        Matrix view = Matrix.LookAtLH(position, target, Vector3.UnitY);
        Matrix projection = Matrix.PerspectiveFovLH((float)(Math.PI / 4.0), 1.0f, 0.0f, 100.0f);
        Matrix world = Matrix.Identity;

        DataBox dataBox = Context.MapSubresource(MatrixBuffer, MapMode.WriteDiscard, MapFlags.None);
        dataBox.Data.Write(world);
        dataBox.Data.Write(view);
        dataBox.Data.Write(projection);

        Context.UnmapSubresource(MatrixBuffer, 0);

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



    public override void Render(int inCount = -1)
    {
        Context.DrawIndexed(4, 0, 0);
    }
}
}

这是我的着色器文件(ShaderFX.fx):

And here is my shader file (ShaderFX.fx):

float4 VShader(float4 position : POSITION) : SV_POSITION
{
return position;
}



float4 PShader_Counties(float4 position : SV_POSITION) : SV_Target
{
return float4(0.5f, 0.5f, 0.5f, 1.0f);
}



float4 PShader_States(float4 position : SV_POSITION) : SV_Target
{
return float4(0.883f, 0.883f, 0.883f, 1.0f);
}



struct VertexShaderInput
{
float2 pos : POSITION;
};



struct PixelShaderInput
{
float4 pos : SV_POSITION;
};



PixelShaderInput SimpleVertexShader(VertexShaderInput input)
{
PixelShaderInput vertexShaderOutput;

vertexShaderOutput.pos = float4(input.pos, 0.5f, 1.0f);

return vertexShaderOutput;
}



float4 SimplePixelShader(PixelShaderInput input) : SV_TARGET
{
return float4(1.0f, 1.0f, 0.0f, 1.0f);
}

推荐答案

这里有很多内容.

首先,您为每个渲染器创建一个设备,这不是必需的,您可以在同一设备上渲染所有内容.

First you create one device per renderer, which is not necessary, you can render everything against the same device.

要创建设备:

Device device = new Device(DriverType.Hardware,DeviceCreationFlags.Debug);

然后,您可以使用同一设备创建多个交换链(每个面板一个)

Then you can create several swapchains using same device (one for each panel)

SwapChain swapchain = new SwapChain(device.Factory, device, chainDescription);

第二个问题,您的四边形缺少纹理坐标,因此您将无法使用它显示纹理.请注意,您当然每个设备只需要一个Quad,而每个渲染器则不需要一个Quad.

Second issue, your quad is missing texture coordinates, so you will not be able to display a texture using it. Please note that you of course need only one quad per device, you don't need one per renderer.

DataStream data = new DataStream(20 * 4, true, true);
data.Write(new Vector3(-0.9f, -0.9f, 0.0f));
data.Write(new Vector2(0.0f,1.0f));

data.Write(new Vector3(-0.9f, 0.9f, 0.0f));
data.Write(new Vector2(0.0f,0.0f));

data.Write(new Vector3(0.9f, -0.9f, 0.0f));
data.Write(new Vector2(1.0f,1.0f));

data.Write(new Vector3(0.9f, 0.9f, 0.0f));
data.Write(new Vector2(1.0f,0.0f));
data.Position = 0;

您的输入布局已经考虑了纹理坐标,因此您无需进行修改.

Your input layout already takes Texture Coordinate into account, so you don't need to modify that.

接下来,您将不在顶点着色器中使用任何投影矩阵,因此,除非您计划这么做,否则可以忽略该代码.

Next you don't use any of the projection matrices in your vertex shader, so unless you plan to, you can just ignore that code.

最后,使用单个设备,确保设备上下文调用在render函数中,例如:

Finally, using a single device, make sure device context calls are in the render function, for example:

public override void Render(int inCount = -1)
{
    Context.OutputMerger.SetTargets(RenderTarget);

    Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(VertexBuffer, 12, 0));
    Context.InputAssembler.SetIndexBuffer(indexBuffer, 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.SetShaderResource(resourceView, 0);

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

最后,您当然需要在着色器中传递纹理坐标才能正确采样纹理:

Finally you will of course need to pass texture coordinates in your shader in order to sample the texture properly:

struct vsInput
{
float4 position: POSITION;
float2 texCoord: TEXCOORD0;
};

struct psInput
{
    float4 posScreen : SV_POSITION;
    float2 texCoord : TEXCOORD0;
};

Texture2D texture : register(t0);
SamplerState linearSampler : register(s0);

psInput VS(vsInput input)
{
    psInput output;
    output.posScreen = input.position;
    output.texCoord = input.texCoord;
    return output;
}

float4 PS(psInput input): SV_Target
{
    return texture.Sample(linearSampler, input.texCoord);
}

这篇关于尝试在Windows.Forms.Panels上渲染纹理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆