SharpDX初学者教程第5部分:着色三角形

原文 http://www.johanfalk.eu/blog/sharpdx-beginners-tutorial-part-5-coloring-the-triangle

第4部分中,我们创建了一个三角形,我们可以在像素着色器中为整个三角形设置单一颜色。在本教程中,我们将看到如何为三角形的每个顶点添加单独的颜色。我们将继续处理上一个教程中的代码,您也可以在此处找到该代码。

最终结果如下:

最后结果

1.创建顶点结构

请记住,当我们渲染三角形时,我们上传了一个数组Vector3,因为每个顶点只是一个位置。现在我们希望每个顶点都有一个位置和一个颜色。因此,我们首先创建一个VertexPositionColor.cs通过右键单击项目调用的新文件,然后选择Add -> New Item...:

选择“ 代码文件 ” 类型,并为其命名VertexPositionColor.cs,然后单击“ 添加”

现在使用以下代码创建一个结构:

using SharpDX;
using System.Runtime.InteropServices;

namespace MySharpDXGame
{
    [StructLayoutAttribute(LayoutKind.Sequential)]
    public struct VertexPositionColor { public readonly Vector3 Position; public readonly Color4 Color; public VertexPositionColor(Vector3 position, Color4 color) { Position = position; Color = color; } } } 

所以,现在我们有一个不可变的结构,它同时具有PositionColor。我们还将该[StructLayoutAttribute(LayoutKind.Sequential)] 属性添加到结构中。这样可以确保值以与struct中指定的顺序相同的顺序排列在内存中。这很重要,因为我们后来需要告诉GPU。

2.更改顶点

作为下一步,我们需要Game.cs使用新顶点类型的数组替换上一个教程中的顶点数组。我们还为每个顶点选择一种颜色。所以替换这段代码:

private Vector3[] vertices = new Vector3[] { new Vector3(-0.5f, 0.5f, 0.0f), new Vector3(0.5f, 0.5f, 0.0f), new Vector3(0.0f, -0.5f, 0.0f) };

使用此代码:

private VertexPositionColor[] vertices = new VertexPositionColor[] 
{ 
    new VertexPositionColor(new Vector3(-0.5f, 0.5f, 0.0f), SharpDX.Color.Red), new VertexPositionColor(new Vector3(0.5f, 0.5f, 0.0f), SharpDX.Color.Green), new VertexPositionColor(new Vector3(0.0f, -0.5f, 0.0f), SharpDX.Color.Blue) };

3.更新VertexBuffer

我们还需要更改我们的顶点缓冲区以包含新的顶点结构而不是Vector3,所以<Vector3>从以下行中删除(在InitializeTriangle()方法中):

triangleVertexBuffer = D3D11.Buffer.Create<Vector3>(d3dDevice, D3D11.BindFlags.VertexBuffer, vertices);

现在编译器会自动推断它是<VertexPositionColor>来自参数的,所以如果我们以后更改它,我们将不需要再次更改。

我们也必须改变在顶点缓冲器中的每个元件的尺寸,所以更换Vector3 VertexPositionColor 下面的行(在Draw()法):

d3dDeviceContext.InputAssembler.SetVertexBuffers(0, new D3D11.VertexBufferBinding(triangleVertexBuffer, Utilities.SizeOf<Vector3VertexPositionColor>(), 0));

4.更改输入布局

您可能还记得在上一个教程中我们创建了一个输入布局,它描述了顶点数据的结构。在上一个教程中,它看起来像这样:

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

由于我们还为每个顶点添加了颜色,我们需要将输入布局更改为以下内容:

private D3D11.InputElement[] inputElements = new D3D11.InputElement[] 
{
    new D3D11.InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0, D3D11.InputClassification.PerVertexData, 0), new D3D11.InputElement("COLOR", 0, Format.R32G32B32A32_Float, 12, 0, D3D11.InputClassification.PerVertexData, 0) };

我们添加了另一个InputElement,其中类型是a R32G32B32A32_Float,因为SharpDX.Color4我们在vertex结构中使用的结构包含4个浮点数(以RGBA顺序)。我们还添加了一些其他参数,大多数现在都是无关紧要的,除了第4个,我们为“POSITION”指定0 ,但为“COLOR”元素指定12 。此参数是此数据开始的结构中的偏移量(以字节为单位),并且因为位置首先出现偏移0,并且每个位置Vector3 包含3个浮点数(x,y,z),每个字节数为4个字节= 12字节。因此,颜色数据将在12个字节后找到。

5.更新顶点着色器

打开vertexShader.hlsl文件。首先,我们将更改主要功能参数列表以包含颜色:

float4 main(float4 position : POSITION, float4 color : COLOR) : SV_POSITION
{
   [...]
}

正如您所看到的,顶点着色器现在也会接收颜色,但由于颜色是在像素着色器中设置的,因此我们还需要从此函数返回颜色。要从函数返回多个值,我们需要创建一个结构,其中包含着色器文件顶部的位置和颜色:

struct VSOut
{
    float4 position : SV_POSITION;
    float4 color : COLOR;
};

现在我们将函数返回值更改为此结构,并删除SV_POSITION 语义:

VSOut main(float4 position : POSITION, float4 color : COLOR)
{
    […]
}

而不是仅仅从着色器返回位置,我们将创建一个VSOut 结构,并在其中设置位置和颜色值。所以最终的顶点着色器应如下所示:

struct VSOut
{
    float4 position : SV_POSITION;
    float4 color : COLOR;
};

VSOut main(float4 position : POSITION, float4 color : COLOR)
{
    VSOut output;
    output.position = position;
    output.color = color;

    return output; }

6.更新像素着色器

在像素着色器(pixelShader.hlsl)中,我们需要将颜色添加为函数参数,然后返回红色而不是返回提供的颜色,因此完整像素着色器应如下所示:

float4 main(float4 position : SV_POSITION, float4 color : COLOR) : SV_TARGET
{
    return color;
}

7.修复bug

如果您在02-08-2016之前已经按照之前的教程进行操作,那么您可能会遇到错误(在GitHub repo和教程中已修复)。你必须移动这一行 Game.cs

d3dDeviceContext.OutputMerger.SetRenderTargets(renderTargetView);

从最后开始InitializeDeviceResources(), 并将其置于第一位Draw(),因为必须在每帧的开头调用它。

8.最终结果

我们现在已经完成了,如果您运行该项目,您现在应该得到以下结果:

最后结果。

和往常一样,GitHub上提供了完整的代码:https//github.com/mrjfalk/SharpDXTutorials/tree/master/BeginnersTutorial-Part5

    public class Game : IDisposable
    {
        private RenderForm renderForm;

        private const int Width = 1280;
        private const int Height = 720;

        private D3D11.Device d3dDevice;
        private D3D11.DeviceContext d3dDeviceContext;
        private SwapChain swapChain;
        private D3D11.RenderTargetView renderTargetView;
        private Viewport viewport;

        // Shaders
        private D3D11.VertexShader vertexShader;
        private D3D11.PixelShader pixelShader;
        private ShaderSignature inputSignature;
        private D3D11.InputLayout inputLayout;

        private D3D11.InputElement[] inputElements = new D3D11.InputElement[] 
        {
            new D3D11.InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0, D3D11.InputClassification.PerVertexData, 0),
            new D3D11.InputElement("COLOR", 0, Format.R32G32B32A32_Float, 12, 0, D3D11.InputClassification.PerVertexData, 0)
        };

        // Triangle vertices
        private VertexPositionColor[] vertices = new VertexPositionColor[] { new VertexPositionColor(new Vector3(-0.5f, 0.5f, 0.0f), SharpDX.Color.Red), new VertexPositionColor(new Vector3(0.5f, 0.5f, 0.0f), SharpDX.Color.Green), new VertexPositionColor(new Vector3(0.0f, -0.5f, 0.0f), SharpDX.Color.Blue) };
        private D3D11.Buffer triangleVertexBuffer;

        /// <summary>
        /// Create and initialize a new game.
        /// </summary>
        public Game()
        {
            // Set window properties
            renderForm = new RenderForm("My first SharpDX game");
            renderForm.ClientSize = new Size(Width, Height);
            renderForm.AllowUserResizing = false;

            InitializeDeviceResources();
            InitializeShaders();
            InitializeTriangle();
        }

        /// <summary>
        /// Start the game.
        /// </summary>
        public void Run()
        {
            // Start the render loop
            RenderLoop.Run(renderForm, RenderCallback);
        }

        private void RenderCallback()
        {
            Draw();
        }

        private void InitializeDeviceResources()
        {
            ModeDescription backBufferDesc = new ModeDescription(Width, Height, new Rational(60, 1), Format.R8G8B8A8_UNorm);
            
            // Descriptor for the swap chain
            SwapChainDescription swapChainDesc = new SwapChainDescription()
            {
                ModeDescription = backBufferDesc,
                SampleDescription = new SampleDescription(1, 0),
                Usage = Usage.RenderTargetOutput,
                BufferCount = 1,
                OutputHandle = renderForm.Handle,
                IsWindowed = true
            };

            // Create device and swap chain
            D3D11.Device.CreateWithSwapChain(DriverType.Hardware, D3D11.DeviceCreationFlags.None, swapChainDesc, out d3dDevice, out swapChain);
            d3dDeviceContext = d3dDevice.ImmediateContext;

            viewport = new Viewport(0, 0, Width, Height);
            d3dDeviceContext.Rasterizer.SetViewport(viewport);

            // Create render target view for back buffer
            using(D3D11.Texture2D backBuffer = swapChain.GetBackBuffer<D3D11.Texture2D>(0))
            {
                renderTargetView = new D3D11.RenderTargetView(d3dDevice, backBuffer);
            }
        }

        private void InitializeShaders()
        {
            // Compile the vertex shader code
            using(var vertexShaderByteCode = ShaderBytecode.CompileFromFile("vertexShader.hlsl", "main", "vs_4_0", ShaderFlags.Debug))
            {
                // Read input signature from shader code
                inputSignature = ShaderSignature.GetInputSignature(vertexShaderByteCode);

                vertexShader = new D3D11.VertexShader(d3dDevice, vertexShaderByteCode);
            }

            // Compile the pixel shader code
            using(var pixelShaderByteCode = ShaderBytecode.CompileFromFile("pixelShader.hlsl", "main", "ps_4_0", ShaderFlags.Debug))
            {
                pixelShader = new D3D11.PixelShader(d3dDevice, pixelShaderByteCode);
            }

            // Set as current vertex and pixel shaders
            d3dDeviceContext.VertexShader.Set(vertexShader);
            d3dDeviceContext.PixelShader.Set(pixelShader);

            d3dDeviceContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;

            // Create the input layout from the input signature and the input elements
            inputLayout = new D3D11.InputLayout(d3dDevice, inputSignature, inputElements);

            // Set input layout to use
            d3dDeviceContext.InputAssembler.InputLayout = inputLayout;
        }

        private void InitializeTriangle()
        {
            // Create a vertex buffer, and use our array with vertices as data
            triangleVertexBuffer = D3D11.Buffer.Create(d3dDevice, D3D11.BindFlags.VertexBuffer, vertices);
        }

        /// <summary>
        /// Draw the game.
        /// </summary>
        private void Draw()
        {
            // Set render targets
            d3dDeviceContext.OutputMerger.SetRenderTargets(renderTargetView);

            // Clear the screen
            d3dDeviceContext.ClearRenderTargetView(renderTargetView, new SharpDX.Color(32, 103, 178));

            // Set vertex buffer
            d3dDeviceContext.InputAssembler.SetVertexBuffers(0, new D3D11.VertexBufferBinding(triangleVertexBuffer, Utilities.SizeOf<VertexPositionColor>(), 0));

            // Draw the triangle
            d3dDeviceContext.Draw(vertices.Count(), 0);

            // Swap front and back buffer
            swapChain.Present(1, PresentFlags.None);
        }

        public void Dispose()
        {
            inputLayout.Dispose();
            inputSignature.Dispose();
            triangleVertexBuffer.Dispose();
            vertexShader.Dispose();
            pixelShader.Dispose();
            renderTargetView.Dispose();
            swapChain.Dispose();
            d3dDevice.Dispose();
            d3dDeviceContext.Dispose();
            renderForm.Dispose();
        }
    }

 

posted on 2019-05-03 01:33 NET未来之路 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/10804118.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值