SharpDX初学者教程第4部分:绘制三角形

原文 http://www.johanfalk.eu/blog/sharpdx-beginners-tutorial-part-4-drawing-a-triangle

现在我们有了一个Direct3D初始化的窗口,现在是时候绘制一些东西了,就像所有其他教程一样,我们也将开始绘制一个三角形!要渲染我们的第一个三角形,实际上我们必须添加很多部分,所以让我们开始吧。

1.顶点

要创建三角形,我们将使用顶点。顶点是3D空间中的精确点,也可以包含其他信息(我们将在后面的教程中看到)。目前,我们的顶点仅由3个值表示,即x,y和z坐标。

对于三角形,我们将需要3个顶点,每个角落一个。稍后我们将介绍有关不同坐标系的更多细节,但是现在我们的可见空间在x,y和z方向上介于-1和1之间。这就是我决定设置三角形的方法,您可以使用不同的值来查看三角形的变化:

所以我们添加的第一个代码是我们的Game类的变量,它保存了这些坐标,为此我们使用SharpDX中提供的Vector3类:

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) };

2.顶点缓冲区

我们刚刚创建的顶点数组存储在系统内存中,但是为了渲染我们的对象,我们需要将数据传输到视频内存。为此,我们将使用缓冲区。在DirectX中,我们有三种不同类型的缓冲区:Vertex,Index和Constant缓冲区。当我们渲染需要DirectX的数据时,缓冲区中的数据会自动从系统内存复制到视频内存。

顶点缓冲区是我们现在将使用的,这个缓冲区类型,顾名思义,保存每个顶点的数据。目前,我们的顶点只有一个位置向量,但稍后我们会向每个顶点添加更多信息。这里的第一步是向我们的类添加一个新变量,它是对缓冲区的引用:

private D3D11.Buffer triangleVertexBuffer;

然后我们在我们的类中添加一个名为InitializeTriangle的新方法,如下所示:

private void InitializeTriangle() { triangleVertexBuffer = D3D11.Buffer.Create<Vector3>(d3dDevice, D3D11.BindFlags.VertexBuffer, vertices); }

这里方法D3D.Buffer.Create <T>用于创建新缓冲区,泛型类型参数T指定缓冲区中每个元素的哪种数据类型。第一个参数是我们希望使用的Direct3D设备。第二个参数是我们想要创建的缓冲区类型,在本例中是顶点缓冲区。最后,我们提供了加载到缓冲区的初始数据,在本例中是我们的位置数组。
还要在Game类构造函数的末尾添加对此方法的调用,并释放缓冲区:

public Game()
{[...]InitializeTriangle();
} public void Dispose() { triangleVertexBuffer.Dispose(); [...] }

3.顶点和像素着色器

DirectX 11中的图形管道包含几个可编程步骤。现在我们将重点关注Vertex Shader Stage和Pixel Shader Stage。

顶点着色器阶段负责处理顶点,这可以包括例如变换(平移,旋转,缩放等)。

像素着色器阶段处理针对每个像素运行,并接收插值的每顶点数据,以及常量变量和纹理。该着色器针对渲染图元的每个像素运行,并应返回像素的最终颜色。

首先我们添加两个类变量,我们的顶点和像素着色器:

private D3D11.VertexShader vertexShader;
private D3D11.PixelShader pixelShader;

接下来我们需要编译我们的着色器代码(我们将很快编写),我们将其置于一个新的私有方法中,顶部的using指令也是必需的:

using SharpDX.D3DCompiler;
[...]
private void InitializeShaders() { using(var vertexShaderByteCode = ShaderBytecode.CompileFromFile("vertexShader.hlsl", "main", "vs_4_0", ShaderFlags.Debug)) { vertexShader = new D3D11.VertexShader(d3dDevice, vertexShaderByteCode); } using(var pixelShaderByteCode = ShaderBytecode.CompileFromFile("pixelShader.hlsl", "main", "ps_4_0", ShaderFlags.Debug)) { pixelShader = new D3D11.PixelShader(d3dDevice, pixelShaderByteCode); } }

这里我们首先指出要编译的文件,vertexShader.hlsl和pixelShader.hlsl。我们还在着色器代码“main”中指定入口点方法的名称。然后我们还设置要使用的HLSL版本,在本例中为4.0。最后,我们还将编译设置为调试模式。

现在还必须将设备上下文配置为在绘制时使用这些着色器,因此将此代码添加到InitializeShaders()方法的末尾:

private void InitializeShaders() { [...] // Set as current vertex and pixel shaders d3dDeviceContext.VertexShader.Set(vertexShader); d3dDeviceContext.PixelShader.Set(pixelShader); d3dDeviceContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList; }

这里我们还设置了原始拓扑,它指定了如何绘制顶点。在这种情况下,我们将使用“Triangle List”,我们将在后面的教程中使用其他类型,但您可以查看MSDN文档以获得不同类型的良好说明。

现在,让我们添加着色器代码:

  1. 右键单击解决方案资源管理器中的项目,然后选择添加 - >新项...
  2. 找到“文本文件”并输入“vertexShader.hlsl”作为名称。按添加。
  3. 在解决方案资源管理器中选择该文件,然后在“属性”窗口中,将“复制到输出目录”设置为“始终复制”。
  4. 重复步骤1-3,但将文件命名为“pixelShader.hlsl”。

现在打开vertexShader.hlsl并写入:

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

在这里,我们创建入口点方法“main”,如前所述。从方法开始只返回从顶点缓冲区获得的相同位置。注意“:POSITION”和“:SV_POSITION”,这称为语义并指定变量的预期用途,我们将在本教程后面看到更多为什么这很重要。

现在打开pixelShader.hlsl文件并输入以下代码:

float4 main(float4 position : SV_POSITION) : SV_TARGET
{return float4(1.0, 0.0, 0.0, 1.0); } 

我们再次创建一个main方法,该方法的参数是顶点着色器的输出。但请记住,顶点着色器是针对每个顶点运行的,而像素着色器是针对每个像素运行的,因此这将是一个插值位置。从这个方法我们返回一个float4,它是我们的颜色,格式为红色,绿色,蓝色,alpha。因此,这将为所有像素生成红色。值得注意的是float4中的值介于0和1之间,因此float4(0,0,0,1)将给出黑色,而float4(1,1,1,1)将给出白色像素。

当然,我们也在游戏构造函数中调用InitializeShaders()方法并处理着色器,这应该在InitializeTriangle()方法之前进行:

public Game()
{[...]InitializeDeviceResources();InitializeShaders();InitializeTriangle();
}
public void Dispose() { triangleVertexBuffer.Dispose(); vertexShader.Dispose(); pixelShader.Dispose(); [...] }

4.输入布局

我们现在有一个顶点缓冲区,它有我们的顶点数据。但DirectX还想知道数据的结构以及每个顶点元素的类型,为此我们使用输入布局。这需要两步。首先,我们需要描述顶点中的每个元素,然后从中创建输入布局。

由于我们的顶点到目前为止只有一个元素,所以让我们在Game类中添加一个新的InputElements数组:

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

可以从着色器代码识别“POSITION”,这称为语义,用于与着色器中的输入签名匹配。第二个参数是要使用的语义槽,如果您有多个POSITION语义,则使用此参数。第三个是这个元素的数据类型,在这种情况下3个浮点数作为我们的顶点的位置是Vector3。

接下来,我们需要从编译的顶点着色器中获取输入着色器。首先创建一个新变量来保存我们的Game类的输入签名:

private ShaderSignature inputSignature;

然后在InitializeShaders()方法中,我们可以从编译的着色器字节代码中获取签名,如下所示:

using(var vertexShaderByteCode = ShaderBytecode.CompileFromFile("vertexShader.hlsl", "main", "vs_4_0", ShaderFlags.Debug)) { inputSignature = ShaderSignature.GetInputSignature(vertexShaderByteCode); [...] }

现在我们需要从InputElement数组和输入签名创建一个输入布局,所以在Game类中添加另一个变量:

private D3D11.InputLayout inputLayout;

然后通过创建一个新的InputLayout实例在InitializeShaders()方法的末尾分配它。然后我们将其设置为设备上下文中的当前输入布局。

private void InitializeShaders() { [...] inputLayout = new D3D11.InputLayout(d3dDevice, inputSignature, inputElements); d3dDeviceContext.InputAssembler.InputLayout = inputLayout; }

第一个元素是我们的Direct3D设备,然后是着色器的输入签名,最后是输入元素数组。

并且不要忘记处理输入布局和输入签名:

public void Dispose() { inputLayout.Dispose(); inputSignature.Dispose(); [...] }

5.设置视口:

在我们绘制任何东西之前,我们必须指定视口。DirectX使用称为标准化设备坐标的东西,在左上角指定为(-1,-1),在屏幕右下角指定为(1,1),因此在中间指定(0,0)。视口将这些角映射到像素坐标。

首先在Viewport的Game类中创建另一个变量:

private Viewport viewport;

在InitializeDeviceResources()方法中,使用以下代码创建一个新视口并在设备上下文中设置它:

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

前两个参数是(-1,-1)的x和y位置,最后两个参数是视口的宽度和高度。因为我们想要使用完整的窗口,我们将它映射到左上角(0,0)并将其设置为窗口的整个宽度和高度。

6.绘制顶点数据

完成所有这些工作后,终于可以在屏幕上绘制三角形!这只是两个方法调用,我们在draw()方法的中间添加:

private void Draw() { d3dDeviceContext.OutputMerger.SetRenderTargets(renderTargetView); d3dDeviceContext.ClearRenderTargetView(renderTargetView, new SharpDX.Color(32, 103, 178)); d3dDeviceContext.InputAssembler.SetVertexBuffers(0, new D3D11.VertexBufferBinding(triangleVertexBuffer, Utilities.SizeOf<Vector3>(), 0)); d3dDeviceContext.Draw(vertices.Count(), 0); swapChain.Present(1, PresentFlags.None); }

第一种方法告诉设备上下文使用保存三角形顶点数据的顶点缓冲区,第二个参数指定每个顶点数据的大小(以字节为单位)。要获得这个大小,我们使用SharpDX中提供的一个很好的帮助方法。

设备上下文中的Draw()方法从顶点缓冲区中绘制vertices.Count()许多顶点。第二个参数指定顶点缓冲区中的偏移量,通过将此设置为1,例如,将跳过第一个顶点。

现在,当您运行该程序时,您应该得到以下结果:

像往常一样,代码可以在GitHub上找到:https://github.com/mrjfalk/SharpDXTutorials/tree/master/BeginnersTutorial-Part4

 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;// Shadersprivate 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)};// Triangle verticesprivate 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 D3D11.Buffer triangleVertexBuffer;/// <summary>/// Create and initialize a new game./// </summary>public Game(){// Set window propertiesrenderForm = 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 chainSwapChainDescription swapChainDesc = new SwapChainDescription(){ModeDescription = backBufferDesc,SampleDescription = new SampleDescription(1, 0),Usage = Usage.RenderTargetOutput,BufferCount = 1,OutputHandle = renderForm.Handle,IsWindowed = true};// Create device and swap chainD3D11.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 bufferusing (D3D11.Texture2D backBuffer = swapChain.GetBackBuffer<D3D11.Texture2D>(0)){renderTargetView = new D3D11.RenderTargetView(d3dDevice, backBuffer);}}private void InitializeShaders(){// Compile the vertex shader codeusing (var vertexShaderByteCode = ShaderBytecode.CompileFromFile("vertexShader.hlsl", "main", "vs_4_0", ShaderFlags.Debug)){// Read input signature from shader codeinputSignature = ShaderSignature.GetInputSignature(vertexShaderByteCode);vertexShader = new D3D11.VertexShader(d3dDevice, vertexShaderByteCode);}// Compile the pixel shader codeusing (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 elementsinputLayout = new D3D11.InputLayout(d3dDevice, inputSignature, inputElements);// Set input layout to used3dDeviceContext.InputAssembler.InputLayout = inputLayout;}private void InitializeTriangle(){// Create a vertex buffer, and use our array with vertices as datatriangleVertexBuffer = D3D11.Buffer.Create<Vector3>(d3dDevice, D3D11.BindFlags.VertexBuffer, vertices);}/// <summary>/// Draw the game./// </summary>private void Draw(){// Set back buffer as current render target view
            d3dDeviceContext.OutputMerger.SetRenderTargets(renderTargetView);// Clear the screend3dDeviceContext.ClearRenderTargetView(renderTargetView, new SharpDX.Color(32, 103, 178));// Set vertex bufferd3dDeviceContext.InputAssembler.SetVertexBuffers(0, new D3D11.VertexBufferBinding(triangleVertexBuffer, Utilities.SizeOf<Vector3>(), 0));// Draw the triangled3dDeviceContext.Draw(vertices.Count(), 0);// Swap front and back bufferswapChain.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:32 NET未来之路 阅读( ...) 评论( ...) 编辑 收藏

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

SharpDX初学者教程第4部分:绘制三角形相关推荐

  1. SharpDX初学者教程第2部分:创建窗口

    SharpDX初学者教程第2部分:创建窗口 原文 http://www.johanfalk.eu/blog/sharpdx-tutorial-part-2-creating-a-window 在第二篇 ...

  2. 现代OpenGL教程(一):绘制三角形(imgui+OpenGL3.3)

    前言:imgui 是一个开源的GUI框架,自带的例子里面直接集成了glfw+gl3w环境,本例使用的版本是imgui v1.61,下载地址:https://github.com/ocornut/img ...

  3. OpenGL ES基础教程,绘制三角形(补充,附代码)

    简介 OpenGL OpenGL(全写Open Graphics Library)是指定义了一个跨编程语言.跨平台的编程接口规格的专业的图形程序接口.它用于三维图像(二维亦可),是一个功能强大,调用方 ...

  4. matlab 绘制等高线图,contourf等高线填充,并优化(初学者教程)

    matlab 绘制等高线图,contourf等高线填充,并优化(初学者教程) 本人是matlab初学者,由于科研作图需要,最近经常使用matlab画等高线图,想把我的代码分享出来. 我就拿txt文本作 ...

  5. Cocos2d-x初学者教程

    Cocos2d-x初学者教程 Cocos2d-x初学者教程 入门 分辨率设置 添加精灵 移动怪物 射击弹丸 碰撞检测与物理 画龙点睛 关于本项目在其他系统如Windows上的移植 参考资料 本文翻译自 ...

  6. SAP UI5 初学者教程之应用开发 - 过滤器 filter 的开发和使用

    通过本教程前一步骤SAP UI5 初学者教程之二十一 - SAP UI5 的自定义格式器 Custom Formatter的学习,我们已经得到了一张发票列表: 本步骤我们更进一步,给这个列表添加一个搜 ...

  7. css 绘制三角形_解释CSS形状:如何使用纯CSS绘制圆,三角形等

    css 绘制三角形 Before we start. If you want more free content but in video format. Don't miss out on my Y ...

  8. h5画三角形_H5如何在网页中绘制三角形,值得一看

    H5是目前比较火的编程工具之一,功能十分强大,深受编程人员的喜爱.对于初学者来说,利用H5绘制图形是必须经历的学习阶段.例:如用H5绘制一个三角形.具体方法如下: 工具/材料 dw软件 操作方法 01 ...

  9. OPenGL 学习笔记之 VAO VBO EBO 以及SHADER 并使用其绘制三角形

    译注 在学习此节之前,建议将这三个单词先记下来: 顶点数组对象:Vertex Array Object,VAO 顶点缓冲对象:Vertex Buffer Object,VBO 索引缓冲对象:Eleme ...

最新文章

  1. 图片出处识别_图片模糊怎么变清晰?方法都在这里了
  2. Configure Drill
  3. python3 限定方法参数 返回值 变量 类型
  4. 开启算法编程之旅的准备工作——如何在Windows 上安装 Anaconda 和 PyCharm
  5. Java RMI 入门
  6. 【C语言进阶深度学习记录】二十七 C语言中字符串的相等比较
  7. 手机玩html5游戏很卡,手机游戏卡怎么办_手机玩游戏卡顿解决办法-系统城
  8. wkhtmltopdf网页转PDF程序安装教程
  9. 关于CWMP基础(二)----TR069通信流程
  10. 电阻应用电路之运放如何消除偏置电流的影响
  11. WPS广告弹窗永久关闭
  12. 图像处理库Pillow的使用
  13. 下一步工作应该怎样开展
  14. Exp外贸/出口英文商城系统在国际电商贸易中的角色扮演
  15. SIP协议之代理服务器
  16. 报错:The server time zone value ‘�й���׼ʱ��‘ is unrecognied
  17. L1-014 简单题 - java
  18. 关于山寨版istream_iterator的实现……
  19. PQ比例控制阀放大板HNC-1085%HNC-4075
  20. 搭建 yapi 接口管理平台

热门文章

  1. 物联网卡收费标准有哪些
  2. 平面设计专业的就业前景如何?就业方向有哪些?
  3. EntityFramework 报错 调用的目标发生了异常 可能的原因之一
  4. Invoke、InvokeMember提示“调用的目标发生了异常”
  5. 中国数据复制第一股:英方软件做对了什么?
  6. 关于一起深度学习的那些事
  7. MySQL简介和基本使用
  8. k8s之持久化存储PV、PVC
  9. css overflow使用总结
  10. 瑞士轮赛制模拟器_【科普】瑞士轮比赛赛制(简称瑞士制)