这段时间阅读了英文版的NVidia官方的《The Cg Tutorial》,借此来学习基本的图形学知识和着色器编程。html
在此作一个阅读笔记。编程
实现动画渲染,须要应用程序对时间进行监测,并将它做为一个全局变量传递给着色器。函数
尽可能在GPU上使用顶点着色器执行动画计算是一种高效的动画实现方式,它可以释放CPU,让CPU处理更多的复杂计算,好比碰撞检测,人工智能与游戏玩法。学习
下面是一个如何让一个对象周期性膨胀变形的例子。这个例子的目标是将时间做为输入参数,而后根据时间修改对象几何体的顶点位置。更确切地说,你须要沿着表面法线移动表面顶点的位置。动画
根据时间的变化,改变顶点位移Displacement的幅度,就能够建立一个膨胀或脉冲效果。ui
在上述动画实现的过程当中,一个重要的过程是计算顶点在法线方向上的位移displacement。你能够为displacement选择一个你喜欢的函数,好比:人工智能
displacement = timespa
也许你不但愿物体随时间无限变大,那么你能够选择使用一个周期函数来计算displacement,好比sin函数:htm
displacement = 0.5 * (sin(time) + 1)对象
此外,你还能够经过为displacement增长参数来控膨胀的幅度、频率,甚至改变膨胀效果:
displacement = scaleFactor * 0.5 * (sin(position.y * frequency * time) + 1)
有时,不一样于让顶点在网格中运动,咱们但愿把每个顶点都做为一个独立的对象,或者称为一个粒子。而遵循某种规律运动的粒子的集合被称为粒子系统。粒子系统会随着时间发生变化。
粒子的运动规律可使用一个方程来描述,好比物理中的简单矢量运动学方程:
pfinal = pinitial + v * t + 0.5 * a * t2
在程序中,经过监测全局时间globaTime并将它做为统一参数传递给顶点着色器,当每一个粒子被建立时,粒子建立的时间被做为一个变量tInitial传递给顶点着色器。为了知道粒子被激活的时间,你须要使用globaTime减去tInitial:
float t = globaTime - tInitial
再将t代入上一节中的公式:
float4 pFinal = pInitial + vInitial * t + 0.5f * acceleration * t * t
对象空间的位置还须要被转换到裁剪空间:
oPosition = mul(ModelViewProjectionMatrix, pFinal)
顶点着色器提供了一个名为PSIZE的输出语义Semantic用于表示顶点的尺寸,当你将一个点Point渲染到屏幕中时,具备该语义的输出参数将会决定该点在像素上的宽高。
咱们能够经过使用点精灵Point Sprites提高粒子的外观。使用点精灵时,硬件将会把每一个点看成由四个顶点组成矩形来渲染,而不是一个单独的顶点。点精灵的每一个顶点会被自动分配纹理坐标,它容许你经过纹理贴图改变粒子的外观。
点精灵可以在不绘制额外三角形的状况下建立复杂的几何效果。
关键帧这个术语来自卡通动画。画家在绘制动画时,会先勾勒出一个粗糙的帧序列动画,其中并无包含每一帧的画面,而只有重要的,也就是“关键”的帧。随后,画家会补上缺失的帧。有了关键帧作参考,这些中间帧会更容易画。
计算机动画也使用了相似的技术,3D建模师会为动画角色的每一个姿式制做一个关键帧。每一个关键帧都须要使用相同个数的顶点,且每一个顶点必须互相对应。也就是一个关键帧中的顶点必须可以对应到这个模型其余关键帧中相同的点。对于这种关键帧模型,游戏会取模型的两个关键帧,而后将其中每对对应的顶点混合。
关键帧插值假定了顶点在每一个关键帧中的个数和顺序都是相同的,这样一来就可以保证顶点着色器总可以正确地将顶点进行配对与混合。
插值的方法有不少,常见的两种是线性插值和二次插值。
经过线性插值,位置会以固定的速率转。线性插值公式为:
BlendedPosition = positionA * (1 - f) + position * f
若是想让转换速率根据时间变化,能够采用二次插值,公式为:
IntermediatePosition = positionA * (1 – f * f) + position * f * f
除了上诉两种插值公式之外,你还可使用阶梯函数、样条函数或者指数函数进行插值。
当你须要对关键帧模型进行照明时,关键帧插值就不只涉及到位置的混合,还包括了顶点法线的混合。混合后的法线可能再也不是单位向量,所以此时须要对它进行标准化。
动画的另外一种实现方式是顶点蒙皮,这项技术也被称为“矩阵调色混合“。
不一样于关键帧动画,顶点蒙皮动画存储了模型的一个默认姿式和大量用于旋转与移动默认姿式的多边形网格子区域的矩阵,一般,这些矩阵变换被称为骨骼Bones。
每一个默认姿式中多边形网格的顶点都被一个或多个这种矩阵所控制,每一个矩阵都没指定了一个权重因子,用于指明当前矩阵对顶点的影响程度。假定每一个顶点的全部控制矩阵的权重和为1。
当你须要渲染拥有顶点蒙皮的模型时,你须要使用每一个顶点的骨骼集合中的全部矩阵对这个顶点执行变换,再将它们按照权重进行混合,获得的位置就是蒙皮顶点的位置。
当全部的矩阵都是单位矩阵时,模型展示的就是默认姿式——一般是站立面向前方,手脚分开向外伸展。
经过控制矩阵,你可以建立出不同的姿式。3D建模师须要将矩阵和对应的权重分配到模型的默认姿式上,而建立姿式的过程就变成了操做矩阵的过程,而不是控制每一个独立的顶点。经过这种方式,改变模型的姿式与制做动画变得很是简单。
一般,影响一个顶点的矩阵不会超过4个。
对于角色模型来讲,最重要的矩阵被用来表明人物身体中骨骼的移动和旋转,所以顶点蒙皮矩阵被称为骨骼。而顶点则表明了皮肤上的点。
同关键帧插值动画同样,在启用光照时,顶点蒙皮动画也须要对法向量进行变换。须要注意的是你须要对每一个法向量只须要使用旋转缩放矩阵而不是原矩阵进行变换。同时,混合后也须要对法向量进行标准化。
关键帧动画中,每一个姿式都须要不一样的顶点位置与法向量集合,当角色动做不少时,采用这种方式存储动画是很是不明智的。
顶点蒙皮动画,只须要存储一个默认姿式的顶点位置与法向量集合以及每一个姿式的矩阵。一般对一个模型来讲,由于矩阵的个数远少于顶点个数,因此使用顶点蒙皮的方式存储动画须要的空间远远少于关键帧动画。
存储顶点蒙皮动画时,每一个顶点还须要额外存储控制该顶点的矩阵索引,以及相应的权重因子。
顶点蒙皮很是适合用于存储和回放动做捕捉序列。咱们能够将每个动做捕捉的帧做为骨骼矩阵集合存储起来,并将它应用在拥有相同默认姿式的不一样模型上。反向运动学求解器Inverse Kinematics Solver也能够经过生成骨骼矩阵来实现。反向运动学求解器的目的是找到一个能让一个姿式真实天然地过渡到另外一个姿式的增量骨骼矩阵序列。