引擎设计跟踪(九) 3DS MAX 导出插件
1. SDK和工程配置的什么的就不多说了,安装完SDK并且把工程模板复制到VC文件夹里,就可以根据模板创建工程了.
2.Ogre的导出插件
为了学习Ogre的MAX导出,下了最新的Ogre, v1.81大概.
对Ogre的导出感到很好奇, 他好像没有直接导出二进制,而是导出了xml,据说有另外的命令行工具把xml转成二进制.
还有,Ogre的官方插件, 把所有三角形共享的顶点都重复了一次,也就是说,每个三角形都有自己唯一的顶点,按它文档说明,这是为了处理多维材质时,
一个顶点有不同uv和法线,材质等属性的问题, 但是我觉得只需要复制重叠的边缘顶点就可以了,而且
即便是重复每个顶点,我记得Ogre的Mesh是按不同的材质分成不同的SubMesh的, 但在代码里面没有看到按多维子材质分组.
还有,Max的多维子材质被导出成了multi-pass,即每个子材质是一个pass,这个我也很不理解,
因为一个pass是针对该材质的所有几何数据的, 但Max的子材质貌似是分到不同的面上去的,即一个子材质对应该材质的所有几何数据中的一部分(或者全部).
或许是我的理解有问题吧.
3.切空间的导出.
根据Max的文档, 切空间向量只有在使用平滑组(smoothing group)的时候才会被计算, 问了一个朋友, 以前的美术同事, 他说现在平滑组基本不怎么用了, 所以最好的方法还是自己算. 也许可以手动调用max接口,生成平滑组
DllExport void AutoSmooth (float angle, BOOL useSel, BOOL preventIndirectSmoothing=FALSE);
但我手生,不知道这样会不会对artist有影响,所以暂不考虑.
第一个参考:
http://www.terathon.com/code/tangent.html
里面有导出切空间并且处理镜像的方法.
关于切空间,谈谈个人的理解.一个面有一个法线,无数个切线,理论上,这个法线和任何两个垂直的切线都可以构成正交的"切空间", 然而, 一般说的切空间的两个切线,是沿着空间几何表面的纹理的U和V方向上的两条空间切线.顺便,binormal这个叫法,个人觉得叫做bitangent更合适, 因为法线是唯一的,切线不是.上面的链接中也提到了这一点,大概原因是在曲线相关的术语中,是tagent,binormal,normal,但这个用法被(误)用到了面的范畴(切空间).
第二个参考: 龚敏敏大大的文章: 压缩tangent frame
http://www.opengpu.org/forum.php?mod=viewthread&tid=10467
思考:
为什么用了quaternion的情况下,三个向量都有了,为什么还要保存镜像符号, 而不是直接把bitangent取反?
答:bitangent取反以后得到了三个向量需要的最终向量,但是非正交了,不能用quaternion保存了.
更正: bitangent取反以后仍然是三个正交基, 但还不确定这种方法为什么不行,也许真的可以, 准备试一下.
以前镜像保存在tangent.w里面是因为只用了两个向量,如果把tangent取反,虽然cross以后得到的bitangent对了,但是tangent已经反了...而用了quaternion以后,理论上可以直接取反一个向量,所以应该不需要保存镜像符号.
第三个参考: 作者是提问的,但也提到了他的步骤,还有相关的问题.
http://www.gamedev.net/topic/347799-mirrored-uvs-and-tangent-space-solved/
其中一个问题就是镜像的UV,在两边镜像的衔接出(uv-mirror center line), 共享的顶点有两个tangent space, 一个是非镜像部份,一个镜像部份.
一般的导出,没有额外处理的,渲染会有缝的,见下图.(顺便搜到了Maya里面有专门处理这个问题的导出选项)
上图中,右边是镜像的UV导出的切空间,可以看到中间的一条缝,左边的只是加了detail normal盖住了缝.
图片出处:
http://wiki.polycount.com/NormalMap/#UV_Coordinates
这个问题只是原帖中,下面回答的人提醒的,但作者已经处理了,处理方法值得借鉴:
(前面的一些操作blah blah跟这个问题无关,我就不说了)
先根据镜像与否,把顶点/三角形分成两个组, 镜像中心顶点被重复放在两个组里面,然后再分组处理.
这个问题其实也是相同顶点的渲染属性不同,需要复制顶点的问题.
顺便贴一下作者的步骤,没时间翻译了
-First, I pass an array of positions, UV's, and indicies into my "mesh mender".
-I do some pre-processing to generate triangle connectivity and such
-I generate a per-triangle normal and tangent/bitangent, using the methods below:
(code fragment) //作者的代码被我省略了, 原链接(参考三)内有.
-The triangles are divided into smoothing groups based on a normal threshold
-Verticies that lie on a smoothing group edge are duplicated
-Per-vertex
normals are calculated by summing up the normals of each triangle that
shares that vertex and belongs to the same smoothing group, then
normalizing
-Triangles are again divided into smoothing groups, but
this time there are only two and they are determined by the handedness
of the tangent and bitangent.
-Verticies are again duplicated based
on smoothing group. This process is not affected by splits made in the
normal smoothing process.
-Per-Vertex tangents/bitangents are calculated in the same fasion as the normals.
-The tangents are orthogonalized with the normal
-The
new vertex vectors are mapped onto the original array (adding any new
verts that were created) and indicies are adjusted accordingly.
更新:
使用quaternion时, 不能取反bitangent. 本来一个正交空间的三个基构造的quaternion可以被解出来.
但是取反一个轴以后, 手系改变的情况下不能使用quaternion保存了, 解出的三个轴向量也不对. 笔者数学不是特别好, 不知道这个是quaternion的什么性质.
比如如下代码:
srand((unsigned) time(NULL)); Vector3 x( rand(), rand(), rand() ); x.normalize(); Vector3 y( rand(), rand(), rand() ); Vector3 z = x.crossProduct(y); z.normalize(); y = z.crossProduct(x); y.normalize(); scalar t = x.dotProduct(y); assert( t < 1e-6 ); t = x.dotProduct(z); assert( t < 1e-6 ); Matrix33 m(x, y, z); //Matrix33 m(x, -y, z); Quaternion q(m); q.normalize(); Vector3 x2 = q*Vector3::UNIT_X; Vector3 y2 = q*Vector3::UNIT_Y; Vector3 z2 = q*Vector3::UNIT_Z; Vector3 x3 = Vector3::UNIT_X*m; Vector3 y3 = Vector3::UNIT_Y*m; Vector3 z3 = Vector3::UNIT_Z*m;
用矩阵解出的x3 == x, y3== y, z3==z
用四元数解出来的x2== x, y2== y, z2 ==y.
但是如果取反y轴: Matrix33 m(x, -y, z) 之后,
矩阵解出来仍然正确, 但是四元数的已经不一样了.
所以只能把镜像符号保存到w分量中.
另外再记录两个链接方便以后查资料.
//crytek网站上tangent space的计算, 带有代码和pdf
http://crytek.com/cryengine/presentations/triangle-mesh-tangent-space-calculation
//nvidia网站上meshmender(原工具找不到了)的pdf.