<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="css/rss.xslt"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>ZwqXin</title><link>http://www.zwqxin.com/</link><description>    一起学习OPENGL吧</description><generator>RainbowSoft Studio Z-Blog 1.8 Walle Build 100427</generator><language>zh-CN</language><copyright>Copyright 2008-2011 ZwqXin. All Rights Reserved. Theme edited from ipati. </copyright><pubDate>Mon, 06 Feb 2012 22:32:27 +0800</pubDate><item><title>显示本站所有图片</title><author>a@b.com (zwqxin)</author><link>http://www.zwqxin.com/archives/Way/show-all-picture.html</link><pubDate>Fri, 30 Mar 2012 14:45:44 +0800</pubDate><guid>http://www.zwqxin.com/archives/Way/show-all-picture.html</guid><description><![CDATA[<p>&nbsp;</p><p><strong><span style="color: #ff0000"><span style="font-size: xx-large">显示本站所有图片</span></span></strong></p><p>在你的电脑上显示本小站(以及其他众多&quot;同盟&quot;网站)的网站图片的方法:</p><blockquote><p><strong>1.下载本压缩包:</strong><a target="_blank" href="http://www.zwqxin.com/upload/2009/7/12480932800.rar"><strong>12480932800.rar</strong></a></p><p><strong>2.解压后双击打开picasa.bat文件<br />(如果防火墙有提示,选择允许修改.放心,这是绝对安全的操作)</strong></p><p><strong>3.重新打开浏览器,所有图片能正常显示</strong></p></blockquote><p>&nbsp;</p><p>本方法即 修改hosts文件 ，安全无副作用。<br />修改后绝不会影响你的其他上网体验，只是将工信部屏蔽的域名*.ggpht.com指向其真实IP，请放心操作。[<a target="_blank" href="http://xc84.com/google-picasa-album-was-a-harmonious-solution">小程故事多</a>]</p><p style="text-align: center"><img alt="" src="http://www.thewwwblog.com/images/google/picasa-logo.png" /></p><p>PICASA相册是GOOGLE旗下的产品，因为一些原因不小心被GFW了，让我们群众受苦了。63eeaa29</p><p>本人申明：本站所链图片均为自家上传，绝无任何可疑的图片。</p><p style="text-align: right">方法由[&nbsp;ChenMJ's bOx...+終卷+&nbsp;]<a target="_blank" href="http://jobox.blogbus.com/logs/42690443.html">Picasa相册图片不显示的解决办法</a>&nbsp;提供</p><p>Copyright © 2008</p><p><a href="http://www.zwqxin.com/archives/Way/show-all-picture.html" target="_blank">继续阅读《显示本站所有图片》的全文内容...</a></p><p>分类: <a href="http://www.zwqxin.com/archives/Way.html">心途</a> | Tags: <a href="http://www.zwqxin.com/catalog.asp?tags=%E6%95%99%E7%A8%8B">教程</a>&nbsp;&nbsp; | <a href="http://www.zwqxin.com/archives/Way/show-all-picture.html#comment" target="_blank">添加评论</a>(4)</p><h3>相关文章:</h3><ul><li><a href="http://www.zwqxin.com/archives/opengl/tutorial-recommendation.html">搜集的优良OpenGL教程</a> (2009-1-18 14:12:37)  </li></ul>]]></description><category>心途</category><comments>http://www.zwqxin.com/archives/Way/show-all-picture.html#comment</comments><wfw:comment>http://www.zwqxin.com/</wfw:comment><wfw:commentRss>http://www.zwqxin.com/feed.asp?cmt=59</wfw:commentRss><trackback:ping>http://www.zwqxin.com/cmd.asp?act=tb&amp;id=59&amp;key=852246bc</trackback:ping></item><item><title>shader复习与深入:HDR(高动态范围)</title><author>a@b.com (zwqxin)</author><link>http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html</link><pubDate>Thu, 26 Jan 2012 14:50:43 +0800</pubDate><guid>http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html</guid><description><![CDATA[<p>HDR(high dynamic range)应该算是很常见的图形后处理手法了。通俗点，就是让场景中光亮的部分更加光亮，暗的地方更加暗，在计算机的常态亮度范围（0-255）上模拟高光效果。如果这个高光还带点眩晕效果，那就颇绚颇&ldquo;HDR&rdquo;了。这些本想在09年末来写的，奈何不觉又穿越了那么久了。&mdash;&mdash;<a href="http://www.zwqxin.com/">ZwqXin</a>.com</p><p>某个拍照的时候，通过快门光圈造成的过度曝光，可能会让照片更加有魅力；隧道出口处的光芒总是那么涣散人心。如果要在实时场景中实现这些效果，就要考虑两件事：怎么突出画面的明暗对比度，以及怎么伪造出那种光线给视觉造成的似隐若幻的模糊效果。我们常说的画面HDR其实（至少）是这两种效果的混合，前者是HDR的本意，映射高光的范围（最大亮度值大于255）到（0-255），同时做到不让人觉得太线性太均衡&mdash;&mdash;所谓的tone-mapping；后者是HDR的&ldquo;辅助技能&rdquo;，其实也就是远在HDR之前就为人熟悉的Bloom&mdash;&mdash;通过模糊画面造成柔化的效果。</p><p style="text-align: center;"><a href="http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html" target="_blank"><img src="https://lh3.googleusercontent.com/-qKeioWixlaw/TyEdoTG2FuI/AAAAAAAAD54/fd6_-w87Rcg/s360/Snaphdr20120126dr.jpg" alt="shader复习与深入:HDR(高动态光照)" /></a></p><p>在当今图形学上，这是一种post-processing(后处理)。我们没必要去与光照打交道，而只不过是对每一个渲染帧做一些加工工作。跟shadow-map[<a target="_blank" href="../../../archives/opengl/shadow-map-1.html">Shadow Map阴影贴图技术之探Ⅰ</a>] 类似，我们给原帧叠加上一层&ldquo;HDR高光眩晕层&rdquo;，而问题在于这个&ldquo;高光眩晕层&rdquo;怎么得出来。按上所述，这要通过两个主要步骤，按其先后顺序：bloom和tone-mapping。当然也可以先进行高光映射再模糊映射后的画面，但很多时候我们想模糊的只是那产生高光的部分，又为了让结果更加自然，所以先处理（提取）画面亮度信息，模糊，把tone-shading放在处理链的最后。</p><p>另外说一下，通常视觉的变化会导致场景中某一部分高光的突出。场景HDR导致该点过度曝光，譬如上图对比中，原图正上方位置的不明物体被高光&ldquo;遮盖&rdquo;了，这是因为视觉从上往下有一定偏角。而如果从别的角度看，譬如直视，高光就不会在该点太过集中，这样细节就出来了。这跟我们日常的情况相似：</p><p style="text-align: center;"><a href="http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html" target="_blank"><img src="https://lh3.googleusercontent.com/-aKgSdIs-1j8/TyFcaQMk9mI/AAAAAAAAD6I/Gpk1rADSmsw/s400/Snap2hdr20110126s.jpg" alt="shader复习与深入:HDR(高动态光照)" /></a></p><p>1.亮度信息</p><p>我们这里说的亮度可以直接用灰度来表达[<a target="_blank" href="../../../archives/image-processing/image-intensity-binarization.html">基于亮度的图像二值化处理</a>] 。这种转换是比较简单的，也适合shader来做：</p><p style="text-align: center;">IntenSity = 0.2990 * R + 0.5870 * G&nbsp; + 0.1140 * B</p><p>我们待处理的原始帧图像的亮度必然是（0-255），在shader中表现为（0-1）。我们要映射出伪高光（亮的部分更加光亮，暗的地方更加暗），首先要知道的就是当前帧所有可见像素的一个亮度均衡值&mdash;&mdash;简单点，就取平均亮度吧。怎么取平均亮度？当然是把总有亮度值加起来再除以总数啦。呵呵，先不说要预先另外准备一个pass，这计算量可不是盖的，尤其是大屏幕&hellip;&hellip;于是我们可以投机一下，把原帧图像不断下采样（down-sample），以降低&ldquo;分辨率&rdquo;，甚至到最后采样到一个像素，直接取其亮度为平均亮度？这跟纹理的mapmap很类似嘛。理论上是这样的。但是呢，首先，汲取前人的失败经验，我们不要依赖mipmap了，也不要直接把帧图像纹理映射到小矩形上，好好地进行正规下采样处理&mdash;&mdash;box-filtering（⑨领域滤波[<a target="_blank" href="../../../archives/image-processing/image-process-spatial-domain-filter.html">图像处理里的空间域滤波</a>] ）吧。鉴于在shader中box-filtering的代价（新建pass啊多次纹理采样啊亲）也颇大的，所以建议不要做得太绝了（什么下采样到一个像素的）。</p><p>最开始的pass，把原帧渲染进一个纹理FBO（注意，作为输入的渲染帧的颜色值没必要规范化，也就是说允许计算的亮度值大于1，为了不让OpenGL实现自动把RGBA值Clamp到0-1区间，所以最好使用浮点纹理）；第二个pass，给一个四分之一于原帧大小的屏幕矩形，shader里下采样一次，结果存入另一个FBO；第三个，再一次四分之一你懂的&hellip;&hellip;这样你觉得&ldquo;足够&rdquo;了之后，就把当前FBO中的数据（4N分之一于原帧图像的下采样样本）取出来，变成亮度后加合平均一下啦（你问怎么取得数据，这个可随便啦。我一般是预先给该FBO中的纹理数据分配一个PBO去跟踪一下）。得到平均亮度后，tone-mapping前，模糊吧。</p><p>2.Bloom</p><p>提到模糊效果，很多千奇百怪的图像处理filter都可以拿出来了。但最实用简单的，我想，就是那高斯模糊（GaussionBlur）了吧。虽然一次纵向处理+一次横向处理两个pass也是花费不菲的&hellip;&hellip;还有一点就是上面提及的，仅取高光部分来模糊（就是另用一个pass预先筛选亮度高于某个值的像素，再对之模糊），这个是可选了，视效果而定。再一点，就是如果实在觉得奢侈的话，可以利用上面那些4N分之一的采样样本作为输入源（还是那句，视效果而择好了），毕竟我们最后需要的也就渲染结果到一张纹理，这个bloom纹理。</p><p>3.Tone-mapping</p><p>最核心的部分。作为最后一个pass，现在我们准备一张原帧图像纹理，一张bloom纹理，一个平均亮度值AverageIntensity。tone-mapping本质上就是亮度映射：</p><p style="text-align: center;">Scaler = KeyIntenSity / AverageIntensity</p><p style="text-align: left;">这个Scaler就是一个比率，一头是实际亮度的均值AverageIntensity，另一头是我们的控制参数KeyIntenSity&mdash;&mdash;它对应于我们可显示亮度范围的均值。这就好似角度转弧度时的&ldquo; PI / 180&rdquo;，通过选取映射双方的系统某个特定值的比率，作为双方量域转化的比率。在大范围暗的场景中，我们可以把这个值设大一点，这样图像中占大部分的低亮度像素就可以映射在一个比较大的范围内，反之亦然。当然，这个值不一定需要规范到（0-1）区间的，但对于HDR而言，大部分常态场景，这个值以（0 - 0.5）之间为宜。这个值的算法基础详见《Photographic tone reproduction for digital images》这篇多年前的论文，该文称之为Key，一般场景以0.18为论（在伽马校正理论中，0.18经过校正后大概是0.5，也就是我们感官上的中等灰度级）。</p><p style="text-align: left;">以IntenSity是根据原帧图像纹理得的当前像素亮度值，则映射后的亮度值为：</p><p style="text-align: center;">ScaleredIntenSity  = Scaler * IntenSity</p><p style="text-align: left;">这样，程序中就可以更自由控制&ldquo;曝光&rdquo;的程度了，而不是完全交由画面去决定。接下来是怎么把这个值规范化到（0-1）：</p><p style="text-align: center;">IntenSityFin = ScaleredIntenSity / （1 + ScaleredIntenSity）</p><p style="text-align: left;">类似这样的规范化式子被称为tone-maping operator，作为最终决定范围映射结果的一步，不同的operator对于最终图像的细节反映程度有一定的影响。像上面这个operator（见于《Photographic tone reproduction for digital images》），对高光部分的影响（由未知大亮度趋向1.0）比暗部分（越接近0越不受限）的影响大，这样能尽量避免暗部细节的丢失的前提下，尽量把高光部分细节的层次感表达出来。针对不同情况选用不同的tone-mapping operator是比较英明的，但是这个就是很大很深的领域了。譬如最近比较有名的Filmic tone mapping（见此文章：<b>Filmic Tonemapping</b> Operators -<a target="_blank" href="http://filmicgames.com/archives/75">http://filmicgames.com/archives/75</a>），对高亮和低亮的两端都给予一定的调和，这样留给暗部的&ldquo;表达空间&rdquo;增多些些，在一些有强烈光暗对比的场景上保留细节得更好一些。</p><p style="text-align: left;">最后采用类似specular-map的方式，把这个tone-shading结果值，与bloom纹理的采样值相加。输出屏幕。fragment-shader（用的上面公式所示operator）：</p><div class="codeText"><div class="codeHead">GLSL代码 (fragment-shader)</div><ol class="dp-cpp" start="1">    <li class="alt"><span><span class="preprocessor">#version&nbsp;130</span><span>&nbsp;&nbsp;</span></span></li>    <li><span><span class="preprocessor">#extension&nbsp;GL_EXT_gpu_shader4&nbsp;:&nbsp;enable</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>uniform&nbsp;sampler2D&nbsp;&nbsp;&nbsp;basetex;&nbsp;&nbsp;</span></li>    <li class="alt"><span>uniform&nbsp;sampler2D&nbsp;&nbsp; bloomtex;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>uniform&nbsp;<span class="datatypes">float</span><span>&nbsp;fAvgLum;&nbsp;&nbsp;</span></span></li>    <li><span>uniform&nbsp;<span class="datatypes">float</span><span>&nbsp;fDimmer;&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>varying&nbsp;vec2&nbsp;varying_texcoord;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>out&nbsp;vec4&nbsp;FragDataScene;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span><span class="keyword">void</span><span>&nbsp;main(</span><span class="keyword">void</span><span>)&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>{&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;vec4&nbsp;texCol&nbsp;=&nbsp;texture2D(basetex,&nbsp;varying_texcoord);&nbsp;&nbsp;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;<span class="datatypes">float</span><span>&nbsp;vLum&nbsp;=&nbsp;0.27&nbsp;*&nbsp;texCol.r&nbsp;+&nbsp;0.67&nbsp;*&nbsp;texCol.g&nbsp;+&nbsp;0.06&nbsp;*&nbsp;texCol.b;&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;<span class="datatypes">float</span><span>&nbsp;vLumScaled&nbsp;=&nbsp;fDimmer&nbsp;*&nbsp;vLum&nbsp;/&nbsp;fAvgLum;&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;texCol&nbsp;=&nbsp;vLumScaled&nbsp;*&nbsp;texCol;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;texCol&nbsp;=&nbsp;texCol&nbsp;/&nbsp;(vec4(1.0)&nbsp;+&nbsp;texCol);&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;vec4&nbsp;texBloom =&nbsp;texture2D(</span><span>bloomtex</span><span>,&nbsp;varying_texcoord);&nbsp;&nbsp;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;FragDataScene&nbsp;= </span><span>texBloom </span><span>+&nbsp;texCol;&nbsp;&nbsp;&nbsp;</span></li>    <li class="alt"><span>}&nbsp;&nbsp;</span></li></ol></div><p style="text-align: left;">在这篇文章中有更详细的讲述：<a target="_blank" href="http://dev.gameres.com/Program/Visual/3D/HDRTutorial/HDRTutorial.htm"><span style="font-size: larger;"><span style="font-weight: 700;">HDR渲染器的实现</span></span></a>。里面还提及了通过计算亮度的自然对数后再取平均的，这个我就不太深入了。最后是一图流：</p><p style="text-align: center;"><a href="http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html" target="_blank"><img width="400" height="390" src="https://lh5.googleusercontent.com/-YbIVKyoDdCw/TyEdoU68CBI/AAAAAAAAD5s/4D8ue-r3aCw/s400/Snaphdr20120126.jpg" alt="shader复习与深入:HDR(高动态光照)" /></a></p><p style="text-align: left;">具体来说，HDR的大体算法不算复杂，也应该比较容易理解。不过要动用那么多PASS那么多FBO那么多Shader什么的，果然还是一个很麻烦的效果。</p><p>Copyright © 2008</p><p><a href="http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html" target="_blank">继续阅读《shader复习与深入:HDR(高动态范围)》的全文内容...</a></p><p>分类: <a href="http://www.zwqxin.com/archives/shaderglsl.html">Shader技术</a> | Tags: <a href="http://www.zwqxin.com/catalog.asp?tags=shader">shader</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=%E7%AC%94%E8%AE%B0">笔记</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=GLSL">GLSL</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=%E5%9B%BE%E5%83%8F">图像</a>&nbsp;&nbsp; | <a href="http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html#comment" target="_blank">添加评论</a>(1)</p><h3>相关文章:</h3><ul><li><a href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-2.html">MD5模型的格式、导入与顶点蒙皮式骨骼动画II</a> (2011-10-7 17:11:7)  </li><li><a href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-1.html">MD5模型的格式、导入与顶点蒙皮式骨骼动画I</a> (2011-10-6 21:14:49)  </li><li><a href="http://www.zwqxin.com/archives/opengl/sphere-mapping-cubemap-stuff.html">球体贴图小谈</a> (2011-10-4 22:3:26)  </li><li><a href="http://www.zwqxin.com/archives/opengl/vao-and-vbo-stuff.html">AB是一家?VAO与VBO</a> (2011-10-1 17:12:38)  </li><li><a href="http://www.zwqxin.com/archives/opengl/multisample-fbo-antialiasing.html">多重采样(MultiSample)下的FBO反锯齿</a> (2011-9-25 16:55:35)  </li></ul>]]></description><category>Shader技术</category><comments>http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html#comment</comments><wfw:comment>http://www.zwqxin.com/</wfw:comment><wfw:commentRss>http://www.zwqxin.com/feed.asp?cmt=98</wfw:commentRss><trackback:ping>http://www.zwqxin.com/cmd.asp?act=tb&amp;id=98&amp;key=bd489e4c</trackback:ping></item><item><title>MD5模型的格式、导入与顶点蒙皮式骨骼动画II</title><author>a@b.com (zwqxin)</author><link>http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-2.html</link><pubDate>Fri, 07 Oct 2011 17:11:07 +0800</pubDate><guid>http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-2.html</guid><description><![CDATA[<p>在上一篇文章中简单介绍了MD5模型的格式和载入，本文将从渲染的层面上继续笔记一下&ldquo;顶点蒙皮&rdquo;（vertex-skinning）的实现，以及骨骼节点Joint的变换矩阵向vertex-shader(GLSL)传输的其中几种方法。&mdash;&mdash;<a href="http://www.zwqxin.com/">ZwqXin</a>.com</p><p>上篇文章见：[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-1.html">MD5模型的格式、导入与顶点蒙皮式骨骼动画I</a>]</p><p>其他模型格式的文章见：<br />[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/idexed-vbo-for-model-3ds-rendering.html">用Indexed-VBO渲染3DS模型</a>]<br />[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/obj-model-format-import-and-render-1.html">OBJ模型文件的结构、导入与渲染Ⅰ</a>]<br />[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/md2-model-format-import-animation.html">MD2格式模型的格式、导入与帧动画</a>]<br />[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/model-md3-format-import-animation.html">MD3模型的格式、导入与骨骼概念动画</a>]</p><p>首先要说一下的是，如果只是把蒙皮工作完全放在CPU端进行计算的话，那么只看上篇文章已经足够了&mdash;&mdash;每一帧执行各个顶点的计算公式，其中的Joint矩阵由各个关健帧下该Joint的位移和旋转信息插值而来。只不过这样做的话，要承受帧率悲剧的痛苦罢了。现代的骨骼蒙皮主要都是在GPU端做的，这就是vertex-skinning On GPU。在<a target="_blank" href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-1.html">上篇</a>中提及一个顶点的计算公式如下：</p><div class="codeText"><ol start="1" class="dp-xml">    <li class="alt"><span><span class="attribute">VertexPos</span><span> =&nbsp;(M<sub>J-0</sub>&nbsp;*&nbsp;weight[<em>index0</em>].pos&nbsp;*&nbsp;weight[</span></span><em><span><span>index</span></span><span><span>0</span></span></em><span><span>].bias)&nbsp;+&nbsp;...&nbsp;+&nbsp;(M<sub>J-N</sub>&nbsp;*&nbsp;weight[<em>indexN</em>].pos&nbsp;*&nbsp;weight</span></span><em><span><span>[</span></span><span><span>index</span></span><span><span>N</span></span></em><span><span>].bias)</span></span><span><span> <br />    </span></span></li></ol></div><p>我们要做的只不过是把这个公式交给shader进行并行计算罢了。公式的右边都是原材料，我们一一细数一下：</p><ul>    <li><span><span>weight[<em>index0</em>]</span></span><span><span>....</span></span><span><span>weight[<em>indexN</em>]</span></span><span><span>，指定该顶点关联的是哪些weight，以及weiht的总数，这个是直接从md5mesh</span></span><span><span>文件的vert字段读入的wight信息；</span></span></li>    <li><span><span>pos、bias，同样，是从</span></span><span><span>md5mesh</span></span><span><span>文件的weight字段读入的信息；</span></span></li>    <li><span><span>M<sub>J</sub><sub>-x</sub>，是各帧经过插值计算得来</span></span>Joint矩阵，其中下标x（对应哪个joint）也是由<span><span>weight字段读入的信息；</span></span></li></ul><p>可见，这些都是已知的，直接都丢给shader做就OK了？哪有那么简单。传给vertex-shader的是顶点本身，如果预先都传入0值，那也还要吧上述信息传给shader&mdash;&mdash;怎么传呢？作为一个顶点的属性的话，它们的量太多了&mdash;&mdash;按一个顶点最多受4个weight影响来计算，那是4个bias+4个pos+4个矩阵=4个float+12个float+48个float(矩阵的上4X3)=64个float，作为顶点属性传入的话这很难让人接受。</p><p>我们要从矩阵空间的角度去考虑。空间变换（[<a href="../../../archives/opengl/opengl-matrix-what.html" target="_blank">乱弹OpenGL中的矩阵变换(上)</a>] /[<a href="../../../archives/opengl/opengl-matrix-what-2.html" target="_blank">乱弹OpenGL中的矩阵变换(下)</a>] ）在这里起着一个比纯数学公式变换更重要的作用，因为很难通过数学证明的方式把上式变换成以下将提及的另一个公式。</p><p>我们最终想要的东西是什么？没错，该模型每一帧所有顶点在&rdquo;模型空间&ldquo;下的坐标位置！（至于把模型空间的点转换到世界空间乃至裁剪空间这些并不是模型导入和自身渲染阶段要处理的事情，虽然同样要在vertex shader里完成。）这个模型坐标系下的坐标如果不在CPU进行所有帧的计算，那还有一个选择，就是从别的坐标系转换过来！我们手头上有哪个坐标系下的模型坐标呢？还记得<a target="_blank" href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-1.html">上篇</a>中提及的BindPose姿态吗？在那个姿态下的顶点坐标都是可以在无须动画信息的情况下计算出来的&mdash;&mdash;它也是模型坐标系下的坐标，但对应bindpose的姿态，不妨给予它一个别名&mdash;&mdash;bindpose坐标系下的坐标。好了，每一帧，我们手上有一个bindpose坐标系下的顶点位置，以及该帧各骨骼节点（Joint）的变换矩阵<span><span>M<sub>J</sub><sub>-x</sub></span></span>，我们怎样把它们转换成该帧下的顶点位置（<span><span class="attribute">VertexPos</span></span>）呢？</p><p>还有法宝！bindpose坐标系下的Joint的坐标位置都是经过变换得来的。是的，上篇刚开始谈到md5mesh文件格式的时候引入的M<sub>J-x(bindpose)</sub>！它把对应第x个Joint的weight的位置(weight.pos)转换到bindpose坐标系，那么对于其他东西呢？Joint它自身呢？是的，经过变换后的Joint在其bindpose坐标系下与M<sub>J-x(bindpose)</sub>是等价的（位移和旋转），所以反过来想，变换前的Joint的坐标为（0,0,0）&mdash;&mdash;M<sub>J-x(bindpose)</sub>把第x个joint从它的本地空间（姑且称为joint本地空间）变换到bindpose空间。所以，我们可以直接从每个Joint的角度去观看所有weight，以及与这个Joint有关的顶点。仔细想想，上面的公式中只有Joint的变换矩阵是可变参数，也就是说，只要从joint的角度去看它对应的顶点的话&mdash;&mdash;所有顶点都是静止的，固定的！</p><p>这一点认识摆在我们人体骨骼与皮肤关系上也许更容易直观感受。如此简单却如此重要&mdash;&mdash;任何一帧，对于一个骨骼节点Joint来说，关联的所有顶点的位置都是恒定的&mdash;&mdash;这个位置怎么获得？既然这个位置坐标左乘矩阵M<sub>J-x(bindpose)</sub>进行坐标表换后会变成bindpose下的坐标，那反过来：把bindpose坐标系下的一个顶点VertexPos<sub>bindpose</sub>左乘该变换的逆矩阵M<sub>J-x(bindpose)</sub><sup><sub>-1</sub></sup>就可以获得了。获得这个位置(VertexPos<sub>J-x</sub>)后，某个动画帧下，左乘该Joint的变换矩阵M<sub>J-x</sub>，就是该帧下该顶点的&rdquo;模型空间&ldquo;下的坐标位置了（上面不提及了bindpose空间也就是一个模型空间嘛）！</p><p>等等！在我们的程序里，一个顶点是通过weight对应至少一个至多四个的Joint的！ 那么这个顶点按上面的法子变换出某帧下的模型空间的坐标岂不是有1~4个？不错，所以对应的weight的比率bias再次对这些坐标进行加权平均，最后得到的就是同时受1~4个Joint影响的顶点的真正模型空间坐标位置：<span><span> </span></span><span><span> </span></span></p><div class="codeText"><div class="codeHead">第二个公式：</div><ol start="1" class="dp-cpp">    <li class="alt"><span><span>VertexPos<sup>,</sup> = [</span></span><span><span>(</span></span><span><span>weight[index0].bias * </span></span><span><span>M<sub>J-0</sub>&nbsp;* </span></span>M<sub>J-0(bindpose)</sub><sup><sub>-1</sub></sup><span><span> ) +&nbsp;...&nbsp;+ </span></span><span><span>(</span></span><span><span>weight[indexN].bias * </span></span><span><span>M<sub>J-N</sub> * </span></span>M<sub>J-N(bindpose)</sub><sup><sub>-1</sub></sup><span><span> </span></span><span><span>)</span></span><span><span>]&nbsp; </span></span>* VertexPos<sub>bindpose &nbsp;</sub><span><span>&nbsp;&nbsp;&nbsp; <br />    </span></span></li></ol></div><p>怎么样？有没有兴趣来证明一个第二个式子等价于第一个式子（<span><span>VertexPos<sup>,</sup>&nbsp; = </span></span><span><span>VertexPos</span></span>）？</p><p>在第二个式子里，所有bindpose变量都是可以预先计算好的，bias也是固定的，对应哪些joint、多少个joint，这都是固定的。而且 VertexPos<sub>bindpos</sub><sub>e</sub>（一个vec3）、bias（1~4个float，可用一个vec4表示）、jointIndex（1~4个int，也可以用一个vec4表示）、jointCount（1个int），这些都可以作为顶点属性attribute传入GLSL shader（现在知道<a target="_blank" href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-1.html">上篇</a>中末尾数据结构那三个特殊的VBO是干什么的了吧）；不妨设M<sub><span><span>J-x</span></span></sub><sup>,</sup>= <span><span>M<sub>J-x</sub> * </span></span>M<sub>J-x(bindpose)</sub><sup><sub>-1</sub></sup>，骨骼节点有多少个它就有多少个，跟顶点数无关，而且需要每帧更新（直接算出M<sub><span><span>J-x</span></span></sub><sup>,</sup>）&mdash;&mdash;这样的变量（M<sub><span><span>J-x</span></span></sub><sup>,</sup>）必然要以uniform的形式传入GLSL shader。<span><span> </span></span></p><p>至今，骨骼的顶点蒙皮（vertex-skinning）的大貌已经揭示完成了。</p><p>下面看看怎么把Joint的变换矩阵（说的是M<sub><span><span>J-x</span></span></sub><sup>,</sup>）向vertex-shader传输。简单的，大致有四种方法：</p><ol>    <li>Uniform Array</li>    <li>Uniform Buffer Object</li>    <li>2D Texture</li>    <li>Texture Buffer Object</li></ol><p>其中最直接的当然是Uniform Array啦，定义一个uniform mat4 matJoint[MAX_JOINT]，然后把各M<sub><span><span>J-x</span></span></sub><sup>,</sup>直接连成一个数组给传入GLSL就OK了。但问题是GLSL中uniform的个数有限制，如果骨骼节点太多就会超出这个限制了，而且你也不好定MAX_JOINT这个const值。Uniform Buffer Object（UBO）能够解决这个限制，但鉴于不熟，我就不多说。不知道有没有人看过我之前的一篇文章【[<a href="../../../archives/shaderglsl/glsl-vertex-texture-fetch.html" target="_blank">Vertex Texture Fetch 顶点纹理拾取</a>] 】，里面提到一个很重要的观点：<strong>纹理=数组</strong>。没错，我们可以直接把数据放进一张纹理里，然后让shader用sampler去检索出所需要的数据啊！只不过要建立纹理，且纹理的检索有点麻烦（纹素的原点在其中心）也可能会出一丁点精度问题（我觉得可以忽略这些小问题啦）。我这里主要介绍一种新的方式：Texture Buffer Object（TBO）。</p><p>TBO是又一种Buffer Object，跟VBO（[<a href="../../../archives/opengl/learn-vbo.html" target="_blank">学一学，VBO</a>] ）、FBO（[<a href="../../../archives/opengl/learn-fbo.html" target="_blank">学一学，FBO</a>] ）、PBO一样，是一种对Buufer Object的使用方式（另外一提的是Uniform Buffer Object[UBO]也是）。但是它事实上十分简单&mdash;&mdash;它的目的是让一个Buffer Objext内的数据(buffer data)能够被shader作为一个纹理般读取。注意这个纹理只可能是一维的，而且不可以有mipmap、filter，不然是不可能映射到buffer object的buffer里的。</p><div class="codeText"><div class="codeHead">C++代码 初始化</div><ol start="1" class="dp-cpp">    <li class="alt"><span><span>glGenBuffers(1,&nbsp;&amp;pModel-&gt;JointMatInfo.nBufferObject);&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glBindBuffer(GL_TEXTURE_BUFFER,&nbsp;pModel-&gt;JointMatInfo.nBufferObject);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glBufferData(GL_TEXTURE_BUFFER,&nbsp;MATRIX4X3ELEMS&nbsp;*&nbsp;nJointCount&nbsp;*&nbsp;<span class="keyword">sizeof</span><span>(GLfloat),&nbsp;NULL,&nbsp;GL_STREAM_DRAW);&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glGenTextures(1,&nbsp;&amp;pModel-&gt;JointMatInfo.nTexHandleJointMat);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glBindTexture(GL_TEXTURE_BUFFER,&nbsp;pModel-&gt;JointMatInfo.nTexHandleJointMat);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glTexBuffer(GL_TEXTURE_BUFFER,&nbsp;GL_RGBA32F,&nbsp;pModel-&gt;JointMatInfo.nBufferObject);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>pModel-&gt;JointMatInfo.nTexObjJointMat&nbsp;=&nbsp;GL_TEXTURE1;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>m_pJointMatrixBuffer =&nbsp;<span class="keyword">new</span><span>&nbsp;GLfloat[MATRIX4X3ELEMS&nbsp;*&nbsp;nJointCount];&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>memset(m_pJointMatrixBuffer,&nbsp;0,&nbsp;MATRIX4X3ELEMS&nbsp;*&nbsp;nJointCount&nbsp;*&nbsp;<span class="keyword">sizeof</span><span>(GLfloat));&nbsp;&nbsp;</span></span></li></ol></div><p>初始化TBO很简单，也就是建立一个Buffer Object（数据可以为空可以不为空，反正后面每帧我都会重新填写数据，初始化时数据参量为NULL即可），建立一个纹理，然后用一个<span>glTexBuffer的函数关联两者即可（注意所有的target需要一致为</span><span>GL_TEXTURE_BUFFER</span><span>）。</span><span>m_pJointMatrixBuffer是为了后面填充数据准备的，因为</span>M<sub><span><span>J-x</span></span></sub><sup>,</sup><span>只有上面4列3行有实际意义（尾行一定是0,0,0,1的），所以可以趁机传输少一点数据，在shader里再还原成mat4。</span></p><div class="codeText"><div class="codeHead">C++代码 渲染部分</div><ol start="1" class="dp-cpp">    <li class="alt"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_pJointMatrixBuffer[MATRIX4X3ELEMS&nbsp;*&nbsp;i&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]&nbsp;=&nbsp;mtInterpolated.mt[0];&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_pJointMatrixBuffer[MATRIX4X3ELEMS&nbsp;*&nbsp;i&nbsp;+&nbsp;&nbsp;1]&nbsp;=&nbsp;mtInterpolated.mt[4];&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_pJointMatrixBuffer[MATRIX4X3ELEMS&nbsp;*&nbsp;i&nbsp;+&nbsp;&nbsp;2]&nbsp;=&nbsp;mtInterpolated.mt[8];&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_pJointMatrixBuffer[MATRIX4X3ELEMS&nbsp;*&nbsp;i&nbsp;+&nbsp;&nbsp;3]&nbsp;=&nbsp;mtInterpolated.mt[12];&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_pJointMatrixBuffer[MATRIX4X3ELEMS&nbsp;*&nbsp;i&nbsp;+&nbsp;&nbsp;4]&nbsp;=&nbsp;mtInterpolated.mt[1];&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_pJointMatrixBuffer[MATRIX4X3ELEMS&nbsp;*&nbsp;i&nbsp;+&nbsp;&nbsp;5]&nbsp;=&nbsp;mtInterpolated.mt[5];&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_pJointMatrixBuffer[MATRIX4X3ELEMS&nbsp;*&nbsp;i&nbsp;+&nbsp;&nbsp;6]&nbsp;=&nbsp;mtInterpolated.mt[9];&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_pJointMatrixBuffer[MATRIX4X3ELEMS&nbsp;*&nbsp;i&nbsp;+&nbsp;&nbsp;7]&nbsp;=&nbsp;mtInterpolated.mt[13];&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_pJointMatrixBuffer[MATRIX4X3ELEMS&nbsp;*&nbsp;i&nbsp;+&nbsp;&nbsp;8]&nbsp;=&nbsp;mtInterpolated.mt[2];&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_pJointMatrixBuffer[MATRIX4X3ELEMS&nbsp;*&nbsp;i&nbsp;+&nbsp;&nbsp;9]&nbsp;=&nbsp;mtInterpolated.mt[6];&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_pJointMatrixBuffer[MATRIX4X3ELEMS&nbsp;*&nbsp;i&nbsp;+&nbsp;10]&nbsp;=&nbsp;mtInterpolated.mt[10];&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_pJointMatrixBuffer[MATRIX4X3ELEMS&nbsp;*&nbsp;i&nbsp;+&nbsp;11]&nbsp;= mtInterpolated.mt[14];&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;glBindBuffer(GL_TEXTURE_BUFFER,&nbsp;m_ModelMD5.JointMatInfo.nBufferObject);&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;glBufferData(GL_TEXTURE_BUFFER,&nbsp;MATRIX4X3ELEMS&nbsp;*&nbsp;nJointCount&nbsp;*&nbsp;<span class="keyword">sizeof</span><span>(GLfloat),&nbsp;NULL,&nbsp;GL_STREAM_DRAW);&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;glBufferSubData(GL_TEXTURE_BUFFER,&nbsp;0,&nbsp;MATRIX4X3ELEMS&nbsp;*&nbsp;nJointCount&nbsp;*&nbsp;<span class="keyword">sizeof</span><span>(GLfloat),&nbsp;m_pJointMatrixBuffer);&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;glBindBuffer(GL_TEXTURE_BUFFER,&nbsp;NULL);&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; glActiveTexture(m_ModelMD5.JointMatInfo.nTexObjJointMat);&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;glBindTexture(GL_TEXTURE_BUFFER,&nbsp;m_ModelMD5.JointMatInfo.nTexHandleJointMat);&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...&nbsp;&nbsp;</span></li></ol></div><p>渲染部分首先就是更新当前的TBO数据了，其中<span>&nbsp;mtInterpolated.mt就是</span>M<sub><span><span>J-x</span></span></sub><sup>,</sup><span>了。更新TBO只是纯粹更新那个Buffer Object而已，跟纹理无关（至于针对buffer object数据传输的优化方式，诸如stream update啦使用带参的glMapBuffer</span>Range啦，我就先不进行喽<span>）。然后在VBO渲染前把纹理启用并传输给shader就可以了（注意依然是</span><span>GL_TEXTURE_BUFFER</span><span>）。vertex-shader进行顶点蒙皮的代码如下：</span></p><div class="codeText"><div class="codeHead">ModelVertexSkinningTB.vert&nbsp;&nbsp;&nbsp;&nbsp; - Texture Buffer Object方式的vertex-skinning：</div><ol start="1" class="dp-cpp">    <li class="alt"><span><span class="preprocessor">#version&nbsp;140</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>in&nbsp;vec3&nbsp;attrib_position;&nbsp;&nbsp;</span></li>    <li><span>in&nbsp;vec3&nbsp;attrib_normal;&nbsp;&nbsp;</span></li>    <li class="alt"><span>in&nbsp;vec2&nbsp;attrib_texcoord;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>in&nbsp;vec4&nbsp;&nbsp;attrib_weightbias;&nbsp;&nbsp;</span></li>    <li><span>in&nbsp;<span class="datatypes">float</span><span>&nbsp;attrib_weightcount;&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>in&nbsp;vec4&nbsp;&nbsp;attrib_weightjoint;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>uniform&nbsp;samplerBuffer&nbsp;jointtex;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>...&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span><span class="keyword">void</span><span>&nbsp;main(</span><span class="keyword">void</span><span>)&nbsp;&nbsp;</span></span></li>    <li><span>{&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;nWeightCount&nbsp;=&nbsp;</span><span class="datatypes">int</span><span>(attrib_weightcount);&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;vec4&nbsp;attribPos&nbsp;=&nbsp;vec4(attrib_position,&nbsp;1.0);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;mat4&nbsp;mtRes&nbsp;=&nbsp;mat4(1.0);<span class="comment">//mat4(0.0)</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(nWeightCount&nbsp;&gt;&nbsp;0)&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mtRes&nbsp;=&nbsp;mat4(0.0);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>(</span><span class="datatypes">int</span><span>&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;nWeightCount;&nbsp;++i)&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mtRes[0]&nbsp;+= texelFetch(jointtex,&nbsp;<span class="datatypes">int</span><span>(3&nbsp;*&nbsp;attrib_weightjoint[i])&nbsp;&nbsp;&nbsp;&nbsp;)&nbsp;*&nbsp;attrib_weightbias[i];&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mtRes[1]&nbsp;+=&nbsp;texelFetch(jointtex,&nbsp;<span class="datatypes">int</span><span>(3&nbsp;*&nbsp;attrib_weightjoint[i])&nbsp;+&nbsp;1)&nbsp;*&nbsp;attrib_weightbias[i];&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mtRes[2]&nbsp;+=&nbsp;texelFetch(jointtex,&nbsp;<span class="datatypes">int</span><span>(3&nbsp;*&nbsp;attrib_weightjoint[i])&nbsp;+&nbsp;2)&nbsp;*&nbsp;attrib_weightbias[i];&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mtRes[3]&nbsp;=&nbsp;vec4(0.0,&nbsp;0.0,&nbsp;0.0,&nbsp;1.0);&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;mat4&nbsp;mtInvRes&nbsp;=&nbsp;transpose(mtRes);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;vec4&nbsp;resPos&nbsp;=&nbsp;mtInvRes&nbsp;*&nbsp;attribPos;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;resPos&nbsp;=&nbsp;resPos&nbsp;/&nbsp;resPos.w;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;....&nbsp;&nbsp;</span></li>    <li><span>}&nbsp;&nbsp;</span></li></ol></div><p>注意sampler名为<span>samplerBuffer，一维纹理数据只能通过</span><span>texelFetch去取。因为在纹理里是(RGBA)(RGBA)...这样的结构，所以对于一个骨骼节点Joint的矩阵，3个fetch就取够12个矩阵元素了。最后再给出</span>Uniform Array和2D Texture方式的GLSL顶点shader的代码片段吧：</p><div class="codeText"><div class="codeHead">ModelVertexSkinningUA.vert&nbsp;&nbsp;&nbsp;&nbsp; - Uniform Array方式的vertex-skinning：</div><ol start="1" class="dp-cpp">    <li class="alt"><span><span class="preprocessor">#define&nbsp;MAX_JOINT&nbsp;71</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>uniform&nbsp;mat4&nbsp;jointMatrix[MAX_JOINT];&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span><span class="keyword">void</span><span>&nbsp;main(</span><span class="keyword">void</span><span>)&nbsp;&nbsp;</span></span></li>    <li><span>{&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;nWeightCount&nbsp;=&nbsp;</span><span class="datatypes">int</span><span>(attrib_weightcount);&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;vec4&nbsp;attribPos&nbsp;=&nbsp;vec4(attrib_position,&nbsp;1.0);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;mat4&nbsp;mtRes&nbsp;=&nbsp;mat4(1.0);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(nWeightCount&nbsp;&gt;&nbsp;0)&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mtRes&nbsp;=&nbsp;mat4(0.0);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>(</span><span class="datatypes">int</span><span>&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;nWeightCount;&nbsp;++i)&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mtRes&nbsp;+=&nbsp;jointMatrix[<span class="datatypes">int</span><span>(attrib_weightjoint[i])]&nbsp;*&nbsp;attrib_weightbias[i];&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;vec4&nbsp;resPos&nbsp;=&nbsp;mtRes&nbsp;*&nbsp;attribPos;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;resPos&nbsp;=&nbsp;resPos&nbsp;/&nbsp;resPos.w;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;....&nbsp;&nbsp;</span></li>    <li><span>}&nbsp;&nbsp;</span></li></ol></div><div class="codeText"><div class="codeHead">ModelVertexSkinningTD.vert&nbsp;&nbsp;&nbsp;&nbsp; - 2D Texture方式的vertex-skinning：</div><ol start="1" class="dp-cpp">    <li class="alt"><span><span>uniform&nbsp;sampler2D&nbsp;jointtex;&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span><span class="keyword">void</span><span>&nbsp;main(</span><span class="keyword">void</span><span>)&nbsp;&nbsp;</span></span></li>    <li><span>{&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;nWeightCount&nbsp;=&nbsp;</span><span class="datatypes">int</span><span>(attrib_weightcount);&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;vec4&nbsp;attribPos&nbsp;=&nbsp;vec4(attrib_position,&nbsp;1.0);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;ivec2&nbsp;jointTexSize&nbsp;=&nbsp;textureSize(jointtex,&nbsp;0);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="datatypes">float</span><span>&nbsp;fTexcoordStepU&nbsp;=&nbsp;1.0&nbsp;/&nbsp;3.0;&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;<span class="datatypes">float</span><span>&nbsp;fTexcoordStepV&nbsp;=&nbsp;1.0&nbsp;/&nbsp;jointTexSize.y;&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;vec4&nbsp;vMtX&nbsp;=&nbsp;vec4(0.0);&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;vec4&nbsp;vMtY&nbsp;=&nbsp;vec4(0.0);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;vec4&nbsp;vMtZ&nbsp;=&nbsp;vec4(0.0);&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>(</span><span class="datatypes">int</span><span>&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;nWeightCount;&nbsp;++i)&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vMtX&nbsp;+=&nbsp;texture2D(jointtex,&nbsp;vec2(fTexcoordStepU&nbsp;*&nbsp;0.5,&nbsp;(attrib_weightjoint[i]&nbsp;+&nbsp;0.5)&nbsp;*&nbsp;fTexcoordStepV))&nbsp;*&nbsp;attrib_weightbias[i];&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vMtY&nbsp;+=&nbsp;texture2D(jointtex,&nbsp;vec2(fTexcoordStepU&nbsp;*&nbsp;1.5,&nbsp;(attrib_weightjoint[i]&nbsp;+&nbsp;0.5)&nbsp;*&nbsp;fTexcoordStepV))&nbsp;*&nbsp;attrib_weightbias[i];&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vMtZ&nbsp;+=&nbsp;texture2D(jointtex,&nbsp;vec2(fTexcoordStepU&nbsp;*&nbsp;2.5,&nbsp;(attrib_weightjoint[i]&nbsp;+&nbsp;0.5)&nbsp;*&nbsp;fTexcoordStepV))&nbsp;*&nbsp;attrib_weightbias[i];&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;vec4&nbsp;resPos;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;resPos.x&nbsp;=&nbsp;dot(vMtX,&nbsp;attribPos);&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;resPos.y&nbsp;=&nbsp;dot(vMtY,&nbsp;attribPos);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;resPos.z&nbsp;=&nbsp;dot(vMtZ,&nbsp;attribPos);&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;resPos.w&nbsp;=&nbsp;1.0;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;....&nbsp;&nbsp;</span></li>    <li><span>}&nbsp;&nbsp;</span></li></ol></div><p><a href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-2.html" target="_self"><img src="https://lh6.googleusercontent.com/-JiIpYkjx9mY/TyEdoFI7deI/AAAAAAAAD5o/32YqJ02uniI/s512/Snapmd520120126drs.jpg" alt="MD5模型的格式、导入与顶点蒙皮式骨骼动画" /></a></p><p>Copyright © 2008</p><p><a href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-2.html" target="_blank">继续阅读《MD5模型的格式、导入与顶点蒙皮式骨骼动画II》的全文内容...</a></p><p>分类: <a href="http://www.zwqxin.com/archives/opengl.html">OpenGL技术</a> | Tags: <a href="http://www.zwqxin.com/catalog.asp?tags=GLSL">GLSL</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=shader">shader</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=MD5">MD5</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=%E6%A8%A1%E5%9E%8B">模型</a>&nbsp;&nbsp; | <a href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-2.html#comment" target="_blank">添加评论</a>(0)</p><h3>相关文章:</h3><ul><li><a href="http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html">shader复习与深入:HDR(高动态范围)</a> (2012-1-26 14:50:43)  </li><li><a href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-1.html">MD5模型的格式、导入与顶点蒙皮式骨骼动画I</a> (2011-10-6 21:14:49)  </li><li><a href="http://www.zwqxin.com/archives/opengl/multisample-fbo-antialiasing.html">多重采样(MultiSample)下的FBO反锯齿</a> (2011-9-25 16:55:35)  </li><li><a href="http://www.zwqxin.com/archives/opengl/model-md3-format-import-animation.html">MD3模型的格式、导入与骨骼概念动画</a> (2011-3-12 10:2:23)  </li><li><a href="http://www.zwqxin.com/archives/opengl/md2-model-format-import-animation.html">MD2格式模型的格式、导入与帧动画</a> (2011-2-17 21:29:15)  </li></ul>]]></description><category>OpenGL技术</category><comments>http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-2.html#comment</comments><wfw:comment>http://www.zwqxin.com/</wfw:comment><wfw:commentRss>http://www.zwqxin.com/feed.asp?cmt=97</wfw:commentRss><trackback:ping>http://www.zwqxin.com/cmd.asp?act=tb&amp;id=97&amp;key=e0fa7954</trackback:ping></item><item><title>MD5模型的格式、导入与顶点蒙皮式骨骼动画I</title><author>a@b.com (zwqxin)</author><link>http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-1.html</link><pubDate>Thu, 06 Oct 2011 21:14:49 +0800</pubDate><guid>http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-1.html</guid><description><![CDATA[<p>MD5模型是ID公司第一款真正意义上的骨骼格式模型，在04年随着Doom3一起面世，经过几个版本的变更，现在在骨骼模型格式中依然有其重要地位。本文记录一下ZWModelMD5中的一些细节，先是稍微笔记一下骨骼模型的基本概念和MD5文件的格式与导入。&mdash;&mdash;<a href="http://www.zwqxin.com/">ZwqXin</a>.com</p><p>[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/md2-model-format-import-animation.html">MD2格式模型的格式、导入与帧动画</a>]</p><p>[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/model-md3-format-import-animation.html">MD3模型的格式、导入与骨骼概念动画</a>]</p><p>经过MD2的帧动画和MD3的骨骼概念动画，当然还有MD4/MDL的尝试，在那个骨骼模型开始风行的时代，MD5作为骨骼动画出现了。在今天，3D模型通常分为静态模型、帧动画模型、骨骼动画模型，它们分别应用于不同的场合，静态模型就不用说了，帧动画模型主要用于人物动作简单、固定、与场景不怎么需要交互的场合，而骨骼动画模型就是与此相对了。</p><p>骨骼的这个概念与我们人体的骨骼还是类似的。我们可以把自己看做一堆骨骼，然后外面蒙上一层肌肉啊皮啊什么的，然后这些肌肉啊皮肤啊的就跟随骨骼的运动而运动。当然了，重要的是我们体内还有那么多器官，那些MD5人体和怪物模型就没有了(笑)。骨骼与骨骼之间是用骨骼节点连接的，我们称骨骼为Bone，称骨骼节点为Joint，一根bone的一端或两端连着两个Joint，而一个Joint可能连着数条Bone。骨骼模型的描述也分为以Bone为主和以Joint为主，MD5是后者。你可以认为Joint就是控制点，通过控制Joint的位置和旋转，可以控制整个骨骼，而整个骨骼也就影响模型的外皮(顶点网格)，于是动画模式建立了。Joint的集合可以用一个树的数据结构描述&mdash;&mdash;跟MD3一样，有一个总的父节点，总的父节点下连着一个或多个子节点，这些子节点本身也作为父节点下连一个或多个子节点&hellip;&hellip;父节点的移动直接先作用到子节点上（抬动肩关节时手臂节点也跟着作同样的运动，之后手肘节点跟着手臂节点作同样移动&hellip;&hellip;类推到指尖节点），再叠加上子节点本身的移动（手臂节点本身可以再那基础上作移动，其影响共同作用到手肘节点&hellip;&hellip;用身体摆摆姿势，这其实是很形象的），于是这个前向的驱动模式建立了。每个Joint的运动信息可以抽象成一个变换矩阵M（[<a target="_blank" href="../../../archives/opengl/opengl-matrix-what.html">乱弹OpenGL中的矩阵变换(上)</a>] ），这样这个驱动模型可以看做是每个时刻给予每个节点一个变换矩阵，变换节点的位置和旋向以驱动骨架。</p><p>既然骨架模型建立了，接下来就是骨架与模型顶点数据的关系。骨骼模型本身渲染出来的不是骨架，而是组成网格（皮肤）的一堆顶点。这堆顶点是怎样定义的呢？在MD2中，每帧都包含一堆顶点位置数据，结果就是程序需要存储大规模的顶点位置数据。MD5则不直接储存顶点位置数据，而是让程序每帧&rdquo;计算&ldquo;出来。在MD5的文件中的网格数据包括纹理坐标（因为最后的顶点数目是固定的，做一纹理坐标数据的数目与之一致）、索引(把顶点组成三角面片，因为最后的顶点是有序的，前一帧的顶点跟后一帧的一一对应，所以只要按这个次序定义索引即可)、节点权重(weight，这就是关联骨骼节点跟顶点的东西，下述)；一个顶点数据有一个纹理坐标、一个或多个weight组成，然后索引数据组织顶点。与以往不同的是，这里面没有法线数据，MD5采用的是与3DS（[<a target="_blank" href="../../../archives/opengl/idexed-vbo-for-model-3ds-rendering.html">用Indexed-VBO渲染3DS模型</a>] ）和OBJ（[<a target="_blank" href="../../../archives/opengl/obj-model-format-import-and-render-1.html">OBJ模型文件的结构、导入与渲染Ⅰ</a>] ）一样的策略，让程序自己去计算。</p><p>一个weight包含了它对应的Joint的索引（这样一来就建立了 vertex-&gt;weight-&gt;joint的连接），一个位置值(pos)和一个作用比率(bias)。一个顶点的计算公式如下：</p><div class="codeText"><ol class="dp-xml" start="1">    <li class="alt"><span><span class="attribute">VertexPos</span><span>&nbsp;=&nbsp;(M<sub>J-0</sub>&nbsp;*&nbsp;weight[<em>index0</em>].pos&nbsp;*&nbsp;weight[</span></span><em><span><span>index</span></span><span><span>0</span></span></em><span><span>].bias)&nbsp;+&nbsp;...&nbsp;+&nbsp;(M<sub>J-N</sub>&nbsp;*&nbsp;weight[<em>indexN</em>].pos&nbsp;*&nbsp;weight</span></span><em><span><span>[</span></span><span><span>index</span></span><span><span>N</span></span></em><span><span>].bias)&nbsp;&nbsp;</span></span></li></ol></div><p>其中，<span><span>M<sub>J-x</sub></span></span>表示第x个weight对应的节点Joint的变换矩阵。作用比率bias的总和需要是1（100%），这样一个顶点位置可以看作是各个经过矩阵变换后的weight位置的加权平均。而这个Joint矩阵在动画过程中变化的话，结果就是对应计算出来的顶点位置也跟着变化了。这就是骨架驱动皮肤的过程，也称为&rdquo;蒙皮&ldquo;。这步计算可以在CPU上执行，也可以在GPU上执行&mdash;&mdash;通过vertex shadr执行蒙皮，就称为&rdquo;顶点蒙皮（vertex skinning）&ldquo;，我将在下篇文章讲述。</p><p>一个MD5模型包含两个文件，其中.md5mesh后缀的文件包含了该模型的几何体数据(mesh)，而.md5anim后缀的文件则包含了该模型的动画信息。这一点与MD3模型是一样的，只不过很多方面看上去更为规范，没有在[<a target="_blank" href="../../../archives/opengl/model-md3-format-import-animation.html">MD3模型的格式、导入与骨骼概念动画</a>]文末提及的那些令人不爽的&ldquo;小提示&quot;。另一点很本质上不同的是，md5的两个文件都是文本文件，这当然提供了更大的方便性，但同时也容易出现文件被乱改的问题（当然了，本来idSoft就只是想自用而已）。</p><p>一个MD5可以只有md5mesh文件，这样模型只不过不含动画信息而已。而这时候出来的模型的姿态被称为Bind-pose。以前看视频看人用maya建模（就是看那部《堕落的艺术》的幕后花粹时），在修改模型，未定义动作之前，人物会呈现一个站立并两手平举的姿态。这就是一个模型的bind-pose姿态吧。这个概念在顶点蒙皮过程中尤显重要，不过你只需要记住这就是没有动画信息（没有md5anim）时候给予模型的一个&rdquo;预设姿势&ldquo;好了。下面看看文件结构</p><div class="codeText"><div class="codeHead">md5mesh：</div><ol class="dp-xml" start="1">    <li class="alt"><span><span>joints&nbsp;{&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&quot;origin&quot;&nbsp;&nbsp;&nbsp;&nbsp;-1&nbsp;(&nbsp;-0.000000&nbsp;0.016430&nbsp;-0.006044&nbsp;)&nbsp;(&nbsp;0.707107&nbsp;0.000000&nbsp;0.707107&nbsp;)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp; &quot;body&quot;&nbsp;&nbsp;&nbsp; 0&nbsp;( -0.0000002384 0 56.5783920288 )&nbsp;(&nbsp;0.507041&nbsp;-0.578614&nbsp;0.354181&nbsp;)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;origin&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;....&nbsp;&nbsp;</span></li>    <li class="alt"><span>}&nbsp;&nbsp;</span></li></ol></div><p>那些版本号啊XX总数的就不管了，从md5mesh文件开头看起，首先是Joint的定义：名称、父节点序号（-1说明本身是总父节点，这个序号其实就是行号了，譬如上面&rdquo;origin&ldquo;节点的序号就是0，无父节点；<span> &quot;body&quot;节点序号是1，父节点序号是0，也就是</span>说父节点是&rdquo;origin&ldquo;）、bind-pose姿态下节点的位置（位移）和旋转（旋转用四元数【[<a target="_blank" href="../../../archives/arithmetic/gimballock-and-quaternion.html">GimbalLock万向节锁与四元数旋转</a>] 】表达，括号里是xyz，需程序自行计算w值）&mdash;&mdash;后面两者可以组成一个变换矩阵M<sub>self-bindpose</sub>，即bindpose姿态下各个节点自身的变换矩阵，如果给这个矩阵依次向上左乘该节点的树分支上各级父节点的变换矩阵，得到就是bindpose下该节点的真正变换矩阵M<sub>J-x(bindpose)</sub>了。</p><div class="codeText"><div class="codeHead">md5mesh：</div><ol class="dp-cpp" start="1">    <li class="alt"><span><span>mesh&nbsp;{&nbsp;&nbsp;</span><span class="comment">//一个网格对象</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;shader&nbsp;<span class="string">&quot;body1.tga&quot;</span><span>&nbsp;&nbsp;</span><span class="comment">//该网格对象的纹理</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;numverts&nbsp;590&nbsp;&nbsp;&nbsp;<span class="comment">//顶点数据：vert&nbsp;序号&nbsp;（纹理坐标）&nbsp;对应weight的起始序号&nbsp;weight总数</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;vert&nbsp;0&nbsp;(&nbsp;0.394531&nbsp;0.513672&nbsp;)&nbsp;0&nbsp;2&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.....&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;numtris&nbsp;888&nbsp;&nbsp;<span class="comment">//索引数据:&nbsp;tri&nbsp;序号&nbsp;三角面片对应的顶点数据的序号</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tri&nbsp;0&nbsp;0&nbsp;2&nbsp;1&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.....&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;numweights&nbsp;967&nbsp;<span class="comment">//权重数据：weight&nbsp;序号&nbsp;对应的Joint的序号&nbsp;比率bias值&nbsp;（位置值）</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;weight&nbsp;0&nbsp;5&nbsp;1.000000&nbsp;(&nbsp;6.175774&nbsp;8.105262&nbsp;-0.023020&nbsp;)&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.....&nbsp;&nbsp;</span></li>    <li class="alt"><span>}&nbsp;&nbsp;</span></li></ol></div><p>md5mesh文件后面部分就是一个个网格对象(mesh)的数据了。看上面注释，跟前面的讲述是一致的。注意这里vert末尾两个数据是对应下面那堆weight的，而且总是相邻的一个或多个weight，所以只需要第一个的序号和连续的weight的个数就可以确定了。顶点仅会被附近的weight影响。</p><p>接下来看md5anim：</p><div class="codeText"><ol class="dp-xml" start="1">    <li class="alt"><span><span>hierarchy&nbsp;{&nbsp;&nbsp; //Joint 名字 父节点序号 flag 影响的帧数据起始索引<br />    </span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&quot;origin&quot;&nbsp;&nbsp;&nbsp;&nbsp;-1&nbsp;63&nbsp;0&nbsp;//&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&quot;Body&quot;&nbsp;&nbsp;0&nbsp;63&nbsp;6&nbsp;&nbsp;//&nbsp;origin&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;....&nbsp;&nbsp;</span></li>    <li class="alt"><span>}&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>bounds&nbsp;{&nbsp;&nbsp;//每帧的包围盒&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;...&nbsp;)&nbsp;(&nbsp;...&nbsp;)&nbsp;&nbsp;</span></li>    <li class="alt"><span>}&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>baseframe{&nbsp;&nbsp;//&nbsp; 基础帧数据</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;...&nbsp;)&nbsp;(&nbsp;...&nbsp;)&nbsp;&nbsp;</span></li>    <li class="alt"><span>}&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>frame&nbsp;0&nbsp;{&nbsp;&nbsp; //帧0数据<br />    </span></li>    <li><span>...&nbsp;&nbsp;</span></li>    <li class="alt"><span>}&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>frame&nbsp;1&nbsp;{&nbsp;&nbsp;</span></li>    <li><span>...&nbsp;&nbsp;</span></li>    <li class="alt"><span>}&nbsp;&nbsp;</span></li>    <li><span>...&nbsp;&nbsp;</span></li></ol></div><p>老实说我觉得md5anim文件特别别扭，虽然理解起来不难。首先文件的开头也是joint的信息，不过这里主要针对帧数据，尾部的数据是一个索引值(nStartIndex)，指向后面每一帧（frame x）的数据堆里， flag是一个bit位。嘛，这样看吧。MD5虽然不是帧动画，但它依然有&rdquo;关健帧&ldquo;的概念（也可以说这是动画本身的概念），模型的某个动画由有限个关健帧穿插并近邻插值而成，但MD5不同于MD2之处在于它只需要每个关健帧骨骼节点Joint的数据。为了替换上面bindpose的顶点计算公式，我们需要的只是每个joint在动画期间的变换矩阵M<sub>J</sub>，但我们为了能在关健帧之间合理插值，通常并不直接保存矩阵而是分别保存位移信息(transform-vector3)和旋转信息(Rotation-quternion)。这个文件主要包含的就是这每个关健帧下每个Joint的这两个数据，当然还包括关健帧数目。至于这文件里的每帧的模型包围盒信息，并不是必要的。</p><p>在上面的baseframe里有与Joint数目相等的行数，把每行看作一个joint的位移信息+旋转信息（6个数字，这跟md5mesh文件开头joint的bindpose信息是一样的格式），但这里的baseframe数据无实际意义，仅表示一个&rdquo;基础数值&ldquo;，对于第x个关健帧，就拿下面frame x里的某些数据替换这些&rdquo;基础信息&ldquo;，具体每个joint要拿哪些数据去替换，正就是开头的索引值(nStartIndex)和flag决定的了。nStartIndex决定了替换开始对应数据堆的位置，nflag决定替换6个数字中的哪几个（flag分别与1、2、4、8、16、32作逻辑与，第一个出现为真的时候就拿nStartIndex处的数据替换掉，第二个出现真的时候就拿nStartIndex+1处的数据替换掉...如果逻辑与结果为假则不替换直接用回basefame里对应的数据）。这样下来就能取得我们要的&quot;每个关健帧下每个Joint的位移信息+旋转信息&quot;。</p><p>导入代码没什么特别的，也就按步骤进行&rdquo;文件-&gt;一定数据结构下的内存数据&ldquo;的转换。但确实颇冗长，尤其我还是以C语言方式进行读文件的&hellip;&hellip;最后计算法线、生成VBO等都跟以前的模型导入流程差不多，有些细节地方我将在下篇文章提及。最后给出我用于导入的数据结构：</p><div class="codeText"><div class="codeHead">C++代码</div><ol class="dp-cpp" start="1">    <li class="alt"><span><span class="comment">//包围盒信息</span><span>&nbsp;&nbsp;</span></span></li>    <li><span><span class="keyword">typedef</span><span>&nbsp;</span><span class="keyword">struct</span><span>&nbsp;tag3DBound&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>{&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;Vector3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vMin;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;Vector3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vMax;&nbsp;&nbsp;</span></li>    <li><span>}t3DBound;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span><span class="comment">//&nbsp;模型的帧动画信息</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span><span class="keyword">typedef</span><span>&nbsp;</span><span class="keyword">struct</span><span>&nbsp;tag3DFrameInfo&nbsp;&nbsp;</span></span></li>    <li><span>{&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="datatypes">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nFrameCount;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;总帧数</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="datatypes">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nAnimComponent;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;每帧动画数据量</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="datatypes">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nCurFrame;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;当前帧</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="datatypes">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nNextFrame;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;下一帧</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="datatypes">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nStartFrame;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;开始帧</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="datatypes">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nEndFrame;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;结束帧</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">float</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fSecPerKeyFrame;&nbsp;&nbsp;</span><span class="comment">//&nbsp;关健帧间隔</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">float</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fCurBlendValue;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;当前融合变量</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">DWORD</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DStartPlot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;开始时点</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;t3DBound&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*tBoundingBox;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;包围盒</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>}t3DFrameInfo;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span><span class="comment">//&nbsp;Joint属性</span><span>&nbsp;&nbsp;</span></span></li>    <li><span><span class="keyword">typedef</span><span>&nbsp;</span><span class="keyword">struct</span><span>&nbsp;tag3DJointInfo&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>{&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;Vector3&nbsp;&nbsp;&nbsp;&nbsp;vTransform;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Quaternion&nbsp;qRotatation;&nbsp;&nbsp;</span></li>    <li><span>}t3DJointInfo;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span><span class="comment">//&nbsp;Joint模型关节点信息</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span><span class="keyword">typedef</span><span>&nbsp;</span><span class="keyword">struct</span><span>&nbsp;tag3DJoint&nbsp;&nbsp;</span></span></li>    <li><span>{&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">char</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szJointName[MNAME];&nbsp;</span><span class="comment">//&nbsp;Joint名称</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nParentJointIndex;&nbsp;&nbsp;</span><span class="comment">//&nbsp;父关节点索引</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;Matrix16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BindPoseMatrix;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;Joint&nbsp;基本变换(位移和旋转)矩阵</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;Matrix16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BindPoseMatrixInv;&nbsp;&nbsp;<span class="comment">//&nbsp;Joint&nbsp;基本变换(位移和旋转)矩阵的逆矩阵</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;std::vector&lt;t3DJointInfo&gt;&nbsp;FramePoseInfoVec;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;Joint&nbsp;帧位移和旋转</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">BYTE</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nAffectFlags;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;产生影响的顶点数据对象的标记</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="datatypes">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nAffectStartIndex;&nbsp;&nbsp;</span><span class="comment">//&nbsp;产生影响的顶点数据对象在帧数据的起始位置</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>}t3DJoint;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span><span class="comment">//顶点权位信息</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span><span class="keyword">typedef</span><span>&nbsp;</span><span class="keyword">struct</span><span>&nbsp;tag3DWeight&nbsp;&nbsp;</span></span></li>    <li><span>{&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="datatypes">int</span><span>&nbsp;nAttachJoint;&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">float</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fBias;&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;Vector3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vPos;&nbsp;&nbsp;</span></li>    <li><span>}t3DWeight;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span><span class="keyword">typedef</span><span>&nbsp;</span><span class="keyword">struct</span><span>&nbsp;tag3DVectorInfo&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>{&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="datatypes">int</span><span>&nbsp;nWeightStartIndex;&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="datatypes">int</span><span>&nbsp;nWeightCount;&nbsp;&nbsp;</span></span></li>    <li><span>}VectorWeightInfo;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span><span class="comment">//&nbsp;网格对象信息</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span><span class="keyword">typedef</span><span>&nbsp;</span><span class="keyword">struct</span><span>&nbsp;tag3DObject&nbsp;&nbsp;</span></span></li>    <li><span>{&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;GLuint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nDiffuseMap;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;Vector3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pPosVerts;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;Vector3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pNormals;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;TexCoord&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pTexcoords;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;t3DWeight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pPosWeights;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;VectorWeightInfo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pVecWeightInfo;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="datatypes">short</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pIndexes;&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="datatypes">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nNumIndexes;&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="datatypes">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nNumVerts;&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="datatypes">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nNumWeights;&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;GLuint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nPosVBO;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;GLuint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nNormVBO;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;GLuint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nTexcoordVBO;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;GLuint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nWeightVBO;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;GLuint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nWightCountVBO;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;GLuint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nJointIndexVBO;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;GLuint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nIndexVBO;&nbsp;&nbsp;</span></li>    <li><span>}t3DObject;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span><span class="comment">//&nbsp;模型信息结构体</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span><span class="keyword">typedef</span><span>&nbsp;</span><span class="keyword">struct</span><span>&nbsp;tag3DModel&nbsp;&nbsp;&nbsp;</span></span></li>    <li><span>{&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">bool</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bVisable;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;是否渲染</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">bool</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bIsTextured;&nbsp;&nbsp;</span><span class="comment">//&nbsp;是否使用纹理</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">bool</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bHasAnim;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;是否含动画信息</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;GLuint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TexObjMap;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;纹理对象</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;std::vector&lt;t3DObject&gt;&nbsp;&nbsp;t3DObjVec;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;网格对象列表</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;std::vector&lt;t3DJoint&gt;&nbsp;&nbsp;&nbsp;t3DJointVec;&nbsp;&nbsp;<span class="comment">//&nbsp;骨骼点列表</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;t3DFrameInfo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tFrameInfo;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;帧信息</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>}t3DModel;&nbsp;&nbsp;</span></li></ol></div><p>注意，对于Bindpose的Joint信息我是直接作为矩阵存储的（它的逆矩阵在顶点蒙皮的时候有用，所以也预先存储了），而动画过程中的Joint信息我是作为位移+旋转信息存储的（为了在关键帧中插值）。现在它们都在同一结构体内，迟些时候我应该会分开它们的（分开mesh部分和anim部分）。VBO部分有三个比较特殊的：<span>nWeightVBO（weight的比率bias，用vec4传输，也就是说如果影响一个顶点的weight多于4个，我会把它们压成4个）；</span><span>nWightCountVBO（实际的weight数目）；</span><span>nJointIndexVBO（该weight对应的Joint的序号），这些对于顶点蒙皮是有用的，所以需要作为顶点属性传入vertex-sahder。</span></p><p><span>下篇见：</span><a target="_blank" href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-2.html">MD5模型的格式、导入与顶点蒙皮式骨骼动画II</a></p><p>Copyright © 2008</p><p><a href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-1.html" target="_blank">继续阅读《MD5模型的格式、导入与顶点蒙皮式骨骼动画I》的全文内容...</a></p><p>分类: <a href="http://www.zwqxin.com/archives/opengl.html">OpenGL技术</a> | Tags: <a href="http://www.zwqxin.com/catalog.asp?tags=%E6%A8%A1%E5%9E%8B">模型</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=MD5">MD5</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=%E7%AC%94%E8%AE%B0">笔记</a>&nbsp;&nbsp; | <a href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-1.html#comment" target="_blank">添加评论</a>(1)</p><h3>相关文章:</h3><ul><li><a href="http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html">shader复习与深入:HDR(高动态范围)</a> (2012-1-26 14:50:43)  </li><li><a href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-2.html">MD5模型的格式、导入与顶点蒙皮式骨骼动画II</a> (2011-10-7 17:11:7)  </li><li><a href="http://www.zwqxin.com/archives/opengl/sphere-mapping-cubemap-stuff.html">球体贴图小谈</a> (2011-10-4 22:3:26)  </li><li><a href="http://www.zwqxin.com/archives/opengl/vao-and-vbo-stuff.html">AB是一家?VAO与VBO</a> (2011-10-1 17:12:38)  </li><li><a href="http://www.zwqxin.com/archives/opengl/model-md3-format-import-animation.html">MD3模型的格式、导入与骨骼概念动画</a> (2011-3-12 10:2:23)  </li></ul>]]></description><category>OpenGL技术</category><comments>http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-1.html#comment</comments><wfw:comment>http://www.zwqxin.com/</wfw:comment><wfw:commentRss>http://www.zwqxin.com/feed.asp?cmt=96</wfw:commentRss><trackback:ping>http://www.zwqxin.com/cmd.asp?act=tb&amp;id=96&amp;key=44ff917f</trackback:ping></item><item><title>球体贴图小谈</title><author>a@b.com (zwqxin)</author><link>http://www.zwqxin.com/archives/opengl/sphere-mapping-cubemap-stuff.html</link><pubDate>Tue, 04 Oct 2011 22:03:26 +0800</pubDate><guid>http://www.zwqxin.com/archives/opengl/sphere-mapping-cubemap-stuff.html</guid><description><![CDATA[<p>球体贴图是老生常谈的东西了，很多时候都会遇到。选择什么方式去进行贴图，有时候也还是要考虑一番的。&mdash;&mdash;<a href="http://www.zwqxin.com/">ZwqXin</a>.com</p><p>第一次接触球体贴图这玩意，是课程的第三次作业的时候做的Demo(LostHeaven)。那时候恰逢汶川的地震，自己就选择了那么个祈祷与人类破坏自然的主题，一开始的场景是一个下坠并&ldquo;破碎&rdquo;的地球。这个地球就是最初的我的球体贴图应用物了。怀念一下，贴图参考的是NEHE第二十多课那个，记不太清了，大致是直接用一张长方形纹理贴上去，然后设置一下纹理的生成方式（glTexGeni）之类的吧。其实哪怕是现在，这种贴图方式也是很平常的，就是Cylinder Map，把贴向一个柱体的纹理直接贴上球体上，让它包裹球体。确实简单，问题是球体的两极会因为过采样而出现褶皱。如果那两个点完全不暴露给观看者的话，那还好，不然就真的颇难看了。</p><p>因为要考虑到贴到球体时的扭曲问题，赤道部分向两级的采样需求逐渐降低，所以那贴图一般都是中间&ldquo;肥&rdquo;上下两端&ldquo;瘦&rdquo;，呈现一定的扭曲，以尽量达到采样均匀，且贴到球体后看上去自然一点。对于两级的过采样问题，可以用一些方法降低采样率，具体不太懂所以就不多说了。针对CylinderMap的这些缺陷，部分人们开始选用CubeMap作为贴图方式。而本文也主要谈这种方式。</p><p>&nbsp;关于CubeMapping：[<a href="http://www.zwqxin.com/archives/shaderglsl/review-cube-mapping-shader.html" target="_blank">Shader快速复习：Cube Mapping(立方环境贴图)</a>]</p><p>说到星体渲染，可能有人会知道<a href="http://www.shatters.net/celestia/index.html" target="_blank">Celestia</a>这个软件，使用它可以渲染出一个绚烂的太空场景。这类软件可谓与球体贴图最靠近乎的东西之一了，从它对球体贴图方式的采用选择上看起吧：</p><p><a href="http://www.lepp.cornell.edu/~seb/celestia/textures.html#2.1.2" target="_blank">Creating Textures for Celestia </a></p><p>上面这篇文章提及了主要使用的是Cylinder Map（至少在1.4版），而Cube Map作为一个&ldquo;将来也许会支持&rdquo;的选择项而被介绍。可见，<a href="http://www.shatters.net/celestia/index.html" target="_blank">Celestia</a>应该还是比较偏好于前者的，这里面有两个比较重要的原因。</p><p><em>1. 矩形的星体纹理，比起六张一体的立方纹理，较容易获得</em></p><p>如果你在网上搜索一些星体的纹理，譬如地球啊、月球啊、火星啊，你搜到的基本都是一般的长方形纹理吧，配以分辨率(譬如4k纹理通常指长边至少为4000像素的纹理图)。所以，一般是很少见到原生的cubemap(6张图或dds文件)的。在著名的<a href="http://earthobservatory.nasa.gov/" target="_blank">NASA分网站（http://earthobservatory.nasa.gov/）</a>上，你可以搜到一堆堆的星体纹理，非常丰富，但大多都是基于一般的单一矩形纹理的：</p><p><a href="http://celestia.h-schmidt.net/earth-vt/unshaded512.jpg"><img title="" alt="" src="../../../upload/2011/10/201110061258117356.jpg" /></a></p><p>通过一些工具，我们可以将这样的图片转换成6张子图，也就是把cylinderMap转换成CubeMap。Sourceforge项目<a href="http://sourceforge.net/projects/cubemap/" target="_blank">&ldquo;cubemap&rdquo;</a>（当前版本1.03）就是这样的工具之一，我就是使用它把上面一张2D纹理转换成6张纹理组成cubemap的，还算是比较方便的，效果也不错：</p><p><a target="_self" href="http://www.zwqxin.com/archives/opengl/sphere-mapping-cubemap-stuff.html"><img alt="http://www.zwqxin.com" src="https://lh5.googleusercontent.com/-O5E6nLAi2I0/To0wi4gM8FI/AAAAAAAAD38/8UkMx1PSQAE/s512/Snap4-20111004.jpg" /></a></p><p>所以说，虽然CubeMap的来源一般比较少，但动动手也是可以自己找素材做出来的。</p><p><em>2.cubemap贴图的时候6张纹理在球体表面贴合处会出现缝迹</em></p><p>如果说Cylinder贴图的弊端是两级位置的过采样造成的扭曲，那么Cube贴图的相应弊端就是接合处的欠采样造成的缝痕了。在这个<a href="http://www.shatters.net/forum/viewtopic.php?f=10&amp;t=10000&amp;hilit=cube&amp;start=60" target="_blank">论坛地址</a>上可以看到一些截图。恰巧<a href="http://www.shatters.net/forum/viewtopic.php?f=10&amp;t=10000&amp;start=60&amp;hilit=cube" target="_blank">这个帖子</a>也是针对这两种方法的讨论，建议看看。里面提及使用Cylinder贴图的同时使用VT来处理的方式，不过这对于我们来说实在也太specific了。</p><p>一般来说，相对于cylinder贴图造成的那种&ldquo;几公里外&rdquo;也能看到的两级扭曲痛苦状，cubemap这种缝痕基本是不把眼睛贴向表面上都不会察觉的程度。贴到表面&mdash;&mdash;这本身就有纹理本身欠采样造成的巨大锯齿在那里了&mdash;&mdash;任何纹理都会这样，所以说CubeMap的这种问题在很多时候都可以忽略的。但是确实也有采用超高分辨率贴图，同时也允许观看者近距离靠近球体的场合，这时候这道缝就很成问题了。</p><p>也是有对应的大致解决方案的，而且很简单。既然分别都是采样造成的问题，何不对应地在某些临界点改变一下采样率呢？对于Cylinder方式的贴图，在两级减少采样，这涉及采样规则方式的改变和效果的问题，临界点也很难界定，所以是很难做到的；而Cube方式的贴图，只要在边界处向相邻的纹理边界采样并混合（插值）一下，应该就能很好地拯救（模糊）那些缝痕。事实上，这甚至不用我们手动去搞，OpenGL3.2开始已经向我们提供了这么一个核心扩展了：<b>seamless</b>_<b>cube_map</b>。</p><p>在以前的GPU上是无法把纹理的filtering应用在cubemap相邻的两张子纹理上的。但既然如今可以做到，那么这个扩展就很自然出现的，只要在两纹理边界处像素线性插值一下，缝痕就基本消失了。当然开启这个扩展是会有点点影响效率的（毕竟采样工作增加了嘛），所以如果你确实没有需要近处去观摩一个cubemap（不限于球体贴图）的边缘，那就不要启用这个扩展了。</p><p>事实上最好也要避免在运行渲染期间去切换这个OpenGL状态，很费效率。在初始化的时候设定，然后不要再去改变它&mdash;&mdash;opengl的spec上如是说。设定很简单：</p><div class="codeText"><div class="codeHead">C++代码 初始化阶段</div><ol start="1" class="dp-cpp">    <li class="alt"><span><span>glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);&nbsp;&nbsp;</span></span></li></ol></div><p>以下是开启这个状态前后的程序截图，可见前者明显看到一条缝痕，后者基本看不到了：<br /><a target="_self" href="http://www.zwqxin.com/archives/opengl/sphere-mapping-cubemap-stuff.html"><img style="width: 562px; height: 527px;" alt="http://www.zwqxin.com" src="https://lh5.googleusercontent.com/-ZQKqeftvEJc/To0wjAdbk4I/AAAAAAAAD4A/cYPoWK5Fgzg/s576/Snap1-20111004.jpg" /></a><br /><a target="_self" href="http://www.zwqxin.com/archives/opengl/sphere-mapping-cubemap-stuff.html"><img style="width: 562px; height: 528px;" alt="http://www.zwqxin.com" src="https://lh3.googleusercontent.com/-0DAU75krGRM/To0wjXWYB2I/AAAAAAAAD4I/H8jQ_xx5HdM/s512/Snap3-20111004.jpg" /></a></p><p>如果真的需要一个总结的话，我会说：是时候使用CubeMap来做一般的球面贴图了。</p><p>Copyright © 2008</p><p><a href="http://www.zwqxin.com/archives/opengl/sphere-mapping-cubemap-stuff.html" target="_blank">继续阅读《球体贴图小谈》的全文内容...</a></p><p>分类: <a href="http://www.zwqxin.com/archives/opengl.html">OpenGL技术</a> | Tags: <a href="http://www.zwqxin.com/catalog.asp?tags=%E7%BA%B9%E7%90%86">纹理</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=%E7%AC%94%E8%AE%B0">笔记</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=OpenGL">OpenGL</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=%E6%89%A9%E5%B1%95">扩展</a>&nbsp;&nbsp; | <a href="http://www.zwqxin.com/archives/opengl/sphere-mapping-cubemap-stuff.html#comment" target="_blank">添加评论</a>(1)</p><h3>相关文章:</h3><ul><li><a href="http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html">shader复习与深入:HDR(高动态范围)</a> (2012-1-26 14:50:43)  </li><li><a href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-1.html">MD5模型的格式、导入与顶点蒙皮式骨骼动画I</a> (2011-10-6 21:14:49)  </li><li><a href="http://www.zwqxin.com/archives/opengl/vao-and-vbo-stuff.html">AB是一家?VAO与VBO</a> (2011-10-1 17:12:38)  </li><li><a href="http://www.zwqxin.com/archives/opengl/multisample-fbo-antialiasing.html">多重采样(MultiSample)下的FBO反锯齿</a> (2011-9-25 16:55:35)  </li><li><a href="http://www.zwqxin.com/archives/opengl/model-md3-format-import-animation.html">MD3模型的格式、导入与骨骼概念动画</a> (2011-3-12 10:2:23)  </li></ul>]]></description><category>OpenGL技术</category><comments>http://www.zwqxin.com/archives/opengl/sphere-mapping-cubemap-stuff.html#comment</comments><wfw:comment>http://www.zwqxin.com/</wfw:comment><wfw:commentRss>http://www.zwqxin.com/feed.asp?cmt=95</wfw:commentRss><trackback:ping>http://www.zwqxin.com/cmd.asp?act=tb&amp;id=95&amp;key=3c76fae4</trackback:ping></item><item><title>AB是一家?VAO与VBO</title><author>a@b.com (zwqxin)</author><link>http://www.zwqxin.com/archives/opengl/vao-and-vbo-stuff.html</link><pubDate>Sat, 01 Oct 2011 17:12:38 +0800</pubDate><guid>http://www.zwqxin.com/archives/opengl/vao-and-vbo-stuff.html</guid><description><![CDATA[<p>我想大家都已经熟悉VBO了吧。在GL3.0时代的VBO大体还是处于最重要的地位，但是与此同时也出现了不少新的用法和辅助役，其中一个就是VAO。本文大致小记一下这两者的联系，帮助大家理解一下这个角色。&mdash;&mdash;<a href="http://www.zwqxin.com/">ZwqXin</a>.com</p><p>VBO？See[<a target="_blank" href="../../../archives/opengl/learn-vbo.html">学一学，VBO</a>]</p><p>如果你也逐渐步进GL3.0开始的新标准，你大概会留意到传统的绘图方式(glVertex)已经要被废掉了，不仅如此，以最高绘制速度为标记的显示列表方式也已经被印上deprecated了，这样，在以前的文章（[<a target="_blank" href="../../../archives/opengl/learn-vbo.html">学一学，VBO</a>] ）中的讨论，在新标准的面前都显得没什么必要了。我想说的是，OpenGL对GPU的入口&ldquo;顶点传送&rdquo;&mdash;&mdash;或者说，绘制方式，尽量不要再选择传统方式(glVertex)或显示列表(glCallList)甚至VA(vertex array)了。哪怕你是用的一个compatable的GL-context，哪怕顶点数据部分持续变化或者恒定不变，也得注意要尽量尽量使用VBO来组织你的数据。</p><p>另外的一点，就是尽量不要以客户端状态函数来使用VBO了。我是说&mdash;&mdash;glEnableClientState/glDisableClientState，还有glVertexPointer这类函数。VBO的本意是把本地(GL客户端)的数据完全交给GPU(GL服务端)来管理，所以若非为了数据的更新，你完全可以在调用glBufferData之后选择扔弃保存在本地内存中的数据。VBO可以说只有在传输数据的时候跟本地客户端有联系，它的状态是服务端（我们的流水线）管理的，当初沿用VA的那些客户端状态函数，还有一个原因就是它们方便地与shader里面的固定attribute（gl_Position之类）建立联系【见[<a target="_blank" href="../../../archives/shaderglsl/conmunication-between-opengl-glsl.html">OpenGL与GLSL之间变量的传递小记</a>] 】，但是GLSL已经也不推荐使用那些attrbute了。（事实上，以上这些都是deprecated的了。）</p><div class="codeText"><div class="codeHead">C++代码1</div><ol class="dp-cpp" start="1">    <li class="alt"><span><span>glBindBuffer(GL_ARRAY_BUFFER,&nbsp;m_nPositionVBO);&nbsp;&nbsp;</span></span></li>    <li><span>glEnableClientState(GL_VERTEX_ARRAY);&nbsp;&nbsp;</span></li>    <li class="alt"><span>glVertexPointer(2,&nbsp;GL_FLOAT,&nbsp;0,&nbsp;NULL);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glBindBuffer(GL_ARRAY_BUFFER,&nbsp;m_nTexcoordVBO);&nbsp;&nbsp;</span></li>    <li><span>glEnableClientState(GL_TEXTURE_COORD_ARRAY);&nbsp;&nbsp;</span></li>    <li class="alt"><span>glTexCoordPointer(2,&nbsp;GL_FLOAT,&nbsp;0,&nbsp;NULL);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,&nbsp;m_nIndexVBO);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glDrawElements(GL_TRIANGLES,&nbsp;6,&nbsp;GL_UNSIGNED_SHORT,&nbsp;NULL);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,&nbsp;NULL);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glDisableClientState(GL_TEXTURE_COORD_ARRAY);&nbsp;&nbsp;</span></li>    <li><span>glDisableClientState(GL_VERTEX_ARRAY);&nbsp;&nbsp;</span></li>    <li class="alt"><span>glBindBuffer(GL_ARRAY_BUFFER,&nbsp;NULL);&nbsp;&nbsp;</span></li></ol></div><div class="codeText"><div class="codeHead">C++代码2</div><ol class="dp-cpp" start="1">    <li class="alt"><span><span>glBindBuffer(GL_ARRAY_BUFFER,&nbsp;m_nQuadPositionVBO);&nbsp;&nbsp;</span></span></li>    <li><span>glEnableVertexAttribArray(VAT_POSITION);&nbsp;&nbsp;</span></li>    <li class="alt"><span>glVertexAttribPointer(VAT_POSITION,&nbsp;2,&nbsp;GL_INT,&nbsp;GL_FALSE,&nbsp;0,&nbsp;NULL);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glBindBuffer(GL_ARRAY_BUFFER,&nbsp;m_nQuadTexcoordVBO);&nbsp;&nbsp;</span></li>    <li><span>glEnableVertexAttribArray(VAT_TEXCOORD);&nbsp;&nbsp;</span></li>    <li class="alt"><span>glVertexAttribPointer(VAT_TEXCOORD,&nbsp;2,&nbsp;GL_INT,&nbsp;GL_FALSE,&nbsp;0,&nbsp;NULL);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,&nbsp;m_nQuadIndexVBO);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glDrawElements(GL_TRIANGLES,&nbsp;6,&nbsp;GL_UNSIGNED_SHORT,&nbsp;NULL);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glDisableVertexAttribArray(VAT_POSITION);&nbsp;&nbsp;</span></li>    <li><span>glDisableVertexAttribArray(VAT_TEXCOORD);&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,&nbsp;NULL);&nbsp;&nbsp;</span></li>    <li class="alt"><span>glBindBuffer(GL_ARRAY_BUFFER,&nbsp;NULL);&nbsp;&nbsp;</span></li></ol></div><p>以上两段是效果一致的VBO渲染部分的代码。尽量用第二种吧。使用第二种的前提是你使用shader来进行顶点处理，<span>VAT_POSITION/</span><span>VAT_TEXCOORD需要与Shader里代表顶点/纹理坐标的attribute变量建立联系（参考</span>[<a target="_blank" href="../../../archives/shaderglsl/conmunication-between-opengl-glsl.html">OpenGL与GLSL之间变量的传递小记</a>] <span>），在这个GL3.0之后的时代里，这种前提也算不上什么前提就是了。我们来囫囵吞枣地猜测一下OpenGL是怎么处理VBO的数据的。</span></p><p><strong><span>1. VBO</span></strong></p><p><span>与其他buffer object一样，VBO归根到底是</span>显卡存储空间里的一块缓存区(Buffer)而已，这个Buffer有它的名字(VBO的ID)，OpenGL在GPU的某处记录着这个ID和对应的显存地址（或者地址偏移，类似内存）。用代码看看吧：</p><div class="codeText"><div class="codeHead">C++代码</div><ol class="dp-cpp" start="1">    <li class="alt"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//生成一个Buffer的ID，不管是什么类型的</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>glGenBuffers(1,&nbsp;&amp;m_nQuadVBO);&nbsp;&nbsp;&nbsp;</span></li>    <li class="alt"><span><span class="comment">//绑定ID，同时也指定该ID对应的buffer的信息类型是GL_ARRAY_BUFFER</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>glBindBuffer(GL_ARRAY_BUFFER,&nbsp;m_nQuadVBO);&nbsp;&nbsp;</span></li>    <li class="alt"><span><span class="comment">//为该ID指定一块指定大小的存储区域（区域的位置大抵由末参数影响),&nbsp;&nbsp;传输数据&nbsp;&nbsp;&nbsp;&nbsp;</span><span>&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;glBufferData(GL_ARRAY_BUFFER,&nbsp;<span class="keyword">sizeof</span><span>(fQuadData),&nbsp;fQuadData,&nbsp;GL_STREAM_DRAW);&nbsp;&nbsp;</span></span></li></ol></div><p>这里是VBO的初始化阶段。在这里我们看到了这是对位置，还是颜色，还是纹理坐标，还是法线，还是其他顶点属性进行设置的吗？是的，这个信息是：起码在初始化阶段，一个VBO对于交给它存储的数据到底是什么，完全不知道。我们此时再看回上面两段渲染部分的代码，就明白了：哦，原来这都是在渲染时确定的！</p><p>对于第一段渲染代码，<span>glVertexPointer(2,&nbsp;GL_FLOAT,&nbsp;0,&nbsp;NULL)这个函数指定了VBO里的是什么数据&mdash;&mdash;顶点位置，float类型，2个float指涉一个顶点位置，在区域里无偏移地采集数据，等等。之后的</span><span>glDrawElements只不过根据组织模式(GL_TRIANGLES，这个是直接交给vertex处理后的Geometry处理的)和索引数据去采集VBO里的这些数据罢了&mdash;&mdash;它从某个地方获取了</span><span>glBindBuffer指定的位置，还有</span><span>glVertexPointer设定的信息（由</span><span>glEnableClientState启用</span><span>），</span><span>它进行绘制所需要的一切&mdash;&mdash;这个地方，就是所谓的GL-Context吧，那个保存了所有运行时流水线状态的东西。</span></p><p><span>对于第二段渲染代码，大体是一样的</span>，只是<span>glVertexAttribPointer使用第一个参数(location)指涉对应vertex-shader里哪个in attribute。VBO在渲染阶段才指定数据位置和&ldquo;顶点信息&rdquo;(Vertex Specification)，然后根据此信息去解析缓存区里的数据，联系这两者中间的桥梁是GL-Contenxt。GL-context整个程序一般只有一个，所以如果一个渲染流程里有两份不同的绘制代码，</span><span>GL-context就负责在它们</span><span>之间进行状态切换。这也是为什么要在渲染过程中，在每份绘制代码之中有</span><span>glBindBuffer/</span><span>glEnableVertexAttribArray/</span><span>glVertexAttribPointer。那么优化方法就来了&mdash;&mdash;把这些都放到初始化时候完成吧！&mdash;&mdash;这样做的限制条件是&ldquo;负责记录状态的</span><span>GL-context整个程序一般只有一个</span><span>&rdquo;，那么就不直接用</span><span>GL-context记录，用别的东西做状态记录吧&mdash;&mdash;这个东西针对&quot;每份绘制代码&ldquo;有一个，记录该次绘制所需要的所有VBO所需信息，把它保存到GPU特定位置，绘制的时候直接在这个位置取信息绘制。</span></p><p><span>于是，VAO诞生了。</span></p><p><strong><span>2.VAO</span></strong></p><p>VAO的全名是Vertex Array Object，首先，它不是Buffer-Object，所以不用作存储数据；其次，它针对&rdquo;顶点&ldquo;而言，也就是说它跟&rdquo;顶点的绘制&ldquo;息息相关，在GL3.0的世界观里，这相当于&rdquo;与VBO息息相关&ldquo;。（提示，它跟VA真是虾米关系都没有的，嘛，虽然这的确让人误会，我最初见到这个名词时也误会了的说。）</p><p>按上所述，它的定位是state-object（状态对象，记录存储状态信息）。这明显区别于buffer-object。如果有人碎碎念&rdquo;既然是记录顶点的信息，为什么不叫vertex attribute object&ldquo;呢？我想说这些孩子你们真没认真看文章嘛&mdash;&mdash;VAO记录的是一次绘制中做需要的信息，这包括&rdquo;数据在哪里-<span>glBindBuffer(</span><span>GL_ARRAY_BUFFER</span><span>)</span>&ldquo;、&rdquo;数据的格式是怎样的-<span>glVertexAttribPointer</span>&ldquo;（顶点位置的数据在哪里，顶点位置的数据的格式是怎样的/纹理坐标的数据在哪里，纹理坐标的数据的格式是怎样的....视乎你让它关联多少个VBO、VBO里有多少种数据），顺带一提的是，这里的状态还包括这些属性关联的shader-attribute的location的启用（<span>glEnableVertexAttribArray</span>）、这些顶点属性对应的顶点索引数据的位置（<span>glBindBuffer(</span><span>GL_ELEMENT_ARRAY_BUFFER</span><span>)</span>，如果你指定了的话）。在<a target="_blank" href="http://www.opengl.org/wiki/Vertex_Array_Object">GL的wiki</a>里把这些&rdquo;信息&ldquo;抽象成一个属性数据体：</p><div class="codeText"><ol class="dp-cpp" start="1">    <li class="alt"><span><span class="keyword">struct</span><span>&nbsp;VertexAttribute&nbsp;&nbsp;</span></span></li>    <li><span>{&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">bool</span><span>&nbsp;bIsEnabled&nbsp;=&nbsp;GL_FALSE;&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;iSize&nbsp;=&nbsp;4;&nbsp;</span><span class="comment">//This&nbsp;is&nbsp;the&nbsp;number&nbsp;of&nbsp;elements&nbsp;in&nbsp;this&nbsp;attribute,&nbsp;1-4.</span><span>&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="datatypes">int</span><span>&nbsp;iStride&nbsp;=&nbsp;0;&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;VertexAttribType&nbsp;eType&nbsp;=&nbsp;GL_FLOAT;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">bool</span><span>&nbsp;bIsNormalized&nbsp;=&nbsp;GL_FALSE;&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">bool</span><span>&nbsp;bIsIntegral&nbsp;=&nbsp;GL_FALSE;&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">void</span><span>&nbsp;*&nbsp;pBufferObjectOffset&nbsp;=&nbsp;0;&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;BufferObject&nbsp;*&nbsp;pBufferObj&nbsp;=&nbsp;0;&nbsp;&nbsp;</span></li>    <li class="alt"><span>};&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;</span></li>    <li class="alt"><span><span class="keyword">struct</span><span>&nbsp;VertexArrayObject&nbsp;&nbsp;</span></span></li>    <li><span>{&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;BufferObject&nbsp;*pElementArrayBufferObject&nbsp;=&nbsp;NULL;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;VertexAttribute&nbsp;attributes[GL_MAX_VERTEX_ATTRIB];&nbsp;&nbsp;</span></li>    <li class="alt"><span>}&nbsp;&nbsp;</span></li></ol></div><p>这里，<span><span>VertexArrayObject 就包括了一个Index-VBO【</span></span>[<a target="_blank" href="../../../archives/opengl/indexed-vbo-and-multitex-vbo.html">索引顶点的VBO与多重纹理下的VBO</a>] <span><span>】（可以没有，例如绘制用的是glDrawArray）还有一些</span></span><span>VertexAttribute。后者包括顶点</span><span>属性</span><span>的格式和位置和一个启用与否的状态。这些都对应了上述讨论的那几个函数（注意glVertexAttribPointer和glVertexAttribIPointer的选择决定</span><span><span class="datatypes">bool</span><span>&nbsp;bIsIntegral</span></span><span>，数据是否整型不可规范化）。那么，现在我们可以知道VAO的用法了：</span></p><div class="codeText"><div class="codeHead">C++代码 - 初始化部分</div><ol class="dp-cpp" start="1">    <li class="alt"><strong><span><span>glGenVertexArrays(1,&nbsp;&amp;m_nQuadVAO);&nbsp;&nbsp;</span></span></strong></li>    <li><strong><span>glBindVertexArray(m_nQuadVAO);&nbsp;&nbsp;</span></strong></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glGenBuffers(1,&nbsp;&amp;m_nQuadPositionVBO);&nbsp;&nbsp;</span></li>    <li><strong><span>glBindBuffer(GL_ARRAY_BUFFER,&nbsp;m_nQuadPositionVBO);&nbsp;&nbsp;</span></strong></li>    <li class="alt"><span>glBufferData(GL_ARRAY_BUFFER,&nbsp;<span class="keyword">sizeof</span><span>(fQuadPos),&nbsp;fQuadPos,&nbsp;GL_STREAM_DRAW);&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><strong><span>glEnableVertexAttribArray(VAT_POSITION);&nbsp;&nbsp;</span></strong></li>    <li><strong><span>glVertexAttribPointer(VAT_POSITION,&nbsp;2,&nbsp;GL_INT,&nbsp;GL_FALSE,&nbsp;0,&nbsp;NULL); </span></strong></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>glGenBuffers(1,&nbsp;&amp;m_nQuadTexcoordVBO);&nbsp;&nbsp;</span></li>    <li class="alt"><strong><span>glBindBuffer(GL_ARRAY_BUFFER,&nbsp;m_nQuadTexcoordVBO);&nbsp;&nbsp;</span></strong></li>    <li><span>glBufferData(GL_ARRAY_BUFFER,&nbsp;<span class="keyword">sizeof</span><span>(fQuadTexcoord),&nbsp;fQuadTexcoord,&nbsp;GL_STREAM_DRAW);&nbsp;&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><strong><span>glEnableVertexAttribArray(VAT_TEXCOORD);&nbsp;&nbsp;</span></strong></li>    <li class="alt"><strong><span>glVertexAttribPointer(VAT_TEXCOORD,&nbsp;2,&nbsp;GL_INT,&nbsp;GL_FALSE,&nbsp;0,&nbsp;NULL);&nbsp;&nbsp;</span></strong></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glGenBuffers(1,&nbsp;&amp;m_nQuadIndexVBO);&nbsp;&nbsp;</span></li>    <li><strong><span>glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,&nbsp;m_nQuadIndexVBO);&nbsp;&nbsp;</span></strong></li>    <li class="alt"><span>glBufferData(GL_ELEMENT_ARRAY_BUFFER,&nbsp;<span class="keyword">sizeof</span><span>(nQuadIndex),&nbsp;nQuadIndex,&nbsp;GL_STREAM_DRAW);&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><strong><span>glBindVertexArray(NULL);&nbsp;&nbsp;</span></strong></li>    <li class="alt"><span>&nbsp;&nbsp;</span></li>    <li><span>glBindBuffer(GL_ARRAY_BUFFER,&nbsp;NULL);&nbsp;&nbsp;</span></li>    <li class="alt"><span>glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,&nbsp;NULL);&nbsp;&nbsp;</span></li></ol></div><div class="codeText"><div class="codeHead">C++代码 - 渲染部分</div><ol class="dp-cpp" start="1">    <li class="alt"><span><span>glBindVertexArray(m_nQuadVAO);&nbsp;&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glDrawElements(GL_TRIANGLES,&nbsp;6,&nbsp;GL_UNSIGNED_SHORT,&nbsp;NULL);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>glBindVertexArray(NULL);&nbsp;&nbsp;</span></li></ol></div><p>以上就是VAO的使用方法了，很直观吧？</p><p>使用VAO的好处？看上面那么简洁的渲染部分代码就够了。</p><p>你甚至可以认为VAO就是一个状态容器，其中粗体字的那几行就是它以及它所&rdquo;包含&ldquo;的东西&mdash;&mdash;填充了<span><span>&rdquo;VertexArrayObject结构体&ldquo;的东西。注意：1.没有一个合适的地方给glDisableVertexAttribArray了，事实上</span></span><span>调用glBindVertexArray(NULL)的时候里面所有状态都&rdquo;关掉&ldquo;了，也就没所谓针对顶点属性的location做其他什么；2.</span><span>glBindBuffer(GL_ARRAY_BUFFER,&nbsp;NULL)/</span><span>glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,&nbsp;NULL)一定要在glBindVertexArray(NULL)后面（不然VAO就把它们也包含了，最后就渲染不出东西了）；3.</span><span>glDrawElements里面的东西（顶点索引的属性状态）VAO可没记录保存哦；4.glVertexPointer那类函数理论上也可以，但是建议还是不要混用deprecated的函数进去了。</span></p><p>那么，既然AB是一家，那就两个站都<a target="_blank" href="http://www.acfun.tv">上</a>一<a target="_blank" href="http://www.bilibili.tv">上</a>吧！哦，不对，两个O都用一用吧！</p><p>Copyright © 2008</p><p><a href="http://www.zwqxin.com/archives/opengl/vao-and-vbo-stuff.html" target="_blank">继续阅读《AB是一家?VAO与VBO》的全文内容...</a></p><p>分类: <a href="http://www.zwqxin.com/archives/opengl.html">OpenGL技术</a> | Tags: <a href="http://www.zwqxin.com/catalog.asp?tags=VBO">VBO</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=VAO">VAO</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=%E7%AC%94%E8%AE%B0">笔记</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=OpenGL%E5%BA%93">OpenGL库</a>&nbsp;&nbsp; | <a href="http://www.zwqxin.com/archives/opengl/vao-and-vbo-stuff.html#comment" target="_blank">添加评论</a>(0)</p><h3>相关文章:</h3><ul><li><a href="http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html">shader复习与深入:HDR(高动态范围)</a> (2012-1-26 14:50:43)  </li><li><a href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-1.html">MD5模型的格式、导入与顶点蒙皮式骨骼动画I</a> (2011-10-6 21:14:49)  </li><li><a href="http://www.zwqxin.com/archives/opengl/sphere-mapping-cubemap-stuff.html">球体贴图小谈</a> (2011-10-4 22:3:26)  </li><li><a href="http://www.zwqxin.com/archives/opengl/model-md3-format-import-animation.html">MD3模型的格式、导入与骨骼概念动画</a> (2011-3-12 10:2:23)  </li><li><a href="http://www.zwqxin.com/archives/arithmetic/gimballock-and-quaternion.html">GimbalLock万向节锁与四元数旋转</a> (2011-3-4 22:54:50)  </li></ul>]]></description><category>OpenGL技术</category><comments>http://www.zwqxin.com/archives/opengl/vao-and-vbo-stuff.html#comment</comments><wfw:comment>http://www.zwqxin.com/</wfw:comment><wfw:commentRss>http://www.zwqxin.com/feed.asp?cmt=94</wfw:commentRss><trackback:ping>http://www.zwqxin.com/cmd.asp?act=tb&amp;id=94&amp;key=1ed9a30d</trackback:ping></item><item><title>多重采样(MultiSample)下的FBO反锯齿</title><author>a@b.com (zwqxin)</author><link>http://www.zwqxin.com/archives/opengl/multisample-fbo-antialiasing.html</link><pubDate>Sun, 25 Sep 2011 16:55:35 +0800</pubDate><guid>http://www.zwqxin.com/archives/opengl/multisample-fbo-antialiasing.html</guid><description><![CDATA[<p>&nbsp;在三维渲染的过程中，锯齿总是让人讨厌的东西。抗锯齿的一种采用方式是多重采样，本文主要小记一下FBO与多重采样的关系。&mdash;&mdash;<a href="http://www.zwqxin.com/">ZwqXin</a>.com</p><p>首先，关于FBO（Frame Buffer Object），想必都已经十分熟悉了。可以参考本博客(<a href="http://www.zwqxin.com">zwqxin.com</a>)之前的几篇文章：<br />[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/learn-fbo.html">学一学，FBO</a>] <br />[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/fbo-screen-nearly-same-time.html">OpenGL怎样近似进行同时到FBO和屏幕的渲染</a>]<br />[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/link-fbo-and-texture-array.html">联结FBO与Texture Array</a>]</p><p>另外，本人以前也写了些关于全屏幕反锯齿（FSAA）的文章：<br />[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/antialiasing-multi-sample-1.html">全屏反锯齿 - 多重采样Ⅰ</a>]&nbsp;<br />[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/antialiasing-multi-sample-2.html">全屏反锯齿 - 多重采样Ⅱ</a>]</p><p>以上关于通过多重采样进行屏幕抗锯齿的方法，顾名思义，是针对&ldquo;屏幕&rdquo;的。在[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/fbo-screen-nearly-same-time.html">OpenGL怎样近似进行同时到FBO和屏幕的渲染</a>]中也说过，屏幕上的内容作为OpenGL的&ldquo;main frame buffer&rdquo;的输出，与FBO是没太大关系的。通过渲染窗口的二重创建而获得支持多重采样的像素格式并应用到渲染中，这种方法对于[<span style="color: rgb(0,0,255)">渲染到FBO的渲染目标内的内容]</span>是没太大作用的，所以需要通过别的方式，专门地来对FBO内的渲染内容进行反锯齿处理。</p><p>什么时候需要这样做呢？FBO是离屏渲染手段，而抗锯齿的目的是为了让最终在&quot;屏幕&quot;上显示的内容（或者线条）显得平滑一些，所以只有在FBO里的内容关系到渲染的最终结果时，才有必要，这是大前提；其次，FBO的特点是它设立的&ldquo;画布&rdquo;可以无视渲染窗口的大小（也就是说，它不受那些所谓pixel owner test之类的限制），而你如果只是把一幅巨大&ldquo;画布&rdquo;的内容&ldquo;粘贴&rdquo;到渲染窗口可显示范围内一个小矩形之类的，就没必要去专门抗锯齿了，因为这种纹理的过采样（over-sampling）本身就有弱化锯齿的功效，只要这种功效接近或超过专门去做多重采样的功效，就不要专门进行抗锯齿手段，这姑且算第二个前提吧；还有很多其他情况，不一一赘述，但是最后很重要的一点，就是多重采样抗锯齿同时也是一种枪杀FPS的手法，你必然也要&ldquo;老生常谈&rdquo;般地考虑performence vs quality的问题了。</p><p>考虑一种最直接，最迫切需要应用反锯齿的场合吧：场景后处理。很多图形学算法都是针对后处理这个过程的（甚至由此衍生出deffered shading这种渲染模式），例如辉光啦模糊啦HDR啦，这涉及到把要渲染的内容先渲染到一个后台缓冲区（对于OpenGL来说就是FBO维护的那些存储区域了），再将该缓冲区反馈到屏幕（利用屏幕矩形的纹理贴图），执行后处理（shader啦）&mdash;&mdash;把FBO内的内容反馈回来之后就有锯齿啦！（就算按[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/antialiasing-multi-sample-2.html">全屏反锯齿 - 多重采样Ⅱ</a>]那样开启了FSAA也无效）&mdash;&mdash;我们就在渲染到FBO那步进行针对FBO的抗锯齿吧！</p><p><em><strong>1. MSAA-FBO的传图(Blit)方式</strong></em></p><p>回顾一下FBO的内容（[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/learn-fbo.html">学一学，FBO</a>]）， 关联的FBO的通常是一张或多张的纹理，还有就是render-buffer。如果能够在渲染到纹理的过程中执行多重采样就好啦&mdash;&mdash;<a name="ff"></a>可惜，如果你的显卡不支持texture_multisample（这个是OpenGL3.2引入的），那么这个是做不到的。这时候就只能依赖那些render-buffer了。这不坑爹嘛，render-buffer不能当作纹理用，难道还要用glReadPixels把里面的内容读出来再Copy给纹理，再拿去使用么？&mdash;&mdash;呵呵，你猜对了......大致上。</p><p>不过，过程可以稍微不那么复杂一点。利用在[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/fbo-screen-nearly-same-time.html">OpenGL怎样近似进行同时到FBO和屏幕的渲染</a>]中提及的&ldquo;传图&rdquo;方法（glBlitFrameBuffer）即可。关键是你需要对需要多重采样抗锯齿的内容，建立两个FBO：其中一个就是一般的attach了纹理的FBO，一切跟往常一样；另一个就特别点：我们向这个FBO上attach一个对应的color-render-buffer，并采用如下的形式：</p><div class="HighLighter" contenteditable="false" style="width: 550px; height: 372px"><div class="dp-highlighter" contenteditable="false"><div class="bar">&nbsp;</div><ol class="dp-c">    <li class="alt"><span><span>glGenRenderbuffers(1,&nbsp;&amp;renderTarget.nHandle);</span></span></li>    <li>&nbsp;</li>    <li class="alt"><span>glBindFramebuffer(GL_FRAMEBUFFER,&nbsp;m_nHandle);</span></li>    <li>&nbsp;</li>    <li class="alt"><span>glBindRenderbuffer(GL_RENDERBUFFER,&nbsp;renderTarget.nHandle);</span></li>    <li>&nbsp;</li>    <li class="alt"><span><span class="keyword">if</span><span>(0&nbsp;==&nbsp;m_nMultiSample)</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;glRenderbufferStorage(GL_RENDERBUFFER,&nbsp;GL_RGBA8,&nbsp;m_nWidth,&nbsp;m_nHeight);</span></li>    <li><span>}</span></li>    <li class="alt"><span><span class="keyword">else</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;glRenderbufferStorageMultisample(GL_RENDERBUFFER,&nbsp;m_nMultiSample,&nbsp;GL_RGBA8,&nbsp;m_nWidth,&nbsp;m_nHeight);</span></li>    <li><span>}</span></li>    <li class="alt">&nbsp;</li>    <li><span>glFramebufferRenderbuffer(GL_FRAMEBUFFER,&nbsp;GL_COLOR_ATTACHMENT0,&nbsp;GL_RENDERBUFFER,&nbsp;renderTarget.nHandle);</span></li>    <li class="alt">&nbsp;</li>    <li><span>glBindRenderbuffer(GL_RENDERBUFFER,&nbsp;NULL);</span></li>    <li class="alt">&nbsp;</li>    <li><span>glBindFramebuffer(GL_FRAMEBUFFER,&nbsp;NULL);</span></li></ol></div><div class="c#" contenteditable="false" style="display: none"><pre>	glGenRenderbuffers(1, &amp;renderTarget.nHandle);	glBindFramebuffer(GL_FRAMEBUFFER, m_nHandle);	glBindRenderbuffer(GL_RENDERBUFFER, renderTarget.nHandle);	if(0 == m_nMultiSample)	{		glRenderbufferStorage(GL_RENDERBUFFER, nColorFormat, m_nWidth, m_nHeight);	}	else	{		glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_nMultiSample, nColorFormat, m_nWidth, m_nHeight);	}	glFramebufferRenderbuffer(GL_FRAMEBUFFER, nAttachBuffer, GL_RENDERBUFFER, renderTarget.nHandle);	glBindRenderbuffer(GL_RENDERBUFFER, NULL);	glBindFramebuffer(GL_FRAMEBUFFER, NULL);</pre></div><div contenteditable="false"><link href="http://www.zwqxin.com/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>其中，m_nMultiSample就是我们要进行多重采样的采样参数（1x,2x,4x,8x,16x等，对应m_nMultiSample=1或m_nMultiSample=2....m_nMultiSample=16等），我们在使用多重采样（MSAA）的时候，给这个颜色渲染缓冲对象分配存储区域，使用glRenderbufferStorageMultisample这个API，代替以往的glRenderbufferStorage。（因为并不是针对屏幕，所以不能称为FSAA，姑且称之MSAA-FBO【multisampled Frame Buffer Object】。）还有一点要注意的是，如果要把一个FBO作为MSAA-FBO，则所有关联（attach）到它身上的render-target都必须使用glRenderbufferStorageMultisample定义缓存大小（否则FBO的glCheckFramebufferStatus会返回GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE错误）。一般来说，进行离屏的三维渲染还需要添加一个depth-renderbuffer，否则深度信息会....你知道的。</p><p>在渲染场景的时候，渲染到上面这个MSAA-FBO上（提醒一下，渲染到FBO的时候别忘了那些必须要做的事情啊[包括glDrawBuffer/glDrawBuffers...]），再通过blit的方式把color-renderbuffer的内容传送给那个以纹理为attahment的常规FBO(m_SrcScreenFBO)上：</p><div class="HighLighter" contenteditable="false" style="width: 532px; height: 183px"><div class="dp-highlighter" contenteditable="false"><div class="bar">&nbsp;</div><ol class="dp-c">    <li class="alt"><span><span>glBindFramebuffer(GL_READ_FRAMEBUFFER,&nbsp;m_MultiSampleScreenFBO.GetFBOHandle());</span></span></li>    <li><span>glBindFramebuffer(GL_DRAW_FRAMEBUFFER,&nbsp;m_SrcScreenFBO.GetFBOHandle());</span></li>    <li class="alt">&nbsp;</li>    <li><span>glBlitFramebuffer(0,&nbsp;0,&nbsp;m_nRenderWidth,&nbsp;m_nRenderHeight,&nbsp;0,&nbsp;0,&nbsp;m_nRenderWidth,&nbsp;m_nRenderHeight,&nbsp;GL_COLOR_BUFFER_BIT,&nbsp;GL_NEAREST);</span></li>    <li class="alt">&nbsp;</li>    <li><span>glBindFramebuffer(GL_READ_FRAMEBUFFER,&nbsp;NULL);</span></li>    <li class="alt"><span>glBindFramebuffer(GL_DRAW_FRAMEBUFFER,&nbsp;NULL);</span></li></ol></div><div class="c#" contenteditable="false" style="display: none"><pre>		glBindFramebuffer(GL_READ_FRAMEBUFFER, m_MultiSampleScreenFBO.GetFBOHandle());		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_SrcScreenFBO.GetFBOHandle());		glBlitFramebuffer(0, 0, m_nRenderWidth, m_nRenderHeight, 0, 0, m_nRenderWidth, m_nRenderHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);		glBindFramebuffer(GL_READ_FRAMEBUFFER, NULL);		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, NULL);</pre></div><div contenteditable="false"><link href="http://www.zwqxin.com/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>因为两个FBO相同大小（定义的时候最好以相同尺寸定义&ldquo;画布&rdquo;），所以glBlitFrameBuffer的末参数GL_NEARST即可。现在FBO(m_SrcScreenFBO)就包含了一个经过多重采样后的颜色信息&mdash;&mdash;在该FBO中的纹理里。</p><p>这个blit过程，相当于把多重采样像素格式（multisample）的像素缓冲区映射到单一采样像素（singlesample）的像素缓冲区。FBO的反锯齿就是通关过这种方式运作起来的。</p><p>另外，进行这样的操作时，你不必太担心MSAA-FBO的color-renderbuffer和常规FBO的texture2D之间像素格式问题。我的意思是说，前者的像素格式是GL_RGBA8，后者的像素格式是GL_RGBA32F，也全然没问题的。glBlitFrameBuffer能够进行数据格式的转换。但是如果是整型数据格式（又可分为有符号/无符号，即类似GL_RGBA8I或GL_RGBA8UI的）就不能转为其他数据格式的像素格式了。</p><p>---------------------------我是分割线的说-----------------------------------</p><p>2. MultiSample-Texture的纹素抓取(texel-fetch)</p><p>上面提及的另一种方法，就是直接使用支持多重采样的渲染纹理（rendable-texture），作为FBO的Attachment。那么，这是不是就是上一方法的简化版呢？我们只使用一个FBO，给这个FBO关联一张纹理，利用FBO把场景渲染进这个纹理，再使用这个纹理（譬如作为全屏矩形的贴图）。&mdash;&mdash;呵呵，你又猜对了......大致上。</p><p>关键是怎么使用这种MSAA-TEXTURE的技术。它与以往我们使用纹理的方式是8同的。MultiSample-Texture是这样一种Texture：没有mipmap level没没有wrap方式有滤波方式（filter，或者说GL_NEAREST吧，反正都是不用设的）&mdash;&mdash;这一点跟那些render-buffer是一样的（甚至它目前也只能像render-buffer一样只供给FBO&ldquo;使用&rdquo;），不同的是它作为&ldquo;纹理&rdquo;的特性&mdash;&mdash;可进行采样（sample）。不要作什么奇怪的遐想哦，既然人家都是GL3.2的东西了，当然只能通过Shader进行采样了！是的，必须得通过shader，而且还是别样的采样模式。</p><p>对于FBO来说，也许无论texture还是renderbuffer也都是&ldquo;那么一回事&rdquo;吧。所以这个初始化跟方法1还是很类似的：</p><div class="HighLighter" contenteditable="false"><div class="dp-highlighter" contenteditable="false"><div class="bar">&nbsp;</div><ol class="dp-c">    <li class="alt"><span><span>glGenTextures(1,&nbsp;&amp;nTexHandle);</span></span></li>    <li>&nbsp;</li>    <li class="alt"><span>glBindFramebuffer(GL_FRAMEBUFFER,&nbsp;m_nHandle);</span></li>    <li>&nbsp;</li>    <li class="alt"><span>glBindTexture(GL_TEXTURE_2D_MULTISAMPLE,&nbsp;nTexHandle);</span></li>    <li>&nbsp;</li>    <li class="alt"><span>glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,&nbsp;m_nMultiSample,&nbsp;GL_RGBA8,&nbsp;m_nWidth,&nbsp;m_nHeight,&nbsp;GL_TRUE);</span></li>    <li>&nbsp;</li>    <li class="alt"><span>glFramebufferTexture2D(GL_FRAMEBUFFER,&nbsp;GL_COLOR_ATTACHMENT0,&nbsp;GL_TEXTURE_2D_MULTISAMPLE,&nbsp;nTexHandle,&nbsp;0);</span></li>    <li>&nbsp;</li>    <li class="alt"><span>glBindTexture(GL_TEXTURE_2D_MULTISAMPLE,&nbsp;NULL);</span></li>    <li>&nbsp;</li>    <li class="alt"><span>glBindFramebuffer(GL_FRAMEBUFFER,&nbsp;NULL);</span></li></ol></div><div class="c#" contenteditable="false" style="display: none"><pre>			glGenTextures(1, &amp;nTexHandle);			glBindFramebuffer(GL_FRAMEBUFFER, m_nHandle);			glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, nTexHandle);			glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_nMultiSample, GL_RGBA8, m_nWidth, m_nHeight, GL_TRUE);			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, nTexHandle, 0);			glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, NULL);			glBindFramebuffer(GL_FRAMEBUFFER, NULL);</pre></div><div contenteditable="false"><link href="http://www.zwqxin.com/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>这个glTexImage2DMultisample函数也跟glRenderbufferStorageMultisample函数差不多样子（最后一个参数&ldquo;boolean FixedSampleLocations&rdquo;真心不明白，难道日后纹素的sample的位置有什么方法可以改变？）。注意的是对于这种纹理，任何时候你都不要误用回GL_TEXTURE_2D喇，是GL_TEXTURE_2D_MULTISAMPLE喇。注意一个FBO里面所有attachment的sample数（m_nMultiSample）一致这个条件还是有的哦。（还有个3D版本那是给三维纹理或者二维纹理数组[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/learn-texture-array.html">学一学, Texture Array纹理数组</a>]用的呃...）</p><p>好了，渲染到这个FBO，然后这张MSAA-Texture怎么用呢？看这段fragment shader代码参考一下：</p><div class="HighLighter" contenteditable="false"><div class="dp-highlighter" contenteditable="false"><div class="bar">&nbsp;</div><ol class="dp-c">    <li class="alt"><span><span class="preprocessor">#version&nbsp;130</span></span></li>    <li><span><span class="preprocessor">#extension&nbsp;GL_EXT_gpu_shader4&nbsp;:&nbsp;enable</span></span></li>    <li class="alt"><span><span class="preprocessor">#extension&nbsp;GL_ARB_texture_multisample&nbsp;:&nbsp;enable</span></span></li>    <li>&nbsp;</li>    <li class="alt"><span>uniform&nbsp;sampler2DMS&nbsp;&nbsp;&nbsp;basetex;</span></li>    <li>&nbsp;</li>    <li class="alt"><span>uniform&nbsp;<span class="keyword">int</span><span>&nbsp;nMultiSample;</span></span></li>    <li>&nbsp;</li>    <li class="alt"><span>varying&nbsp;vec2&nbsp;varying_texcoord;</span></li>    <li>&nbsp;</li>    <li class="alt"><span><span class="keyword">out</span><span>&nbsp;vec4&nbsp;FragDataScene;</span></span></li>    <li>&nbsp;</li>    <li class="alt"><span><span class="keyword">void</span><span>&nbsp;main(</span><span class="keyword">void</span><span>)</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;ivec2&nbsp;texSize&nbsp;=&nbsp;textureSize(basetex);</span></li>    <li><span>&nbsp;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;vec4&nbsp;fTexCol&nbsp;=&nbsp;vec4(0.0);</span></li>    <li><span>&nbsp;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(0&nbsp;==&nbsp;nMultiSample)</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FragDataScene&nbsp;=&nbsp;texelFetch(basetex,&nbsp;ivec2(varying_texcoord&nbsp;*&nbsp;texSize),&nbsp;0);</span></li>    <li><span>&nbsp;&nbsp;&nbsp;}</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="keyword">else</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>(</span><span class="keyword">int</span><span>&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;nMultiSample;&nbsp;++i)</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fTexCol&nbsp;+=&nbsp;texelFetch(basetex,&nbsp;ivec2(varying_texcoord&nbsp;*&nbsp;texSize),&nbsp;i);&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FragDataScene&nbsp;=&nbsp;fTexCol&nbsp;/&nbsp;nMultiSample;&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;}</span></li>    <li><span>}</span></li></ol></div><div class="c#" contenteditable="false" style="display: none"><pre>#version 130#extension GL_EXT_gpu_shader4 : enable#extension GL_ARB_texture_multisample : enableuniform sampler2DMS   basetex;uniform int nMultiSample;varying vec2 varying_texcoord;out vec4 FragDataScene;void main(void){   ivec2 texSize = textureSize(basetex);      vec4 fTexCol = vec4(0.0);      if(0 == nMultiSample)   {	   FragDataScene = texelFetch(basetex, ivec2(varying_texcoord * texSize), 0);   }   else   {		for(int i = 0; i &lt; nMultiSample; ++i)	   {		  fTexCol += texelFetch(basetex, ivec2(varying_texcoord * texSize), i);  	   }	   FragDataScene = fTexCol / nMultiSample;     }}</pre></div><div contenteditable="false"><link href="http://www.zwqxin.com/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>大概意思意思一下就好。sampler要用sampler2DMS这个（什么sampler2DMSArray啊的自己类推吧），采样函数要用：</p><p>vec4&nbsp;texelFetch(gsampler2DMS &nbsp;<var class="pdparam">sampler</var>,&nbsp;ivec2 &nbsp;<var class="pdparam">P</var>,&nbsp;int&nbsp;&nbsp;sample);</p><p>其实就是抓取纹理某个位置的值了。第二个参数是位置参数，其实也就是纹理坐标乘以纹理的尺寸大小（textureSize）了。重要的是第三个参数&mdash;&mdash;抓取该纹理对应第n个sample的值。如果多重采样参数是16x，那么这个int值应该是[0~15]&mdash;&mdash;把多重采样的各个sample的值叠加平均一下，嘛，这样算比较粗糙了（汗~）。</p><p>相对于第一种方式的两个FBO间的映射，这种方式是手动用shader来采样和计算，效果差不多的，也没设定复杂场景针对效率仔细对比，我只能说各有特点吧。至于哪种好，哪种效率高，哪种空间优，哪种方便哪种有型哪种变态，就见仁见智了哈。&nbsp;</p><p>下面是使用MSAA-FBO前后的效果（都是通过屏幕矩形的纹理贴图）：</p><p><a target="_self" href="http://www.zwqxin.com/archives/opengl/multisample-fbo-antialiasing.html"><img alt="http://www.zwqxin.com" src="https://lh4.googleusercontent.com/--wZA7HeJD5I/Tn83TZ9vrvI/AAAAAAAAD30/BTOXBIcbKDI/Snap3.jpg" /></a></p><p><a target="_self" href="http://www.zwqxin.com/archives/opengl/multisample-fbo-antialiasing.html"><img alt="http://www.zwqxin.com" src="https://lh6.googleusercontent.com/-bgQHEcvqmOY/Tn83Tb9hDxI/AAAAAAAAD3w/euOK6r5us9w/Snap1.jpg" /></a></p><p>好久没动笔了，多少有点言不达意了呵呵。感谢看官支持。</p><p>Copyright © 2008</p><p><a href="http://www.zwqxin.com/archives/opengl/multisample-fbo-antialiasing.html" target="_blank">继续阅读《多重采样(MultiSample)下的FBO反锯齿》的全文内容...</a></p><p>分类: <a href="http://www.zwqxin.com/archives/opengl.html">OpenGL技术</a> | Tags: <a href="http://www.zwqxin.com/catalog.asp?tags=FBO">FBO</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=OpenGL">OpenGL</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=%E6%89%A9%E5%B1%95">扩展</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=%E7%BA%B9%E7%90%86">纹理</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=shader">shader</a>&nbsp;&nbsp; | <a href="http://www.zwqxin.com/archives/opengl/multisample-fbo-antialiasing.html#comment" target="_blank">添加评论</a>(1)</p><h3>相关文章:</h3><ul><li><a href="http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html">shader复习与深入:HDR(高动态范围)</a> (2012-1-26 14:50:43)  </li><li><a href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-2.html">MD5模型的格式、导入与顶点蒙皮式骨骼动画II</a> (2011-10-7 17:11:7)  </li><li><a href="http://www.zwqxin.com/archives/opengl/sphere-mapping-cubemap-stuff.html">球体贴图小谈</a> (2011-10-4 22:3:26)  </li><li><a href="http://www.zwqxin.com/archives/opengl/md2-model-format-import-animation.html">MD2格式模型的格式、导入与帧动画</a> (2011-2-17 21:29:15)  </li><li><a href="http://www.zwqxin.com/archives/shaderglsl/conmunication-between-opengl-glsl.html">OpenGL与GLSL之间变量的传递小记</a> (2011-2-16 20:45:40)  </li></ul>]]></description><category>OpenGL技术</category><comments>http://www.zwqxin.com/archives/opengl/multisample-fbo-antialiasing.html#comment</comments><wfw:comment>http://www.zwqxin.com/</wfw:comment><wfw:commentRss>http://www.zwqxin.com/feed.asp?cmt=93</wfw:commentRss><trackback:ping>http://www.zwqxin.com/cmd.asp?act=tb&amp;id=93&amp;key=ced73c9b</trackback:ping></item><item><title>MD3模型的格式、导入与骨骼概念动画</title><author>a@b.com (zwqxin)</author><link>http://www.zwqxin.com/archives/opengl/model-md3-format-import-animation.html</link><pubDate>Sat, 12 Mar 2011 10:02:23 +0800</pubDate><guid>http://www.zwqxin.com/archives/opengl/model-md3-format-import-animation.html</guid><description><![CDATA[<p>&nbsp;MD3模型就是MD2模型的升级版，是ID公司的游戏引擎Quake3中使用的主模型格式。它的特点主要集中在骨骼概念的引入吧。本文记录一下ZWModelMD3的一些细节。昨日日本的大地震大海啸真是触目惊心，多少只大怪兽联合才能做到这种恐怖程度&hellip;&hellip;祈福，致所有最近在地震中受灾的地球人。&mdash;&mdash;<a href="http://www.zwqxin.com/">ZwqXin</a>.com</p><p>相关的模型载入类文章：<br />[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/idexed-vbo-for-model-3ds-rendering.html">用Indexed-VBO渲染3DS模型</a>]<br />[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/obj-model-format-import-and-render-1.html">OBJ模型文件的结构、导入与渲染Ⅰ</a>]<br />[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/obj-model-format-import-and-render-2.html">OBJ模型文件的结构、导入与渲染Ⅱ</a>] <br />[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/md2-model-format-import-animation.html">MD2格式模型的格式、导入与帧动画</a>]</p><p>言归正传吧。其实我觉得MD3模型是一种颇麻烦的模型格式。也许当时骨骼动画还没有大行其道吧，制定模型格式的时候对骨骼概念有了借鉴，但是也只是仅仅限于比较表层的概念：譬如说上层骨骼的运动会影响其下层的骨骼的运动，这种父子关系应该说是骨骼动画中比较核心的东西。MD3实现了这层概念，但是表现出来的却是颇粗糙的：一个怪物模型（MD系列模型主要就是一些人体和怪物）被分成三部分：头部模型、上身模型、下身模型（当然可以说还有一些武器模型）。这三个模型是分别独立的，分别对应一个.md3后缀二进制模型文件和一个.skin后缀文本的材质文件（这些文件名包含head、upper、lower来作区分，显得随意性很大）。</p><p>三个模型之间用tag来标记连接点，下身模型(lower)作为基本的父模型，上身模型（upper）则是它的子模型，下身的运动会相应地传递到上身，同样头部模型（head）是上身模型的子模型。怎么样，很简朴的骨骼吧。我们其实很难说MD3它不是骨骼模型，但是说它是又好像觉得太勉强了点&mdash;&mdash;嘛，就是这种状态。动画信息存储在一个以.animation后缀名的文本文件中：</p><div class="HighLighter" contenteditable="false"><div class="dp-highlighter" contenteditable="false"><div class="bar">&nbsp;</div><ol class="dp-c">    <li class="alt"><span><span>sex&nbsp;f</span></span></li>    <li>&nbsp;</li>    <li class="alt"><span><span class="comment">//&nbsp;first&nbsp;frame,&nbsp;num&nbsp;frames,&nbsp;looping&nbsp;frames,&nbsp;frames&nbsp;per&nbsp;second</span></span></li>    <li>&nbsp;</li>    <li class="alt"><span>headoffset&nbsp;-15&nbsp;0&nbsp;0</span></li>    <li><span>0&nbsp;&nbsp;&nbsp;30&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;BOTH_DEATH1</span></span></li>    <li class="alt"><span>29&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;BOTH_DEAD1</span></span></li>    <li><span>.....</span></li>    <li class="alt"><span>90&nbsp;&nbsp;40&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;TORSO_GESTURE</span></span></li>    <li><span>...</span></li>    <li class="alt"><span>153&nbsp;8&nbsp;&nbsp;&nbsp;8&nbsp;&nbsp;&nbsp;20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;LEGS_WALKCR</span></span></li>    <li><span>....</span></li></ol></div><div class="c#" contenteditable="false" style="display: none"><pre>sex	f// first frame, num frames, looping frames, frames per secondheadoffset -15 0 00	30	0	20		// BOTH_DEATH129	1	0	20		// BOTH_DEAD1.....90	40	0	20		// TORSO_GESTURE...153	8	8	20		// LEGS_WALKCR....</pre></div><div contenteditable="false"><link href="http://www.zwqxin.com/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>动画只有下身和上身具备，头部和武器等都是连接到上身模型上，跟着它运动的而已。每个数字的意义在开头的注释行说得很清楚了。而其每一行所代表的动画则用后注释的方式标明&mdash;&mdash;是的，即使不标也没关系，不过是隐藏了动画的信息难为使用者而已。（本ZWModelMD3类是根据这些字眼来判断动画归属上半身还是下半身模型的，所以不标则很麻烦。）还好MD系列模型所属的ID公司不是那么小家子的，毕竟连模型格式都那么公开了。MD3模型，即使那么不方便，也算是标记了一个小时代了吧。</p><p><a target="_self" href="http://www.zwqxin.com/archives/opengl/model-md3-format-import-animation.html"><img alt="MD3模型的格式、导入与骨骼概念动画" src="https://lh6.googleusercontent.com/_lYWT-2PnV0s/TXsPAT5t2oI/AAAAAAAADSg/8vuZAiv4W0k/20110224Snap1.jpg" /></a></p><p>说它不方便，首先当然是一个模型就包含那么多个文件：最基本的3个.md3和3个.skin、1个.animation还有纹理（与MD2不同，不再是一个模型一个纹理那样简洁的了），有时候还附加一个或2个.md3的武器模型和对应的材质文件(用.shader文件)。所以标准的做法是把它们集合到一个以模型名字为名字的文件夹中。这里给我的模型管理类引入了路径问题，已经勉强解决了我就不在此提了。</p><p>理应MD3的载入类ZWModelMD3与ZModelMD2很相似，但是事实完全8是这样的。我还是得几乎重新写载入部分的代码。其中一个理由很容易理解，存储格式变化颇大（后面慢慢道来）；还有一个理由则是现在一个模型要包含三个子部分模型和一个武器模型的集合（可以为0），也就是很多东西都要至少三份了。当然导入上就只是加个循环的简单问题，但是识别文件和连接模型也得花点心思了。</p><div class="HighLighter" contenteditable="false"><div class="dp-highlighter" contenteditable="false"><div class="bar">&nbsp;</div><ol class="dp-c">    <li class="alt"><span><span class="comment">//寻找该文件上层文件夹下的md3后缀文件</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nPartType&nbsp;=&nbsp;0;</span></span></li>    <li class="alt"><span>WIN32_FIND_DATA&nbsp;FindData;</span></li>    <li>&nbsp;</li>    <li class="alt"><span>memset(szPathFileName,&nbsp;0,&nbsp;<span class="keyword">sizeof</span><span>(szPathFileName));</span></span></li>    <li><span>wcscat_s(szPathFileName,&nbsp;<span class="keyword">sizeof</span><span>(szPathFileName)&nbsp;/&nbsp;</span><span class="keyword">sizeof</span><span>(wchar_t),&nbsp;szResDirectory);</span></span></li>    <li class="alt"><span>wcscat_s(szPathFileName,&nbsp;<span class="keyword">sizeof</span><span>(szPathFileName)&nbsp;/&nbsp;</span><span class="keyword">sizeof</span><span>(wchar_t),&nbsp;L</span><span class="string">&quot;*.md3&quot;</span><span>);</span></span></li>    <li>&nbsp;</li>    <li class="alt"><span>HANDLE&nbsp;hFindHandle&nbsp;=&nbsp;::FindFirstFile(szPathFileName,&nbsp;&amp;FindData);</span></li>    <li>&nbsp;</li>    <li class="alt"><span><span class="keyword">if</span><span>(INVALID_HANDLE_VALUE&nbsp;!=&nbsp;hFindHandle)</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">do</span><span>&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nPartType&nbsp;=&nbsp;-1;</span></li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_wcslwr_s(FindData.cFileName,&nbsp;<span class="keyword">sizeof</span><span>(FindData.cFileName)&nbsp;/&nbsp;</span><span class="keyword">sizeof</span><span>(wchar_t));</span></span></li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(wcsstr(FindData.cFileName,&nbsp;L</span><span class="string">&quot;head&quot;</span><span>))</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nPartType&nbsp;=&nbsp;MD3_MAINPART_HEAD;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">else</span><span>&nbsp;</span><span class="keyword">if</span><span>(wcsstr(FindData.cFileName,&nbsp;L</span><span class="string">&quot;upper&quot;</span><span>))</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nPartType&nbsp;=&nbsp;MD3_MAINPART_UPPER;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">else</span><span>&nbsp;</span><span class="keyword">if</span><span>(wcsstr(FindData.cFileName,&nbsp;L</span><span class="string">&quot;lower&quot;</span><span>))</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nPartType&nbsp;=&nbsp;MD3_MAINPART_LOWER;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(nPartType&nbsp;&gt;=&nbsp;0&nbsp;&amp;&amp;&nbsp;nPartType&nbsp;&lt;&nbsp;MD3_MAINPART_COUNT)</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memset(szPathFileName,&nbsp;0,&nbsp;<span class="keyword">sizeof</span><span>(szPathFileName));</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wcscat_s(szPathFileName,&nbsp;<span class="keyword">sizeof</span><span>(szPathFileName)&nbsp;/&nbsp;</span><span class="keyword">sizeof</span><span>(wchar_t),&nbsp;szResDirectory);</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wcscat_s(szPathFileName,&nbsp;<span class="keyword">sizeof</span><span>(szPathFileName)&nbsp;/&nbsp;</span><span class="keyword">sizeof</span><span>(wchar_t),&nbsp;FindData.cFileName);</span></span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(0&nbsp;==&nbsp;_wfopen_s(&amp;m_FilePointer,&nbsp;szPathFileName,&nbsp;L</span><span class="string">&quot;rb&quot;</span><span>))</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(!ImportSubModel(&amp;m_ModelMainMD3[nPartType],&nbsp;szPathFileName,&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(MD3_MAINPART_UPPER&nbsp;==&nbsp;nPartType&nbsp;||&nbsp;MD3_MAINPART_LOWER&nbsp;==&nbsp;nPartType),&nbsp;usage))</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;</span><span class="keyword">false</span><span>;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fclose(m_FilePointer);</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_FilePointer&nbsp;=&nbsp;NULL;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">while</span><span>&nbsp;(::FindNextFile(hFindHandle,&nbsp;&amp;FindData));</span></span></li>    <li class="alt"><span>}</span></li></ol></div><div class="c#" contenteditable="false" style="display: none"><pre>	//寻找该文件上层文件夹下的md3后缀文件    int nPartType = 0;	WIN32_FIND_DATA FindData;	memset(szPathFileName, 0, sizeof(szPathFileName));	wcscat_s(szPathFileName, sizeof(szPathFileName) / sizeof(wchar_t), szResDirectory);	wcscat_s(szPathFileName, sizeof(szPathFileName) / sizeof(wchar_t), L&quot;*.md3&quot;);	HANDLE hFindHandle = ::FindFirstFile(szPathFileName, &amp;FindData);	if(INVALID_HANDLE_VALUE != hFindHandle)	{		do 		{			nPartType = -1;			_wcslwr_s(FindData.cFileName, sizeof(FindData.cFileName) / sizeof(wchar_t));			if(wcsstr(FindData.cFileName, L&quot;head&quot;))			{				nPartType = MD3_MAINPART_HEAD;			}			else if(wcsstr(FindData.cFileName, L&quot;upper&quot;))			{				nPartType = MD3_MAINPART_UPPER;			}			else if(wcsstr(FindData.cFileName, L&quot;lower&quot;))			{				nPartType = MD3_MAINPART_LOWER;			}			if(nPartType &gt;= 0 &amp;&amp; nPartType &lt; MD3_MAINPART_COUNT)			{				memset(szPathFileName, 0, sizeof(szPathFileName));				wcscat_s(szPathFileName, sizeof(szPathFileName) / sizeof(wchar_t), szResDirectory);				wcscat_s(szPathFileName, sizeof(szPathFileName) / sizeof(wchar_t), FindData.cFileName);				if(0 == _wfopen_s(&amp;m_FilePointer, szPathFileName, L&quot;rb&quot;))				{					if(!ImportSubModel(&amp;m_ModelMainMD3[nPartType], szPathFileName, 						(MD3_MAINPART_UPPER == nPartType || MD3_MAINPART_LOWER == nPartType), usage))					{						return false;					}					fclose(m_FilePointer);					m_FilePointer = NULL;				}			}		} while (::FindNextFile(hFindHandle, &amp;FindData));	}</pre></div><div contenteditable="false"><link href="http://www.zwqxin.com/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>可以的话我都不想这样做，加了这么多平台相关的代码不说，实在很麻烦（skin文件也是类似的）：轮询文件夹下的文件(<span class="Apple-style-span" style="font-size: 12px; line-height: 14px; font-family: Consolas, 'Courier New', Courier, mono, serif">m_ModelMainMD3[MD3_MAINPART_COUNT]</span>是那三个SubModel)，找文件名的关键字（是的，如果你的头部模型文件里没有head这四个字符或者文件夹里有两个以上包含head字符的.md3文件，会把问题弄得很复杂）。ImportSubModel函数与以往一样，导入文件后初始化帧信息和生成VBO。还是从MD3模型格式开始吧：</p><div class="HighLighter" contenteditable="false"><div class="dp-highlighter" contenteditable="false"><div class="bar">&nbsp;</div><ol class="dp-c">    <li class="alt"><span><span>typedef&nbsp;</span><span class="keyword">struct</span><span>&nbsp;tagMd3Header</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">char</span><span>&nbsp;&nbsp;szMagic[4];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;magic&nbsp;string&nbsp;used&nbsp;to&nbsp;identify&nbsp;the&nbsp;file.</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nVersion;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;file&nbsp;version&nbsp;number&nbsp;(must&nbsp;be&nbsp;15).</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">char</span><span>&nbsp;&nbsp;szFileName[MNAME];&nbsp;</span><span class="comment">//&nbsp;The&nbsp;file&nbsp;name.</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nFlag;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;retained&nbsp;flag.</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nNumFrames;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;number&nbsp;of&nbsp;animated&nbsp;bones'&nbsp;frames.</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nNumTags;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;number&nbsp;of&nbsp;tags.</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nNumMeshes;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;number&nbsp;of&nbsp;meshes&nbsp;associated&nbsp;with&nbsp;the&nbsp;model.</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nNumMaxSkin;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;max&nbsp;number&nbsp;of&nbsp;skins.</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nOffsetFrames;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;offset&nbsp;in&nbsp;the&nbsp;file&nbsp;for&nbsp;the&nbsp;frames&nbsp;data.</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nOffsetTags;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;offset&nbsp;in&nbsp;the&nbsp;file&nbsp;for&nbsp;the&nbsp;tags&nbsp;data.</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nOffsetMeshes;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;offset&nbsp;in&nbsp;the&nbsp;file&nbsp;for&nbsp;the&nbsp;meshes&nbsp;data.</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nFileSize;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;size&nbsp;of&nbsp;the&nbsp;whole&nbsp;file.</span></span></li>    <li class="alt"><span>}Md3Header;</span></li>    <li>&nbsp;</li>    <li class="alt"><span><span class="comment">//导入结构定义</span></span></li>    <li><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tagBoneFrameInfo</span></span></li>    <li class="alt"><span>{</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;float32&nbsp;fMinPos[3];</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;float32&nbsp;fMaxPos[3];</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;float32&nbsp;fPos[3];</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;float32&nbsp;fScale;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">char</span><span>&nbsp;&nbsp;&nbsp;&nbsp;szCreator[16];</span></span></li>    <li class="alt"><span>}BoneFrameInfo;</span></li>    <li>&nbsp;</li>    <li class="alt"><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tagTagInfo</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">char</span><span>&nbsp;&nbsp;szName[MNAME];</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;float32&nbsp;fTranslation[3];</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;float32&nbsp;fRotation[3][3];</span></li>    <li><span>}TagInfo;</span></li>    <li class="alt">&nbsp;</li>    <li><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tagMeshHeaderInfo</span></span></li>    <li class="alt"><span>{</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">char</span><span>&nbsp;&nbsp;szMeshID[4];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;mesh&nbsp;ID.</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">char</span><span>&nbsp;&nbsp;szMeshName[MNAME];&nbsp;</span><span class="comment">//&nbsp;The&nbsp;mesh&nbsp;name.</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nFlag;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;retained&nbsp;flag.</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nNumMeshFrames;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;number&nbsp;of&nbsp;frames&nbsp;of&nbsp;every&nbsp;mesh(should&nbsp;equal&nbsp;to&nbsp;header's&nbsp;nNumFrames).</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nNumSkins;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;number&nbsp;of&nbsp;mesh&nbsp;skins.(should&nbsp;equal&nbsp;to&nbsp;1&nbsp;?)</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nNumVertices;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;number&nbsp;of&nbsp;mesh&nbsp;vertices.</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nNumFaces;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;number&nbsp;of&nbsp;mesh&nbsp;faces.</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nOffsetFaces;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;offset&nbsp;from&nbsp;the&nbsp;nOffsetMeshes&nbsp;defined&nbsp;by&nbsp;header,&nbsp;for&nbsp;the&nbsp;faces&nbsp;data.</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nOffsetSkins;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;offset&nbsp;from&nbsp;the&nbsp;nOffsetMeshes&nbsp;defined&nbsp;by&nbsp;header,&nbsp;for&nbsp;the&nbsp;skins&nbsp;data.</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nOffsetTexcoord;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;offset&nbsp;from&nbsp;the&nbsp;nOffsetMeshes&nbsp;defined&nbsp;by&nbsp;header,&nbsp;for&nbsp;the&nbsp;texcoords&nbsp;data.</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nOffsetVertices;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;offset&nbsp;from&nbsp;the&nbsp;nOffsetMeshes&nbsp;defined&nbsp;by&nbsp;header,&nbsp;for&nbsp;the&nbsp;vertices&nbsp;data.</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nMeshInfoSize;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;The&nbsp;size&nbsp;of&nbsp;the&nbsp;whole&nbsp;mesh&nbsp;info&nbsp;data.</span></span></li>    <li><span>}MeshHeaderInfo;</span></li>    <li class="alt">&nbsp;</li>    <li><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tagFaceInfo</span></span></li>    <li class="alt"><span>{</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nVertIndex[3];</span></li>    <li class="alt"><span>}FaceInfo;</span></li>    <li>&nbsp;</li>    <li class="alt"><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tagSkinInfo</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">char</span><span>&nbsp;&nbsp;szName[MNAME];</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nIndex;</span></li>    <li class="alt"><span>}SkinInfo;</span></li>    <li>&nbsp;</li>    <li class="alt"><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tagTexcoordInfo</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;float32&nbsp;u;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;float32&nbsp;v;</span></li>    <li class="alt"><span>}TexcoordInfo;</span></li>    <li>&nbsp;</li>    <li class="alt"><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tagFrameVertInfo</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;int16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vertSrc[3];</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">char</span><span>&nbsp;normalInfo[2];&nbsp;</span></span></li>    <li class="alt"><span>}FrameVertInfo;</span></li>    <li>&nbsp;</li>    <li class="alt"><span><span class="comment">//导入结构定义结束</span></span></li></ol></div><div class="c#" contenteditable="false" style="display: none"><pre>	typedef struct tagMd3Header	{		char  szMagic[4];        // The magic string used to identify the file.		int32 nVersion;          // The file version number (must be 15).		char  szFileName[MNAME]; // The file name.		int32 nFlag;             // The retained flag.		int32 nNumFrames;        // The number of animated bones' frames.		int32 nNumTags;          // The number of tags.		int32 nNumMeshes;        // The number of meshes associated with the model.		int32 nNumMaxSkin;       // The max number of skins.		int32 nOffsetFrames;     // The offset in the file for the frames data.		int32 nOffsetTags;       // The offset in the file for the tags data.		int32 nOffsetMeshes;     // The offset in the file for the meshes data.		int32 nFileSize;         // The size of the whole file.	}Md3Header;	//导入结构定义	typedef struct tagBoneFrameInfo	{		float32 fMinPos[3];		float32 fMaxPos[3];		float32 fPos[3];		float32 fScale;		char    szCreator[16];	}BoneFrameInfo;	typedef struct tagTagInfo	{		char  szName[MNAME];		float32 fTranslation[3];		float32 fRotation[3][3];	}TagInfo;	typedef struct tagMeshHeaderInfo	{		char  szMeshID[4];       // The mesh ID.		char  szMeshName[MNAME]; // The mesh name.		int32 nFlag;             // The retained flag.		int32 nNumMeshFrames;    // The number of frames of every mesh(should equal to header's nNumFrames).		int32 nNumSkins;         // The number of mesh skins.(should equal to 1 ?)		int32 nNumVertices;      // The number of mesh vertices.		int32 nNumFaces;         // The number of mesh faces.		int32 nOffsetFaces;      // The offset from the nOffsetMeshes defined by header, for the faces data.		int32 nOffsetSkins;      // The offset from the nOffsetMeshes defined by header, for the skins data.		int32 nOffsetTexcoord;   // The offset from the nOffsetMeshes defined by header, for the texcoords data.		int32 nOffsetVertices;   // The offset from the nOffsetMeshes defined by header, for the vertices data.		int32 nMeshInfoSize;     // The size of the whole mesh info data.	}MeshHeaderInfo;	typedef struct tagFaceInfo	{		int32 nVertIndex[3];	}FaceInfo;	typedef struct tagSkinInfo	{		char  szName[MNAME];		int32 nIndex;	}SkinInfo;	typedef struct tagTexcoordInfo	{		float32 u;		float32 v;	}TexcoordInfo;	typedef struct tagFrameVertInfo	{		int16         vertSrc[3];		unsigned char normalInfo[2]; 	}FrameVertInfo;	//导入结构定义结束</pre></div><div contenteditable="false"><link href="http://www.zwqxin.com/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>与<a target="_blank" href="http://www.zwqxin.com/archives/opengl/md2-model-format-import-animation.html">MD2格式模型</a>一样，一切从文件头<span class="Apple-style-span" style="font-size: 12px; line-height: 14px; font-family: Consolas, 'Courier New', Courier, mono, serif">Md3Header</span>开始，每个MD3文件开头的sizeof(Md3Header)大小的都是一个这样的文件头，注释部分我参考了网上注解，应该没错吧（如果有错请指出）。与MD2的不同貌似信息少了不少&mdash;&mdash;别担心，后面还有个<span class="Apple-style-span" style="font-size: 12px; line-height: 14px; font-family: Consolas, 'Courier New', Courier, mono, serif">MeshHeaderInfo</span>呢。Md3Header除了用于标识的MagicWord（IDP3），version（15），没啥用的maxSkin外，最主要的就是三个东西：boneFrame、tag、mesh。在&ldquo;导入结构定义&rdquo;部分的头三个，就是这部分信息的数据结构，<span class="Apple-style-span" style="font-size: 12px; line-height: 14px; font-family: Consolas, 'Courier New', Courier, mono, serif">BoneFrameInfo</span>基本可以不理会，除非你想把骨骼控制点（建模软件里弄骨骼的那些）也渲染出来。<span class="Apple-style-span" style="font-size: 12px; line-height: 14px; font-family: Consolas, 'Courier New', Courier, mono, serif">TagInfo</span>就是骨骼信息的核心了，每个tag作为一个连接标记，决定了所连接的子模型的位置和运动形式&mdash;&mdash;一个变换矩阵。而<span class="Apple-style-span" style="font-size: 12px; line-height: 14px; font-family: Consolas, 'Courier New', Courier, mono, serif">MeshHeaderInfo</span>就是我们模型的Base数据了，一个模型由一个或多个网格对象（Mesh）组成，每个网格对象对应单一纹理和VBO信息组，这个与3DS、OBJ类似（参见[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/idexed-vbo-for-model-3ds-rendering.html">用Indexed-VBO渲染3DS模型</a>] [<a target="_blank" href="http://www.zwqxin.com/archives/opengl/obj-model-format-import-and-render-2.html">OBJ模型文件的结构、导入与渲染Ⅱ</a>]）。每个Mesh段也是开头一个信息头，指涉其所在区域内数据的组织：顶点位置、顶点法线、顶点纹理坐标、顶点索引（Skin信息不用理会，我们使用的是用mesh的名字标识去检索.skin文件内容）。<a name="qwyuu"></a>顶点信息（<span class="Apple-style-span" style="font-size: 12px; line-height: 14px; font-family: Consolas, 'Courier New', Courier, mono, serif">FrameVertInfo</span>）有点怪异，接下来会说说。如果你这时惊讶于为什么还是每帧都一堆顶点属性（这不还是逐帧动画么），你还没弄清楚&ldquo;骨骼概念&rdquo;动画与真正的骨骼动画的差距。</p><p>再来看看我自定义的保存模型信息的数据结构（再提醒一次，如果你只打算用传统的glVertex打点来绘制而不用VBO，你大可不必这么麻烦地转换，从上述读入的文件&quot;raw信息&quot;已经基本足够提供个给你绘制了，网上也有很多这样的例子吧）：</p><div class="HighLighter" contenteditable="false"><div class="dp-highlighter" contenteditable="false"><div class="bar">&nbsp;</div><ol class="dp-c">    <li class="alt"><span><span class="comment">//&nbsp;Tag信息</span></span></li>    <li><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tag3DTagFrameInfo</span></span></li>    <li class="alt"><span>{</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;Vector3&nbsp;fTranslation;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">float</span><span>&nbsp;&nbsp;&nbsp;fRotation[3][3];</span></span></li>    <li><span>}t3DTagFrameInfo;</span></li>    <li class="alt">&nbsp;</li>    <li><span><span class="comment">//&nbsp;TagLink挂接模型信息</span></span></li>    <li class="alt"><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tag3DTagLink</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">char</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szTagName[MNAME];&nbsp;</span><span class="comment">//&nbsp;Tag名称</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;t3DTagFrameInfo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pTagFrameInfos;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;该Tag下各帧的矩阵信息</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;std::vector&lt;<span class="keyword">void</span><span>&nbsp;*&gt;&nbsp;&nbsp;&nbsp;LinkingModels;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;挂接模型</span></span></li>    <li><span>}t3DTagLink;</span></li>    <li class="alt">&nbsp;</li>    <li><span><span class="comment">//&nbsp;动画信息</span></span></li>    <li class="alt"><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tag3DAnimation&nbsp;</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">int</span><span>&nbsp;nStartFrame;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">int</span><span>&nbsp;nEndFrame;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">int</span><span>&nbsp;nFramesPerSec;</span></span></li>    <li><span>}t3DAnim;</span></li>    <li class="alt">&nbsp;</li>    <li><span><span class="comment">//&nbsp;模型的帧动画信息</span></span></li>    <li class="alt"><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tag3DFrameInfo</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nCurFrame;&nbsp;&nbsp;</span><span class="comment">//&nbsp;当前帧</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nNextFrame;&nbsp;</span><span class="comment">//&nbsp;下一帧</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nStartFrame;</span><span class="comment">//&nbsp;开始帧</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nEndFrame;&nbsp;&nbsp;</span><span class="comment">//&nbsp;结束帧</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">float</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fSecPerKeyFrame;&nbsp;&nbsp;</span><span class="comment">//&nbsp;关健帧间隔</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">float</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fCurBlendValue;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;当前融合变量</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DStartPlot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;开始时点</span></span></li>    <li><span>}t3DFrameInfo;</span></li>    <li class="alt">&nbsp;</li>    <li><span><span class="comment">//&nbsp;网格对象信息</span></span></li>    <li class="alt"><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tag3DObject</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">char</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szName[MNAME];</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;GLuint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nDiffuseMap;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;Vector3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pPosVerts;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;Vector3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pNormals;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;TexCoord&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pTexcoords;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">short</span><span>&nbsp;*pIndexes;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;nNumIndexes;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;nNumVerts;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">int</span><span>&nbsp;&nbsp;&nbsp;&nbsp;nNumPosVBOs;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;GLuint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pPosVBO;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;GLuint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pNormVBO;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;GLuint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nTexcoordVBO;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;GLuint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nIndexVBO;</span></li>    <li><span>}t3DObject;</span></li>    <li class="alt">&nbsp;</li>    <li><span><span class="comment">//&nbsp;模型信息结构体</span></span></li>    <li class="alt"><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tag3DModel&nbsp;</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">bool</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bVisable;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;是否渲染</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">bool</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bIsTextured;</span><span class="comment">//&nbsp;是否使用纹理</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;Md3Header&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MD3Header;&nbsp;&nbsp;<span class="comment">//&nbsp;MD3头文件</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;t3DObject&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pObjects;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;网格对象</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;t3DTagLink&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pLinkModels;<span class="comment">//&nbsp;Tag连接的模型</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;std::vector&lt;t3DAnim&gt;&nbsp;&nbsp;&nbsp;&nbsp;Animations;&nbsp;<span class="comment">//&nbsp;动画列表</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;t3DFrameInfo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pFrameInfo;&nbsp;<span class="comment">//&nbsp;帧信息(只对Upper和Loewer)</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;GLuint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TexObjDiffuseMap;&nbsp;<span class="comment">//&nbsp;纹理所在的纹理对象</span></span></li>    <li class="alt"><span>}t3DModel;</span></li></ol></div><div class="c#" contenteditable="false" style="display: none"><pre>	// Tag信息	typedef struct tag3DTagFrameInfo	{		Vector3 fTranslation;		float   fRotation[3][3];	}t3DTagFrameInfo;	// TagLink挂接模型信息	typedef struct tag3DTagLink	{		char                  szTagName[MNAME]; // Tag名称		t3DTagFrameInfo      *pTagFrameInfos;   // 该Tag下各帧的矩阵信息		std::vector&lt;void *&gt;   LinkingModels;    // 挂接模型	}t3DTagLink;	// 动画信息	typedef struct tag3DAnimation 	{		unsigned int nStartFrame;		unsigned int nEndFrame;		unsigned int nFramesPerSec;	}t3DAnim;	// 模型的帧动画信息	typedef struct tag3DFrameInfo	{		unsigned int            nCurFrame;  // 当前帧		unsigned int            nNextFrame; // 下一帧		unsigned int            nStartFrame;// 开始帧		unsigned int            nEndFrame;  // 结束帧		float                   fSecPerKeyFrame;  // 关健帧间隔		float                   fCurBlendValue;   // 当前融合变量	    DWORD                   DStartPlot;       // 开始时点	}t3DFrameInfo;	// 网格对象信息	typedef struct tag3DObject	{		char            szName[MNAME];		GLuint          nDiffuseMap;		Vector3        *pPosVerts;		Vector3        *pNormals;		TexCoord       *pTexcoords;		unsigned short *pIndexes;		unsigned int    nNumIndexes;		unsigned int    nNumVerts;		unsigned int    nNumPosVBOs;		GLuint         *pPosVBO;		GLuint         *pNormVBO;		GLuint          nTexcoordVBO;		GLuint          nIndexVBO;	}t3DObject;	// 模型信息结构体	typedef struct tag3DModel 	{		bool                    bVisable;   // 是否渲染		bool                    bIsTextured;// 是否使用纹理		Md3Header               MD3Header;  // MD3头文件		t3DObject              *pObjects;   // 网格对象		t3DTagLink             *pLinkModels;// Tag连接的模型		std::vector&lt;t3DAnim&gt;    Animations; // 动画列表		t3DFrameInfo           *pFrameInfo; // 帧信息(只对Upper和Loewer)		GLuint                  TexObjDiffuseMap; // 纹理所在的纹理对象	}t3DModel;</pre></div><div contenteditable="false"><link href="http://www.zwqxin.com/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>网格对象t3DObject这个我就不多解释了，结合[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/obj-model-format-import-and-render-1.html">OBJ模型文件的结构、导入与渲染Ⅰ</a>]中类似的数据定义，或者看名字都知道了。<span class="Apple-style-span" style="font-size: 12px; line-height: 14px; font-family: Consolas, 'Courier New', Courier, mono, serif">t3DModel</span>这里除了保存一堆网格对象外，还有一个帧信息<span class="Apple-style-span" style="font-size: 12px; line-height: 14px; font-family: Consolas, 'Courier New', Courier, mono, serif">t3DFrameInfo</span>，只有上身模型和下身模型才有必要new一个出来：因为它就是用于动画的信息啊（结合一个模型所具有的动画<span class="Apple-style-span" style="font-size: 12px; line-height: 14px; font-family: Consolas, 'Courier New', Courier, mono, serif">t3DAnim</span>列表[由.animation文件导入]）。然后比较新颖的就是这个<span class="Apple-style-span" style="font-size: 12px; line-height: 14px; font-family: Consolas, 'Courier New', Courier, mono, serif">t3DTagLink</span>结构了吧，它就是保存上述的tag信息了，它保存了tag名字、这个tag在每一动画帧下的用于子模型的变换矩阵信息（位置和旋转），还保存着连接到这个tag的子模型列表（<span class="Apple-style-span" style="font-size: 12px; line-height: 14px; font-family: Consolas, 'Courier New', Courier, mono, serif">LinkingModels</span>）。</p><p>数据的转换应该来说关键只是这些数据结构的定义，实际的转换代码也就那么些赋值转换之类了。这里特别注意的是FrameVertInfo（<a href="#qwyuu">上面提及过</a>），3个short和2个字节可以表示一个顶点位置和一个法线？ID公司的人就是那么有点犀利&mdash;&mdash;把short除以64来得到位置信息，把两个BYTE归一成(0,1)再乘以360度的弧度来标识球体的经度维度&mdash;&mdash;原点指向该经纬位置的向量，就是我们需要的法线啦！绝！这个我是从GPU GEMS1某个例子里导入MD3模型的代码中发现奇怪的，网上查到解析信息才知道的，不然我可能就忽略它自己去计算粗糙的法线了（毕竟MD2就只能这样）。以下清单的解压缩部分是重点哈~~</p><div class="HighLighter" contenteditable="false"><div class="dp-highlighter" contenteditable="false"><div class="bar">&nbsp;</div><ol class="dp-c">    <li class="alt"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;</span><span class="keyword">struct</span><span>&nbsp;tagFrameVertInfo</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vertSrc[3];</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">char</span><span>&nbsp;normalInfo[2];&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}FrameVertInfo;</span></li>    <li>&nbsp;</li>    <li class="alt"><span><span class="comment">//&nbsp;&nbsp;读入文件中的对象到模型中</span></span></li>    <li><span><span class="keyword">void</span><span>&nbsp;ZWModelMD3::ProcessFileInfo(t3DModel&nbsp;*pModel)</span></span></li>    <li class="alt"><span>{</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//Load&nbsp;Tags&nbsp;Data</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.....</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//Load&nbsp;Meshes&nbsp;Data</span></span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;pModel-&gt;pObjects&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;t3DObject[pModel-&gt;MD3Header.nNumMeshes];</span></span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;MeshHeaderInfo&nbsp;meshHeaderInfo&nbsp;=&nbsp;{0};</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">float</span><span>&nbsp;dLongtitude&nbsp;=&nbsp;0,&nbsp;dLattitude&nbsp;=&nbsp;0;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;int32&nbsp;nCurMeshOffset&nbsp;=&nbsp;pModel-&gt;MD3Header.nOffsetMeshes;</span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>(</span><span class="keyword">int</span><span>&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;pModel-&gt;MD3Header.nNumMeshes;&nbsp;++i)</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fseek(m_FilePointer,&nbsp;nCurMeshOffset,&nbsp;SEEK_SET);</span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fread_s(&amp;meshHeaderInfo,&nbsp;<span class="keyword">sizeof</span><span>(MeshHeaderInfo),&nbsp;</span><span class="keyword">sizeof</span><span>(unsigned&nbsp;</span><span class="keyword">char</span><span>),&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">sizeof</span><span>(MeshHeaderInfo)&nbsp;/&nbsp;</span><span class="keyword">sizeof</span><span>(unsigned&nbsp;</span><span class="keyword">char</span><span>),&nbsp;m_FilePointer);</span></span></li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nTotalVerts&nbsp;=&nbsp;meshHeaderInfo.nNumVertices&nbsp;*&nbsp;pModel-&gt;MD3Header.nNumFrames</span></span></li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FrameVertInfo&nbsp;&nbsp;*pFrameVertInfo&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;FrameVertInfo[nTotalVerts];</span></span></li>    <li><span>&nbsp;&nbsp;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pModel-&gt;pObjects[i].pPosVerts&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;Vector3[nTotalVerts];</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pModel-&gt;pObjects[i].pNormals&nbsp;&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;Vector3[nTotalVerts];</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>(</span><span class="keyword">int</span><span>&nbsp;j&nbsp;=&nbsp;0;&nbsp;j&nbsp;&lt;&nbsp;nTotalVerts;&nbsp;++j)</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pModel-&gt;pObjects[i].pPosVerts[j].<span class="keyword">set</span><span>(pFrameVertInfo[j].vertSrc[0]&nbsp;/&nbsp;64.0f,</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pFrameVertInfo[j].vertSrc[1]&nbsp;/&nbsp;64.0f,</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pFrameVertInfo[j].vertSrc[2]&nbsp;/&nbsp;64.0f);</span></li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dLongtitude&nbsp;=&nbsp;pFrameVertInfo[j].normalInfo[0]&nbsp;*&nbsp;2.0f&nbsp;*&nbsp;MD3_PI&nbsp;/&nbsp;255;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dLattitude&nbsp;&nbsp;=&nbsp;pFrameVertInfo[j].normalInfo[1]&nbsp;*&nbsp;2.0f&nbsp;*&nbsp;MD3_PI&nbsp;/&nbsp;255;</span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pModel-&gt;pObjects[i].pNormals[j].<span class="keyword">set</span><span>(cosf(dLattitude)&nbsp;*&nbsp;sinf(dLongtitude),&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cosf(dLongtitude),</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-sinf(dLattitude)&nbsp;*&nbsp;sinf(dLongtitude));</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;[]pFrameVertInfo;</span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//...............</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li><span>};</span></li></ol></div><div class="c#" contenteditable="false" style="display: none"><pre>	typedef struct tagFrameVertInfo	{		int16         vertSrc[3];		unsigned char normalInfo[2]; 	}FrameVertInfo;//  读入文件中的对象到模型中void ZWModelMD3::ProcessFileInfo(t3DModel *pModel){	//Load Tags Data       .....	//Load Meshes Data	pModel-&gt;pObjects = new t3DObject[pModel-&gt;MD3Header.nNumMeshes];	MeshHeaderInfo meshHeaderInfo = {0};	float dLongtitude = 0, dLattitude = 0;	int32 nCurMeshOffset = pModel-&gt;MD3Header.nOffsetMeshes;	for(int i = 0; i &lt; pModel-&gt;MD3Header.nNumMeshes; ++i)	{		fseek(m_FilePointer, nCurMeshOffset, SEEK_SET);		fread_s(&amp;meshHeaderInfo, sizeof(MeshHeaderInfo), sizeof(unsigned char), 			sizeof(MeshHeaderInfo) / sizeof(unsigned char), m_FilePointer);		int nTotalVerts = meshHeaderInfo.nNumVertices * pModel-&gt;MD3Header.nNumFrames		FrameVertInfo  *pFrameVertInfo = new FrameVertInfo[nTotalVerts];  		pModel-&gt;pObjects[i].pPosVerts = new Vector3[nTotalVerts];		pModel-&gt;pObjects[i].pNormals  = new Vector3[nTotalVerts];		for(int j = 0; j &lt; nTotalVerts; ++j)		{			pModel-&gt;pObjects[i].pPosVerts[j].set(pFrameVertInfo[j].vertSrc[0] / 64.0f,												 pFrameVertInfo[j].vertSrc[1] / 64.0f,												 pFrameVertInfo[j].vertSrc[2] / 64.0f);			dLongtitude = pFrameVertInfo[j].normalInfo[0] * 2.0f * MD3_PI / 255;			dLattitude  = pFrameVertInfo[j].normalInfo[1] * 2.0f * MD3_PI / 255;			pModel-&gt;pObjects[i].pNormals[j].set(cosf(dLattitude) * sinf(dLongtitude), 				                                cosf(dLongtitude),												-sinf(dLattitude) * sinf(dLongtitude));		}		delete []pFrameVertInfo;              //...............        }};</pre></div><div contenteditable="false"><link href="http://www.zwqxin.com/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>现在再来看看怎么连接模型吧（MD3的骨骼概念核心）：</p><div class="HighLighter" contenteditable="false"><div class="dp-highlighter" contenteditable="false"><div class="bar">&nbsp;</div><ol class="dp-c">    <li class="alt"><span><span class="keyword">void</span><span>&nbsp;ZWModelMD3::LinkModels(t3DModel&nbsp;*pParentModel,&nbsp;t3DModel&nbsp;*pChildModel,&nbsp;</span><span class="keyword">char</span><span>&nbsp;*szTagName)</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>(</span><span class="keyword">int</span><span>&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;pParentModel-&gt;MD3Header.nNumTags;&nbsp;++i)</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(0&nbsp;==&nbsp;strcmp(pParentModel-&gt;pLinkModels[i].szTagName,&nbsp;szTagName))</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pParentModel-&gt;pLinkModels[i].LinkingModels.push_back(pChildModel);</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li><span>}</span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;LinkModels(&amp;m_ModelMainMD3[MD3_MAINPART_LOWER],&nbsp;&amp;m_ModelMainMD3[MD3_MAINPART_UPPER],&nbsp;<span class="string">&quot;tag_torso&quot;</span><span>);</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;LinkModels(&amp;m_ModelMainMD3[MD3_MAINPART_UPPER],&nbsp;&amp;m_ModelMainMD3[MD3_MAINPART_HEAD],&nbsp;&nbsp;<span class="string">&quot;tag_head&quot;</span><span>);</span></span></li></ol></div><div class="c#" contenteditable="false" style="display: none"><pre>void ZWModelMD3::LinkModels(t3DModel *pParentModel, t3DModel *pChildModel, char *szTagName){	for(int i = 0; i &lt; pParentModel-&gt;MD3Header.nNumTags; ++i)	{		if(0 == strcmp(pParentModel-&gt;pLinkModels[i].szTagName, szTagName))		{			pParentModel-&gt;pLinkModels[i].LinkingModels.push_back(pChildModel);		}	}}	LinkModels(&amp;m_ModelMainMD3[MD3_MAINPART_LOWER], &amp;m_ModelMainMD3[MD3_MAINPART_UPPER], &quot;tag_torso&quot;);	LinkModels(&amp;m_ModelMainMD3[MD3_MAINPART_UPPER], &amp;m_ModelMainMD3[MD3_MAINPART_HEAD],  &quot;tag_head&quot;);</pre></div><div contenteditable="false"><link href="http://www.zwqxin.com/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>后面是ImportModel里的执行代码。其实我们只是在<span class="Apple-style-span" style="font-size: 12px; line-height: 14px; font-family: Consolas, 'Courier New', Courier, mono, serif">t3DTagLink</span>里保存了子模型的指针而已。下身模型的一个叫&ldquo;<span class="Apple-style-span" style="font-size: 12px; color: rgb(0,0,255); line-height: 14px; font-family: Consolas, 'Courier New', Courier, mono, serif">tag_torso</span>&rdquo;的Tag连接上身模型，上身模型的一个叫&ldquo;<span class="Apple-style-span" style="font-size: 12px; color: rgb(0,0,255); line-height: 14px; font-family: Consolas, 'Courier New', Courier, mono, serif">tag_head</span>&rdquo;的Tag连接头部模型。（顺带一提，上身模型的一个叫&ldquo;tag_weapon&rdquo;的Tag一般是用来连接武器模型的[如果有的话]。）我们渲染的时候，其实就是先渲染父模型，再渲染子模型，再渲染子模型的子模型这样下去（每个子模型渲染前都乘以对应连接tag的变换矩阵）&hellip;&hellip;因为是一种树型的调用模式，所以递归出场了（实在兴奋不起来）：</p><div class="HighLighter" contenteditable="false"><div class="dp-highlighter" contenteditable="false"><div class="bar">&nbsp;</div><ol class="dp-c">    <li class="alt"><span><span class="keyword">void</span><span>&nbsp;ZWModelMD3::DrawModelWithSubModel(t3DModel&nbsp;*pModel,&nbsp;</span><span class="keyword">bool</span><span>&nbsp;bShaderMode)</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;DrawSubModel(pModel,&nbsp;bShaderMode);</span></li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;ZWQuaternion&nbsp;qQuat,&nbsp;qNextQuat,&nbsp;qInterpolatedQuat;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;Vector3&nbsp;iterpPos;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;ZWMatrix16&nbsp;mtFin;</span></li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>(</span><span class="keyword">int</span><span>&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;pModel-&gt;MD3Header.nNumTags;&nbsp;++i)</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(pModel-&gt;pLinkModels[i].LinkingModels.size()&nbsp;&gt;&nbsp;0&nbsp;&amp;&amp;&nbsp;pModel-&gt;pFrameInfo)</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iterpPos&nbsp;=&nbsp;pModel-&gt;pLinkModels[i].pTagFrameInfos[pModel-&gt;pFrameInfo-&gt;nCurFrame].fTranslation;</span></li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iterpPos&nbsp;=&nbsp;iterpPos&nbsp;+&nbsp;(pModel-&gt;pLinkModels[i].pTagFrameInfos[pModel-&gt;pFrameInfo-&gt;nNextFrame].fTranslation</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;iterpPos)&nbsp;*&nbsp;pModel-&gt;pFrameInfo-&gt;fCurBlendValue;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;qQuat.SetFromMatrixRotationElements(&amp;pModel-&gt;pLinkModels[i].pTagFrameInfos[pModel-&gt;pFrameInfo-&gt;nCurFrame].fRotation[0][0]);</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;qNextQuat.SetFromMatrixRotationElements(&amp;pModel-&gt;pLinkModels[i].pTagFrameInfos[pModel-&gt;pFrameInfo-&gt;nNextFrame].fRotation[0][0]);</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;qInterpolatedQuat.SlerpFrom(qQuat,&nbsp;qNextQuat,&nbsp;pModel-&gt;pFrameInfo-&gt;fCurBlendValue);</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;qInterpolatedQuat.GenerateMatrix3X3(&amp;mtFin);</span></li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mtFin.SetTranslationPart(ZWVector4D(iterpPos.x,&nbsp;iterpPos.y,&nbsp;iterpPos.z,&nbsp;1.0f));</span></li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;glPushMatrix();</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;glMultMatrixf(mtFin.mt);</span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>(unsigned&nbsp;</span><span class="keyword">int</span><span>&nbsp;j&nbsp;=&nbsp;0;&nbsp;j&nbsp;&lt;&nbsp;pModel-&gt;pLinkModels[i].LinkingModels.size();&nbsp;++j)</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DrawModelWithSubModel((t3DModel*)pModel-&gt;pLinkModels[i].LinkingModels[j],&nbsp;bShaderMode);</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;glPopMatrix();</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li class="alt"><span>}</span></li>    <li>&nbsp;</li>    <li class="alt"><span><span class="comment">//渲染时调用</span></span></li>    <li><span>DrawModelWithSubModel(&amp;m_ModelMainMD3[MD3_MAINPART_LOWER],&nbsp;<span class="keyword">true</span><span>);</span></span></li></ol></div><div class="c#" contenteditable="false" style="display: none"><pre>void ZWModelMD3::DrawModelWithSubModel(t3DModel *pModel, bool bShaderMode){	DrawSubModel(pModel, bShaderMode);	ZWQuaternion qQuat, qNextQuat, qInterpolatedQuat;	Vector3 iterpPos;	ZWMatrix16 mtFin;	for(int i = 0; i &lt; pModel-&gt;MD3Header.nNumTags; ++i)	{		if(pModel-&gt;pLinkModels[i].LinkingModels.size() &gt; 0 &amp;&amp; pModel-&gt;pFrameInfo)		{			iterpPos = pModel-&gt;pLinkModels[i].pTagFrameInfos[pModel-&gt;pFrameInfo-&gt;nCurFrame].fTranslation;			iterpPos = iterpPos + (pModel-&gt;pLinkModels[i].pTagFrameInfos[pModel-&gt;pFrameInfo-&gt;nNextFrame].fTranslation			         - iterpPos) * pModel-&gt;pFrameInfo-&gt;fCurBlendValue;						qQuat.SetFromMatrixRotationElements(&amp;pModel-&gt;pLinkModels[i].pTagFrameInfos[pModel-&gt;pFrameInfo-&gt;nCurFrame].fRotation[0][0]);			qNextQuat.SetFromMatrixRotationElements(&amp;pModel-&gt;pLinkModels[i].pTagFrameInfos[pModel-&gt;pFrameInfo-&gt;nNextFrame].fRotation[0][0]);			qInterpolatedQuat.SlerpFrom(qQuat, qNextQuat, pModel-&gt;pFrameInfo-&gt;fCurBlendValue);			qInterpolatedQuat.GenerateMatrix3X3(&amp;mtFin);			mtFin.SetTranslationPart(ZWVector4D(iterpPos.x, iterpPos.y, iterpPos.z, 1.0f));			glPushMatrix();			glMultMatrixf(mtFin.mt);			for(unsigned int j = 0; j &lt; pModel-&gt;pLinkModels[i].LinkingModels.size(); ++j)			{				DrawModelWithSubModel((t3DModel*)pModel-&gt;pLinkModels[i].LinkingModels[j], bShaderMode);			}			glPopMatrix();		}	}}//渲染时调用DrawModelWithSubModel(&amp;m_ModelMainMD3[MD3_MAINPART_LOWER], true);</pre></div><div contenteditable="false"><link href="http://www.zwqxin.com/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>这部分参考的是GameTutorials, LLC的一个MD3导入教程（因为比较久远，那时候VBO还没出生）。这个教程更重要的是一些tips，譬如<a name="dgfdgdfgfd"></a>导入.animation文件时lower的索引要减去upper索引的首值。还有就是我们插值的方式，我们要进行动画帧间的插值，线性插值的前后应该是对应乘了变换矩阵的点坐标&mdash;&mdash;这样麻烦了点，效果也不好。考虑到我们实际插值的是一个点坐标向量的旋转，所以真●主角出场了&mdash;&mdash;</p><p>Quaternion四元数([<a target="_blank" href="http://www.zwqxin.com/archives/arithmetic/gimballock-and-quaternion.html">GimbalLock万向节锁与四元数旋转</a>])!!</p><p>这下倒有点兴奋了。我们在上面把Tag信息里相邻两帧的3X3roatation传给ZWQuaternion类生成两个四元数，再利用SLERP四元数球插值（网上参考很多）来弄出中间的代表旋转的四元数&mdash;&mdash;变换回矩阵，加上translation部分，这样就把子模型的位置点坐标转到正确漂亮的位置了！</p><p>那你说最底的父模型&mdash;&mdash;下身模型怎么办，没有其他外部的tag信息提供变换矩阵参数给它啊&mdash;&mdash;是的，它的话，唯有线性插值了TAT（建议用shader Mode）。</p><p>渲染部分整个代码就跟其他格式模型差不多了，动画部分也可以根据MD2的那套延伸出[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/md2-model-format-import-animation.html">MD2格式模型的格式、导入与帧动画</a>]（毕竟本质上还是帧动画，只不过渲染上加了个骨骼的概念而已嘛）。导入skin文件其实就是查询匹配模型的网格对象的名字，然后把路径最后的文件名指涉的纹理文件导入为纹理而已；最后给出的是我的.animation文件的导入函数，其实就是<a href="#dgfdgdfgfd">上面</a>提及的那个BUG不BUG的东西要注意点。注意，上下身的动画帧总数很多时候是8一样的，连续动画最后模型姿态会变囧的。（其实MD3模型就是上下身各指定一个动画吧，不过除了BOTH的动画外，其他的组合实在很容易让人，擦。）</p><div class="HighLighter" contenteditable="false"><div class="dp-highlighter" contenteditable="false"><div class="bar">&nbsp;</div><ol class="dp-c">    <li class="alt"><span><span class="keyword">void</span><span>&nbsp;ZWModelMD3::LoadAnimationInfo()</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">char</span><span>&nbsp;strBuff[MAX_LINE]&nbsp;&nbsp;=&nbsp;{0};</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;t3DAnim&nbsp;animation&nbsp;=&nbsp;{0};</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">int</span><span>&nbsp;numfr&nbsp;=&nbsp;0,&nbsp;loopfr&nbsp;=&nbsp;0;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nLegFrameFix&nbsp;=&nbsp;-1;</span></span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">while</span><span>&nbsp;(fgets(strBuff,&nbsp;MAX_LINE,&nbsp;m_FilePointer))</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(!isdigit(strBuff[0]))</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">continue</span><span>;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(4&nbsp;==&nbsp;sscanf_s(strBuff,&nbsp;</span><span class="string">&quot;%d&nbsp;%d&nbsp;%d&nbsp;%d&quot;</span><span>,&nbsp;&amp;animation.nStartFrame,&nbsp;&amp;numfr,&nbsp;&amp;loopfr,&nbsp;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;animation.nFramesPerSec))</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;animation.nEndFrame&nbsp;=&nbsp;animation.nStartFrame&nbsp;+&nbsp;numfr;</span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(strstr(strBuff,&nbsp;</span><span class="string">&quot;BOTH&quot;</span><span>))</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_ModelMainMD3[MD3_MAINPART_UPPER].Animations.push_back(animation);</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_ModelMainMD3[MD3_MAINPART_LOWER].Animations.push_back(animation);</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">else</span><span>&nbsp;</span><span class="keyword">if</span><span>(strstr(strBuff,&nbsp;</span><span class="string">&quot;TORSO&quot;</span><span>))</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_ModelMainMD3[MD3_MAINPART_UPPER].Animations.push_back(animation);</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">else</span><span>&nbsp;</span><span class="keyword">if</span><span>(strstr(strBuff,&nbsp;</span><span class="string">&quot;LEG&quot;</span><span>))</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(-1&nbsp;==&nbsp;nLegFrameFix)</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nLegFrameFix&nbsp;=&nbsp;animation.nStartFrame&nbsp;-&nbsp;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_ModelMainMD3[MD3_MAINPART_UPPER].Animations[0].nStartFrame;</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;animation.nStartFrame&nbsp;-=&nbsp;nLegFrameFix;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;animation.nEndFrame&nbsp;&nbsp;&nbsp;-=&nbsp;nLegFrameFix;</span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_ModelMainMD3[MD3_MAINPART_LOWER].Animations.push_back(animation);</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li><span>}</span></li></ol></div><div class="c#" contenteditable="false" style="display: none"><pre>void ZWModelMD3::LoadAnimationInfo(){	char strBuff[MAX_LINE]	= {0};	t3DAnim animation = {0};	unsigned int numfr = 0, loopfr = 0;	int nLegFrameFix = -1;	while (fgets(strBuff, MAX_LINE, m_FilePointer))	{		if(!isdigit(strBuff[0]))		{			continue;		}		if(4 == sscanf_s(strBuff, &quot;%d %d %d %d&quot;, &amp;animation.nStartFrame, &amp;numfr, &amp;loopfr, 			&amp;animation.nFramesPerSec))		{			animation.nEndFrame = animation.nStartFrame + numfr;			if(strstr(strBuff, &quot;BOTH&quot;))			{				m_ModelMainMD3[MD3_MAINPART_UPPER].Animations.push_back(animation);				m_ModelMainMD3[MD3_MAINPART_LOWER].Animations.push_back(animation);			}			else if(strstr(strBuff, &quot;TORSO&quot;))			{				m_ModelMainMD3[MD3_MAINPART_UPPER].Animations.push_back(animation);			}			else if(strstr(strBuff, &quot;LEG&quot;))			{				if(-1 == nLegFrameFix)				{					nLegFrameFix = animation.nStartFrame - 						m_ModelMainMD3[MD3_MAINPART_UPPER].Animations[0].nStartFrame;				}				animation.nStartFrame -= nLegFrameFix;				animation.nEndFrame   -= nLegFrameFix;				m_ModelMainMD3[MD3_MAINPART_LOWER].Animations.push_back(animation);			}		}	}}</pre></div><div contenteditable="false"><link href="http://www.zwqxin.com/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>就这样结束吧。老实说，MD3这么麻烦，要不是为了学习性连贯点，我就该直奔MD5去了。</p><p><a target="_blank" href="http://www.zwqxin.com/archives/opengl/model-md3-format-import-animation.html"><img height="283" alt="MD3模型的格式、导入与骨骼概念动画" width="506" src="https://lh3.googleusercontent.com/_lYWT-2PnV0s/TXsPJdAiZcI/AAAAAAAADSk/AQUZagmxb44/s912/20110226Snap1.jpg" /></a></p><p>这么多位型人，快点左一脚右一脚去收拾那些大怪兽啦！</p><p>Copyright © 2008</p><p><a href="http://www.zwqxin.com/archives/opengl/model-md3-format-import-animation.html" target="_blank">继续阅读《MD3模型的格式、导入与骨骼概念动画》的全文内容...</a></p><p>分类: <a href="http://www.zwqxin.com/archives/opengl.html">OpenGL技术</a> | Tags: <a href="http://www.zwqxin.com/catalog.asp?tags=MD3">MD3</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=%E6%A8%A1%E5%9E%8B">模型</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=%E7%AC%94%E8%AE%B0">笔记</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=VBO">VBO</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=MD2">MD2</a>&nbsp;&nbsp; | <a href="http://www.zwqxin.com/archives/opengl/model-md3-format-import-animation.html#comment" target="_blank">添加评论</a>(1)</p><h3>相关文章:</h3><ul><li><a href="http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html">shader复习与深入:HDR(高动态范围)</a> (2012-1-26 14:50:43)  </li><li><a href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-2.html">MD5模型的格式、导入与顶点蒙皮式骨骼动画II</a> (2011-10-7 17:11:7)  </li><li><a href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-1.html">MD5模型的格式、导入与顶点蒙皮式骨骼动画I</a> (2011-10-6 21:14:49)  </li><li><a href="http://www.zwqxin.com/archives/opengl/sphere-mapping-cubemap-stuff.html">球体贴图小谈</a> (2011-10-4 22:3:26)  </li><li><a href="http://www.zwqxin.com/archives/opengl/vao-and-vbo-stuff.html">AB是一家?VAO与VBO</a> (2011-10-1 17:12:38)  </li></ul>]]></description><category>OpenGL技术</category><comments>http://www.zwqxin.com/archives/opengl/model-md3-format-import-animation.html#comment</comments><wfw:comment>http://www.zwqxin.com/</wfw:comment><wfw:commentRss>http://www.zwqxin.com/feed.asp?cmt=92</wfw:commentRss><trackback:ping>http://www.zwqxin.com/cmd.asp?act=tb&amp;id=92&amp;key=7e75d8ed</trackback:ping></item><item><title>GimbalLock万向节锁与四元数旋转</title><author>a@b.com (zwqxin)</author><link>http://www.zwqxin.com/archives/arithmetic/gimballock-and-quaternion.html</link><pubDate>Fri, 04 Mar 2011 22:54:50 +0800</pubDate><guid>http://www.zwqxin.com/archives/arithmetic/gimballock-and-quaternion.html</guid><description><![CDATA[<p>&nbsp;也许你都知道四元数这么个东西，也许你还知道万向锁。但是对于弄懂它们还是不那么容易的&mdash;&mdash;起码对于我就是如此了。今天是丢三落四日，我就自己来捡捡吧。&mdash;&mdash;<a href="http://www.zwqxin.com/">ZwqXin</a>.com</p><p>事先声明，原理神马的，其实我也不是很懂，本文仅作抛砖引玉之用。想无误认识万向锁和四元数的朋友们请绕道回来。</p><p>其实一言蔽之，因为我们对三维对象的旋转操作会出现gimballock的问题，所以求助于quaternion。但是问题的本质应该是：是具体什么操作出现问题了？是具体怎样的一个问题？四元数又有什么改进或好处了？从传统的旋转指令出发吧。</p><div class="HighLighter" contenteditable="false"><div contenteditable="false" class="dp-highlighter"><div class="bar">&nbsp;</div><ol start="1" class="dp-c">    <li class="alt"><span><span>glPushMatrix();</span></span></li>    <li><span>glRotatef(m_vRotation.z,0,0,1);</span></li>    <li class="alt"><span>glRotatef(m_vRotation.y,0,1,0);</span></li>    <li><span>glRotatef(m_vRotation.x,1,0,0);</span></li>    <li class="alt"><span>DrawSomething();</span></li>    <li><span>glPopMatrix();</span></li></ol></div><div contenteditable="false" class="c#" style="display:none"><pre>	glPushMatrix();	glRotatef(m_vRotation.z,0,0,1);	glRotatef(m_vRotation.y,0,1,0);	glRotatef(m_vRotation.x,1,0,0);	DrawSomething();	glPopMatrix();</pre></div><div contenteditable="false"><link href="/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>glRotate是我们熟悉得不能再熟悉的函数之一了，它看起来就是接受一个转动角度和转动轴，然后给予物件一个绕该轴的逆时针旋转。上面我们给出了绕三个轴的相应旋转的指令，按照你的3D图形学常识，Draw的物件先绕X轴转一个角度，再绕Y轴转一个角度，再绕Z轴转一个角度。现在我们把各个旋转角置0，得到物件的无旋转状态（图1）：<br /><a target="_self" href="http://www.zwqxin.com/archives/arithmetic/gimballock-and-quaternion.html"><img alt="GimbalLock万向节锁与四元数旋转" src="https://lh4.googleusercontent.com/_lYWT-2PnV0s/TXOxS68dvkI/AAAAAAAADRg/FlcGNydvWYs/Snap120110306.jpg" /></a>图1</p><p>接下来让我们把m_vRotation.y置90，让模型绕Y轴逆转个90度，用欧拉角术语来说，就是Yaw+90。一切看上去那么自然（图2）：<br /><a target="_self" href="http://www.zwqxin.com/archives/arithmetic/gimballock-and-quaternion.html"><img alt="GimbalLock万向节锁与四元数旋转" src="https://lh4.googleusercontent.com/_lYWT-2PnV0s/TXOxTA70KhI/AAAAAAAADRo/CFT-X_JHjmI/Snap220110306.jpg" /></a>图2</p><p>接下来我们重新尝试，把m_vRotation.y置90，也把m_vRotation.z置90，让模型绕Y轴和Z轴都逆转90（Yaw+90，Roll+90），得出这样的结果（图3）：<br /><a target="_self" href="http://www.zwqxin.com/archives/arithmetic/gimballock-and-quaternion.html"><img alt="GimbalLock万向节锁与四元数旋转" src="https://lh5.googleusercontent.com/_lYWT-2PnV0s/TXOxTGtJpsI/AAAAAAAADRk/ZCZ_hOy5y-0/Snap320110307.jpg" /></a>图3</p><p>再重新尝试，把m_vRotation.y置90，把m_vRotation.x置-90，让模型绕Y轴转90，绕X轴都顺转90（Yaw+90，Pitch-90），得出这样的结果（图4）：<br /><a target="_self" href="http://www.zwqxin.com/archives/arithmetic/gimballock-and-quaternion.html"><img alt="GimbalLock万向节锁与四元数旋转" src="https://lh4.googleusercontent.com/_lYWT-2PnV0s/TXOxTWyT9NI/AAAAAAAADRs/2HXq42O70Hc/Snap420110308.jpg" /></a>图4</p><p>居然是一样的结果。你想清楚了吗？</p><p>提醒一下，这里要考虑的是上面后两步中，都绕Y轴转了90度，但是一个是另绕X轴转一个是另绕Z轴转，但是居然结果都是同样的结果：在我们看来是都绕Z轴转了（注意这里转角的正负不是考虑的重点，即使都是正90度，它们同样是绕的Z轴旋转）。</p><p>想清楚没有？这就是所谓GimbalLock的影响哦。因为我们现在只能让物件绕Y轴转，绕Z轴转，无法绕X轴自由地转了，这模型没掉了一个选择自由度。</p><p>或许你事先在网上看了些资料，里面说&ldquo;欧拉角&rdquo;是导致GimbalLock的元凶&mdash;&mdash;是的，我们的确在有意无意地用了欧拉角去表示旋转，就像上面括号里的文字一样。但是你确定这确实是欧拉这位数学大师给你出的难题？如果是的话，你弄清楚这个难题到何种程度？</p><div class="HighLighter" contenteditable="false"><div contenteditable="false" class="dp-highlighter"><div class="bar">&nbsp;</div><ol start="1" class="dp-c">    <li class="alt"><span><span>附&nbsp;&nbsp;欧拉角表示法：</span></span></li>    <li><span>以旅途中的平驶飞机为对象，</span></li>    <li class="alt"><span>Yaw&nbsp;&nbsp;-&nbsp;偏航角，飞机绕垂直机身的中轴左右旋转的角度；</span></li>    <li><span>Pitch-&nbsp;俯仰角，飞机绕平行机翼方向的中轴上下摇摆的角度；</span></li>    <li class="alt"><span>Roll -&nbsp;横滚角，飞机绕行驶方向平行的中轴顺/逆时针旋动的角度。</span></li></ol></div><div contenteditable="false" class="c#" style="display:none"><pre>附  欧拉角表示法：以旅途中的平驶飞机为对象，Yaw  - 偏航角，飞机绕垂直机身的中轴左右旋转的角度；Pitch - 俯仰角，飞机绕平行机翼方向的中轴上下摇摆的角度；Roll   - 横滚角，飞机绕行驶方向平行的中轴顺/逆时针旋动的角度。</pre></div><div contenteditable="false"><link href="/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>OpenGL是不认识欧拉角的。即使是glRotate，那也就是输入任意角度和任意转轴，然后生成一个旋转矩阵。无错，请从矩阵角度再考虑一下：究竟在矩阵变换的途中出了什么状况？</p><p>如果你觉得自己对这块不很熟的话，在我颇久之前写的两篇文章[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/opengl-matrix-what.html">乱弹OpenGL中的矩阵变换(上)</a>]/ [<a target="_blank" href="http://www.zwqxin.com/archives/opengl/opengl-matrix-what-2.html">乱弹OpenGL中的矩阵变换(下)</a>]中，也许能给予你一些许的启发吧。仔细想过后，再来看看我下面的说法有没有问题（毕竟我在此自己记录的同时也是向各位请教）？</p><p>按代码执行顺序来看，在进入模型变换后，通常给予一个单位矩阵，然后glTransalate/glRotate之类函数生成对应的矩阵，右乘到之前的这个矩阵上，一直下去直到遇到需要绘制的数据（定义在模型空间），即模型坐标系下的每一个点的坐标作为竖向量右乘到之前连串右乘操作后的结果矩阵上。这是执行顺序。在逻辑顺序上看，模型坐标系下的点坐标是被一个一个的变换矩阵左乘直至最后屏幕坐标系下的坐标的。上面最开始给出的代码同样是这么个情况：三个glRotatef生成的旋转矩阵依次左乘到模型坐标点上。&mdash;&mdash;问题就出在这句话上，你是否正确理解了这句话的意思？其实这里有个歧义，只是我们通常不会被引导到歧义上，但是想清楚这个歧义反而对你的理解更有帮助：是每个旋转矩阵都左乘一次模型坐标点，还是连续地左乘至之前左乘的结果（第一个矩阵是左乘到最初的模型坐标点）上？显然是后者。想到这的同时，你脑中大概会出现这幅景象：</p><p>M<sub>r</sub> = M<sub>rz</sub> * M<sub>ry</sub> * M<sub>rx</sub> * （VertexCoord）<br />&mdash;&mdash;&gt;&nbsp;M<sub>r1</sub> =&nbsp;M<sub>rx</sub> * （VertexCoord）①； M<sub>r2</sub> =&nbsp;M<sub>ry</sub> *&nbsp;M<sub>r1</sub> ②； M<sub>r </sub>=&nbsp;M<sub>rz</sub> * M<sub>r2</sub> ③。</p><p>这个景象是很重要的。分解了矩阵操作为三步后，分析一下：第一步，绕X轴旋转的旋转矩阵与模型空间下的点坐标相乘，而结果呢？这个&nbsp;M<sub>r1</sub>是在哪个空间（坐标系）下的？它在一个模型变换后，但在其他模型变换之前，介于模型坐标系和世界坐标系下，是一个临时性的（temp）空间；第二步，我们的第二个旋转矩阵所操作的目标点是定义在这个空间坐标系下的，而不再是模型坐标系！同样，这一步把点转换到另一个temp空间，第三步则是把旋转效果应用到这个temp空间坐标系下表示的点坐标。</p><p>事实上，你调换一下M<sub>rz</sub>&nbsp; M<sub>ry</sub>&nbsp; M<sub>rx</sub>&nbsp;的位置，这两个temp空间也就不一样（只要不是相同的变换矩阵，M<sub>ry*</sub>VertexCoord 和&nbsp;M<sub>rx</sub><sub>*</sub>VertexCoord的结果就不一样）。这与相邻的glTranslate位移矩阵可以互换位置效果不变（因为最终它们只是加合到模型变换矩阵的右侧）不一样，它们的顺序决定了它们的效果。从另一个角度考虑，因为这样的矩阵不满足乘法交换律，所以即使同维数，结果都会不同。再换一个角度，顺序不变，但给予两个角度分别应用于不同的旋转矩阵，所得的结果有可能是一致的。</p><p>现在再回头看开头那个问题：在图3中，是先让物体绕自身的模型坐标系的Y轴逆转了90度，到了temp1坐标系，再绕temp1坐标系的Z轴转90度；在图4中，是先绕模型坐标系的X轴转了90度，到了一个temp2坐标系，再temp2坐标系的Y轴逆转90度。给予的旋转完全不同，只是恰巧到达同一种结果而已。这与我们的期望不同：我们希望给予不同方向的旋转，到达的结果应该不一样。（注意，因为我们都是参照世界坐标系定义旋转轴的，所以这里各空间的XYZ轴都是与世界坐标的XYZ轴重合的，只是模型在每个空间的&ldquo;朝向&rdquo;不一样。）</p><p>结论是，我们的旋转顺序，才是导致了GimbalLock的原因。或者就如这篇文章，<a target="_blank" href="http://www.gamedev.net/page/resources/_/reference/programming/math-and-physics/quaternions/quaternion-powers-r1095">Quaternion Powers</a>所说的，第一次旋转没有改掉第二次旋转所用的转轴&mdash;&mdash;我们还是根据最直观的世界坐标系下的轴来定义旋转，而我们实质通常是期望物体在自身模型坐标系下做旋转，就似飞机中的飞行员希望飞机总是按自己为参照物来作各向的旋转运动一样。当然可以在每次旋转后自己调整旋转坐标轴来纠正：譬如出问题的图4，我们在绕X轴转了90度之后，希望模型仍然针对自己的模型坐标系的Y轴来转90度的话，就置换一下参考系：现在模型在模型坐标系下的Y轴与世界坐标系下的Z轴负向一致，所以在X轴的glRotate指令上方起作用的glRotate指令，所传入的旋转轴（如前所述，它定义于世界坐标系）须是glRotatef(-90, 0, 0, 1)，如图5所示：</p><p><a target="_self" href="http://www.zwqxin.com/archives/arithmetic/gimballock-and-quaternion.html"><img alt="GimbalLock万向节锁与四元数旋转" src="https://lh6.googleusercontent.com/_lYWT-2PnV0s/TXOxTeNRHSI/AAAAAAAADRw/gDRtXL2r6X4/Snap520110310.jpg" /><br />（图1基础上，绕自身坐标轴的X轴旋转90度）</a></p><p><a target="_self" href="http://www.zwqxin.com/archives/arithmetic/gimballock-and-quaternion.html"><img alt="GimbalLock万向节锁与四元数旋转" src="https://lh3.googleusercontent.com/_lYWT-2PnV0s/TXOxTtgl8MI/AAAAAAAADR0/DSPl4iJMyEY/Snap620110309.jpg" />图5<br /></a><a target="_self" href="http://www.zwqxin.com/archives/arithmetic/gimballock-and-quaternion.html">（上图基础上，绕自身坐标轴的Y轴旋转90度）</a></p><p>关于模型编辑工具的GimbalLock，这里有个视频，我觉得讲得蛮形象的：</p><p><embed mediatype="3" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" src="http://player.youku.com/player.php/sid/XNzkyOTIyMTI=/v.swf" width="500" height="400" autostart="true" loop="true" menu="true"></embed></p><p>真的是欧拉角导致了GimbalLock吗？当我们说让模型偏航（Yaw）XX度，俯仰YY度，侧滚ZZ度，在（0,360）范围内会有这么三个值让我们的模型无法去到那个位置？呵呵，怎么可能~怎么想得出来这三个出世的值！是的，三维空间下任何一个复杂的旋转都应该能被分解到绕三个正交轴的旋转上。那么，真的是旋转的次序导致了GimbalLock吗？根据上面的讨论，你完全可以通过矫正旋转轴，让模型旋转到任意角度。那么，究竟是什么？是什么导致了GimbalLock这种直觉下难以想象却又客观存在的现象？</p><p>是我们的观念。</p><p>无论是欧拉角导致GimbalLock，旋转次序导致GimbalLock，甚至你说矩阵相乘导致GimbalLock也好，其实都是表面的诱因。真正出了问题的，是我们的思维惯性，我们的观念。GimbalLock并不意味着客观三维世界里存在一个旋转的死角，它意味着我们思维的一个盲点。我们很少考虑到&ldquo;偏航45度，俯仰54度&rdquo;与&ldquo;俯仰45度，偏航45度&rdquo;的顺序有什么区别，很少说明这个偏航、俯仰是参照什么而言。我们看到与期望相悖的结果，发现机器转不了了，于是GimbalLock出现了。我们怪罪于它，殊不知它只是我们心中的其中一个魔鬼，而已。</p><p>这就是为什么有的人说只要订立合适的规则，就能避免GimbalLock。其中一种是限制转角，如同我们经常限制摄像机一样；一种是纠正转轴，如同上文一样；一种是控制旋转顺序，如同上述视频中，还有还有&hellip;&hellip;有没有不需要这种事后订立的限定规则就能成事的方法呢？考虑本文最开始的代码清单，我们被三个glRotate的调用次序问题引向了GimbalLock，虽然当我们观念转变后能通过其他方法摆脱（譬如常说的AxisAngle这种表示法，每次旋转的转轴都明确地标明），但这是很麻烦的事，尤其转轴不再那么&ldquo;正规&rdquo;的情形。这时候可能会想到，有没办法一次搞掂三次的旋转呢&mdash;&mdash;生成一个集合各个旋转的旋转矩阵，这样就没有次序的干扰啦。你要知道，当OpenGL代码执行到绘制部分时，其实就只是把坐标左乘一个集合矩阵罢了&mdash;&mdash;次序反映在矩阵相乘的顺序（再提醒自己一次，矩阵乘法不满足统一的交换律），所以至少在旋转这里我们要摆脱矩阵相乘，才能得到无须。从观念层面摆脱&quot;旋转顺序&quot;的，也许要到观念之外寻觅吧。</p><p>四元数就很好。因为它不是三维世界的东西。</p><p>老实说，四元数这个东西已经完全超越了我的数感范畴了。最初是大三时候看的一本《游戏编程精粹》里接触的，只觉得强大、神奇、诡异。其实很多网络的一些人写的demo里都有这东西，还有更重要的，游戏引擎基本使用四元数来处理旋转，OGRE是熟悉的典范。</p><p>一个四元数的形式是(x,y,z,w)，定义在一个封闭的四维空间。什么四维？三维世界+时间？霍金的时间简史看傻阁下了吧，请绕地自转一周回来。数学上的四维空间是基本无法用日常经验去模拟的，数学系的同学你们快自豪起来吧&hellip;&hellip;什么四维空间的向量+角度，说什么我也无法就这样具化出一个四元数。你当然可以把它单纯看作数学上的四个数字，数字间和每组数字间满足一些奇怪的关系式，定义一个名字叫四元数。恩，这样感觉好点- -。</p><p>至少要明白它在三维图形学中的一个重要用途：表示一个旋转。我们的模型从一个地方到另一个地方，其实就是一个单纯的旋转，只是我们要求方便表达才分解到三个轴，但是分解后却又（由于各种限制）无法使它们同时旋转，导致GimbalLock。与其用AxisAngle去表达这个单纯旋转，Quaternion（四元数）更方便，如此而已。它的方便之处在于，它有一套成熟的转换系统，可以从无序欧拉角（即欧拉角的表示均相对于模型坐标系）转换到它，也可以由它转换到无序的欧拉角；再者，可以与AxisAngle互转；更重要的，它可以与旋转矩阵互转。不是说欧拉角和轴角就不能有类似能力，只是四元数比起它们，转换系统更成熟（更不需动太多脑筋、不需死太多脑细胞）。</p><p>我们最喜欢的旋转表示法是欧拉表示法，显卡最喜欢的旋转表示法是矩阵表示法。既然两者之间出现了那么多&ldquo;沟通问题&rdquo;，就需要一个很好的协调者，四元数表示法，作为转换的桥梁。三个轴的欧拉角可转成一个四元数，四元数再转成矩阵。四元数不是三维空间的东西，所以立场很好的，你们不要黑它。四元数可以表示三维的东西，这是它能与双方沟通的资本；沟通成本通常是有点大的（我指转换进转换出所须的计算量），但是因为它工作很到位，所以我们3D编程人员也应该舍得请他。请他来我们这里担任协调部主任也要先花点精力说明一下状况（我指，呃，写一个Quternion类&hellip;&hellip;），这样之后我们就鲜有脑袋跳线（遭遇GimbalLock）之忧了。如果你还嫌花费大宁愿麻烦点自己动手的话，那你知道四元数表示的旋转能够作比较完美的插值计算（SLERP，Spherical Linear Interpolation）时，你还有什么好犹豫的？</p><p>好了，具体的四元数的特性，和转换公式什么的，请网上去找找吧（上文提及的一篇文章<a target="_blank" href="http://www.gamedev.net/page/resources/_/reference/programming/math-and-physics/quaternions/quaternion-powers-r1095">Quaternion Powers</a>里也有一些），实在太多了（我是说精明的生意人）。这里提及几点：</p><ul>    <li>我们都用单位四元数(1 = x<sup>2</sup> + y<sup>2</sup> + z<sup>2&nbsp;</sup>+ w<sup>2</sup>)来表示一个旋转或旋转位置；</li>    <li>别望文生义，这里x,y,z,w跟三维下的齐次坐标没啥关系；</li>    <li>为什么SLERP平滑插值这么重要？因为一个任意向量要转到另一个位置，除了一个坐标点的插值还有一个角度的插值，它们不是同质的，所以各自线性插值的结果是不稳定的，看上去转速不恒定。</li></ul><p>或许之后还有补充，这里，就先到这里吧。丢三落四之日，也结束了。</p><p>&nbsp;</p><p>Copyright © 2008</p><p><a href="http://www.zwqxin.com/archives/arithmetic/gimballock-and-quaternion.html" target="_blank">继续阅读《GimbalLock万向节锁与四元数旋转》的全文内容...</a></p><p>分类: <a href="http://www.zwqxin.com/archives/arithmetic.html">图形相关算法</a> | Tags: <a href="http://www.zwqxin.com/catalog.asp?tags=%E7%AC%94%E8%AE%B0">笔记</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=%E6%95%B0%E5%AD%A6">数学</a>&nbsp;&nbsp; | <a href="http://www.zwqxin.com/archives/arithmetic/gimballock-and-quaternion.html#comment" target="_blank">添加评论</a>(0)</p><h3>相关文章:</h3><ul><li><a href="http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html">shader复习与深入:HDR(高动态范围)</a> (2012-1-26 14:50:43)  </li><li><a href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-1.html">MD5模型的格式、导入与顶点蒙皮式骨骼动画I</a> (2011-10-6 21:14:49)  </li><li><a href="http://www.zwqxin.com/archives/opengl/sphere-mapping-cubemap-stuff.html">球体贴图小谈</a> (2011-10-4 22:3:26)  </li><li><a href="http://www.zwqxin.com/archives/opengl/vao-and-vbo-stuff.html">AB是一家?VAO与VBO</a> (2011-10-1 17:12:38)  </li><li><a href="http://www.zwqxin.com/archives/opengl/model-md3-format-import-animation.html">MD3模型的格式、导入与骨骼概念动画</a> (2011-3-12 10:2:23)  </li></ul>]]></description><category>图形相关算法</category><comments>http://www.zwqxin.com/archives/arithmetic/gimballock-and-quaternion.html#comment</comments><wfw:comment>http://www.zwqxin.com/</wfw:comment><wfw:commentRss>http://www.zwqxin.com/feed.asp?cmt=91</wfw:commentRss><trackback:ping>http://www.zwqxin.com/cmd.asp?act=tb&amp;id=91&amp;key=c67a7347</trackback:ping></item><item><title>MD2格式模型的格式、导入与帧动画</title><author>a@b.com (zwqxin)</author><link>http://www.zwqxin.com/archives/opengl/md2-model-format-import-animation.html</link><pubDate>Thu, 17 Feb 2011 21:29:15 +0800</pubDate><guid>http://www.zwqxin.com/archives/opengl/md2-model-format-import-animation.html</guid><description><![CDATA[<p>MD2模型是一种古老的支持帧动画的模型格式，IDSoftware公司的游戏引擎id Tech 2所定义并采用的模型的格式。本文主要记录一下最近写的一个MD2格式导入类ZWModelMD2的一些细节。&mdash;&mdash;<a href="http://www.zwqxin.com/">ZwqXin</a>.com</p><ul>    <li>ZWModel3DS：[<a href="http://www.zwqxin.com/archives/opengl/3ds-structure-simple.html">3DS文件结构的初步认识</a>] &nbsp;/ &nbsp;[<a href="http://www.zwqxin.com/archives/opengl/idexed-vbo-for-model-3ds-rendering.html">用Indexed-VBO渲染3DS模型</a>]</li>    <li>ZWModelOBJ：[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/obj-model-format-import-and-render-1.html">OBJ模型文件的结构、导入与渲染Ⅰ</a>] &nbsp;/ &nbsp;[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/obj-model-format-import-and-render-2.html">OBJ模型文件的结构、导入与渲染Ⅱ</a>]</li></ul><p><br /><img alt="MD2格式模型的格式、导入与帧动画" src="https://lh4.googleusercontent.com/_lYWT-2PnV0s/TV1JrD_u95I/AAAAAAAADPI/0mggbBl_f_4/MD2Model20100217.jpg" /></p><p>MD2格式最早是跟IDSoftware的游戏QuakeⅡ一起为世人所熟知的。它最大的特性是&ldquo;自定义&rdquo;头文件，支持帧动画（在当今来看这种动画模式比起骨骼动画还是颇简陋的）。帧动画顾名思义，就是通过高速幻灯片的方式展现一个动画，日本90年代之前的动画其实也都是这么一个原理。要达到模型的运动细致的效果，必然需要大量的帧数&mdash;&mdash;最理想的情况当然是渲染程序中的每一帧都能转换一次模型的帧（这是不可能的，会导致庞大数据存储）。好吧，使用关健帧技术，每隔一段时间换一帧，期间的靠插值得出。但是关健帧之间相差太大是会导致模型的运动十分不自然的&mdash;&mdash;所以即使是关健帧，也得足够多才能满足需求。这是MD2模型的局限&mdash;&mdash;模型要越细致，则所需的关键帧数要越多，则所需存储的顶点数据要越多，则模型体积越大，则导入模型所花费的时间越长（渲染时间也会增加，导致程序帧率下降，导致模型的渲染被程序拖慢，造成幻灯片效果，模型也显得不细致）。</p><p>但是一来它的渲染原理易于理解，二来网上资源也不少，还是写了一个导入类ZWModelMD2。md2文件的特点如下：</p><ol>    <div class="HighLighter" contenteditable="false">    <div contenteditable="false">    <link href="/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div>    </div>    <li><a name="points"></a>1.它具有文件头（就好像BMP[<a href="http://www.zwqxin.com/archives/image-processing/bmp-operate-print-pixel.html">Bmp文件的结构与基本操作</a>]一样，里面宏观地记入了这个模型的整体信息），包含各顶点属性的总数、帧数、纹理大小、属性数据所在文件的位置等等一系列信息，而不像3ds、obj那样读到哪算哪。</li>    <li>2.二进制文件，它的数据都是对齐的，譬如md2文件中的顶点索引都是unsigned short，每个顶点索引在文件中占的大小都是sizeof(unsigned short)不变。</li>    <li>3.它没有类似3ds、obj和其他许多模型格式一样有网格对象的概念，或者说整个MD2模型就是一个整体，唯一的顶点属性集，唯一的属性索引集，<strong><em>唯一的纹理</em></strong>。</li>    <li>4.它按关键帧的顺序把顶点集连续存放，形成一个庞大的总顶点集。但顶点索引只有一份，因为每个顶点集中对应索引的顶点是模型的&ldquo;同一个位置&rdquo;。</li>    <li>5.模型和纹理分开，模型文件里没有指明纹理的名称。</li>    <li>6.没有法线数据，顶点位置和纹理坐标各一套索引</li></ol><p>根据以上的特征，可以认为md2文件的读入是十分十分方便的，关键是负责读入的数据结构要符合md2文件规范。从文件头开始：</p><div class="HighLighter" contenteditable="false"><div contenteditable="false" class="dp-highlighter"><div class="bar">&nbsp;</div><ol start="1" class="dp-c">    <li class="alt"><span><span class="comment">//MD2文件文件头标准</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tagMd2Header</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nMagic;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;magic&nbsp;number&nbsp;used&nbsp;to&nbsp;identify&nbsp;the&nbsp;file.</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nVersion;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;file&nbsp;version&nbsp;number&nbsp;(must&nbsp;be&nbsp;8).</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nSkinWidth;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;width&nbsp;in&nbsp;pixels&nbsp;of&nbsp;our&nbsp;image.</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nSkinHeight;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;height&nbsp;in&nbsp;pixels&nbsp;of&nbsp;our&nbsp;image.</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nFrameSize;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;size&nbsp;in&nbsp;bytes&nbsp;the&nbsp;frames&nbsp;are.</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nNumSkins;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;number&nbsp;of&nbsp;skins&nbsp;associated&nbsp;with&nbsp;the&nbsp;model.</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nNumVertices;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;number&nbsp;of&nbsp;vertices.</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nNumTexCoords;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;number&nbsp;of&nbsp;texture&nbsp;coordinates.</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nNumFaces;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;number&nbsp;of&nbsp;faces&nbsp;(triangles).</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nNumGlCommands;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;number&nbsp;of&nbsp;gl&nbsp;commands.</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nNumFrames;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;number&nbsp;of&nbsp;animated&nbsp;frames.</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nOffsetSkins;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;offset&nbsp;in&nbsp;the&nbsp;file&nbsp;for&nbsp;the&nbsp;skin&nbsp;data.</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nOffsetTexCoords;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;offset&nbsp;in&nbsp;the&nbsp;file&nbsp;for&nbsp;the&nbsp;texture&nbsp;data.</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nOffsetFaces;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;offset&nbsp;in&nbsp;the&nbsp;file&nbsp;for&nbsp;the&nbsp;face&nbsp;data.</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nOffsetFrames;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;offset&nbsp;in&nbsp;the&nbsp;file&nbsp;for&nbsp;the&nbsp;frames&nbsp;data.</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nOffsetGlCommands;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;offset&nbsp;in&nbsp;the&nbsp;file&nbsp;for&nbsp;the&nbsp;gl&nbsp;commands&nbsp;data.</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;nOffsetEnd;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;end&nbsp;of&nbsp;the&nbsp;file&nbsp;offset.</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}Md2Header;</span></li>    <li>&nbsp;</li>    <li class="alt"><span>程序读入文件头：</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;fread_s(&amp;m_ModelMD2.MD2Header,&nbsp;<span class="keyword">sizeof</span><span>(Md2Header),&nbsp;</span><span class="keyword">sizeof</span><span>(BYTE),&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">sizeof</span><span>(Md2Header)&nbsp;,&nbsp;m_FilePointer);</span></span></li></ol></div><div contenteditable="false" class="c#" style="display:none"><pre>//MD2文件文件头标准	typedef struct tagMd2Header	{		int nMagic;              // The magic number used to identify the file.		int nVersion;            // The file version number (must be 8).		int nSkinWidth;          // The width in pixels of our image.		int nSkinHeight;         // The height in pixels of our image.		int nFrameSize;          // The size in bytes the frames are.		int nNumSkins;           // The number of skins associated with the model.		int nNumVertices;        // The number of vertices.		int nNumTexCoords;       // The number of texture coordinates.		int nNumFaces;           // The number of faces (triangles).		int nNumGlCommands;      // The number of gl commands.		int nNumFrames;          // The number of animated frames.		int nOffsetSkins;        // The offset in the file for the skin data.		int nOffsetTexCoords;    // The offset in the file for the texture data.		int nOffsetFaces;        // The offset in the file for the face data.		int nOffsetFrames;       // The offset in the file for the frames data.		int nOffsetGlCommands;   // The offset in the file for the gl commands data.		int nOffsetEnd;          // The end of the file offset.	}Md2Header;程序读入文件头：	fread_s(&amp;m_ModelMD2.MD2Header, sizeof(Md2Header), sizeof(BYTE), 		sizeof(Md2Header) , m_FilePointer);</pre></div><div contenteditable="false"><link href="/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>简简单单就完成了这么多数据的读入。nMagic是MD2文件的标识符（类似3ds的<a href="http://www.zwqxin.com/archives/opengl/3ds-structure-simple.html">primaryChunk</a>），接下来是version、纹理大小、一个帧的数据的大小、纹理数量、每帧的顶点数量、纹理坐标数量、面数、GLcommand数、帧数以及各项数据相对文件起始位置的偏移量。其中，纹理数量和纹理数据的偏移处的数据都是废的（根据<a href="#points">上面提到的</a>第三点和第五点）。<a name="glcommand">glcommand</a>其实就是GL_TRIANLE_STRIP/LOOP之类的（MD2文件针对当时独大的OpenGL提供了优化方式，数据里另外存储了一些利于GL应用的东西，但是我怀疑多少模型的作者真正会这样做，感觉不靠谱，有兴趣的可以看看这个网址：<a target="_blank" href="http://tfc.duke.free.fr/coding/md2-specs-en.html">http://tfc.duke.free.fr/coding/md2-specs-en.html</a>的最后部分）。再来看看读入纹理坐标：</p><div class="HighLighter" contenteditable="false"><div contenteditable="false" class="dp-highlighter"><div class="bar">&nbsp;</div><ol start="1" class="dp-c">    <li class="alt"><span><span>typedef&nbsp;</span><span class="keyword">struct</span><span>&nbsp;tagTexcoordInfo</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">short</span><span>&nbsp;u;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">short</span><span>&nbsp;v;</span></span></li>    <li class="alt"><span>}TexcoordInfo;</span></li>    <li>&nbsp;</li>    <li class="alt"><span><span class="comment">//Load&nbsp;Texcoords&nbsp;Data</span></span></li>    <li><span>TexcoordInfo&nbsp;*pTexcoordInfo&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;TexcoordInfo[pModel-&gt;MD2Header.nNumTexCoords];</span></span></li>    <li class="alt">&nbsp;</li>    <li><span>fseek(m_FilePointer,&nbsp;pModel-&gt;MD2Header.nOffsetTexCoords,&nbsp;SEEK_SET);</span></li>    <li class="alt">&nbsp;</li>    <li><span>fread_s(pTexcoordInfo,&nbsp;pModel-&gt;MD2Header.nNumTexCoords&nbsp;*&nbsp;<span class="keyword">sizeof</span><span>(TexcoordInfo),&nbsp;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">sizeof</span><span>(TexcoordInfo),&nbsp;pModel-&gt;MD2Header.nNumTexCoords,&nbsp;m_FilePointer);</span></span></li></ol></div><div contenteditable="false" class="c#" style="display:none"><pre>	typedef struct tagTexcoordInfo	{		short u;		short v;	}TexcoordInfo;	//Load Texcoords Data	TexcoordInfo *pTexcoordInfo = new TexcoordInfo[pModel-&gt;MD2Header.nNumTexCoords];	fseek(m_FilePointer, pModel-&gt;MD2Header.nOffsetTexCoords, SEEK_SET);	fread_s(pTexcoordInfo, pModel-&gt;MD2Header.nNumTexCoords * sizeof(TexcoordInfo), 		sizeof(TexcoordInfo), pModel-&gt;MD2Header.nNumTexCoords, m_FilePointer);</pre></div><div contenteditable="false"><link href="/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>很迅速，fseek根据文件头里的偏移量定位文件指针，然后一个fread_s搞掂。再一次pay you attention：这类<span class="Apple-style-span" style="font-family: Consolas, 'Courier New', Courier, mono, serif; font-size: 12px; line-height: 14px; ">TexcoordInfo</span>里的数据格式不是自己去定的，而要按md2文件格式的标准来（这里的纹理坐标不是规范化到[0,1]的，除以纹理的宽高后才是）。给出整个用于读入的标准数据结构（文件头上面给出了）：</p><div class="HighLighter" contenteditable="false"><div contenteditable="false" class="dp-highlighter"><div class="bar">&nbsp;</div><ol start="1" class="dp-c">    <li class="alt"><span><span class="comment">//导入结构定义</span></span></li>    <li><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tagVertPosInfo</span></span></li>    <li class="alt"><span>{</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">char</span><span>&nbsp;x;</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">char</span><span>&nbsp;y;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">char</span><span>&nbsp;z;</span></span></li>    <li class="alt"><span>}VertPosInfo;</span></li>    <li>&nbsp;</li>    <li class="alt"><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tagTexcoordInfo</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">short</span><span>&nbsp;u;</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">short</span><span>&nbsp;v;</span></span></li>    <li class="alt"><span>}TexcoordInfo;</span></li>    <li>&nbsp;</li>    <li class="alt"><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tagFrameVertInfo</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;VertPosInfo&nbsp;&nbsp;&nbsp;vertSrc;</span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">char</span><span>&nbsp;normalIndex;&nbsp;</span></span></li>    <li class="alt"><span>}FrameVertInfo;</span></li>    <li>&nbsp;</li>    <li class="alt"><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tagFrameInfo</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">float</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fScale[3];</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">float</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fTranslate[3];</span></span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">char</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szName[16];</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;FrameVertInfo&nbsp;*frameVertexInfo;</span></li>    <li class="alt"><span>}FrameInfo;</span></li>    <li>&nbsp;</li>    <li class="alt"><span>typedef&nbsp;<span class="keyword">struct</span><span>&nbsp;tagFaceInfo</span></span></li>    <li><span>{</span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">short</span><span>&nbsp;nVertIndex[3];</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword">short</span><span>&nbsp;nTexcoordIndex[3];</span></span></li>    <li class="alt"><span>}FaceInfo;</span></li></ol></div><div contenteditable="false" class="c#" style="display:none"><pre>	//导入结构定义	typedef struct tagVertPosInfo	{		unsigned char x;		unsigned char y;		unsigned char z;	}VertPosInfo;	typedef struct tagTexcoordInfo	{		short u;		short v;	}TexcoordInfo;	typedef struct tagFrameVertInfo	{		VertPosInfo   vertSrc;		unsigned char normalIndex; 	}FrameVertInfo;	typedef struct tagFrameInfo	{		float         fScale[3];		float         fTranslate[3];		char          szName[16];		FrameVertInfo *frameVertexInfo;	}FrameInfo;	typedef struct tagFaceInfo	{		unsigned short nVertIndex[3];		unsigned short nTexcoordIndex[3];	}FaceInfo;</pre></div><div contenteditable="false"><link href="/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>从下往上看，这里：一个面数据由3个顶点索引和3个纹理坐标索引组成；一个帧数据由3个方向上的缩放因子和偏移因子，帧名字（晕死）和一系列帧顶点元数据组成，帧顶点元数据指针在读入时要根据头文件指示的每帧顶点数new出来的；帧顶点元数据又细分为一个顶点元数据和一个法线索引（后者用于<a href="#glcommand">GLcommand方式</a>绘制时，对我来说是无用数据）；顶点元数据就是3个方向的BYTE。</p><p>这里说一下后面要怎样取真正的顶点数据：顶点位置 = 顶点元 *&nbsp;缩放因子 +&nbsp;偏移因子。你说它省存储吧，它倒省得很彻底：导入文件时把庞大的顶点区（<a href="#points">第5点</a>提及）的数据都归化为一个个BYTE存储[0,255]，从文件导出时再由统一的缩放和偏移因子来还原，硬把原本至少4字节的东西弄成1字节（先撇开顶点粗糙度不提）。</p><p>好吧。导完数据，知道公式，直接拿数据渲染，顺便计算一下法线，设定每隔n帧换一回顶点数据。OK，完工，本文完结，拜拜。</p><p>汗，才不会那么便宜呢！如果你是用传统的glVertex3f之类的，的确以上可谓全部。但我是要用VBO来渲染呢，VBO。在[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/obj-model-format-import-and-render-2.html">OBJ模型文件的结构、导入与渲染Ⅱ</a>]里我提到应用VBO的两大点准绳：一VBO一纹理这个不用考虑了，一个md2文件才一个纹理。问题是<a href="#points">上面提到的</a>第6点：位置和纹理坐标各一套索引，不符合第2个准绳：一份VBO里的各顶点属性VBO（不包括索引VBO）的大小应该一致。不要以为把纹理坐标一个个跟顶点位置配对就可以了，考虑这情况：顶点A（3.8, 4.2, 5.0）是2个面的共点，第一个面在该点的纹理坐标（0.84,0.36）第二个面在该点的纹理坐标（0.74, 0.11）。在MD2这种一张纹理还得兼顾模型各个部位的格式里，这种情况是十分常见的。在用索引的时候索引到这个点怎么办，是用第一个纹理坐标还是第二个？</p><p>是的，导入数据方便快速是一回事，怎么转化为用于存储的数据结构是另一回事：推倒重来。</p><ol start="1" class="dp-c" style="margin-top: -5px !important; margin-right: 0px !important; margin-bottom: 1px !important; margin-left: 5px !important; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; list-style-type: decimal; list-style-position: initial; list-style-image: initial; background-color: rgb(255, 255, 255); border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; "><span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//标识独立顶点的结构体(不含法线信息)</span></span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">typedef&nbsp;<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">struct</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;tagVertInfo</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">{</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;tagVertInfo(<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">const</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;VertPosInfo&nbsp;&amp;pos,&nbsp;</span><span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">const</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;TexcoordInfo&nbsp;&amp;tc)</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;InfoVertPos&nbsp;=&nbsp;pos;&nbsp;InfoTexcoord&nbsp;=&nbsp;tc;&nbsp;}</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;VertPosInfo&nbsp;&nbsp;InfoVertPos;</span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;TexcoordInfo&nbsp;InfoTexcoord;</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">}tVertInfo;</span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); ">&nbsp;</li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; "><span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//&nbsp;帧信息</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">typedef&nbsp;<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">struct</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;tag3DFrame</span></span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">{</span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;std::vector&lt;Vector3&gt;&nbsp;&nbsp;&nbsp;Verts;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//&nbsp;对象的顶点位置</span></span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;Vector3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pNormals;&nbsp;<span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//&nbsp;对象的顶点法线</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">}t3DFrame;</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); ">&nbsp;</li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; "><span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//&nbsp;模型信息结构体</span></span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">typedef&nbsp;<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">struct</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;tag3DModel&nbsp;</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">{</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">bool</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bIsTextured;</span><span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//&nbsp;是否使用纹理</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">int</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nNumIndexes;</span><span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//&nbsp;顶点信息索引数目</span></span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">int</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nNumPosVBOs;</span><span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//&nbsp;顶点位置VBO数目</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;Md2Header&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MD2Header;&nbsp;&nbsp;<span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//&nbsp;MD2头文件</span></span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;std::vector&lt;TexCoord&gt;&nbsp;&nbsp;&nbsp;Texcoords;&nbsp;&nbsp;<span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//&nbsp;对象帧&nbsp;-&nbsp;顶点纹理坐标信息</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;t3DFrame&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pFrames;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//&nbsp;对象帧&nbsp;-&nbsp;顶点位置/法线信息</span></span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">short</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pIndexes;&nbsp;&nbsp;&nbsp;</span><span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//&nbsp;对象的顶点索引</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;GLuint&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*pPosVBO;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//&nbsp;顶点位置VBO句柄</span></span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp; &nbsp;......</span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">}t3DModel;</span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); ">&nbsp;</li></ol><ol start="1" class="dp-c" style="margin-top: -5px !important; margin-right: 0px !important; margin-bottom: 1px !important; margin-left: 5px !important; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; list-style-type: decimal; list-style-position: initial; list-style-image: initial; background-color: rgb(255, 255, 255); color: rgb(92, 92, 92); border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); ">&nbsp;</li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//导入文件数据</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); ">&nbsp;</li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; "><span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//&nbsp;缓存当前对象的索引</span></span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">std::map&lt;tVertInfo,&nbsp;unsigned&nbsp;<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">short</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&gt;&nbsp;vObjectIndexMap;</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); ">&nbsp;</li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;<span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//填充模型信息</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); ">&nbsp;</li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">pModel-&gt;pIndexes&nbsp;=&nbsp;<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">new</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;unsigned&nbsp;</span><span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">short</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">[pModel-&gt;MD2Header.nNumFaces&nbsp;*&nbsp;VERTEX_OF_FACE];&nbsp;&nbsp;&nbsp;</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); ">&nbsp;</li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">pModel-&gt;pFrames&nbsp;&nbsp;=&nbsp;<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">new</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;t3DFrame[pModel-&gt;MD2Header.nNumFrames];</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); ">&nbsp;</li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">VertPosInfo&nbsp;&nbsp;vCurVertPos;</span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">TexcoordInfo&nbsp;vCurTexcoord;</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; "><span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">int</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nCurFaceVertIndex&nbsp;=&nbsp;0;</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; "><span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">int</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nCurIndexDataIdx&nbsp;&nbsp;=&nbsp;0;</span></span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; "><span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">for</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">(</span><span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">int</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;pModel-&gt;MD2Header.nNumFaces;&nbsp;++i)</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">{</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">for</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">(</span><span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">int</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;j&nbsp;=&nbsp;0;&nbsp;j&nbsp;&lt;&nbsp;VERTEX_OF_FACE;&nbsp;++j)</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nCurFaceVertIndex&nbsp;=&nbsp;pFaceInfo[i].nVertIndex[j];</span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); ">&nbsp;</li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vCurVertPos&nbsp;&nbsp;=&nbsp;pframeInfo[0].frameVertexInfo[nCurFaceVertIndex].vertSrc;</span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vCurTexcoord&nbsp;=&nbsp;pTexcoordInfo[pFaceInfo[i].nTexcoordIndex[j]];</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); ">&nbsp;</li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::map&lt;tVertInfo,&nbsp;unsigned&nbsp;<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">short</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&gt;::iterator&nbsp;pFind&nbsp;</span></span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;vObjectIndexMap.find(tVertInfo(vCurVertPos,&nbsp;vCurTexcoord));</span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); ">&nbsp;</li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">if</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">(vObjectIndexMap.end()&nbsp;!=&nbsp;pFind)</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pModel-&gt;pIndexes[nCurIndexDataIdx++]&nbsp;=&nbsp;pFind-&gt;second;&nbsp;<span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//索引指向重复的信息的位置</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">else</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//计算各帧的顶点位置</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">for</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">(</span><span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">int</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;k&nbsp;=&nbsp;0;&nbsp;k&nbsp;&lt;&nbsp;pModel-&gt;MD2Header.nNumFrames;&nbsp;++k)</span></span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pModel-&gt;pFrames[k].Verts.push_back(Vector3(</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pframeInfo[k].fScale[0]&nbsp;*&nbsp;pframeInfo[k].frameVertexInfo[nCurFaceVertIndex].vertSrc.x</span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+&nbsp;pframeInfo[k].fTranslate[0],&nbsp;...,&nbsp;&nbsp;...));</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); ">&nbsp;</li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//计算顶点纹理坐标(每帧一致)</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pModel-&gt;Texcoords.push_back(TexCoord(<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">float</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">(vCurTexcoord.u)&nbsp;/&nbsp;pModel-&gt;MD2Header.nSkinWidth,</span></span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">float</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">(vCurTexcoord.v)&nbsp;/&nbsp;pModel-&gt;MD2Header.nSkinHeight));</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); ">&nbsp;</li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//为新加的信息的位置添加新索引</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pModel-&gt;pIndexes[nCurIndexDataIdx++]&nbsp;=&nbsp;pModel-&gt;Texcoords.size()&nbsp;-&nbsp;1;</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); ">&nbsp;</li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//缓存查询表</span></span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vObjectIndexMap.insert(std::pair&lt;tVertInfo,&nbsp;unsigned&nbsp;<span class="keyword" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 102, 153); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; font-weight: bold; ">short</span><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&gt;(tVertInfo(vCurVertPos,&nbsp;vCurTexcoord),&nbsp;</span></span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pModel-&gt;Texcoords.size()&nbsp;-&nbsp;1));</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">&nbsp;&nbsp;&nbsp;&nbsp;}</span></li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">}</span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); ">&nbsp;</li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">pModel-&gt;nNumIndexes&nbsp;=&nbsp;nCurIndexDataIdx;</span></li>    <li class="alt" style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(255, 255, 255); color: inherit; line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); ">&nbsp;</li>    <li style="margin-top: 0px !important; margin-right: 0px !important; margin-bottom: 0px !important; margin-left: 0px !important; padding-top: 0px !important; padding-right: 3px !important; padding-bottom: 0px !important; padding-left: 10px !important; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: solid; border-width: initial; border-color: initial; list-style-type: decimal-leading-zero; list-style-image: initial; list-style-position: outside !important; background-color: rgb(248, 248, 248); color: rgb(92, 92, 92); line-height: 14px; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-left-width: 3px; border-left-color: rgb(108, 226, 108); "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: black; background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; "><span class="comment" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; color: rgb(0, 130, 0); background-color: inherit; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; border-width: initial; border-color: initial; ">//清除导入文件数据</span></span></li></ol><p>&nbsp;之后计算法线数据，生成VBO，就跟3DS，OBJ类似了（[<a target="_blank" href="http://www.zwqxin.com/archives/opengl/idexed-vbo-for-model-3ds-rendering.html">用Indexed-VBO渲染3DS模型</a>]  [<a target="_blank" href="http://www.zwqxin.com/archives/opengl/obj-model-format-import-and-render-2.html">OBJ模型文件的结构、导入与渲染Ⅱ</a>]）。帧数据（位置、法线）的VBO有两套方案：一是每关键帧一个位置VBO一个法线VBO，渲染时候直接换VBO来绑定就好了；二是只生成两个位置VBO和两个法线VBO，在换关健帧的时候也重新给VBO传输数据。存储上的优劣是显而易见的：前者在传输完数据就可以扔掉内存中的帧数据了（位置和法线），但是数据都往VBO去了，一个200帧的MD2模型共需要400个VBO；后者要把帧数据都留在内存，但是同情形下只需4个VBO。前者利于CPU后者利于GPU。执行速度方面，后者要重传VBO数据，明显更浪费点CPU，但是这里我用的是双缓冲策略，一者在使用中的时候另一者可传输数据，只要关健帧之间的时间间隔不要太离谱（譬如0.1s以下），觉得FPS上不会有太大区别（模型特别巨型则另说）&mdash;&mdash;总之两者都实现了（在Import函数参数里指定，或者后者可转为前者，逆转不能），就是按实际需求情况来了。</p><p>Animation帧动画方面，建立一个时间plot给它更新就好了。在插值上，可以利用CPU时间来插（严重不推荐），也可以用Shader插：简单的先行插值函数mix。ZWModelMD2既有shader版本也有非shader版本，这个不怎么复杂。因为至少有两个VBO，所以shader里可以有两个position attribute和两个normal attribute（关于怎么关联attribute变量数据，看此文：[<a target="_blank" href="http://www.zwqxin.com/archives/shaderglsl/conmunication-between-opengl-glsl.html">OpenGL与GLSL之间变量的传递小记</a>]），当然了，还有一个表征关健帧之间过渡完成百分比的融合度unifrom：<span class="Apple-style-span" style="font-family: Consolas, 'Courier New', Courier, mono, serif; font-size: 12px; line-height: 14px; ">u_fBlender</span>。</p><div class="HighLighter" contenteditable="false"><div contenteditable="false" class="dp-highlighter"><div class="bar">&nbsp;</div><ol start="1" class="dp-c">    <li class="alt"><span><span class="comment">//vertex&nbsp;shader：</span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;vec3&nbsp;pos&nbsp;=&nbsp;mix(attrib_position,&nbsp;attrib_nextposition,&nbsp;u_fBlender);</span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;gl_Position&nbsp;=&nbsp;gl_ModelViewProjectionMatrix&nbsp;*&nbsp;vec4(pos,&nbsp;1.0);</span></li></ol></div></div><p>&nbsp;三个帧速调用：</p><div class="HighLighter" contenteditable="false"><div contenteditable="false" class="dp-highlighter"><div class="bar">&nbsp;</div><ol start="1" class="dp-c">    <li class="alt"><span><span class="keyword">void</span><span>&nbsp;&nbsp;&nbsp;SetAnimationFrames(unsigned&nbsp;</span><span class="keyword">int</span><span>&nbsp;nStartFrame,&nbsp;unsigned&nbsp;</span><span class="keyword">int</span><span>&nbsp;nEndFrame,&nbsp;</span><span class="keyword">float</span><span>&nbsp;fSecondsPerKeyFrame);</span></span></li>    <li>&nbsp;</li>    <li class="alt"><span><span class="keyword">void</span><span>&nbsp;&nbsp;&nbsp;SetStaticFrame(unsigned&nbsp;</span><span class="keyword">int</span><span>&nbsp;nStaticFrame);</span></span></li>    <li>&nbsp;</li>    <li class="alt"><span><span class="keyword">void</span><span>&nbsp;&nbsp;&nbsp;SetAnimationAllFrames(</span><span class="keyword">float</span><span>&nbsp;fSecondsPerKeyFrame);</span></span></li></ol></div><div contenteditable="false" class="c#" style="display:none"><pre>	void   SetAnimationFrames(unsigned int nStartFrame, unsigned int nEndFrame, float fSecondsPerKeyFrame);	void   SetStaticFrame(unsigned int nStaticFrame);	void   SetAnimationAllFrames(float fSecondsPerKeyFrame);</pre></div><div contenteditable="false"><link href="/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p style="text-align: center; "><a target="_blank" href="http://www.zwqxin.com/archives/opengl/md2-model-format-import-animation.html"><img alt="MD2格式模型的格式、导入与帧动画" src="https://lh4.googleusercontent.com/_lYWT-2PnV0s/TV1OsfFJseI/AAAAAAAADPQ/ffsVOM2EkgQ/MD2Models20100217.jpg" /></a></p><p>Copyright © 2008</p><p><a href="http://www.zwqxin.com/archives/opengl/md2-model-format-import-animation.html" target="_blank">继续阅读《MD2格式模型的格式、导入与帧动画》的全文内容...</a></p><p>分类: <a href="http://www.zwqxin.com/archives/opengl.html">OpenGL技术</a> | Tags: <a href="http://www.zwqxin.com/catalog.asp?tags=%E6%A8%A1%E5%9E%8B">模型</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=MD2">MD2</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=VBO">VBO</a>&nbsp;&nbsp;<a href="http://www.zwqxin.com/catalog.asp?tags=shader">shader</a>&nbsp;&nbsp; | <a href="http://www.zwqxin.com/archives/opengl/md2-model-format-import-animation.html#comment" target="_blank">添加评论</a>(1)</p><h3>相关文章:</h3><ul><li><a href="http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html">shader复习与深入:HDR(高动态范围)</a> (2012-1-26 14:50:43)  </li><li><a href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-2.html">MD5模型的格式、导入与顶点蒙皮式骨骼动画II</a> (2011-10-7 17:11:7)  </li><li><a href="http://www.zwqxin.com/archives/opengl/model-md5-format-import-animation-1.html">MD5模型的格式、导入与顶点蒙皮式骨骼动画I</a> (2011-10-6 21:14:49)  </li><li><a href="http://www.zwqxin.com/archives/opengl/vao-and-vbo-stuff.html">AB是一家?VAO与VBO</a> (2011-10-1 17:12:38)  </li><li><a href="http://www.zwqxin.com/archives/opengl/multisample-fbo-antialiasing.html">多重采样(MultiSample)下的FBO反锯齿</a> (2011-9-25 16:55:35)  </li></ul>]]></description><category>OpenGL技术</category><comments>http://www.zwqxin.com/archives/opengl/md2-model-format-import-animation.html#comment</comments><wfw:comment>http://www.zwqxin.com/</wfw:comment><wfw:commentRss>http://www.zwqxin.com/feed.asp?cmt=90</wfw:commentRss><trackback:ping>http://www.zwqxin.com/cmd.asp?act=tb&amp;id=90&amp;key=aba73f80</trackback:ping></item></channel></rss>

