用VMD做太极拳动画

用VMD做太极拳动画
Making TaiChi animation using VMD

文/Sobereva@北京科音    2009-May-25



做出来的动画:http://sobereva.com/attach/41/VMD_Taiji.avi


VMD不仅仅可以用来做研究,还可以用来娱乐,在娱乐过程中也可以学到很多使用技巧。


这里我用VMD做了一个小人打太极拳的轨迹动画,以此为基础对方法进行说明,希望起到抛砖引玉的作用,由于时间所限,只作了5个动作。所用VMD为windows版1.8.6。





动画文件下载地址:
/usr/uploads/file/20150605/20150605011055_88604.rar
下载后,把解压后的文件放到vmd默认目录下(vmd控制台输入pwd后显示的路径)。启动一个新的vmd,在控制台输入source start.tcl,即开始播放,如上图。视角会自动调好,上方文字显示动作名称。


制作方法:

制作前先考虑做什么内容,不适合通过VMD来实现的题材尽量避开,这需要对VMD比较熟悉才能判断。用原子构成小人,做太极拳动作在VMD里是比较容易实现的。


首先绘制小人,虽然很多软件都可以干这个活,但是GaussView在我看来是最方便的。首先通过旋转调整好坐标轴,使YZ平面与屏幕平行。然后选择成添加原子的模式,在屏幕上点出来小人的关节原子,之后用设置化学键的方法将关节间连上。建议将头部、胳膊、腿、身子分别用不同元素原子,这可以使不同部位有不同颜色。此例中身体使用5个氮原子,名字为N1、N2、N3、N4、N5。最终绘制好后小人的整体平面应当恰在YZ平面上,脚踩在XY平面上。如果小人相对于坐标轴偏斜了,可以用这两个操作来调整:按住ALT后左键/右键拖动小人可以让小人旋转,但不旋转坐标轴。按住ALT和SHIFT后左键拖动小人可以让小人平移,但不平移坐标轴。



之后保存为man.mol2。mol2格式的一个好处是包含了原子间的拓扑关系,避免读入VMD后胡乱判断成键。接下来制作动画过程中的工作目录假定为d:\study\VMD186\manmovie(VMD启动后默认目录为d:\study\VMD186)。将man.mol2拷到工作目录下。



做动画之前应当先把做动画的工具准备好,工欲善其事必先利其器,否则很难做。显然不可能做动画中每一帧时都挪动一次小人的原子然后保存,太费事。可以使用类似做flash的方法,先通过移动原子创建两个关键帧,然后生成过渡帧。我编了一个小软件vmdmovie,下载地址/usr/uploads/file/20150605/20150605011319_86069.rar。将压缩包内的vmdmovie.exe拷到工作目录下。

使用方法:vmdmovie f.pdb l.pdb 10 3,其中f.pdb为起始关键帧,l.pdb为结束关键帧,10代表生成的过渡帧数,3代表过渡帧名字的前缀。vmdmovie输入和输出的都是.pdb格式。此例会输出003-00001.pdb 003-00002.pdb ..... 003-00011.pdb。实际共生成了11帧,其中最后一帧003-00011.pdb与结束关键帧l.pdb是一样的。

接下来要在vmd里构建好制作动画的环境。通过移动原子设定人物动作需要有准确的坐标,需要有东西作为参考,否则可能小人越做越歪。VMD的坐标轴在左下角,不好用来作为参考,所以需要在坐标原点处自行绘制一个新的坐标轴,并且显示出地面(XY平面)。另外每次移动小人原子后通过VMD菜单保存坐标太麻烦,若每次按一个键就能保存一个新坐标文件,且文件名连续就会方便很多。这需要下面的脚本。

在d:\study\VMD186下面创建一个reset.tcl文件,内容如下:
set nowframe 0  #关键帧起始编号
cd D:\\study\\VMD186\\manmovie  #进入工作目录

mol delete top
mol default style CPK  #设默认显示方式为CPK,新载入的结构就会以CPK显示
mol new D:\\study\\VMD186\\manmovie\\man.mol2

draw delete all  #删除其它自行绘制的物件,绘制新的坐标轴
draw color red
draw cylinder { 0 0 0 } { 20 0 0 } radius 0.2
draw cone { 20 0 0 } { 22 0 0 } radius 1 resolution 20
draw color green
draw cylinder { 0 0 0 } { 0 20 0 } radius 0.2
draw cone { 0 20 0 } { 0 22 0 } radius 1 resolution 20
draw color blue
draw cylinder { 0 0 0 } { 0 0 20 } radius 0.1
draw cone { 0 0 20 } { 0 0 22 } radius 1 resolution 20
draw color white  #绘制两个白色的三角组成矩形,来表示地面
draw triangle {15 -35 0} {-15 -35 0} {-15 35 0}
draw triangle {15 -35 0} {15 35 0} {-15 35 0}

rotate y by -90  #旋转、调整好视角
rotate z by 270
scale to 0.12  #设定缩放尺寸,越小则人物越小
mol addrep top  #新增一个representation(以下简称rep)
mol modselect 1 top {name N1 N2 N3 N4 N5}  #新rep所选内容设为小人的身体原子

set sel [atomselect top all]

user add key o {  #新加入一个快捷键,在VMD的3D窗口中按o,小人的坐标就会被保存一次
global nowframe
incr nowframe  #每次保存坐标时更新文件名,最终得到1.pdb 2.pdb ......
$sel writepdb $nowframe.pdb}

启动vmd,控制台运行source reset.tcl,此时会看到场景被布置好了。



现在按o,得到第一个关键帧。会看到工作目录出现了1.pdb。然后按数字键5,即选成移动原子的模式,拖动每个关节原子,将它们摆成下一个关键帧的位置,再按o,工作目录就有了2.pdb,依此类推,得到所有关键帧的结构文件。挪动原子时主要靠三视图来定位原子,以避免偏离,也就是依次在三个坐标轴垂直于屏幕时挪动原子。建议不要使用透视模式,而使用正交模式(Display-Orthographic),这样可以比较容易看出当前视角是否摆正了。

涉及到小人身体移动的时候将组成身体的5个原子一个一个地移动比较麻烦,而且可能导致身体变形。VMD里面有个很好的功能,就是可以移动整个rep包含的原子,由于rep的内容可以十分灵活地选择,所以可以整体移动任意范围的原子。前面的脚本已经将小人的身体设定了一个rep,但是由于身体的rep与整个小人rep相重叠,鼠标点这个rep不到,所以在Representations里先将身体的rep原子半径设大(Sphere Scale设大),这样就可以点到了。之后在3D窗口里点数字9进入Rep移动模式,就可以鼠标拖动身体平移了,按住shift拖动是旋转身体。



之后我们把所有关键帧之间生成过渡帧,控制台运行:
for {set i 0} {$i<100} {incr i 1} {vmdmovie $i.pdb [expr $i+1].pdb 10 $i}
这里假设关键帧数小于100,每个关键帧之间插10帧。

现在我们来看看结果,删除当前分子的所有帧,然后运行:
foreach i [glob 0*.pdb] {mol addfile $i}
这里假设关键帧数小于100,所以生成的帧名字开头为0,这条命令就把所有生成的帧读进去了。注意读入的不仅仅是过渡帧,也包括关键帧,因为vmdmovie每次生成的帧的最后一帧就是关键帧。

现在就可以播放了。如果发现某帧不合适,就把那帧读入,改完坐标后保存,再用vmdmovie生成过渡帧,vmdmovie的速度是比较快的。

如果没问题,就file-save coordinates,选择原子范围设all,文件类型设.trr,保存为all.trr放到工作目录下。



最后我们希望在动画播放时加一些花样,比如显示字幕、用VMD绘图函数绘制场景等等,可以使用一个.tcl脚本来完成。太极拳动画压缩包里的start.tcl就是做这个用的,这里解释一下:

trace variable vmd_frame(1) w sdf  #每当ID=1的分子帧数变化时(比如播放时),即vmd_frame(1)变量变化时,就调用sdf命令,这里ID=1就是小人的动画
mol new  #新生成一个层,即ID=0的层,用来绘制地面、显示文字

proc sdf {args} {  #下面定义sdf命令的行为,用来显示当前小人动作的名称
global vmd_frame  #vmd_frame是VMD自带的数组变量,第n个元素就是ID=n的帧的当前帧号,在自定义指令里调用这个全局数组变量需要先用这条命令使它在内部可用。
graphics 0 delete all  #删除之前的字
graphics 0 color white  #设字为白色

if {$vmd_frame(1)<150} {graphics 0 text {0 -23 18} "Qi Shi" size 4
} elseif {$vmd_frame(1)<580} {graphics 0 text {0 -23 18} "ZuoYouYeMaFenZong" size 3  #当帧数在150~580之间的时候就在屏幕上方显示ZuoYouYeMaFenZong,文字的坐标需要自行调整尝试才能合适。VMD不支持中文,所以只能将“左右野马分鬃”用拼音来写。
} elseif {$vmd_frame(1)<640} {graphics 0 text {0 -23 18} "BaiHeLiangChi" size 3
} elseif {$vmd_frame(1)<850} {graphics 0 text {0 -23 18} "ZuoLouXiAoBu" size 3
} elseif {$vmd_frame(1)<964} {graphics 0 text {0 -23 18} "Shou Shi" size 4}

if {$vmd_frame(1)==640} {after 800}  #在白鹤亮翅这个动作做完时停顿一下,停止800ms
if {$vmd_frame(1)==545} {after 500}
}

mol default style CPK
mol new man.mol2  #读入小人.mol2文件作为初始帧并确定拓扑关系,随后读入动画轨迹all.trr
mol addfile all.trr
draw color white  #绘制地面
draw triangle {15 -35 0} {-15 -35 0} {-15 35 0}
draw triangle {15 -35 0} {15 35 0} {-15 35 0}
rotate y by -90
rotate z by 270
scale to 0.1
animate speed 0.96  #播放速度,1为全速
translate by 1 0 0  #平移场景至位置合适
animate forward  #播放动画


本文的目的是希望大家能够解放思想,运用VMD可以制作出有趣的动画,寓教于乐。VMD还可以用来制作简单游戏,我会在以后谈到。