会员: 密码:  免费注册 | 忘记密码 | 会员登录 网页功能: 加入收藏 设为首页 网站搜索  
游戏开发 > 程序设计 > 3D图形
利用Vertex Shader实现关键帧动画
发表日期:2007-03-16 16:56:49作者: 出处:  

一般来讲,在D3DOpenGL中最简单的动画实现方式就是对模型进行矩阵变换,改变模型的各个组成部分的相对位置以及在世界坐标系中的绝对坐标。在许多初级的OpenGL教程中,往往以这种动画为例子来说明矩阵变换的含义,但是这种动画制作方式,只适合于刚体运动的描述,所为极为有限,当需要产生难以进行数学描述的模型扭曲变形动画时,就变得很难实现。通常对于这种情况我们使用不断修改顶点缓冲区数据的方法来完成从一个关键桢到另外一个关键桢的模型变形过程,当模型数据量比较大的时候,这种方法是很低效的,而在DirectX9中我们可以很容易的利用Vertex ShaderTweens技术来完成。

下面是笔者写的例程中的几幅截图:

    

原理

实现关键桢动画的生成原理都是相同的,就是差值。实际上所谓Tweens就是差值的意思。所以原理很简单,可用下图表示

假设我们已知在KeyFrame1 顶点 VertexA = VertexValue1,

KeyFrame2中顶点 VertexA = VertexValue2,所以当生成动画时我们只需让

VertexA = VertexValue1*(1-Weight) +VertexValue2*Weight Weight 0 ——>1变化)就可以实现动画效果了。当所有的顶点都按规则变化模型的变形动画就产生了。

实现 

我们知道Vertex shader能够在渲染前能够对顶点进行逐个变换和修改,利用这一点很容易我们就可以实现关键桢动画的生成。具体操作如下:

1、确定Vertex Shader的输入

两个顶点数据流,索引号可假设为0(作为KeyFrame1)和1(作为KeyFrame2),分别指向顶点缓冲区pVBKeyFrame1pVBKeyFame2,分别存储顶点在两个关键帧中的值

    Tweens的权值,即前面所提到的Weight,用来确定当前要输出的顶点值

2、渲染方法

       在读入模型文件时我们创建索引缓冲区,确定好索引号与顶点之间的对应关系,在渲染时使用索引缓冲区渲染(DrawIndexedPrimitive()),而这时索引缓冲区指向的是Tweens方法利用两个输入缓冲区生成一个新的顶点缓冲区。这种做法的好处是减少了实际进行运算的顶点数目(对共享顶点进行变换),提高了速度,并且易于控制,不易出错。

整个处理流程如下图所示:

其中,所有的模型使用共享的索引缓冲区,所以对所使用的关键桢模型是有要求的,即要求模型的索引值对应的顶点具有相同的含义,换句话说,假设index =1对应的三角形在模型1中是手指甲,则在模型二中也应保证该对应关系,一般来讲是用常用的三维建模工具变换所得的模型对这一点能够保证,但切忌不要增删顶点数目,这样会导致对应关系混乱,因此在笔者的例程中对这种情况进行了检查。

程序

下面是vs的代码段

;------------------------------------------------------------------------------

; Constants specified by the app

;    c0      = (  1-fWeight,fWeight, 0.0f, 0.0f ),其中1-fWeight作为数据流0的权值,fWeight作为数据流1的权值

;    c1-c4   = matWorldViewProjection

;    c5      = light color

;    c6      = Diffuse color

;    c7      = Ambient color

;    c8      = 0.0f, 1.0f, 0.0f,0.0f; 保存了一些常用常量0,1

 

;   

; 顶点声明

;    v0,v1    = 数据流0,1的位置

;    v2,c3    = 数据流0,1的法线

;    v4       = 纹理坐标

;------------------------------------------------------------------------------

vs.1.1

;数据流0中的顶点位置

dcl_position0 v0

;数据流1中的顶点位置

dcl_position1 v1

;数据流0中的法线

dcl_normal0   v2

;数据流1中的法线

dcl_normal1   v3

文理坐标

dcl_texcoord0 v4

 

;------------------------------------------------------------------------------

; 顶点变换

;------------------------------------------------------------------------------

 

; 用v0和v1根据权值生成新坐标

mul r0, v0, c0.x

mul r1, v1, c0.y

add r2, r0, r1

 

; 坐标变换并输出

m4x4 oPos, r2, c1

 

;------------------------------------------------------------------------------

; 光照计算

;------------------------------------------------------------------------------

 

; 在法线v2和v3中差值生成新法线

mul r0, v2, c0.x

mul r1, v3, c0.y

add r2, r0, r1

 

; 光照计算

dp3 r1.x, r2, c5    ; r1 = normal dot light

max r1.x, r1.x, c8.x   ; if dot < 0 then dot = 0

mul r0, r1.x, c6    ; Multiply with diffuse

add r0, r0, c7      ; Add in ambient

min oD0, r0, c8.y    ; clamp if > 1

 

 

;------------------------------------------------------------------------------

; 纹理坐标直接输出

;------------------------------------------------------------------------------

mov oT0.xy, v4

 

其中涉及到,法线的变换,及简单的光照计算,文理输出等,不多说了,大家自己看程序吧

 

关于本文和例程

   这是笔者的第一个vertex shader程序,写完之后觉得或许对大家可能会有所帮助所以写了这篇东西,主要针对初学者,希望学习的时候能够省些力气。

   本例程的框架使用了d3d的框架程序,代码参考了direct9 SDK中的DolphinVS例程,

程序实现了多个模型之间的差值变换,增加关键帧数目只需执行方法CTweenNeed::addKeyFrameFromXFile()即可。

返回顶部】 【打印本页】 【关闭窗口

关于我们 / 给我留言 / 版权举报 / 意见建议 / 网站编程QQ群   
Copyright ©2003- 2024 Lihuasoft.net webmaster(at)lihuasoft.net 加载时间 0.00268