zoukankan      html  css  js  c++  java
  • 引擎设计跟踪(九) 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镜像

    上图中,右边是镜像的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.

    https://developer.nvidia.com/sites/default/files/akamai/gamedev/docs/texture_space_on_real_models.pdf

  • 相关阅读:
    生成Ipa安装包的plist文件后生成下载链接
    ssh_key登录服务器,免密码登录
    Ruby中类的进阶(继承,private, public, protect)
    Ruby中的类
    Redis- redis.conf
    Active Job 基础
    rails框架配置
    rails中使用CarrierWave实现文件上传的功能
    Flask-SQLAlchemy
    Linux自动共享USB设备:udev+Samba
  • 原文地址:https://www.cnblogs.com/crazii/p/2997601.html
Copyright © 2011-2022 走看看