XNA Kick Start (六)

 第三章 进入3D世界

本文版权归我所有,仅供个人学习使用,请勿转载,勿用于任何商业用途。
由于本人水平有限,难免出错,欢迎大家和我交流。
作者:clayman
Blog:
http://blog.csdn.net/soilwork
clayman_joe@yahoo.com.cn

三维化三角形
       为了让三角形看起来 3D 一些,所要做的第一步就是在 3D 空间中重新定义三角形顶点。修改代码:
 
        private void InitTriangle()
        {
            verts = new VertexPositionColor[3];
 
            verts[0].Position = new Vector3(0, 1f, 0.0f);
            verts[0].Color = Color.Red;
            verts[1].Position = new Vector3(1f, -1f, 0.0f);
            verts[1].Color = Color.Blue;
            verts[2].Position = new Vector3(-1f, -1f, 0.0f);
            verts[2].Color = Color.Green;
            decl = new VertexDeclaration(this.graphics.GraphicsDevice, VertexPositionColor.VertexElements);
        }
    
    虽然这里的代码看起来和前面差不多,但这一次是在模型空间中来定义三角形。也就是说当前的坐标系以三角形中点为坐标原点。
    接下来创建前面提到的三个坐标变换矩阵。如果你对线性代数不太熟悉也没有关系, xna 已经为我们提供了创建大多数常见矩阵的方法,只需要用希望的参数来调用这个方法就能获得相应矩阵。在 Draw 方法中添加如下代码:
 
     Matrix worldMatrix = Matrix.CreateTranslation(new Vector3(0, 0, -10));
     Matrix viewMatrix = Matrix.CreateLookAt(new Vector3(0,0,0), new Vector3(0,0,-1), new Vector3(0,1,0));
     Matrix projectionMatrix = Matrix.CreatePerspectiveFieldOfView((float)Math.PI/4,
                (float)graphics.GraphicsDevice.Viewport.Width / (float)graphics.GraphicsDevice.Viewport.Height,
                1.0f, 1000.0f);
 
    Matrix 是一个 4x4 的矩阵。上面的代码使用 Matrix 提供的静态方法,分别创建了世界坐标变换矩阵,观察矩阵和投影矩阵。 CreateTranslation ,接收一个 Vector3 类型的参数,这个参数就是将要把三角形放到世界坐标中的位置( 0 0 -10 )。
    CreateLookAt() 方法的第一个参数代表观察点或者说摄像机的位置,第二个参数表示观察的方向。由于三角形位于点( 0 0 -10 ),因此从( 0 0 -1 )方向看过去,三角形刚好位于视野中央。最后一个参数代表一个“向上”的位置,观察物体时,你有可能倒立着看,也有可能偏着脑袋看,( 0 1 0 )表示最常见的观察物体的角度,正立在地面上观察。
    CreatePerspectiveFieldOfView() 看起来比较长,其实也很简单。他的第一个参数表示视野角度:

    如图所示,假设我们从 Z 轴方向直视,那么上下左右所能观察到的最大角度,就是视野角度的一半(图中角 fov/2 )。这里用了最常见的值 90 度也就是 Pi/4 。第二个参数是视野的高宽比,接下来两个参数则是近裁减平面和远裁减平面的距离。
    接下来,把三个矩阵相乘,作为最终的变换矩阵:
 
    Matrix worldViewProj = worldMatrix * viewMatrix * projectionMatrix;
 
    对于矩阵运算来说,相乘时的顺序很重要,矩阵乘法是不满足交换律的,因此上面的相乘顺序不能颠倒。
    最后一步,把最终的变换矩阵与顶点坐标相乘,就能显示出这个 3D 的三角形了。修改 HLSL 代码:
 
uniform float4x4 worldViewProj;
void transform(inout float4 pos :POSITION,
     inout half4 color : COLOR0)
{
     pos = mul(pos,worldViewProj);
     color = color;
}
 
这里,在 Shader 中添加了一个 float4x4 类型的变量用来表示最终的变换矩阵。 Uniform 表示这个这个变量将由外部程序,也就是 C# 程序来赋值。在 transform 方法中把三角形的模型坐标位置与矩阵相乘,得到最终的屏幕坐标。注意,这里是矩阵乘法,应次必须使用 mul() 方法计算乘机,而不能简单的用“ * ”, mul HLSL 中的内置标准方法之一。
    当然,必须先使用 Effect 把把 worldViewProj 变量的值从 C #代码中传递给 Shader
 
effect.Parameters["worldViewProj"].SetValue(worldViewProj);
 
Effect 对象的 Parameters 成员是一个保存了 shader 中所有参数的列表。通过这些参数在 HLSL 的名称来进行索引获得相应变量,并使用 SetValue 方法进行赋值。
    好了,现在运行程序,看看结果吧。
    嗯,我知道,此时你可能相当失望:结果看起来还是和原来一样。不要急,这只是因为三角形并没有运动,因此看不出它是 3D 的。让我们立刻做一点点修改,让三角形旋转起来 :
 
    Matrix rotation = Matrix.CreateRotationY((float)gameTime.TotalGameTime.TotalSeconds * 8f);
Matrix worldMatrix = rotation * Matrix.CreateTranslation(new Vector3(0, 0, -10));
 
    CreateRotationY 将返回一个让物体绕 Y 轴旋转的矩阵,我们根据时间的变化来增加旋转角度,这样三角形看起来就一直在旋转。接下来,把它与世界坐标变换矩阵相乘,这里,乘法顺序同样重要。 Rotation × worldMatrix 表示先在模型控件中旋转三角形,再把它放到世界坐标中的 (0, 0, -10) 位置,而 worldMatrix × rotation 则是先把物体放到世界坐标中的( 0 0 ,- 10 )位置,然后在以世界坐标中的 Y 轴进行旋转,最后的显示结果将是不同的。当然,你可以尝试混合多种旋转,获得更疯狂一些的效果 ^^
    好了,再次运行程序。终于看到一个 3D 三角形了吧。嘿,等等,似乎还有些问题。三角形在旋转时会周期性的消失一阵,是 bug 吗?当然不是,这就是我马上要提到的背面裁减( back face cull 技术。
    默认情况下,当图形背对观察者时,渲染流水线会把这个图形裁减去,即不渲染它。背面裁减是很重要的技术,对减少硬件工作量,提高程序效率有重要作用。大多数情况下,显示背对观察者的图形是没有意义的。那么硬件如何知道一个图形是否背对着观察者呢,如何知道哪个面是正面呢?硬件通过图形的顶点顺序来进行判断,当然确切说应该是通过正面的法线来判断,只不过根据顶点顺序来判断计算量要小很多。回头看看所有创建三角形的代码,都是以顺时针顺序来声明并创建顶点。默认情况下, XNA 认为以顺时针 方向 定义的面是正面。

显然,当三角形旋转到背面时,顶点顺序将颠倒过来,法线也会翻转,因此被硬件裁去。由于目前我们只有一个简单的三角形,所以并不希望硬件对他进行裁减。 XNA 中可以使用 CullMode 枚举来选择裁减哪些图形:顺时针,逆时针,或者不裁减。在 Draw() 方法中绘制图形前添加如下代码:
   
     graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;
 
再次运行程序,可以看到这次显示的很正常了。

 ~~~~~~~~~~~~~~~~~~~~~~~~~第三章完~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

---____---b, 太久没有写教程,这一部分写的实在是太烂了,大家勉强看吧。。。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值