用顶点着色器在 DirectX 8 中渲染动画



摘要:本文讨论了 Microsoft DirectX 8 中对象体和轮廓动画渲染 

介绍
“动画渲染”并没有特定定义它大体上是指以非照片真实感风格渲染对象效果类似于动画片和漫画书通常它使用大面积单色块和对象轮廓线进行简单着色在这里讨论架构中渲染可分为两个问题: 

按照定风格使用分明颜色条渲染对象“体”(有意思大多数情况下人们不希望出现颜色条而在这里我们却要突出它)


将轮廓边渲染为粗黑线 
渲染对象体
我们进行法向漫射光照计算(在此例中使用个单向光源)但是我们不将结果输入漫射迭代颜色而是将光照值作为简单光照纹理条纹理坐标使用加载到漫射迭代器中所需材质颜色调制此纹理可进行染色下面是顶点着色器:

; 输入:     v0   = 位置
;           v1   = 法向
;           c0   = (0,0.5,xxx,xxx) 有用常量
;           c1-4 = WorldView 矩阵
;           c5-9 = WorldViewProjection 矩阵
;           c9   = 光照/材料颜色
;           c10  = 光照方向(在观察空间中)

vs.1.0                             着色器版本 1.0
m4x4    oPos , v0   , c5           计算投影位置
m3x3    r1   , v1   , c1           r1 = 观察空间法向
dp3     r2   ,-r1   , c10          r2 = 漫射光照计算
max     r2   , r2   , c0.x         将 r2 固定为 0
mov     oT0.x, r2                  纹理坐标 0 为 (r2,0.5)
mov     oT0.y, c0.y
mov     oD0  , c9                  漫射颜色 = c9
为简化起见光照计算是在视图空间中进行在对象空间中显然要进行优化使着色器不用执行第 2次矩阵乘法运算(在视图空间我们要进行后向变换以提供光源方向)

关键步骤是我们将光照计算结果加载到纹理坐标“u”分量这将有效地将坐标变为查找表格根据它我们可以准确获得需要纹理条

最后我们将材质颜色(也可以把它看作种光照)加载到漫射迭代器我们将用它来调制从纹理中读取强度值如果我们愿意可以从顶点元素读取这个值但是为了简化我们假设此对象只有单颜色因此只需使用个常数

请注意如何将多个有用常数压缩成个 c0 常数注册项既然我们想使它成为纹理坐标中“v”分量(将其放置于纹理中部避免某些边界抽样问题)那么我们将零加载到 c0.x来限制它光照点积同时将 0.5 加载到 c0.y

渲染轮廓
要渲染对象轮廓我们需要检测轮廓如果条边毗邻两个面具有区别方向性例如个是后向面而另个不是那么这条边是轮廓部分对于平滑对象如果顶点处法线垂直于指向顶点视图矢量就可以近似处理为该顶点位于轮廓上换句话说如果屏幕空间位置和法向点积为零则假设顶点位于轮廓上

这样我们就可以用顶点着色器来计算正交化视图矢量和顶点法向点积等于或近似于零值表明我们位于或者接近轮廓粗略地说点积值表明我们和轮廓边界距离为了加粗轮廓边界以产生良好“卡通”效果我们设置个阈值只要是低于这个值点就认为它是轮廓部分阈值越高则轮廓边越粗

既然我们想获得轮廓分明效果那么就对每个像素测试这个阈值好在已经有执行这种测试 Alpha 测试机制如果我们将点积(从 [-1,-1] 重新调节至 [0,1])加载到漫射迭代器 Alpha 通道那么我们可以通过 Alpha 测试排除不在轮廓上然后把剩下像素渲染为纯黑色

下面是顶点着色器:

; 输入:     v0   = 位置
;           v1   = 法向
;           c0   = 有用常量 (0,xxx,xxx,xxx)
;           c1-4 = WorldView 矩阵
;           c5-9 = WorldViewProjection 矩阵

vs.1.0                             着色器版本 1.0
m4x4    r0   , v0   , c1           r0 = 观察空间位置
m3x3    r1   , v1   , c1           r1 = 观察空间法向


m4x4    oPos , v0   , c5           计算投影位置
dp3     r2.x , r0   , r0           正交化 r0(位置)
rsq     r2.x , r2.x
mul     r0   , r0   , r2.x
dp3     r3.x , r0   , -r1          计算点积
mad     oD0.w, r3.x , c0.y , c0.y  缩放到 [0,1]并进行 Alpha 处理
mov     oD0.xyz     , c0.x         漫射 RGB 为 0
请注意输出位置是用 World+View+Projection 合并矩阵直接变换计算而不是由投影矩阵视图空间乘积以递增方式计算原因是我们要确保执行位置计算思路方法和我们为对象体渲染采用思路方法“完全”否则可能会产生重影效果

进行此处理像素管道设置为复制漫射颜色和进行 Alpha 测试因此代码应为:

m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE , TRUE );
m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC , D3DCMP_LESS );
m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF , m_dwSilhouetteAmount );

我们可以通过更改 Alpha 测试参考值来控制轮廓边粗细即 m_dwSilhouetteAmount

限制
这种技术有些限制特别是对于具有大面积平坦表面或由镶嵌面构成对象渲染效果通常不理想这些面上法线方向变化不大或根本没有变化结果整个对象体都被染成单颜色也可能把大面积区域标记为“轮廓”有时候这种效果可能符合我们期望风格但在般情况下只能说是差强人意运用更复杂点光源光照方案可以在定程度上消除对象体单着色问题但是对于大面积平坦表面应用此处介绍轮廓渲染技术仍有困难然而如果是基本圆滑对象那么效果很好

举例应用
“Toon”举例应用以 Microsoft® DirectX® 8 SDK 中举例应用框架为基础演示了这种技术对简单网格应用要编译该举例请在“MSSDK\\Samples\\Multimedia\\Direct3D\\”路径下创建个目录然后把源文件复制到该目录中(此举例引用了些 DirectX 8 SDK 公用举例应用框架文件)

请在 MSDN Online Code Center(英文)中查看 Toon.exe 举例代码

下载 Toon.exe 举例文件(242 KB)

控制方式如下:

操作 控制 
增大/减小阈值 Q / A 
切换内置网格(圆环面或圆环体) T 
旋转对象 单击左键并拖动 
加载 .X 文件  L 
渲染加载 .X 文件 O 
Tags: 

延伸阅读

最新评论

发表评论