Small Tips : 如何整合3DS模型中的Obj

  lib3ds大家看了园子里发过的Tutorial后可能都会使用了,这里我展示了一个小小的优化技巧,把一个3DS文件中所有Objects的顶点、纹理坐标、向量都捆绑在一个Batch里进行渲染。局限是,如果你的3DS文件使用了多个贴图,那么还是无法使用这个技巧。或者你如同John Camark一样,发明那个MetaTexture技术,把多个贴图放到一个纹理中。
  我对比过STL版本的和C版本的代码,STL慢了不止一秒,而C代码使用了最快速与直接的memcpy,效率当然比STL容器高的多,不过代价是,调试非常麻烦,动不动就出错。
  关键是把所有的索引Index放在一起,正确的组合所有的顶点。代码如下,有些脏:

 1static void InitModel()
 2{
 3    Lib3dsFile* file = 0;
 4    file = lib3ds_file_load("E:\\MyModels\\ELEPHANT\\ELEPHANT.3DS");
 5
 6    deque<GLfloat> _V;
 7    deque<GLfloat> _T;
 8    deque<GLushort> _I;
 9    deque<GLfloat> _N;
10
11    deque<GLushort> _n;
12    _n.push_front(0);
13    _n.pop_back();
14    for(deque<ushort>::reverse_iterator r_itr = _n.rbegin();r_itr!=_n.rend();r_itr++){
15        for( deque<ushort>::reverse_iterator f_itr = r_itr + 1; f_itr != _n.rend() ;f_itr++)
16            *r_itr += *f_itr;
17        //printf("%d\n",*r_itr);
18    }

19    //Get All meshes information
20    Lib3dsMesh *= 0;
21    int VerNum = 0,TexNum = 0,TriNum = 0,IdxNum=0;
22
23    int MeshNum = 0;
24    for( m=file->meshes; m!=0; m=m->next){
25        VerNum += m->points;
26        TexNum += m->texels;
27        TriNum += m->faces;
28        IdxNum += m->faces*3;
29        MeshNum++;
30        _n.push_back(m->points);
31    }
;
32    VerticesPtr = new GLfloat[VerNum * 3];
33    TexCoordsPtr = new GLfloat[TexNum * 2];
34    NormalPtr = new GLfloat[VerNum * 3];
35    //NormalPtr = new GLfloat[TriNum * 3 * 3];
36    IndexPtr = new GLushort[IdxNum];
37    IndexNum = IdxNum;
38    
39
40    printf("<---   mesh num : %d,tri,pointsNum : %d  --->\n",MeshNum,VerNum);
41
42    _n.push_front(0);
43    _n.pop_back();
44    for(deque<ushort>::reverse_iterator r_itr = _n.rbegin();r_itr!=_n.rend();r_itr++){
45        for( deque<ushort>::reverse_iterator f_itr = r_itr + 1; f_itr != _n.rend() ;f_itr++)
46            *r_itr += *f_itr;
47        //printf("%d\n",*r_itr);
48    }

49
50    int offset[4= {0,0,0,0};
51    int j = 0;
52    for( m=file->meshes; m!=0; m=m->next){
53        //copy VerticesPtr
54        forint i = 0;i<m->points;i++ ){
55            memcpy(&(VerticesPtr[offset[0]*3]),&(m->pointL[i].pos[0]),sizeof(float)*3);
56            offset[0]++;
57        }
;
58        //copy Texcoords
59        forint i=0;i<m->texels;i++ ){
60            memcpy(&(TexCoordsPtr[offset[1]*2]),&(m->texelL[i][0]),sizeof(float)*2);
61            offset[1]++;
62        }
;
63
64        Lib3dsVector* normalL = (Lib3dsVector*)malloc(3*sizeof(Lib3dsVector)*m->faces);
65        lib3ds_mesh_calculate_normals(m,normalL);
66
67        forint i=0;i<m->faces;i++ ){
68            ushort _0 = m->faceL[i].points[0+ _n[j];
69            ushort _1 = m->faceL[i].points[1+ _n[j];
70            ushort _2 = m->faceL[i].points[2+ _n[j];
71
72            IndexPtr[ offset[2] ] = _0;
73            offset[2]++;
74            IndexPtr[ offset[2] ] = _1;
75            offset[2]++;
76            IndexPtr[ offset[2] ] = _2;
77            offset[2]++;
78            memcpy(&(NormalPtr[ _0 ]),&(normalL[i*3 + 0]),sizeof(float)*3);
79            memcpy(&(NormalPtr[ _1 ]),&(normalL[i*3 + 1]),sizeof(float)*3);
80            memcpy(&(NormalPtr[ _2 ]),&(normalL[i*3 + 2]),sizeof(float)*3);
81        }
;
82        printf("J : %d\t _n[j] : %d\n",j,_n[j]);
83        j++;
84
85        free(normalL);
86    }
;
87
88    for(int i=0;i<10;i++)
89        printf("%f %f %f\t",NormalPtr[i*3 + 0],NormalPtr[i*3 + 1],NormalPtr[i*3 + 2]);
90        //printf("%d ",IndexPtr[i]);
91    printf("IndexNum : %d\n",_I.size());
92
93    
94}
;

  解释一下思路。3DS文件如果有多个OBJ,那么每一个OBJ都会维护一个自己的索引Index,而且都是从0开始。如果我们仅仅把顶点放在一起,那么是没有意义的,无法得到完整的Mesh。所以我们就必须迭代计算前一个Obj有多少个顶点,并且把当前Obj的索引都加上前面的数据。举例如下。
    3个Obj:
    Obj          0      1      2
    顶点数 10    20    30
  三角形数目    5      8    14
  新索引起点    0      5    13

  deque容器我留在了代码中,如果你不放心可以使用它们来装载数据,看看速度究竟有多么的迟缓。

  如果每个Obj都有自己的纹理,那么就很麻烦了。在你的纹理加载代码中,需要额外的声明一个能够装得下所有纹理的“巨大纹理”,拷贝所有的图象数据到这个大纹理中,记得各自的位置。在整合模型的阶段,处理纹理坐标,根据各自的纹理所在“巨大纹理”图上的位置进行缩放。然后就OK了,还节省纹理通道,非常实用!
posted on 2007-05-11 19:29  Bo Schwarzstein  阅读(1333)  评论(0编辑  收藏  举报