Introduction

图形学领域

三大主要领域:
建模:用计算机能存储的格式描述物体的形状和外表性质
渲染:从3D模型创建图像
动画:从一系列图像中创建运动效果,同时使用建模和渲染

下列是否是图形学核心领域仍存疑
人机交互:(研究设备的界面以及其他可感知的反馈) 虚拟现实、数据可视化、图像处理、3D扫描、计算

主要应用

游戏:越来越多使用复杂3D模型和渲染算法
卡通:很多传统2D卡通也用3D渲染的背景,这样可以使视点不断运动,节省绘画时间
视觉特效:很多电影使用3D建模来创建合成的环境,物体,甚至角色。
动画电影:与视觉特效使用技术类似,但是不需要做的逼真
CAD/CAM:使用CG技术来设计零件并模拟制造过程,进而指导实际生产。
模拟: 可以认为是接近现实的游戏,可以用来在跟安全有关的领域中,对人们进行训练,以避免花费过高或者过于危险的真实训练。
医学图形处理:从扫描数据创建有意义的图像,帮助医生提取重要信息
数据可视化:从数据集创建数据的图形化趋势或者特征。

图形API

图形API是实施相关操作的标准函数集合,这些函数可以绘制图像和3D表面。每个图形程序都需要两个API,一个是图形API来给出视觉输出,和用户API来收集用户的输入。这两个API现在有两个模式,一个是集成的,将标准化过的图形和用户工具集集成在一个包中,从而被编程语言支持,比如java;另一个是将图形API作为库包含在编程语言中,而用户API随系统的不同而可能有差异。对于后者,很利于编写可移植的代码,(尽管对于某些小程序,也可以将特定的用户API封装在可移植的库中)

图形流水线

图形流水线是特别的软件/硬件子系统,它可以高效地绘制图元,通常这些系统针对处理3D多边形和共享顶点做了优化。流水线的基本操作是将3D顶点映射到2D屏幕的特定位置上,并处理这些三角形,使它们看起来像真的,并保证其正确的空间位置
虽然以有效的后-前顺序绘制三角形曾经是图形学中的重要研究问题,然而现在已经通过z-buffer解决了,它使用特殊的内存缓冲区来解决问题。事实证明,图形管道中使用的几何操作可以完全在由三个传统坐标系和一个有助于透视观看的坐标系组成的4D坐标空间中完成。我们使用4×4矩阵和4维向量来操纵这些4D坐标。因此,图形管道包含很多处理和组合这样的矩阵和向量的工具。(很重要!)
因为交互性(帧数)在许多应用中更为重要,所以值得最小化三角形的数量(生成图像的速度在很大程度上取决于三角形的绘制数量),而不是更好地去表示模型。此外,相比于较近距离观看模型,在远处观看模型,需要的三角形更少,说明具有不同细节等级的模型是有必要的。

数值相关

很多图形程序实际上是三维数值代码,所以数值问题在这些程序中是很重要的,过去受限于机器内部表示数字的方法不同,很难去实现一个稳定和可移植的程序,但自从IEEE浮点数标准出现之后,使得程序员可以做很多机器将如何处理数字的假设,方便了程序开发,下面对该标准做简单介绍:

  1. 无穷大(比任何其他合法数字更大的合法数字) 无穷小(比任何其他合法数字更小的合法数字) 非数字(NaN) 一些未定义的行为的执行结果,比如除0
  2. 对于任意实数a 有以下四个规则
    +a/(+∞)=+0+a/(+\infty)=+0+a/(+∞)=+0−a/(+∞)=−0-a/(+\infty)=-0−a/(+∞)=−0+a/(−∞)=−0+a/(-\infty)=-0+a/(−∞)=−0−a/(−∞)=+0-a/(-\infty)=+0−a/(−∞)=+0
  3. 对于无穷数运算,有以下几个规则
    ∞+∞=+∞\infty + \infty =+\infty ∞+∞=+∞∞−∞=NaN\infty - \infty =NaN∞−∞=NaN∞∗∞=∞\infty * \infty =\infty ∞∗∞=∞∞/∞=NaN\infty / \infty =NaN ∞/∞=NaN∞/a=∞\infty / a =\infty∞/a=∞∞/0=∞\infty /0 =\infty∞/0=∞0/0=NaN0/ 0=NaN 0/0=NaN
  4. 在bool表达式中,规定所有有效数字小于+∞+\infty+∞ 大于−∞-\infty−∞ 而且−∞-\infty−∞ 小于+∞+\infty+∞
  5. 对于包含NaN的表达式:所有包含NaN的算术表达式结果都为NaN 而所有bool表达式结果为false
  6. 对于除0的情况 +a/+0=+∞+a/+0=+\infty+a/+0=+∞ −a/+0=−∞-a/+0=-\infty−a/+0=−∞

效率

效率往往是妥协的结果,比如在可见的未来,很可能程序员应当更加注意内存存取的模式,而不是关注操作数目,这是因为这些年来内存速度并没有跟上处理器速度的增长。一个合理的优化效率的途径是这样的:

  1. 以更直接的方式编写代码,别存储计算的中间量
  2. 编译时开更高的优化级别
  3. 用性能分析工具找到重要的性能瓶颈
  4. 检查数据结构以进行本地优化,比如将数据单元大小与缓存大小匹配
  5. 检查汇编代码,找到效率低下的原因

最重要的其实就是第一步,很多优化会使代码非常难读。更何况把时间放在优化代码上总比放在解决bug上要好。注意一些旧的优化手段,可能它们在新的CPU上已经不再奏效了。不过性能分析总是需要的,它可以确定优化的等级。

设计和编写图形程序

类设计

一个图形程序的关键部分是有一个好的矩阵或者向量类,必须简洁,效率高,这和图形实体的颜色和图像一样重要。一个世界级难题是:位置和位移有不同的操作,是否应该是两个不同类?因为位置乘二分之一毫无意义,但是位移乘二分之一有意义。下面列出了一些基础类:

  • vector2一个二维向量类,存储了x y坐标,应当存储在长度为2的数组中。其余操作大概有:向量加法,减法,点积,叉积,标量乘法,标量除法
  • vector3与二维向量类相似的三维向量类
  • hvector齐次坐标系 有四个成员
  • rgb 存储三个成员,操作:加法,减法、乘法、标量乘法、标量除法
  • trasform 4x4矩阵类,操作有矩阵乘法,和应用于位置、方向、平面法向量的不同操作,这些操作是完全不同的
  • image2维度的RGB像素数组,包括一个输出操作

float和double的选择

现代体系构架建议减少内存用量,利用存储器的空间局部性来优化性能,所以建议使用单精度浮点数,但是从减少数值问题的角度出发,又可以用双精度浮点数,这种权衡是取决于程序的,但是最好有个默认规则

debug过程

你会发现,越大的程序,调试器就越不好用,因为很多致命错误是因为实现了错误的功能,用调试器查找这种错误会浪费很多时间在step上,以下是几条调试建议:

  • 调试方法:创建一个图像,看看错误出在哪,假设问题是xxx 然后进行测试。比如在光线追踪器中,有几个阴影点,一般的调试在这时是不起作用的,按我们的方法,我们会假设这些像素被错误地标记成了阴影,所以我们将阴影去掉并重新编译。
  • 很多情况下,最简单的调试信息其实就是输出的图片,如果将监控计算中使用的向量值,直接将三个分量输出成图片。如果你怀疑一个值有时超出了有效范围,此时让你的程序输出红色像素,你就可以知道哪里出问题了。还有比如在物体背面绘制显眼的颜色以标识,对数组按ID着色等等。。。
  • 但是你有时候还是得需要一个“调试器”,因为有时候会将同一段代码执行很多次,就使得step过程很痛苦。这时你可以为程序设置陷阱,首先保证你的程序是确定的,(单线程,随机数等等)然后找到哪个像素有问题,在你怀疑有问题的代码下面打印一句话
if(x==a&&y==b)print("That's it!");

再设置一个断点,你就可以快速定位到问题出现的地方了,

  • 可视化调试:有时候很难搞懂程在干啥,因为它做了太多的中间计算,这和大规模计算时出现的问题相似,一个解决方案是:画出数据的图或表来帮助你明白数据的意义。比如:光线追踪器,你可能写代码去可视化ray trees ,然后就可以看到路径对像素的影响,或者在图像重采样过程中,你可能会画出从输入上采样的所有点。别担心,你花费在这上面的时间会帮助你理解程序,并进一步优化它。

必要的数学

很多图形学程序只是将数学翻译成代码,越明白数学,代码越清楚。

集合与映射

  1. 有两个集合A和B 我们通过笛卡儿积来创建第三个集合,写作AxBAxBAxB 这个新集合包含了所有可能的二元组(a,b)a∈Ab∈B(a,b) a\in A\space b\in B(a,b)a∈A b∈B 我们通过这一运算来从三个集合创建所有可能有序三元组,也可以将其推广到更多的任意集合
  2. S2S^2S2集合是由三维空间上的点构成,但是它们是在一个可以被两个参数参数化的平面上,可看作2D集合
  3. 点f(a)f(a)f(a)可以称为a的象,一个集合的象是包含该集合所有点的象的另一个集合,函数作用域的象被称为值域

向量

点乘与叉乘

  1. 点乘a⋅b=∣a∣∣b∣cosθa·b=|a||b|cos \thetaa⋅b=∣a∣∣b∣cosθ 几何意义是一个向量与另一个向量在该方向上投影的成绩 结果为一个值
  2. 叉乘∣a×b∣=∣a∣∣b∣sinθ|a\times b|=|a||b|sin \theta∣a×b∣=∣a∣∣b∣sinθ 几何意义是找到a b向量构成的平面的法向量,遵循右手定则

标准正交基和坐标

管理坐标系统是CG的核心任务,关键是管理标准正交基,任意2维向量u和v构成的一组标准正交基,表明它们是正交的,并且模是1,因此u⋅v=0u·v=0u⋅v=0 ∣u∣=∣v∣=1|u|=|v|=1∣u∣=∣v∣=1 推广到三维情况,u⋅v=v⋅w=w⋅u=0u·v=v·w=w·u=0u⋅v=v⋅w=w⋅u=0

这样三个向量被称为笛卡尔标准正交基,但是它只是无尽的可能正交基当中的一个,它的特别之处在于它隐式的原点,是程序中一种底层的表达方式。这三个向量和原始位置从来没有被显式存储。这被称为是全局坐标系。

如果我们想用另外一个坐标系,其原点和标准正交基是显式存储的,这个系统被称为参考坐标系

如果我们在坐标系中存储一个向量a=uau+vav+wawa=u_au+v_av+w_awa=ua​u+va​v+wa​w,存储这个三元组即可(ua,va,wa)(u_a,v_a,w_a)(ua​,va​,wa​),如何得到这三元组呢?ua=u⋅a∣u∣2u_a=\frac{u·a}{|u|^2}ua​=∣u∣2u⋅a​ va=v⋅a∣v∣2v_a=\frac{v·a}{|v|^2}va​=∣v∣2v⋅a​ wa=w⋅a∣w∣2w_a=\frac{w·a}{|w|^2}wa​=∣w∣2w⋅a​

从一个向量创建基

给定一个向量a 我们想要一个向量w与a同方向,进而选择两个向量u v构成一组标准正交基,首先构造一个单位向量与a同方向:
w=a∣a∣w = \frac{a}{|a|}w=∣a∣a​
然后选择不与w共线的向量t,找向量t的简单方法是将w的最小分量改成1,然后叉乘t和w,u=t∗w∣t∗w∣u = \frac{t*w}{|t*w|}u=∣t∗w∣t∗w​
可以求出来u,u是垂直于w的,一旦求出来u和w,v自然就可以通过叉乘求出来了

从两个向量创建基

给定两个向量a b 如果相互垂直,那就通过叉乘求出第三个向量,如果不相互垂直,就按如下过程:
w=a∣a∣w= \frac{a}{|a|}w=∣a∣a​ u=b∗w∣b∗w∣u= \frac{b*w}{|b*w|}u=∣b∗w∣b∗w​ v=w∗uv=w*uv=w∗u

w是与a共线的单位向量,v是与w垂直的单位向量中与b最接近的。但是如果a和b共线,上述方法就不行了, 此时问题退化成从一个向量创建基,因为b其实对选择与a垂直的向量毫无贡献。

在设定相机位置一节中,我们构造一个坐标系,w与相机视线方向平行,v指向相机顶部,为了保持相机直立,我们在视线方向建立正交基,以笔直向前的向量作为建立相机目标视向的参考向量,并将v设置为“保持相机笔直”时的相机顶部方向,然后叉乘就可以建立坐标系了。

更新正交基

有的时候你会发现基会导致程序出错,这是因为计算中的数值修正或者是之前存储的正交基精度太低,可以用w和v向量更新新的基,看起来与之前的相似,但实际上提高精度。
这种方法对确实垂直的向量有效,对接近垂直的向量也不会偏离太多。但是,这种方法“偏爱” w 超过v v又超过u(起始值被扔掉了),它确实选择了一个与之前正交基接近的新正交基,但是选择的不一定是最接近的。之后介绍的SVD方法可以计算出与原始基最接近的新正交基

曲线与曲面

一般来说,曲线是点的集合,我们用隐函数方程来表示曲线,二元隐函数形式如下
f(x,y)=0f(x,y)=0f(x,y)=0 使函数值为0的点(x,y)(x,y)(x,y)就是在曲线上的点,更一般的,f(x,y)=(x−xc)2+(y−yc)2−r2f(x,y)=(x-x_c)^2+(y-y_c)^2-r^2f(x,y)=(x−xc​)2+(y−yc​)2−r2
这个表达式指出,f=0时的点是在以(xc,yc)(x_c,y_c)(xc​,yc​)点为圆心,r为半径的圆上,称其为隐式曲线的原因是我们必须求解方程才能得出这些点。值得注意的是,我们可以将f想象为等高线,当f=0时,是海平面高度,而且我们也可以注意大,在曲线内部,f的值小于0,而外部大于0.
我们可以用向量表示这条曲线,设两个点c=(xc,yc)c=(x_c,y_c)c=(xc​,yc​) p=(x,y)p=(x,y)p=(x,y) 曲线方程变为(p−c)(p−c)−r2=0(p-c)(p-c)-r^2=0(p−c)(p−c)−r2=0 这个式子意味着,从c到p的向量的自身点乘的模为r,更进一步,我们将其写成$|p-c|2-r2=0 即即即|p-c|-r=0 $,这表明圆上点p与c的距离为r。这描述了一个方程的向量形式,显然比隐函数形式和x,y表示的笛卡尔形式更直观,所以你最好在你的程序里支持向量运算。

二维梯度

如果将f(x,y)f(x,y)f(x,y)看作高度场,则梯度向量指向坡度最大的方向,是f对x y的偏微分,在曲线上,某点的梯度和该点的切线是垂直的,梯度称为曲线的法向量,此外它还指明了f(x,y)>0的方向,对于圆的隐式方程Ax2+Ay2−1=0Ax^2+Ay^2-1=0Ax2+Ay2−1=0其梯度向量为(2Ax,2Ay)(2Ax,2Ay)(2Ax,2Ay) A>0时,指向圆外,表示圆外区域的函数值大于0,A<0 指向圆内,表示圆内区域大于0,所以A>0时曲线围着一个洼地,A<0时,曲线围着一个突起,A的绝对值越来越大时,则坡度就越来越大。可以认为梯度的方向就指向上坡的方向,幅值等于斜率。

隐式二维直线

通用形式Ax+By+C=0Ax+By+C=0Ax+By+C=0 但是这种形式对于过原点的45°直线不适用,我们引入梯度,对于通用形式,梯度就是(A,B)(A,B)(A,B) 。直线过点(x0,y0)(x1,y1)(x_0,y_0) (x_1,y_1)(x0​,y0​)(x1​,y1​) 的向量为(x1−x0,y1−y0)(x_1-x_0,y_1-y_0)(x1​−x0​,y1​−y0​) 又因为梯度和直线是垂直的,得出与其垂直的一组AB为(y0−y1,x1−x0)(y_0-y_1,x_1-x_0)(y0​−y1​,x1​−x0​)进而得出了AB系数,C是将一个点代入方程求出的为x0y1−x1y0x_0y_1-x_1y_0x0​y1​−x1​y0​ 到这里,我们求得了隐式方程。
(y0−y1)x+(x1−x0)y+x0y1−x1y0=0(y_0-y_1)x+(x_1-x_0)y+x_0y_1-x_1y_0=0(y0​−y1​)x+(x1​−x0​)y+x0​y1​−x1​y0​=0
通用形式还有一个特性,可以计算点到直线的有向距离f(a,b)(A2+B2)\frac{f(a,b)}{\sqrt(A^2+B^2)}(​A2+B2)f(a,b)​ 有向距离指幅值等于距离值,但可正可负。

隐式二维曲线

对于椭圆,圆,双曲线都可以用一个通用的隐式形式表示Ax2+Bxy+Cy2+Dx+Ey+F=0Ax^2+Bxy+Cy^2+Dx+Ey+F=0Ax2+Bxy+Cy2+Dx+Ey+F=0, 对于抛物线,上式变为y−k(x−xc)2=0y-k(x-x_c)^2=0y−k(x−xc​)2=0 xcx_cxc​是抛物线的对称轴。对于椭圆,对称轴与坐标轴平行的方程为(x−xc)2a2+(y−yc)2b2−1=0\frac{(x-x_c)^2}{a^2}+\frac{(y-y_c)^2}{b^2}-1=0a2(x−xc​)2​+b2(y−yc​)2​−1=0

隐式三维曲面

用来定义2维曲线的方程也可以用来定义三维曲面,f(x,y,z)=0f(x,y,z)=0f(x,y,z)=0 任意曲面上的点(x,y,z)(x,y,z)(x,y,z) 的函数值都为0,用向量p(x,y,z)p(x,y,z)p(x,y,z)来表达就是f(p)=0f(p)=0f(p)=0

隐式曲面的法线

曲面上的每个点可能有不同的法线向量,同样,法线向量与梯度方向相同,由f的梯度给出。指向的是f增长最快的方向,且与曲面上该点所有切线垂直。曲面−f(p)=0-f(p)=0−f(p)=0是与曲面f(p)=0f(p)=0f(p)=0一样的,但是却有着相反的梯度方向,即−∇f(p)=∇(−f(p))-\nabla f(p)=\nabla(-f(p))−∇f(p)=∇(−f(p))

隐式平面

  1. 由一个点和一个法向量可以确定一个平面,其隐式方程为(p−a)n=0(p-a)n=0(p−a)n=0 a和n是已知的量,点p是满足方程的未知的点,从a到p的向量与平面的法线向量垂直,如果p不在平面上,(p-a)和n无法成正确角度。

  2. 有时以三个点a,b,c表示平面,(p−a)((b−a)∗(c−a))=0(p-a)((b-a)*(c-a))=0(p−a)((b−a)∗(c−a))=0,这个式子成立充要条件是p−a,b−a,c−a=0p-a,b-a,c-a =0p−a,b−a,c−a=0 只有当p与a,b,c共平面时,上式子才成立。下面给出笛卡尔形式的行列式,它与上式是等价的,只不过上式c从几何方式解释,且易于写出简单代码,对于下式,如果你实现了有关行列式的函数,也很容易写出清晰的代码。然而其他的式子类似x y z的全展开式子很容易出错,并产生令人厌恶的代码。

    上式是一个很好的例子,它说明了简洁的数学才能生成间接的代码

  3. 对于三维二次曲面,与二次多项式相似,x y z构成的二次多项式定义了三维中的二次曲面,比如球体可以写成f(p)=(p−c)2−r2=0;f(p)=(p-c)^2-r^2=0;f(p)=(p−c)2−r2=0; c为圆心,p为用x,y,z表示的向量。轴对称的椭圆体写成f(p)=(x−xc)2a2+(y−yc)2b2+(z−zc)2c2−1=0f(p)=\frac{(x-x_c)^2}{a^2}+\frac{(y-y_c)^2}{b^2}+\frac{(z-z_c)^2}{c^2}-1=0f(p)=a2(x−xc​)2​+b2(y−yc​)2​+c2(z−zc​)2​−1=0

隐式曲面中的三维曲线

有人认为可以从f(p)=0f(p)=0f(p)=0创建三维曲线,这些曲线是退化的曲面,也很少会被用到。三维曲线可以通过两个三维曲面的方程生成,比如通过两个三维平面求交线得到一个三维直线,但是实际上,用参数化曲线更方便。

二维参数曲线

参数曲线通过一个参数进行控制[x,y]=[g(t),h(t)][x,y]=[g(t),h(t)][x,y]=[g(t),h(t)] t是影响曲线的参数,(x,y)是曲线上一点,如果g和h是连续的,那么t发生微小变化的时候,x,y也会产生微小变化,随着t的不断变化就产生了曲线上的一系列的点,常常将参数曲线写成向量的形式p=f(t)p=f(t)p=f(t)

二维参数直线

二维空间中过两点的直线参数方程为[x,y]T=[x0+t(x1−x0),y0+t(y1−y0)]T[x,y]^T=[x_0+t(x_1-x_0),y_0+t(y_1-y_0)]^T[x,y]T=[x0​+t(x1​−x0​),y0​+t(y1​−y0​)]T 意义为在参数t作用下,从p0p_0p0​点出发,经过一段距离走向p1p_1p1​ 点是随着t做线性变化,所以这两点之间的t值就是两点之间相对距离的测度,或者用一个点和一个向量表示:p(t)=o+tdp(t)=o+tdp(t)=o+td 当向量d具有单位长度,直线就是弧长参数化的。

二维参数圆

对于圆心为(xc,yc)(x_c,y_c)(xc​,yc​) 半径为r的圆,其参数形式为[x,y]T=[xc+rcosϕ,yc+rcosϕ]T[x,y]^T=[x_c+rcos \phi,y_c+rcos\phi]^T[x,y]T=[xc​+rcosϕ,yc​+rcosϕ]T 为保证曲线上每个点只对应唯一参数ϕ\phiϕ 可以将其范围设置在长度为2π2\pi2π的半开区间内。

三维参数曲线

与二维参数曲线相似,[x,y,z]T=[cost,sint,t]T[x,y,z]^T=[cost,sint,t]^T[x,y,z]T=[cost,sint,t]T,与二维曲线类似,如果用向量方式表示[x,y,z]T=p(t)[x,y,z]^T=p(t)[x,y,z]T=p(t)

三维参数直线

我们用向量式表达三维参数直线p=o+tdp=o+tdp=o+td o和d是向量,以如下方式给出o=(2,1,3) d=(7,2,-5),写成普通形式为x=2+7ty=1+2tz=3−5tx=2+7t y=1+2t z=3-5tx=2+7ty=1+2tz=3−5t 但是这种形式不易于编写代码。
线段可以用三维参数直线描述p(t)=a+t(b−a)p(t)=a+t(b-a)p(t)=a+t(b−a) a b 为点,p(0)=a p(1)=b 现在,我们将所有的射线,线段,直线都称为光线。

三维参数曲面

曲面具有如下形式[x,y,z]T=[f(u,v),g(u,v),h(u,v)]T[x,y,z]^T=[f(u,v),g(u,v),h(u,v)]^T[x,y,z]T=[f(u,v),g(u,v),h(u,v)]T 向量形式为[x,y,z]=p(u,v)[x,y,z]=p(u,v)[x,y,z]=p(u,v) 。举例,对于球面上一点由经度和纬度两个参数确定,如果把极坐标置于半径为r的球体上,球心在原点,得到球面参数方程:[x,y,z]T=[rcosϕsinθ,rsinθsinθ,rcosθ][x,y,z]^T=[rcos\phi sin\theta, rsin\theta sin\theta,rcos\theta][x,y,z]T=[rcosϕsinθ,rsinθsinθ,rcosθ]
这个是不能用向量表示的,对于某组(x,y,z)我们可以求出对应的(θ,ϕ)(\theta, \phi)(θ,ϕ) θ=acoszx2+y2+z2ϕ=atan2(y,x)\theta = acos{\frac{z}{\sqrt{x^2+y^2+z^2}}} \phi=atan2(y,x)θ=acosx2+y2+z2​z​ϕ=atan2(y,x)

线性插值

其实我们在之前已经见过插值了,曲线的参数形式为p=(1−t)a+tbp=(1-t)a+tbp=(1−t)a+tb 这就是插值,因为t=0 和 t=1时,p通过a和b。
另一种常用插值情况,对于x轴上一组点,每个点有对应的高度,我们想建立一个连续函数y=f(x) 使其通过每一个数据点,f(x)=yi+x−xixi+1−xi(yi+1−yi)f(x)=y_i+\frac{x-x_i}{x_{i+1}-x_i}{(y_{i+1}-y_i)}f(x)=yi​+xi+1​−xi​x−xi​​(yi+1​−yi​) 该加权函数是关于x的多项式,因此是线性插值,意义为从A到B 构造一个t从0变化到1,中间值就是(1-t)A+tB,在上式中t=x−xixi+1−xit=\frac{x-x_i}{x_{i+1}-x_i}t=xi+1​−xi​x−xi​​

三角形

三角形是图形学程序中基本图元,颜色信息标记在三角形的顶点上,并被插值到三角形当中,实现这种插值的坐标系被称为重心坐标系

二维三角形

顶点a b c 的二维三角形 其面积为12(xayb+xbyc+xcya−xayc−xbya−xcyb)\frac{1}{2}(x_ay_b+x_by_c+x_cy_a-x_ay_c-x_by_a-x_cy_b)21​(xa​yb​+xb​yc​+xc​ya​−xa​yc​−xb​ya​−xc​yb​)
若a b c为逆时针顺序,得到的面积为正,否则为负
设坐标原点为a 从a到b和c的向量为基向量,p就可以表示为p=a+β(b−a)+γ(c−a)p=a+\beta(b-a)+\gamma(c-a)p=a+β(b−a)+γ(c−a) 化简后得p=(1−β−γ)a+βb+γcp=(1-\beta-\gamma)a+\beta b+\gamma c p=(1−β−γ)a+βb+γc
重心坐标系对由a,b,c形成的三角形,当且仅当0&lt;α&lt;10&lt;β&lt;10&lt;γ&lt;10&lt;\alpha&lt;1 0&lt;\beta&lt;1 0&lt;\gamma&lt;10<α<10<β<10<γ<1时,p点在三角形内部,如果其中一个为0,则位于三角形边上,若两个为0,另一个为1,则位于顶点上。
已知点p如何求解该点在重心坐标系下的坐标?一种方式是求解如下线性方程组

另一种基于几何的方法是:如果直线fab(x,y)=0f_{ab}(x,y)=0fab​(x,y)=0穿过a b两点,那么就可以计算点(x,y)的γ\gammaγ值,具体如下γ=fab(x,y)fab(xc,yc)\gamma= \frac{f_{ab}(x,y)}{f_{ab}(x_c,y_c)}γ=fab​(xc​,yc​)fab​(x,y)​ 一般根据该式子求出两个坐标,再根据α=1−β−γ\alpha = 1-\beta-\gammaα=1−β−γ 求出第三个,而fab(x,y)=(ya−yb)x+(xb−xa)y+xayb−xbyaf_{ab}(x,y) = (y_a-y_b)x+(x_b-x_a)y+x_ay_b-x_by_afab​(x,y)=(ya​−yb​)x+(xb​−xa​)y+xa​yb​−xb​ya​
根据类似的形式可以求出gamma为γ=(ya−yb)x+(xb−xa)y+xayb−xbya(ya−yb)xc+(xb−xa)yc+xayb−xbya\gamma= \frac{(y_a-y_b)x+(x_b-x_a)y+x_ay_b-x_by_a}{(y_a-y_b)x_c+(x_b-x_a)y_c+x_ay_b-x_by_a}γ=(ya​−yb​)xc​+(xb​−xa​)yc​+xa​yb​−xb​ya​(ya​−yb​)x+(xb​−xa​)y+xa​yb​−xb​ya​​

还有一种方法是根据重心和其他顶点构成的子三角形的面积来求出αβγ\alpha \beta \gammaαβγ

三维三角形

三角形重心坐标扩展到三维空间,仍然有:
p=(1−β−γ)a+βb+γcp=(1-\beta-\gamma)a+\beta b+\gamma c p=(1−β−γ)a+βb+γc
用三角形两条边构造法向量n=(b−a)×(c−a)n=(b-a)\times(c-a)n=(b−a)×(c−a) 进而表示三角形的面积S=12∣(b−a)×(c−a)∣S=\frac{1}{2}|(b-a)\times(c-a)|S=21​∣(b−a)×(c−a)∣ 注意着不是带符号的面积,不能求取重心坐标。
按面积法求重心坐标,公式为:α=n⋅na∣n∣2\alpha = \frac{n\cdot n_a}{|n|^2}α=∣n∣2n⋅na​​ β=n⋅nb∣n∣2\beta = \frac{n\cdot n_b}{|n|^2}β=∣n∣2n⋅nb​​ γ=n⋅nc∣n∣2\gamma = \frac{n\cdot n_c}{|n|^2}γ=∣n∣2n⋅nc​​

其中 n 是法向量,na,nb,ncn_a,n_b ,n_cna​,nb​,nc​ 是各子三角形的法向量:na=(c−b)×(p−b)n_a=(c-b)\times(p-b)na​=(c−b)×(p−b) nb=(a−c)×(p−c)n_b=(a-c)\times(p-c)nb​=(a−c)×(p−c) nc=(b−a)×(p−a)n_c=(b-a)\times(p-a)nc​=(b−a)×(p−a)

计算机图形学(Intro/Math)相关推荐

  1. 计算机图形学直线扫描转论文,计算机图形学实验报告-实验1直线段扫描转换.doc...

    PAGE 32 PAGE 7 计算机图形学 实验报告 班级 计算机工硕班 学号 2011220456 姓名 王泽晶 实验一:直线段扫描转换 实验目的 通过本次试验,学生可以掌握直线段的扫描转换算法及其 ...

  2. 用C#实现计算机图形学算法

    多数情况下计算机图形学算法都用C++实现,下面鄙人用C#实现一部分算法.并附上运行截图. 一 图案 1 金刚石 金刚石图案是每一个顶点都与其他顶点相连的正n边形.金刚石图案有时被用作计算机图形设备的测 ...

  3. 用JavaScript玩转计算机图形学(二)基本光源

    上一篇介绍了简单的光线追踪,凑合了临时用的光源去渲染效果.这次将讲解三种基本光源,及一些背景理论.过分简化的教材和现成API(OpenGL/Direct3D等)可能会做成一些错误理解.在此,希望文章能 ...

  4. 用JavaScript玩转计算机图形学(一)光线追踪入门

    系列简介 记得小时候读过一本关于计算机图形学(computer graphics, CG)的入门书,从此就爱上了CG.本系列希望,采用很多人认识的JavaScript语言去分享CG,令更多人有机会接触 ...

  5. 【计算机图形学课程】一.MFC基本绘图函数使用方法

    这是最近我<计算机图形学>课程实践编程课介绍的相关知识,主要是想通过MFC C++绘图,让学生体会下图形学相关的编程及简单的图形绘制,同时非常佩服学生的想象力,他们做得真的不错.希望这篇基 ...

  6. 计算机图形学Web前端笔记-图形平移放缩原理及实现(two.js鼠标事件适用所有渲染)

    在two.js中,只提供了svg渲染时的鼠标事件,而canvas和webgl并没有提供,这样就对本人造成了很大的困扰,因此学习了下计算机图形学相关的知识,实现了利用two.js绘图在canvas.sv ...

  7. 计算机图形学E1——OpenGL 方中有圆,圆中有方,无穷尽焉

    其他计算机图形学实验见 链接 使用OpenGL绘制如图所示图形 有穷的: #include <GL/glut.h> #include <math.h> #include< ...

  8. [转载]一个图形爱好者的书架/白话说学计算机图形学

    1.一个图形爱好者的书架 原文地址:http://blog.csdn.net/nhsoft/archive/2004/06/23/22992.aspx          早几天看到有人把自己在大学四年 ...

  9. GAMES101笔记_Lec01_计算机图形学概述 Overview of Computer Graphics

    作为一名想要了解图形学的学生,已经在无数地方看到有人推荐闫令琪老师的GAMES101课程,但由于自己是美术专业,在笼统看过这门课程之后认为这门课有一定学习难度,所以为了打下比较扎实的基础和方便自己日后 ...

  10. 计算机图形学第四次上机——鼠标回调图形界面交互实现

    计算机图形学第四次上机实验 课程实验报告 目录 计算机图形学第四次上机实验 课程实验报告 一.实验目的 二.实验环境 三.实验内容 3.1绘制曲线 3.2绘制曲面 3.3颜色 3.4鼠标回调 四.实验 ...

最新文章

  1. 解析 Callable Runnable Future 使用和原理
  2. (已解决)登录火狐浏览器账号后没有同步数据--博主的奇妙寻号之旅
  3. jQuery两把利器
  4. StackOverFlow优选的十条编程观点
  5. pdfplumber解析pdf文件
  6. 使用jQuery Html() 作为客户端htmlEncode的问题
  7. LeetCode 688. “马”在棋盘上的概率
  8. ios之alloc和init
  9. 构建之法读书笔记02
  10. oracle12c dba或者sys身份的账户和密码,怎么一次性安装好oracle 12c依赖包
  11. python consulate_使用python测测你的系统最多能创建多少个线程 | 学步园
  12. 100件不可思议的事
  13. pb 数据窗口设置操作
  14. xyz坐标转换ybc_GNSS仰角和方位角的计算及代码,XYZ转BLH坐标的代码及原理
  15. xpath 解析后和原网页结构不一致
  16. android应用商店完整版源码
  17. ubuntu 8.04下安装yEd
  18. U盘, USB读卡器, U盘读卡器三者技术分析区别
  19. linux版英特尔酷睿i7,英特尔酷睿i7 1165G7和AMD Ryzen 7 Pro 4750U Linux性能对比
  20. Windows - 百度网盘限速下载慢解决方案(官方提速方法)

热门文章

  1. 浏览器无法上网:常用DNS推荐
  2. 乐山计算机学校电话号码,乐山计算机学校网站网址联系方式
  3. PCIE——第 10 章—— MSI 和 MSI⁃X 中断机制
  4. java 时间 精确到毫秒_获取Java代码运行的时间(精确到毫秒) | 恋香缘
  5. hive统计每日的活跃用户和新用户sql开发(附shell脚本)
  6. DAU-----日活跃用户数量
  7. 破解星空极速,共享上网
  8. Power BI(十一)Power Pivot常用DAX函数
  9. python读取doc/docx文件
  10. Excel VBA-单格内,按文字颜色处理文字