仓库源文站点原文


layout: post title: VMD的图形矩阵及其应用 categories:


VMD说到底是一个三维图形显示程序, 只不过主要用于显示较为简单的分子结构, 不太涉及过于复杂的三维模型. 背后的图形显示方式与一般的三维建模或渲染程序类似, 但也有些区别. 我们这里较细节地考察一下, 给定一组原子坐标, VMD到底是如何将其展示在屏幕上的. 这其中涉及很多的矩阵变换, 属于计算机图形学的内容, 就当作对计算机图形学的学习吧.

计算机图形学中常会用到几个不同的空间, 也就是不同的坐标系:

不同空间之间的转换涉及很多坐标变换, 大多是3三维, 四维矩阵的操作. 类似如下

M--世界(模型)变换-->W--观察(相机)变换-->C--投影变换-->P--视口变换-->S

如果这些空间中有些是重合的, 也就是二者的坐标系原点, 取向都相同, 那么就可以省略变换中的一部分, 因为涉及到矩阵是单位矩阵. 有时候, 我们会将世界空间, 相机空间, 屏幕空间重合, 合称视图V空间, 这样最终只需要三个空间, M, V, P, 相应的矩阵是计算机图形学中三个最常见, 最常用的矩阵. 有时甚至会将M, V也重合, 这样就可以直接将模型投影到屏幕了.

在这么多空间中穿梭变换, 有时很容易混淆迷惑, 咫尺天涯, 不知此身何处. 这种时候, 建议重新归位到世界空间. 可以将其视为静止的绝对空间, 虽然可能不会明确用到它, 但可以将其作为其他所有空间的背景, 就像物理学中的绝对时空背景一样. 这种做法类似物理研究的方式, 先定义下一个世界空间, 将模型, 相机等放置到世界中, 然后在世界空间中进行操作, 虽然有时采用特定的空间可能更方便.

测试

我们测试一个简单的分子模型

<table class="highlighttable"><th colspan="2" style="text-align:left">mol.xyz</th><tr><td><div class="linenodiv" style="background-color: #f0f0f0; padding-right: 10px"><pre style="line-height:125%">1 2 3 4 5 6</pre></div></td><td class="code"><div class="highlight"><pre style="line-height:125%"><span></span><span style="color: #666666">4</span> mol C <span style="color: #666666">0</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span> O <span style="color: #666666">1</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span> Cl <span style="color: #666666">0</span> <span style="color: #666666">1</span> <span style="color: #666666">0</span> N <span style="color: #666666">0</span> <span style="color: #666666">0</span> <span style="color: #666666">1</span></pre></div> </td></tr></table>

将其载入VMD, VMD默认显示如下

左边: 设置坐标轴处于左下方; 右边: 设置坐标轴处于原点

下面我们使用tcl脚本获取VMD使用的几个矩阵

中心矩阵center_matrix

<div class="highlight"><pre style="line-height:125%"><span></span><span style="color: #666666">></span> <span style="color: #AA22FF; font-weight: bold">set</span> C <span style="color: #AA22FF; font-weight: bold">[</span><span style="color: #B8860B">molinfo</span> top get center_matrix<span style="color: #AA22FF; font-weight: bold">]</span> <span style="color: #AA22FF; font-weight: bold">{ {</span><span style="color: #B8860B">1</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span> <span style="color: #666666">-0.25</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">1</span> <span style="color: #666666">0</span> <span style="color: #666666">-0.25</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">0</span> <span style="color: #666666">1</span> <span style="color: #666666">-0.25</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span> <span style="color: #666666">1</span><span style="color: #AA22FF; font-weight: bold">}}</span></pre></div>

这代表分子模型空间的原点相对于世界空间原点的偏移, 由于世界空间的原点为分子的几何中心, 所以也就是分子模型空间原点相对于其几何中心的偏移.

旋转矩阵rotate_matrix

<div class="highlight"><pre style="line-height:125%"><span></span><span style="color: #666666">></span> <span style="color: #AA22FF; font-weight: bold">set</span> R <span style="color: #AA22FF; font-weight: bold">[</span><span style="color: #B8860B">molinfo</span> top get rotate_matrix<span style="color: #AA22FF; font-weight: bold">]</span> <span style="color: #AA22FF; font-weight: bold">{ {</span><span style="color: #B8860B">1</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">1</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">0</span> <span style="color: #666666">1</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span> <span style="color: #666666">1</span><span style="color: #AA22FF; font-weight: bold">}}</span></pre></div>

为单位矩阵, 因为我们尚未进行任何旋转操作. 如果使用鼠标或rotate命令对分子进行了旋转, rotate_matrix矩阵就会改变.

缩放矩阵scale_matrix

<div class="highlight"><pre style="line-height:125%"><span></span><span style="color: #666666">></span> <span style="color: #AA22FF; font-weight: bold">set</span> S <span style="color: #AA22FF; font-weight: bold">[</span><span style="color: #B8860B">molinfo</span> top get scale_matrix<span style="color: #AA22FF; font-weight: bold">]</span> <span style="color: #AA22FF; font-weight: bold">{ {</span><span style="color: #B8860B">1.5</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">1.5</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">0</span> <span style="color: #666666">1.5</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span> <span style="color: #666666">1</span><span style="color: #AA22FF; font-weight: bold">}}</span></pre></div>

这是默认的缩放大小, 具体值取决于分子尺寸, VMD默认会采用适当的缩放系数以保证整个分子都可见. 如果使用鼠标滚轮进行了缩放, 相应的矩阵就会变化.

全局矩阵global_matrix

<div class="highlight"><pre style="line-height:125%"><span></span><span style="color: #666666">></span> <span style="color: #AA22FF; font-weight: bold">set</span> G <span style="color: #AA22FF; font-weight: bold">[</span><span style="color: #B8860B">molinfo</span> top get global_matrix<span style="color: #AA22FF; font-weight: bold">]</span> <span style="color: #AA22FF; font-weight: bold">{ {</span><span style="color: #B8860B">1</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">1</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">0</span> <span style="color: #666666">1</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span> <span style="color: #666666">1</span><span style="color: #AA22FF; font-weight: bold">}}</span></pre></div>

这也是单位矩阵, 因为我们尚未进行任何平移. 如果进行了平移, 全局矩阵就会变化. 注意全局矩阵中只有平移部分起作用, 其旋转部分无法通过鼠标或菜单改变.

应用

通过上面的测试, 我们可以推断出, VMD的图形显示方法较为简单, 给定一组原子坐标后, 世界坐标系的原点取为这组原子坐标的几何中心, 世界坐标系的取向与原子模型坐标系的取向一致, 而相机坐标系和世界坐标系重合, X, Y轴处于屏幕内, Z轴垂直于屏幕向外. 大部分分子显示程序默认都是这种设置.

理解了图形显示的原理和VMD的实现, 我们就可以操控相关矩阵以改变视图. 这种操作不会改变分子的原始坐标, 只是改变了显示, 相当于相机在动. 由于相机相对于分子是固定的, 所以也可以认为是分子的模型空间在变而相机不变, 这两者的效果是一致的.

下面我们通过视图调整来实现几个简单的功能, 以示例这些矩阵的使用.

恢复默认视图

对分子进行了各种旋转平移缩放后, 恢复载入时的默认显示方式. 实现这个功能的菜单或命令为display resetview.

实现时只要将所有矩阵置为单位矩阵即可.

<table class="highlighttable"><th colspan="2" style="text-align:left">tcl</th><tr><td><div class="linenodiv" style="background-color: #f0f0f0; padding-right: 10px"><pre style="line-height:125%"> 1 2 3 4 5 6 7 8 9 10</pre></div></td><td class="code"><div class="highlight"><pre style="line-height:125%"><span></span><span style="color: #AA22FF; font-weight: bold">set</span> homeView <span style="color: #AA22FF; font-weight: bold">{</span> <span style="color: #AA22FF; font-weight: bold">{ {</span><span style="color: #B8860B">1</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">1</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">0</span> <span style="color: #666666">1</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span> <span style="color: #666666">1</span><span style="color: #AA22FF; font-weight: bold">}}</span> <span style="color: #AA22FF; font-weight: bold">{ {</span><span style="color: #B8860B">1</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">1</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">0</span> <span style="color: #666666">1</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span> <span style="color: #666666">1</span><span style="color: #AA22FF; font-weight: bold">}}</span> <span style="color: #AA22FF; font-weight: bold">{ {</span><span style="color: #B8860B">1</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">1</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">0</span> <span style="color: #666666">1</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">0</span> <span style="color: #666666">0</span> <span style="color: #666666">1</span><span style="color: #AA22FF; font-weight: bold">}}</span> <span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">proc</span> homeview <span style="color: #AA22FF; font-weight: bold">{}</span> <span style="color: #AA22FF; font-weight: bold">{</span> <span style="color: #AA22FF; font-weight: bold">global</span> homeView <span style="color: #B8860B">molinfo</span> top set <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">center_matrix</span> rotate_matrix scale_matrix<span style="color: #AA22FF; font-weight: bold">}</span> transidentity <span style="color: #AA22FF; font-weight: bold">}</span></pre></div> </td></tr></table>

保存当前视图, 并在需要时重新载入

VMD有几个插件可以实现这个功能, 且功能更多, 这里只是示例如何做.

<table class="highlighttable"><th colspan="2" style="text-align:left">tcl</th><tr><td><div class="linenodiv" style="background-color: #f0f0f0; padding-right: 10px"><pre style="line-height:125%"> 1 2 3 4 5 6 7 8 9 10</pre></div></td><td class="code"><div class="highlight"><pre style="line-height:125%"><span></span><span style="color: #AA22FF; font-weight: bold">set</span> currentView <span style="color: #B8860B">$homeView</span> <span style="color: #AA22FF; font-weight: bold">proc</span> dumpview <span style="color: #AA22FF; font-weight: bold">{}</span> <span style="color: #AA22FF; font-weight: bold">{</span> <span style="color: #AA22FF; font-weight: bold">global</span> currentView <span style="color: #AA22FF; font-weight: bold">set</span> currentView <span style="color: #AA22FF; font-weight: bold">[</span><span style="color: #B8860B">molinfo</span> top get <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">center_matrix</span> rotate_matrix scale_matrix<span style="color: #AA22FF; font-weight: bold">}]</span> <span style="color: #AA22FF">puts</span> <span style="color: #B8860B">$currentView</span> <span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #AA22FF; font-weight: bold">proc</span> loadview <span style="color: #AA22FF; font-weight: bold">{}</span> <span style="color: #AA22FF; font-weight: bold">{</span> <span style="color: #AA22FF; font-weight: bold">global</span> currentView <span style="color: #B8860B">molinfo</span> top set <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">center_matrix</span> rotate_matrix scale_matrix<span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #B8860B">$currentView</span> <span style="color: #AA22FF; font-weight: bold">}</span></pre></div> </td></tr></table>

根据当前视图, 旋转分子, 使其新坐标的默认视图与当前视图一致

前面说过, 改变视图并不会改变分子的坐标, 只是相机在动. 但有时候, 我们调整好了视图后, 希望以后再打开时VMD默认显示调整好的视图. 这可以通过保存VMD的状态文件来实现, 但稍微繁琐些, 因为我们不想另外保存一个与分子坐标文件配套的状态文件. 为此, 我们可以将分子的坐标进行变换, 使其载入后的默认视图就是我们需要的视图, 这样只要打开分子坐标文件, 不进行任何操作, 就可以得到我们需要的显示方式.

做法也比较简单, 根据前面所说的显示原理, 我们需要对分子坐标使用的旋转矩阵就是rotate_matrix.

<table class="highlighttable"><th colspan="2" style="text-align:left">tcl</th><tr><td><div class="linenodiv" style="background-color: #f0f0f0; padding-right: 10px"><pre style="line-height:125%">1 2 3 4</pre></div></td><td class="code"><div class="highlight"><pre style="line-height:125%"><span></span><span style="color: #AA22FF; font-weight: bold">set</span> R <span style="color: #AA22FF; font-weight: bold">[</span><span style="color: #B8860B">molinfo</span> top get rotate_matrix<span style="color: #AA22FF; font-weight: bold">]</span> <span style="color: #AA22FF; font-weight: bold">set</span> topmol <span style="color: #AA22FF; font-weight: bold">[</span><span style="color: #B8860B">atomselect</span> top all<span style="color: #AA22FF; font-weight: bold">]</span> <span style="color: #B8860B">$topmol</span> <span style="color: #B8860B">move</span> <span style="color: #AA22FF; font-weight: bold">[</span><span style="color: #AA22FF">lindex</span> <span style="color: #B8860B">$R</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">];</span> <span style="color: #008800; font-style: italic"># 注意这里的写法, 由于vmd设计的失误, 必须这样写</span> <span style="color: #B8860B">$topmol</span> <span style="color: #B8860B">writepdb</span> <span style="color: #BB4444">"mol~rot.pdb"</span></pre></div> </td></tr></table>

我们也可以对轨迹中的每一帧进行这种操作, 具体代码就作为思考题吧.

直接修改矩阵

只是用来示例如何直接修改几个矩阵的值, 这样有需要的时候可以不用借助于VMD提供的那些矩阵操作来获得矩阵, 虽然可能麻烦点, 但不受限制.

<table class="highlighttable"><th colspan="2" style="text-align:left">tcl</th><tr><td><div class="linenodiv" style="background-color: #f0f0f0; padding-right: 10px"><pre style="line-height:125%">1 2 3 4 5 6</pre></div></td><td class="code"><div class="highlight"><pre style="line-height:125%"><span></span><span style="color: #AA22FF; font-weight: bold">set</span> C <span style="color: #AA22FF; font-weight: bold">[</span><span style="color: #B8860B">molinfo</span> top get center_matrix<span style="color: #AA22FF; font-weight: bold">]</span> <span style="color: #AA22FF">lset</span> C <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">0</span> <span style="color: #666666">3</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #666666">-1</span> <span style="color: #AA22FF">lset</span> C <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">1</span> <span style="color: #666666">3</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #666666">-1</span> <span style="color: #AA22FF">lset</span> C <span style="color: #AA22FF; font-weight: bold">{</span><span style="color: #B8860B">0</span> <span style="color: #666666">2</span> <span style="color: #666666">3</span><span style="color: #AA22FF; font-weight: bold">}</span> <span style="color: #666666">-1</span> <span style="color: #B8860B">molinfo</span> top set center_matrix <span style="color: #B8860B">$C</span> <span style="color: #AA22FF">puts</span> <span style="color: #AA22FF; font-weight: bold">[</span><span style="color: #AA22FF">lindex</span> <span style="color: #AA22FF; font-weight: bold">[</span><span style="color: #AA22FF">lindex</span> <span style="color: #AA22FF; font-weight: bold">[</span><span style="color: #AA22FF">lindex</span> <span style="color: #B8860B">$C</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">]</span> <span style="color: #666666">0</span><span style="color: #AA22FF; font-weight: bold">]</span> <span style="color: #666666">3</span><span style="color: #AA22FF; font-weight: bold">]</span></pre></div> </td></tr></table>

参考