三维坐标系和几何学
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
自己收集整理的
仅供参考交流
如有错误
请指正!谢谢
三维坐标系和几何学
类型:转贴 | 来源:整理 | 时间: 2006-06-12
下面我们将介绍在编制立即模式程序之前需要了解的一些技术上的概念
他并不是对较宽层面上的详细描述
也不是对Direct3D的组成部分的深入分析
要了解更多的有关信息
可以察看"Direct3D立即模式的体系结构"和"Direct3D立即模式的要素"两部分内容
如果你已经对编制三维图形程序有一定经验
可以浏览一下以下的内容
了解一些Direct3D所特有的东西
这些内容分为以下两个部分:
三维坐标系和几何学(3-D Coordinate Systems and Geometry)
矩阵和变换(Matrices and Transformations)
一.3-D坐标系统和几何学
编制Direct3D应用程序要对三维几何学的一些基本内容有一定的了解
这与部分我们将介绍一些重要的有关创建三维场景的几何学概念
分为以下几个部分:
3-D坐标系统(3-D Coordinate Systems)
3-D图元(3-D Primitives)
三角光栅准则(Triangle Rasterization Rules)
明暗处理(Shading)
1. 3-D坐标系统
一般来说
3-D图形应用程序使用两种类型的笛卡尔坐标系统:即左手坐标系统(left-handed)和右手坐标系统(right-handed)
在这两种坐标系统中
x-轴正方向均指向右边
y-轴正方向也都指向上方
z-轴的方向可以用左、右手定则来确定
即握起左(或右)手的四指来代表由x-方向旋转到y-方向
则左(或右)手的拇指就指向z-轴的正方向
如下图:
Direct3D中使用的是左手坐标系统
如果你的程序使用的是右手坐标系统
那么你只需要对Direct3D的数据做两个很小的修改:
改变三角形顶点的顺序
使它们从前面来看按照顺时针的方向排列
换句话说
如果顶点是v0、v1、v2
那么传递给Direc3D的是v0、v2、v1
使用视矩阵(view matrix)来对世界空间进行调整
即将z-方向调整为-1
这样就需要改变D3DMATRIX结构体的_31、_32、_33和_34成员的正负号
它们被用于视矩阵之中
要注意的是
还有其它许多种用于3-D软件的坐标系统
左手和右手系统只是其中最常用的两种
然而在三维造型程序中
y-轴指向或背离观察者
z-轴朝上的坐标系统也经常被采用
既然如此
右手系统中通常将任意一个正坐标方向(x、y或z)指向观察者
左手系统则通常将任意一个坐标的负方向指向观察者
如果你所使用的左手坐标系统中z-轴指向上方
那么除了前面所说的之外
你还需要对所有的顶点数据进行旋转
对三维坐标系统中定义的对象
一些基本的操作包括:平移(translate)
旋转(rotate)
和缩放(scale)
你可以将这些基本的变换组合起来建立一个变化矩阵
想要进一步的了解有关内容
请注意"3-D变换"部分
要记住的是
将这些操作组合在一起的顺序是很重要的
组合顺序的不同
得到的结果也会不同
2. 3-D图元
一个3-D图元就是一些顶点的集合
它们组成了一个三维实体
最简单的图元就是一个三维坐标系统中的点的集合
在Direc3D中我们称为顶点列表(point list)
通常
三维图元都是多边形
Direct3D中的多边形是一个封闭的三维图形
它至少由三个顶点组成
最简单的多边形是一个三角形
Direct3D用三角形来组成大多数的多边形
这是因为一个三角形的三个顶点保证是共面的
渲染非共面的顶点是很困难的
我们可以用三角形来组成更大的更复杂的多边形和多面体(mesh)
下方的左图显示了一个立方体
立方体的每一个面由两个三角形组成
这些三角形一起组成了一个立方体图元
你可以在图元的表面上使用材质和纹理
这样就使它更象一个实心的物体
要了解更多有关的内容
注意"材质和纹理"部分
你也可以使用三角形来构造一个表面由平滑曲面组成的图元
上方的右图展示了一个由三角形构成的球体
使用了材质之后
这个球体的表面看起来会更平滑
如果再使用Gouraud明暗处理方法
它会更加逼真
3. 三角光栅准则
通常
用来表示顶点的点不会和屏幕上的像素很好的吻合
这时
Direct3D会使用三角光栅准则来决定将那些像素用来显示一个给定的三角形
Direct3D使用左上角填充约定(top-left filling convention)
这与应用于GDI和OpenGL中的矩形的约定是一致的
在Direct3D中
我们用像素的中心点来进行判决
当中心点在一个三角形内部时
这个像素就被判定为属于这个三角形
像素的中心点的坐标值都是整数
Direct3D中所使用的这一三角光栅准则并不一定被所有的硬件所使用
经过测试我们会发现
这些约定在执行时会有一些细小的差别
下面左图中显示了一个矩形
它的左上角坐标为(0
0)
右下角坐标为(5
5)
这个三角形填充了25个像素
它的宽为右侧坐标减去左侧坐标
高为底边坐标减去顶边坐标
在左上角填充约定中
"上"一词代表水平跨度(span)在竖直方向上的位置
"左"一词则代表一个跨度内像素的水平位置
如果一条边不是水平的话
那么它就不能被称为一个顶部边缘(top edge)
这样一来
大多数的三角形就都只有左侧和右侧边缘了(left and right edges)
如上面右图所示
当一个三角形的边穿过像素的中心时
也由左上角填充规则来进行判决
左图显示了两个三角形
一个位
于(0, 0)
(5, 0)
和(5, 5)
另一个位于(0, 5)
(0, 0)
和(5, 5)
第一个三角形占据了15个像素
而第二个三角形占据了10个像素
这是因为两个三角形的公共边是第一个三角形的左侧边缘
我们来举个例子
如果我们定义了一个矩形
它的左上角坐标为(0.5, 0.5)
右下角坐标为(2.5, 4.5)
那么这个矩形的中心点就应该在(1.5, 2.5)
当Direct3D的光栅(rasterizer)在这个矩形上覆盖了一层小方格图案之后
每个像素的中心明确的分别位于四个三角形之内
而此时
左上角填充规则就不再需要了
下面的左图就显示了这一例子
位于矩形内的像素会按照它所在的三角形来区分
Direct3D中也包含了这样的情况
如果你将上面例子中的矩形移动一下
使它的左上角位于(1.0, 1.0)
右下角位于(3.0, 5.0)
则中心点位于(2.0, 3.0)
这时
Direct3D就会使用左上角填充准则
这个矩形中的大多数像素就会骑跨在两个或更多的三角形的边界上
如上面右图所示
对这两个矩形来说
相同的像素都要受影响
4. 明暗处理Shading
这一部分我们将讨论Direct3D明暗处理的有关内容
4.1 明暗处理模式Shade Modes
4.2 各种模式的比较Comparing Shading Modes
4.3 设置明暗处理模式Setting the Shade Mode
4.4 面和顶点法向量Face and Vertex Normal Vectors
4.5 三角形内插Triangle Interpolants
4.1 明暗处理模式
渲染多边形时所采用的明暗处理模式对于多边形的外观有很大的影响
明暗处理模式决定了一个多边形的表面上任意一点的颜色和光线的强度
Direct3D目前支持两种明暗处理模式:
平面明暗处理模式(Flat Shading)
Gouraud明暗处理模式(Gouraud Shading)
4.1.1 平面明暗处理模式
使用平面明暗处理模式来渲染一个多边形时
Direct3D的渲染管道(rendering pipeline)使用多边形上第一个顶点的材质的颜色来作为整个多边形的颜色
使用平面明暗处理模式进行渲染的三维对象
在相邻的不共面的两个平面之间
会出现较明显的边缘
下图显示了一个采用平面明暗处理模式进行渲染的茶壶的图片
图片中
每一个多边形的轮廓都非常清晰
平面明暗处理模式所要使用的计算量是两种明暗处理模式中最小的
4.1.2 Gouraud明暗处理模式
使用Gouraud明暗处理模式渲染一个多边形时
Direct3D利用顶点法线(vertex normal)和灯光参数(lighting parameters)来计算每个顶点的颜色
然后
在多边形的表面上进行线性内插运算(见"边面和顶点法向量"部分)
举例来说
如果顶点1的红色值为0.9
顶点2的红色值为0.4
使用Gouraud明暗处理模式和RGB色彩模式
那么这两个顶点间连线的中点的的红颜
色的值就是0.6
下图中显示了使用Gouraud明暗处理模式的效果
图中的茶壶由许多小的三角形平面所组成
然而Gouraud明暗处理模式使得它的表面看起来非常的平滑和完整
Gouraud明暗处理模式也可以用来显示具有明显边缘的对象
具体细节见"表面和顶点法向量"部分
4.2 明暗处理模式的比较
在平面明暗处理模式中
下图中的金字塔的相邻两个面之间会有明显的边缘
而采用Gouraud明暗处理模式时
边缘处的明暗值会由内插运算产生
因而最后会得到一个弯曲的表面
使用Gouraud明暗处理来照亮平坦的表面要比使用平面明暗处理模式更加真实
平面明暗处理模式中的同一个面的颜色是相同的
而Gouraud处理模式允许光线在表面上有更逼真的效果
当离一个表面很近的地方有一个点光源时
它们的区别将会更明显的表现出来
Gouraud模式会将在平面处理模式中明显的边缘平滑掉
然而这样可能会导致马赫带效应(Mach bands)的产生
也就是相邻的颜色或光线带之间不能很平滑的相互融合
对于程序开发人员来说
可以通过增加构成对象的多边形的数目来降低马赫带效应
当然也可以通过提高屏幕分辨率
或者增加程序的颜色深度来达到目的
使用Gouraud模式可能会丢失一些细节
下图的例子显示了这一情况
图中的聚光灯完全位于一个多边形表面上
这样
当Gouraud模式在两个顶点间进行内插的同时
也就将聚光灯一同丢失了;渲染出来的表面将不再有聚光灯
4.3 设置明暗处理模式
Direct3D允许每次选中一种明暗处理模式
缺省情况下为Gouraud模式
可以通过调用IDirect3DDevice3::SetRenderState方法来改变模式
dwRenderStateType参数应该被设定为D3DRENDERSTATE_SHADEMODE
dwRenderState参数应该被设定为D3DSHADEMODE枚举类型的一个成员
下面的代码显示了如何来设定当前的明暗处理模式
// Set to flat shading.
// This code fragment assumes that lpDev3 is a valid pointer to
// an IDirect3DDevice3 interface.
hr = lpDev3->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_FLAT);
if(FAILED(hr))
{
// Code to handle the error goes here.
}
// Set to Gouraud shading (this is the default for Direct3D).
hr = lpDev3->SetRenderState(D3DRENDERSTATE_SHADEMODE,
D3DSHADE_GOURAUD);
if(FAILED(hr))
{
// Code to handle the error goes here.
}
4.4 面和顶点法向量
一个多面体的每一个面都有一个与这个面正交的法向量
这个向量的方向由构成面的顶点的组成顺序以及所使用的坐标系统来决定
面的法线总是远离这个面的正面一侧
即由这个面的正面一侧开始指向向外的方向
在Direct3D中
只有面
的正面一侧是可见的
面的正面也就是指
从这一侧来看面上的顶点按照顺时针方向来构成这个面
任何一个面只有正面和反面两个面
Direct3D是不对反面进行渲染的
因此反面可以说被Culling掉了(be culled)
(如果需要的话
可以改变Culling模式(culling mode)来对反面进行渲染
纤细内容见"Culling状态"部分
)
Direct3D程序不需要对面法向量进行声明;当需要用到它们时
系统会自动进行计算
在平面明暗处理模式中
我们会用到面法向量
而在Gouraud模式中
Direct3D使用顶点法向量(vertex normal)
它还使用顶点法向量来控制灯光和纹理效果
Direct3D程序通常使用顶点的D3DVERTEX类型
D3DVERTEX结构的成员用来描述顶点的位置和方向
这里的方向就是指顶点的法向量
下面的代码显示了如何来设置顶点的各种值
包括顶点法向量
其中法向量指向位于世界坐标系的原点的视口(viewport)
这个例子中顶点的位置就位于世界坐标系中
D3DVERTEX lpVertices[3];
// A vertex can be specified one structure member at a time.
lpVertices[0].x = 0;
lpVertices[0].y = 5;
lpVertices[0].z = 5;
lpVertices[0].nx = 0; // X component of the normal vector.
lpVertices[0].ny = 0; // Y component of the normal vector.
lpVertices[0].nz = -1; // Points the normal back at the origin.
lpVertices[0].tu = 0; // Only used if a texture is being used.
lpVertices[0].tv = 0; // Only used if a texture is being used.
// Vertices can also by specified on one line of code for each vertex
// by using some of the D3DOVERLOADS macros.
lpVertices[1] = D3DVERTEX(D3DVECTOR(-5,-5,5),D3DVECTOR(0,0,-1),0,0);
lpVertices[2] = D3DVERTEX(D3DVECTOR(5,-5,5),D3DVECTOR(0,0,-1),0,0);
使用Gouraud模式时
Direct3D用顶点法向量来计算光源和表面之间的夹角
它还计算顶点的颜色和亮度
并且在原先的表面上通过内差运算来得到其它点上的值
Direct3D是通过夹角来计算亮度值
夹角越大
表面上光线的亮度就越小
.
如果你所创建的对象的表面是平坦的
那么顶点的法向量就应该与对象的表面正交
下图向我们显示了这一情况
图中平坦的表面由两个三角形构成
所有顶点的法向量都与表面正交
一般情况下
我们所创建的对象都是由许多的小的三角带(triangle strip)组成的
并且这些三角形往往是不共面的
这样
在我们在对对象的表面进行平滑的明暗处理时
就有一种简单的方法来得到各个顶点的法向量
我们可以先来计算每一个小多边形平面的法向量
而顶点的法向量就是与这些小平面的法向量的夹角相等的那一个向量
要注意的是
对于复杂的图元
这种方法可能不够有效
下面
左图中向我们演示了这种方法
图中由两个面
S1和S2
我们看到的是它们的侧面
S1和S2的法向量用蓝色表示
顶点的法向量用红色表示
我们可以看到
顶点法向量与S1和S2的面法向量的夹角是相等的
使用Gouraud明暗处理模式时
这两个面之间将是平滑的
不再有明显的边缘或棱角
如果顶点的法向量偏向任何一个面
会使表面上的亮度增加或减少
而这又由它与光源之间的夹角来决定
上面右图的例子显示了这一情况
图中我们还是只能看到两个面的侧面
并且顶点的法向量偏向S1一侧
这样就使它与光源的夹角比正常情况下有所减小
在使用Gouraud明暗处理模式时
我们也可以使一些对象具有尖锐的边缘
如果正在使用执行缓冲(execute buffers)
,那么程序就需要对边缘上的点的法向量制作一个副本
如下图所示
我们可以看到
位于尖锐边缘的点的法向量都有两个
如果使用IDirect3DDevice3::DrawPrimitive或IDirect3DDevice3::DrawIndexedPrimitive方法来渲染场景
必须将具有尖锐边缘的对象定义为三角形列表(triangle list)的形式
而不是采用三角带(triangle strip)的形式
如果对象有三角带来构成
那么Direct3D就会把它当作由许多三角形面片组成的一个单独的多边形来对待
而这时
Gouraud模式对多边形的每一个面片和两个相邻面片之间的部分都有效
这样最终的结果就会使对象具有平滑的表面
然而以三角形列表的形式构成的多边形则是由一系列不相连贯的三角形面片来组成
这种情况下
Gouraud模式只对多边形的每一个面片有效
而对面片之间的部分是无效的
这时
如果三角形列表中的几个三角形相邻的话
那么他们之间就会出现尖锐的边缘
另一种选择是使用平面明暗处理模式
这样在计算量上是很有效的
但是它的效果会不如采用Gouraud模式时的逼真
4.5 三角形内插
当系统渲染一个场景时
它会在三角形上对三角形的顶点间进行内插运算
三角形内插运算包括:
颜色Color
镜面属性Specular
阿尔法值Alpha
内插运算在不同的明暗处理模式下也是不同的
如下所示:
平面模式:不进行内插运算
用三角形中的第一个顶点的颜色作为整个面片的颜色
Gouraud模式:在所有三个顶点之间进行线性内插运算
当色彩模式不同时
颜色内插和镜面属性内插也是不同的
在RGB颜色模式下
系统使用红、绿、蓝三种颜色成分来进行内插
单色模式(或ramp模式)下
系统仅使用顶点颜色的蓝色成分
颜色的阿尔法成分通常单独来进行内插运算
这是因为设备驱动器可以有两种方法来实现透明效果:纹理融合(texture blend
ing)或点画法(stippling)
程序可以使用D3DPRIMCAPS结构的dwShadeCaps成员来决定当前的设备驱动器支持哪种内插形式