网站公告 | 全新unity3d 完整学习路线,最强课程配套、服务!详情点击
查看: 19931|回复: 0
收起左侧

[已翻译] 让我们建立一个3D图形引擎:点,矢量和基本概念

[复制链接]

[已翻译] 让我们建立一个3D图形引擎:点,矢量和基本概念[复制链接]

1375134064 发表于 2018-4-9 14:33:27 [显示全部楼层] |只看大图 回帖奖励 |倒序浏览 |阅读模式 回复:  0 浏览:  19931
版权所有,禁止**转载;禁止商业使用;禁止个人使用。
翻译:崔国军(飞扬971) 审校:张乾光(星际迷航)
当今大型游戏背后的3D游戏引擎是数学和编程相结合的惊人作品,许多游戏开发者发现完整的理解3D游戏引擎是一个非常困难的任务。如果你缺乏经验(或者像我一样没有大学学历),这个任务会变得更加艰巨。在这个系列中,我的目标是带你遍历整个3D引擎图形系统的基础知识。
更具体一点来说,在本教程中我们将讨论点和向量,以及他们带来的全部乐趣。如果你对代数(变量和变量数学)和计算机科学(具有任何面向对象的编程语言的基础知识)有基本的了解,应该对整个教程绝大部分的内容的掌握没有什么困难,但是如果你在任何的概念上有些困扰,请直接提问出来!有些主题可能非常的困难。
坐标系的基础知识
让我们从基础概念开始。三维图形需要三维空间的概念。这些空间中最广泛使用的那个被称为笛卡尔空间,在那个空间我们可以尽情享受笛卡尔坐标带来的便利。(基本的( X,Y)符号和大多数中学教导的基于网格的2D图形)。

DSC0000.png


如图所示:很多高中生痛恨的概念。三维笛卡尔空间有三个坐标轴:x,y ,和z轴。(分别根据水平位置,垂直位置,和深度位置来对位置信息进行描述)。在此空间内的任何点的坐标都被表示为元组(在这种情况下是3元组,因为有三个轴)。在一个二维平面内,一个元祖可以被描述为(x,y),而在一个三维平面内,一个元祖被描述为(x,y,z)。使用这种3元组的原因是,它显示了一个点相对于空间的原点的位置。(原点通常显示为(0,0,0))

小提示:元组:计算机科学或数学里面的一个名词,意思是一组元素的有序列表(或序列)。笛卡尔积中每一个元素(d1,d2,…,dn)叫作一个n元组(n-tuple)或简称元组。
笛卡尔坐标系(Cartesian coordinates):就是直角坐标系和斜角坐标系的统称。相交于原点的两条数轴,构成了平面放射坐标系。如两条数轴上的度量单位相等,则称此放射坐标系为笛卡尔坐标系。两条数轴互相垂直的笛卡尔坐标系,称为笛卡尔直角坐标系,否则称为笛卡尔斜角坐标系。
所以, (K,y,l,e) (将是一个四元组,展示了一组字符可以拼成我的名字。

DSC0001.png


在这个空间中,我们将用3元祖的形式来表示一个点。这也可以被表示为:
P=(x,y,z)
除了点的这个定义以外,我们必须确定它的各个部分。
3元祖里面的每个元素都是一个标量(数字),这个标量(数字)定义了一个沿着基向量(长度为一个单位长度的向量叫做基向量,也叫单位向量)的位置。每个基向量必须长度为一个单位长度(也就是长度正好为1)。所以诸如(1,1,1)和(2,2,2)的3元祖不是基向量,因为他们太长了。我们定义下我们空间的三个基向量:
X=(1,0,0)Y=(0,1,0)Z=(0,0,1)
DSC0002.jpg
小提示:标量(scalar),亦称“无向量”。有些物理量,只具有数值大小,而没有方向,部分有正负之分。物理学中,标量(或作纯量)指在坐标变换下保持不变的物理量。用通俗的说法,标量是只有大小,没有方向的量。例如,欧几里得空间中两点间的距离在坐标变换下保持不变,相对论四维时空时空间隔在坐标变换下保持不变。以此相对的矢量,其分量在不同的坐标系中有不同的值,例如速度。
坐标系统现在,让我们来谈谈我们的坐标系统的数学定义、它是如何影响我们的图形系统以及我们可以在坐标系统内进行的计算。
点的表示
我们坐标系的原点可以用点0来表示,用3元祖表示就是(0,0,0)。这意味着我们的坐标系统的数学表示可被描述为:
{O;X,Y,Z}
通过这个描述,你可以说(X,Y,Z)表示着相对于原点的点的位置。该定义还意味着对于任何点P(A,B,C)中,都可以表示为:
P=O+aX+bY+cZ
从这里开始,我将用小写字母来表示标量,大写字母来表示矢量-所以a,b,c是标量,而X,Y,Z是矢量。(他们实际上是我们先前定义的基向量)。
这意味着,如果一个点用三元组表示是(2,3,4),那么它可以表示成: (2,3,4)=(2,0,0)+(0,3,0)+(0,0,4)=(0,0,0)+(2,0,0)+(0,3,0)+(0,0,4)=(0,0,0)+2(1,0,0)+3(0,1,0)+4(0,0,1)=O+2X+3Y+4Z
所以,我们已经采取了“在三维空间中的一个点”这个抽象的概念,并将其定义为四个独立的对象的叠加。每当我们希望把概念转换成代码,这种定义是非常重要的。
互相垂直
我们使用的坐标系统有一个非常有价值的属性,就是互相垂直。这意味着任意2个坐标轴在它们俩组成的平面里它们之间的角度都是90度。

DSC0003.jpg



我们的坐标系统将也被定义为“右手坐标系” :
DSC0004.jpg
这张图来自 http://viz.aset.psu.edu/gho/sem_notes/3d_fundamentals/html/3d_coordinates.html.
小提示:左手坐标系:解析几何为了沟通空间图形与数的研究,需要建立空间的点与有序数组之间的联系,为此我们通过引进空间直角坐标系来实现。在空间直角坐标系中,让右手拇指指向x轴的正方向,食指指向y轴的正方向,如果中指能指向z轴的正方向,则称这个坐标系为右手直角坐标系.同理左手直角坐标系
在数学术语中,这意味着:
X=Y×Z
其中, ×代表叉积运算符。
如果你还不知道叉积是什么,那么它可以用下面这个式子来定义(假设你使用两个三元组):
(a,b,c)×(d,e,f)=(bf−ce,cd−af,ae−bd)
这些陈述可能看上去有点单调乏味,但在本文的后面一点点的部分,就能看到它们能帮助我们更容易的完成各种不同的计算以及转换。幸运的是,当你构建一个游戏引擎的时候,你并不需要记住所有这些公式,你可以从这些公式构建一些简单的函数,然后再在这些函数上面构建一个稍微复杂的系统。好了,直到你需要编辑你的引擎里面的一些基础函数的时候,你才需要再次面对这些内容!
小提示:叉积,数学中又称外积、向量积,物理中称矢积、叉乘,是一种在向量空间中向量的二元运算。与点积不同,它的运算结果是一个向量而不是一个标量。并且两个向量的叉积与这两个向量的和垂直。两个向量a和b的叉积写作a×b(有时也被写成a∧b,
避免和字母x混淆)。向量积可以被定义为:
|向量a×向量b|=|a||b|sinθ在这里θ表示两向量之间的夹角(共起点的前提下)(0° ≤ θ ≤ 180°),它位于这两个矢量所定义的平面上。
点和向量有了之前描述的所有关于坐标系的基础知识,现在是时候来谈论下点和向量了,更重要的是它们之间互相交互的方式。首先要注意的一点是,点和向量是完全不同的事情:点是你的空间中的物理位置而向量是两个点之间的差。
小提示:在数学中,几何向量(也称为欧几里得向量,通常简称向量、矢量),指具有大小(magnitude)和方向的量。向量可以形象化地表示为带箭头的线段。箭头所指:代表向量的方向;线段长度:代表向量的大小。而在物理学和工程学中,几何向量更常被称为矢量。许多物理量都是矢量,比如一个物体的位移,球撞向墙而对其施加的等等。与之相对的是标量,即只有大小而没有方向的量。一些与向量有关的定义亦与物理概念有密切的联系,例如向量势对应于物理中的势能

DSC0006.png


为了确保这两个不要混淆,我会用点用italics字体的大写来表示, 比如P,向量用粗体大写来表示,比如为V。
当使用点和向量的时候我们主要使用两个公理,它们是:
  • 公理 1: 两点之差是一个向量,所以  V=P−Q
  • 公理2: 一个点和一个向量的和还是一个点,所以 Q=P+V
小提示:公理是指依据人类理性的不证自明的基本事实,经过人类长期反复实践的考验,不需要再加证明的基本命题。
构建引擎
有了上面说的这些公理,我们现在有足够的信息来创建任何3D游戏引擎需要的核心类:点(Point)类和向量(Vector)类。如果我们要利用这些信息来构建我们自己的游戏引擎,那么当创建这些类的时候还有另外一些重要的步骤(主要是对计算进行优化或者处理现有的API),但是我们出于保持教程的简单性我们现在不处理这些问题。
下面的示例类都全部是伪代码,这样你可以用你自己熟悉的编程语言来实现它们。这是我们两个类的大概样子:
[size=1em]

[size=1em][size=1em]
[C++] 纯文本查看 复制代码
Point Class
{
    Variables:
        num tuple[3]; //(x,y,z)
 
    Operators:
        Point AddVectorToPoint(Vector);
        Point SubtractVectorFromPoint(Vector);
        Vector SubtractPointFromPoint(Point);
         
    Function:
        //later this will call a function from a graphics API, but for now
        //this should just be printing the points coordinates to the screen
        drawPoint;
 
}
 
Vector Class
{
    Variables:
        num tuple[3]; //(x,y,z)
 
    Operators:
        Vector AddVectorToVector(Vector);
        Vector SubtractVectorFromVector(Vector);
}





作为练习,尽量在这几个类的每个方法里面填充好工作代码(基于我们目前为止已经讨论到的内容)。一旦你完成了全部的内容,请把它们放入下面这个测试程序看下结果。
[size=1em]

[size=1em][size=1em]
[C++] 纯文本查看 复制代码
main
{
    var point1 = new Point(1,2,1);
    var point2 = new Point(0,4,4);
    var vector1 = new Vector(2,0,0);
    var vector2;
 
    point1.drawPoint(); //should display (1,2,1)
    point2.drawPoint(); //should display (0,4,4)
 
    vector2 = point1.subtractPointFromPoint(point2);
 
    vector1 = vector1.addVectorToVector(vector2);
 
    point1.addVectorToPoint(vector1);
    point1.drawPoint(); //should display (4,0,-2)
 
    point2.subtractVectorFromPoint(vector2);
    point2.drawPoint(); //should display (-1,6,7)
}





结论
你已经学完这一部分了!我知道这一部分看起来像是很可怕的数学教程,全文在编程方面只定义了两个类,这个观点确实也是正确的。在大多数情况,你绝对不会在这个层次上开发游戏,但是对你的游戏引擎的内部工作原理有一个深入的了解仍然是有帮助的(而不仅仅是自我满足)。
如果你觉得这一部分教程足够有趣,那么一定要看下我的下一个图形系统基础知识方面的教程:变换!

关于作者:Kyle Sloka-Frey
evolvingpoet媒体的拥有者。程序员、网页设计师、音乐爱好者、独立开发顾问以及任意我周围的人需要做的角色。我的独立游戏网站:www.evolvingpoet.com
【版权声明】
原文作者未做权利声明,视为共享知识产权进入公共领域,自动获得授权。



+1
19923°C
沙发哦 ^ ^ 马上
因分享而快乐,学习以自强!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

VR/AR版块|Unity3d|Unreal4|新手报道|小黑屋|站点地图|沪ICP备14023207号-9|【泰斗社区】-专注互联网游戏和应用的开发者平台 ( 浙ICP 备 13006852号-15 )|网站地图

© 2001-2013 Comsenz Inc.  Powered by Discuz! X3.4

1
QQ