DirectX9 3D快速上手 3

** DirectX9 3D ** ** 快速上手 ** ** 3

**

By sssa2000

4/15/2005

我们这里暂时先跳过,乏味的索引缓冲和深度缓冲的内容,先看看怎么在 3D 空间中实现一个东西,给自己来点成就感。

正好 SDK 的向导也是这么安排的,呵呵,那我们就继续从向导出发吧,以 Tutorial 3 为例子。

这个例子主要讲解运用变换矩阵来实现物体的变换,学过图形学或者线性代数的肯定就很容易理解,没学过的,找点这方面的资料看看就可以了。

先看看这个例子实现了什么,编译运行,噢,相比前面两个例子,有耳目一新的感觉,一个三角形绕着 Y 轴旋转。

相比 Tutorial 2 , 多了 2 个函数: OnResetDevice 和 SetupMatrices 。其中有注释,中文由我翻译, E 文太差,翻译得不好不要 B4 我啊

public void OnResetDevice( object sender, EventArgs e)

{

Device dev = (Device)sender;

// Turn off culling, so we see the front and back of the triangle

// 关闭剔除,所以我们可以看见前面的和背面的三角形

dev.RenderState.CullMode = Cull.None;

// Turn off D3D lighting, since we are providing our own vertex colors

// 关闭灯光,因为我们已经提供了自己的颜色

dev.RenderState.Lighting = false ;

}

private void SetupMatrices()

{

// For our world matrix, we will just rotate the object about the y-axis.

// Set up the rotation matrix to generate 1 full rotation (2*PI radians)

// every 1000 ms. To avoid the loss of precision inherent in very high

// floating point numbers, the system time is modulated by the rotation

// period before conversion to a radian angle.

// 在世界坐标中,我们要绕 Y 旋转 , 建立旋转矩阵产生每秒 360 度的旋转,为了避免浮点数中的位数造成的时间上的损失,我们在转变为弧度前,强制调整系统时间

int iTime = Environment.TickCount % 1000;

float fAngle = iTime * ( 2.0f * ( float )Math.PI) / 1000.0f ;

device.Transform.World = Matrix.RotationY( fAngle );

// Set up our view matrix. A view matrix can be defined given an eye point,

// a point to lookat, and a direction for which way is up. Here, we set the

// eye five units back along the z-axis and up three units, look at the

// origin, and define "up" to be in the y-direction.

// 建立观察矩阵,它可以被定义为视点,就像一个摄像机一样。这里我们设置在 Z 轴 -5 , Y 轴 3 的位置

device.Transform.View = Matrix.LookAtLH( new Vector3( 0.0f , 3.0f , -5.0f ), new Vector3( 0.0f , 0.0f , 0.0f ), new Vector3( 0.0f , 1.0f , 0.0f ) );

// For the projection matrix, we set up a perspective transform (which

// transforms geometry from 3D view space to 2D viewport space, with

// a perspective divide making objects smaller in the distance). To build

// a perpsective transform, we need the field of view (1/4 pi is common),

// the aspect ratio, and the near and far clipping planes (which define at

// what distances geometry should be no longer be rendered).

// 射影矩阵,我们建立一个透视变换(透视变换把 3D 空间变换到 2D 视口,造成透视的效果),为了建立透视变换,我们需要视觉空间,(通常是 1/4 pi )纵横比 和 远距离剔除(远处物体不渲染)

device.Transform.Projection = Matrix.PerspectiveFovLH( ( float )Math.PI / 4, 1.0f , 1.0f , 100.0f );

}

所有的新东西都在这里了,一共不到 10 条语句,简单吧?有几点要解释一下。

dev.RenderState.CullMode = Cull.None;

这一句,或许很多人会疑惑,首先了解一下 DX 的背面剔除功能,和现实中一样,我们同一时间只能够看到一个物体的一面,看不到它的背面,这就是背面剔除。 Cull 是一个枚举,一共 3 个值:

CounterClockwise

|

3

|

Cull back faces with counterclockwise vertices.

---|---|---

Clockwise

|

2

|

Cull back faces with clockwise vertices.

None

|

1

|

Do not cull back faces.

如果我们指定了背面剔除的方式,那么我们就看不到物体的背面,这样当三角形转过来的时候我们就看不到转过来的东西,所以设置为 none ,如果不理解,可以在程序中修改一下这一句话,就能很直观的理解了。

这个例子就这么多内容,当然你也可以把 RotateY 改为, RotateX, RotateZ 等等,可以更加好的理解一下这个例子。

接下来我们来了解一下 Mesh 。

对我们初学者来说 Mesh 应该是一个让人激动的东西,让我们来看看介绍: Mesh 可以用来储存任何类型的图形数据,但主要用来封装复杂的模型。 Mesh 类同样也有一些用来提高渲染物体性能的方法。用 Mesh 你可以从外部文件读入 3D 的模型例如 .3DS 文件,这样我们就可以在 3D Max 中做好模型,然后读入程序,想想看,一个游戏的雏形是不是已经在你脑海了呢?

Mesh 对象内部也包含了很多几何体的模型,我们来看看怎么使用它,因为使用它比使用顶点要快捷方便得多,一会你就会深刻体会到。

首先我们要先建立一个 Mesh 对象 private Mesh mesh = null;

然后 mesh = Mesh.Box(device, 2.0f , 2.0f , 2.0f ); 这样我们就建立了一个长宽高都为 2 的立方体,很简单吧?如果你用顶点来建立的话,最快的方法,即使用索引缓冲器,深度缓冲器也要写 8 个顶点得值,还要 SetStreamSource 等等繁琐的工作,这一切在 Mesh 中都替我们完成了。当然, Mesh 内置的几何形体还有很多,比如圆柱,茶壶等等,你可以一个一个的试一下。

我们来看看核心的 DrawBox 函数:

this is equivalent

private void DrawBox( float yaw, float pitch, float roll, float x, float y, float z)

{

angle += 0.01f ;

device.Transform.World = Matrix.RotationYawPitchRoll(yaw, pitch, roll) * Matrix.Translation(x, y, z);

Material boxMaterial = new Material();

boxMaterial.Ambient = Color.White; // 环境色

boxMaterial.Diffuse = Color.White; // 漫反射

device.Material = boxMaterial;

mesh.DrawSubset(0);

}

先介绍 Matrix.RotationYawPitchRoll 方法,看看他的原形:

public static Matrix RotationYawPitchRoll (
float yaw , // 偏移量,即绕 Y 轴的转动角度
float pitch ,// 斜度,即绕 X 轴的角度
float roll// _ 滚动,即绕 Z _ _ 的角度 _
);

** 材质( ** ** materials ** ** ) ** 描述了这样的一种属性。你可以指定物体如何反射环境光以及 散射( ** diffuse ** ** ) ** 光线, 镜面高光( ** Specular Highlights ** ** ) ** (少后会讨论它)看起来是什么样,以及物体是否完全 反射( ** emit ** ** ) ** 光线。 这里创建了一个新的材质,它的 环境颜色( ** ambient color ** ** ) ** (注:环境颜色和环境光的颜色是不同的 ^_^ )和散射颜色值都被设置为白色。使用白色表示它会反射所有的光线。接下来,我们把材质赋予了 device 的 Material 属性,这样 Direct3D 就知道渲染时使用那种材质数据。

这里介绍一点关于光线和色彩的知识: 环境色( ** ambient color ** ** ) ** ,当其为黑色时,表示(环境光)不会影响材质的颜色,当环境色变浅时,它就会照亮材质,并将两种颜色混和起来,从而影响材质的颜色。如何场景中有环境光,那么这些光的颜色和亮度就会控制环境色对于最终材质颜色的影响程度)。把材质改为没有红色成分的颜色(比如绿色)会使物体再次变为黑色(注:因为此时物体不会反射红色,红色的光线被物体全部吸收了),改为含一些红色成分的颜色(比如灰色 gray )会使物体呈现深灰色。

Mesh 会被分为一系列的子集( subsets )(依据属性缓冲的大小来分配),同时使用一个叫做 “DrawSubset” 的方法来渲染。使用 Mesh 类创建的普通图元总是只有一个基于 0 的子集。所以使用了 mesh.DrawSubset(0)

下面附上这个例子的全部代码:

using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

using Microsoft.DirectX;

<p class="MsoNormal" style="BACKGROUND: #e5e5e5; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-shading: windowtex

Published At
Categories with Web编程
Tagged with
comments powered by Disqus