65.9K
CodeProject 正在变化。 阅读更多。
Home

Managed DirectX 教程:第三部分 - 渲染图元

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.76/5 (11投票s)

2006年2月3日

6分钟阅读

viewsIcon

61041

downloadIcon

981

这是旨在向您展示如何创建基本地形引擎的一系列教程中的第三部分。

引言

这是关于如何创建自己的游戏引擎(从初始化到完全可旋转、带有高度图的 3D 世界!)的教程系列中的第三部分。

在本教程中,我们将使用 Direct3D 创建和渲染图元,并学习更多 DirectX 概念。

背景

这些教程中的代码摘自我自己的游戏引擎:MAGEngine.NET,开发的不同阶段。

使用代码

您可以根据自己的需要使用我提供的所有代码,但不能用于创建另一个教程。您可以将其作为您自己应用程序的坚固(ish ;)) 框架,或者打印大量副本,这样当我富裕而闻名时,您就可以以每本 100 美元的价格出售它们了 ;)

必备组件

要学习本系列教程,您将需要

  • C# 编译器(最好是 Visual C# 2005 Express)
  • 托管 DirectX 9.0 十月 SDK

好的,在上一个教程中,我们花了很长时间讨论 Direct3D 组件的各个方面,我们创建了一个良好、稳固的示例框架,但我们从未渲染任何东西——这正是 Direct3D 的全部概念。在本教程中,我们将:

  • 了解图元
  • 初始化三角形
  • 设置变换
  • 渲染三角形
  • 创建一个 cObject 类供我们在游戏中使用

理论

所有 3D 世界——无论是角色、地形还是盒子——都由三角形组成。所有这些三角形本质上都是三个点,或称顶点。因此,要渲染我们的三角形,我们需要定义这三个“点”并将它们发送到我们的 OnPaint 函数进行渲染。在托管 DirectX 中,有一组结构用于表示不同类型的点,称为 CustomVertex 类。

从这里,您可以选择适合您需求的“点”结构——如果您想要一个可以旋转的纹理盒子,那么您会选择 PositionTextured;如果您想要那个盒子被着色,那么您会选择 PositionNormalTextured。今天,我们将创建一个静态、有颜色的三角形,因此我们将使用 CustomVertex.TransformedColored 点。

Transformed 表示我们定义的坐标已被声明为屏幕坐标,无需进行缩放、旋转或其他操作。

现在,您最初的反应可能是直接跳到代码并渲染您的三角形——但在此之前,我们应该创建一个类来帮助我们完成这项工作。

我们将创建两个类,一个称为 cObject,它包含一个 CustomVertex.TransformedColored 数组((?)),以及一个 bool 值,指示是否应渲染三角形(IsActive)。然后,我们将创建一个表示三角形的类。它将继承 cObject,但有两个函数:一个初始化函数,用于定义数组和任何坐标;以及它自己的渲染函数。

在 Direct3D 中,渲染的最佳方式是使用 OnPaint 事件,就像我们在上一个教程中所做的那样。但是,如果我们可以在 OnPaint 中设置好所有框架,然后只调用这个渲染方法,那将使未来的工作变得更加容易。我们甚至可以在一个 for() 循环中为三角形对象数组这样做。

上述类将在一个名为 cObject 的新文件中声明,内容如下:

public class cObject
{
  public CustomVertex.TransformedColored[] itsVertices;
}

public class cTriangle : cObject
{
  bool isActive;
  //Should this primitive be rendered?
  
  public cTriangle(CustomVertex.TransformedColored[] itsVerts)
  {
      itsVertices = new CustomVertex.TransformedColored[3];
      isActive = true; itsVertices[0] = itsVerts[0];
      //Assign the parameter vertices to that of the object
      itsVertices[1] = itsVerts[1];
      itsVertices[2] = itsVerts[2];
  }
  
  public void Render(Device device)
  {
      device.DrawUserPrimitives(PrimitiveType.TriangleList, 
                                          1, itsVertices;); 
      // Generic code for the primitive to 'render itself' 
  }

如您所见,cObject 类非常简单——只包含一个未分配的 TransformedColored 顶点数组。cTriangle 类仅添加了 isActive 成员以及初始化和渲染函数。

如您所见,Render 函数调用 DrawUserPrimitives() 函数。这是一个用于渲染图元的函数。您需要提供一个 PrimitiveType——这只是告诉 DirectX 如何渲染顶点。有很多示例,下面展示了它们如何影响图元的位置:

其他参数都很简单——要渲染的图元数量(=1),然后是源(即要渲染的图元所在的位置)。所以,现在我们更新了这个类,为了渲染我们的三角形,我们只需要再做两件事:

  1. 创建一个 cTriangle 对象
  2. 初始化这个对象
  3. 更新我们的 OnPaint 方法以渲染三角形

因此,创建了这个类之后,创建您类的实例应该很容易——在您的窗口类中创建一个公共 cTriangle 对象(在示例中我将将其命名为“Tri”)。现在 comes 一个有点棘手的部分,我们将在下一个教程中解决。

我们需要创建一个 CustomVertex.TransformedColored 数组,将其分配给我们将要创建的 cTriangle 实例,并通过其构造函数传递。为此,请在您的 main() 方法中使用以下代码,其中没有什么应该是全新的:

CustomVertex.TransformedColored[] Verts = 
     new CustomVertex.TransformedColored[3];
Verts[0] = new CustomVertex.TransformedColored(new 
     Vector4(100.0f, 100.0f, 0.0f, 1.0f), Color.Red.ToArgb());
Verts[1] = new CustomVertex.TransformedColored(new 
     Vector4(200.0f, 100.0f, 0.0f, 1.0f), Color.Blue.ToArgb());
Verts[2] = new CustomVertex.TransformedColored(new 
     Vector4(150.0f, 200.0f, 0.0f, 1.0f), Color.Green.ToArgb());

好的,这里唯一有点奇怪的应该是 Vector4 结构。最后一个参数称为 RHW,它用于变换坐标,因为它用于透视。我强烈建议不要纠结于此——在本教程使用带位置的坐标后,我们将不再使用它,并且在本教程中它将始终为 1.0。对于这个三角形,Z 坐标将始终是 0.0f。ToArgb() 函数将 .NET 颜色转换为其 Alpha-Red-Green-Blue 值。例如,白色转换为 ARGB 后值为 (0,255,255,255)(忽略 A,即 Alpha,或透明度),因为白色是所有颜色的混合;而红色将转换为 (0,255,0,0),依此类推。

现在,调用您三角形的构造函数,并将上面定义的顶点作为参数传递。然后,转到您窗体的 OnPaint 事件,我们就完成了本教程。

OnPaint 中,删除所有内容。

OnPaint 将在每一帧中被调用,每次显示需要更新时。所以,我们需要做几件事:

  1. 清除显示区域
  2. 通知 GPU 我们将渲染哪种类型的顶点
  3. 锁定 GPU 进行渲染
  4. 渲染我们的图元
  5. 解锁 GPU
  6. 交换旧帧与新帧
  7. 调用 .NET 的 Invalidate 函数

在渲染期间锁定和解锁 GPU 的原因是减少运行时错误。当我们渲染时,我们是渲染到一个称为后缓冲区的表面。这是一个屏幕外的表面,任何数据都可以存储在那里,直到我们调用 device.Present() 函数将其复制到屏幕上的表面。

代码上,这会转化为:

device.Clear(ClearFlags.Target, 
    System.Drawing.Color.Black, 1.0f, 0);
    //Clear display
device.VertexFormat = 
    CustomVertex.TransformedColored.Format;
    //Notify GPU which vertices 
device.BeginScene(); //Lock GPU
Triangle.Render(device); //Render primitives 
device.EndScene(); //Unlock GPU 
device.Present(); //Swap old with new 
this.Invalidate(); //call invalidate

这应该构成了 OnPaint 函数的全部内容。

如果编译并运行此代码,您应该会在屏幕上看到一个混合颜色的三角形。

X-挑战

  • 使用您创建的类并排放置三个三角形
  • 修改 OnPaint 事件,使其能够渲染所有已初始化的三角形,而无需我们在每次添加或删除数组中的一个时进行编辑。

联系方式

请将所有电子邮件发送至 xpyder@magclan.cwhnetworks.com。我也有 MSN Messenger,我的电子邮件地址是 jamespraveen@aol.com

历史

  • 06 年 1 月 19 日:将教程 1-3 提交给 CodeProject。
© . All rights reserved.