天龙八部生成地形mesh的源码

来源:互联网 发布:阿里云带宽怎么升级 编辑:程序博客网 时间:2024/04/28 02:50

有个网友说他把我csdn博客的零落代码拼起来搞了一周都没能够载入场景....

真的蛮辛苦的....天龙的地形用mesh自己做就好的,

以前我的部分源码效率有问题,因为我低估了tostring函数的开销,

这函数很变态....用io输出流来实现的,代码优雅但是效率就....

如果需要多次循环就不要使用它.

好了,发源码,随便说一句,csdn很烂.....提交老是失败,实在受不了~~~

头文件:

 

  1/**//*
  2**************************************************************************************************************
  3@fileName Terrain.h  
  4@remarks 用来创建地形,和保存地形相关信息
  5@author LYN 2009.10.1
  6***************************************************************************************************************
  7*/

  8#pragma once
  9
 10#include "TLBB.h"
 11#include <vector>
 12using namespace Ogre;
 13using std::vector;
 14
 15const uint TERRAIN_QUERY_MASK = 0x00000001// 地形查询掩码
 16const unsigned short MAIN_BINDING = 0;  // 主绑定
 17
 18/**//* 网格操作标志的枚举*/
 19enum Operate
 20{
 21    FLIP_HORIZINTAL = 1,   // 图片水平翻转,即左右翻转
 22    FLIP_VERTICAL = 2,     // 图片垂直翻转,即上下翻转
 23    ANTICLOCKWISE_90 = 4,  // 逆时针旋转90度
 24    FLIP_DIAGONAL = 8      // 三角形的对角线镜像,IndexOrder==0时就把左上的纹理坐标复制到右下,否则右上到左下
 25}
;
 26
 27/**//* 像素图信息
 28@remarks 保存的是每个网格的纹理图片ID和纹理坐标
 29*/

 30struct PixMap
 31{
 32    int textureId; 
 33    Real left;
 34    Real top;
 35    Real right;
 36    Real bottom;
 37}
;
 38
 39/**//* 高度图文件头信息*/
 40struct HeightMapHeader
 41{
 42    DWORD nMagic;
 43    DWORD nVersion; // 版本号
 44    int nWidth;
 45    int nHeight;
 46}
;
 47
 48/**//* 碰撞图文件头*/
 49struct WCollisionHeader
 50{
 51    DWORD nVersion;
 52    DWORD nNumber;  // 三角形数量
 53}
;
 54
 55/**//* 网格文件头信息*/
 56struct GridHeader
 57{
 58    DWORD nMagic;
 59    DWORD nVersion;
 60    int nWidth;
 61    int nHeight;
 62}
;
 63
 64/**//* 单个网格类
 65@remarks 1个网格就是一个正方,天龙八部的地形是根据网格信息拼接而成,但没有共享顶点,这样可以做很多层uv
 66*/

 67class GridInfo
 68{
 69public:
 70    // 第一层pixelmap的索引, 如果是7字节版本,读取后需交换高8位与低8位的值,
 71    // 需做如下操作 nFirstLayer = (nFirstLayer<<8)|(nFirstLayer>>8)
 72    short nFirstLayer;
 73
 74    // 对nFirstLayer的操作, 取值是上面几个定义的宏, 可以互相组合
 75    BYTE nFirstLayerOp;
 76
 77    // 第二层pixelmap的索引, 天龙八部的地表不算光照图有两层UV来融合
 78    short nSecondLayer;
 79
 80    // 对nSecondLayer的操作,取值同nFirstLayerOp
 81    BYTE nSecondLayerOp;
 82
 83    // 对格子的三角形的操作,可能取值如下, 0正常三角形索引, 1不同于正常的三角形索引
 84    BYTE IndexOrder;
 85}
;
 86
 87/**//* TLBBTerrain类
 88@remarks 用来生成地形
 89*/

 90class TLBBTerrain
 91{
 92public:
 93    /**//* 构造函数
 94    @param filename 地形文件名
 95    @param sceneMgr 场景管理器
 96    */

 97    TLBBTerrain(const String& filename, SceneManager* sceneMgr);
 98    ~TLBBTerrain(void);
 99
100    /**//* 生成地形
101    @remarks 生成地形,直接调用此方法直接可以生成地形.
102    */

103    void createTerrain(void);
104
105    /**//* 获得地图X方向的缩放*/
106    int getScaleX(voidconst;
107
108    /**//* 获得地图Y方向的缩放*/
109    int getScaleY(voidconst;
110
111    /**//* 获得地图Z方向的缩放*/
112    int getScaleZ(voidconst;
113
114    /**//* 获得地图X方向的大小*/
115    int getXSize(voidconst;
116
117    /**//* 获得地图Z方向的大小*/
118    int getZSize(voidconst;
119
120    /**//* 获得地图中心点*/
121    const Vector3& getCentre(voidconst;
122
123    /**//* 获得高度图数据*/
124    const vector<Real>& getHeightMapData(voidconst;
125
126    /**//* 获得手工材质的名字数组
127    @remarks 手动生成的材质换图的时候需要手工清除,所以保留他们的名字
128    */

129    const vector<String>& getManualMatData(voidconst;
130
131    /**//* 获得手工mesh的名字数组
132    @remarks 手动生成的mesh换图的时候需要手工清除,所以保留他们的名字
133    */

134    const vector<String>& getManualMeshData(voidconst;
135
136    /**//* 获得WCollision实体指针数组*/
137    const vector<Entity*>& getmWCollisionEntData(voidconst;
138
139protected:
140
141    /**//* 打开网格文件
142    @remarks 二进制流载入
143    @param filename 网格文件名
144    @param groupName 资源组名字
145    */

146    void openGridFile(const String& fileName, const String &groupName);
147
148    /**//* 打开高度图文件
149    @remarks 二进制流载入
150    @param filename 高度图文件名
151    @param groupName 资源组名字
152    */

153    void openHeightMapFile(const String &fileName, const String &groupName);
154
155    /**//* 翻转纹理图片
156    @remarks 对纹理图片的操作
157    */

158    void flipPicture(int op, Vector2& TL, Vector2& TR, Vector2& BL, Vector2& BR, int indexOrder);
159
160    /**//* 查找此网格的材质是否已经生成了
161    @remarks 如果存在就不用再生成
162    @param gridinfo 资源组名字
163    @param endIndex 结束的索引,控制查询范围
164    @return 如果已经生成了,就返回含有此材质的那个网格的索引, 否则返回-1
165    */

166    int findSameMaterial(GridInfo& gridinfo, int endIndex);  
167
168    /**//* 手工生成材质
169    @remarks 克隆材质模板,再更改纹理别名即可
170    */

171    void createManualMat(void);  
172
173    /**//* 获得顶点法线
174    @remarks 为了简单,只获得网格法线,暂时没有求顶点法线,如果要想效果更好,求平均即可得到顶点法线
175    @param x 顶点缩放后的x坐标
176    @param z 顶点缩放后的z坐标
177    @return 法线坐标
178    */

179    Vector3 getNormalAt(Real x, Real z) const
180
181    /**//* 生成地形tile
182    @remarks 直接操作硬件缓存生成地形mesh
183    @param startx  没有缩放的x起点坐标
184    @param startz 没有缩放的z起点坐标
185    @param tileSizeX tile X方向的大小, 虽然天龙的tilesize都是32,但有的图不是tile整数倍,可以更改此值生成随意大小的tile,
186    @param tileSizeZ tile Z方向的大小
187    @param matName 材质名字
188    */

189    bool createTileMesh(size_t startx, size_t startz, int tileSizeX, int tileSizeZ, const String& matName);
190
191    /**//* 生成地形tile
192    @remarks 用manualObject来做地形, 简单很多,经过测试和操作硬件缓存效率基本差不多,可以二选其一
193    @param startx  没有缩放的x起点坐标
194    @param startz 没有缩放的z起点坐标
195    @param tileSizeX tile X方向的大小, 虽然天龙的tilesize都是32,但有的图不是tile整数倍,可以更改此值生成随意大小的tile,
196    @param tileSizeZ tile Z方向的大小
197    @param matName 材质名字
198    */

199    void createTileManualObject(size_t startx, size_t startz, int tileSizeX, int tileSizeZ, const String& matName);
200
201    /**//* 生成WCollision
202    @remarks WCollision用来地形查询用,不用渲染出来,所以应该按区域分开生成多个WCollision,以减少查询的顶点数量
203    @param fileName  WCollision文件的名字
204    @param groupName 资源组
205    */

206    void createWCollision(const String &fileName , const String &groupName); 
207
208protected:
209
210    // 场景管理器
211    SceneManager* mSceneMgr;
212
213    // 地图分块大小
214    int mTileSize;
215
216    // 地图大小和缩放
217    int mXSize;
218    int mZSize;
219    int mScaleX;
220    int mScaleY;
221    int mScaleZ;
222
223    // 地图中心点位置
224    Vector3 mCentre;
225
226    // 是否有光照图
227    bool mHasLightMap;
228
229    // 光照图文件名
230    String mLightMapName;
231
232    // 材质数量
233    size_t mMaterialNum;     
234
235    // 高度图
236    vector<Real> mHeightMapData;    
237
238    // 网格信息
239    vector<GridInfo> mGridData;  
240
241    // 纹理
242    vector<String> mTextureData;   
243
244    // 像素映射图
245    vector<PixMap> mPixMapData;   
246
247    // 材质模板, 存储顺序:第一层,第一层光照图,第二层,第二层光照图
248    vector<String> mTemplateData;   
249    
250    // 雾
251    vector<String> mFogReplacementData; 
252    
253    // 手动生成的材质
254    vector<String> mManualMatData;    
255
256    // 地面实体(比如桥)的碰撞面数据
257    vector<Vector3> mWCollisionData;        
258
259    // 手动生成的mesh
260    vector<String> mManualMeshData;    
261
262    // WCollision
263    vector<Entity*> mWCollisionEntData;
264
265    // 地形文件名字
266    String mFileName;
267}
;
268


源文件部分重要代码:

 

  1//--------------------------------------------------------------------------------------------------------
  2int TLBBTerrain::findSameMaterial(GridInfo& gridinfo, int endIndex)
  3{
  4    // 网格比较
  5    for (int i = 0; i < endIndex; ++ i)
  6    {
  7
  8        if (mGridData[i].nFirstLayer < 0 )
  9        {
 10            continue;
 11        }

 12
 13        // 如果有第一层
 14        if (gridinfo.nFirstLayer >= 0)
 15        {
 16            // 第一层的纹理图片相同
 17            if (mPixMapData[gridinfo.nFirstLayer].textureId == mPixMapData[mGridData[i].nFirstLayer].textureId)
 18            {
 19                // 如果有第二层
 20                if (gridinfo.nSecondLayer >= 0)
 21                {
 22                    if (mGridData[i].nSecondLayer >= 0)
 23                    {    
 24                        // 第二层的纹理图片相同
 25                        if (mPixMapData[gridinfo.nSecondLayer].textureId == mPixMapData[mGridData[i].nSecondLayer].textureId)
 26                        {
 27                            return i;  // 一,二层的纹理图片都相同
 28                        }

 29                    }

 30                }

 31                else if (mGridData[i].nSecondLayer < 0)
 32                
 33                    return i; // 第一层的纹理图片相同
 34                }

 35            }

 36        }

 37        else
 38        {    
 39            // 如果第一层都没有纹理图片.用第0个网格的材质代替,不清楚为什么会没有纹理
 40            // 可能天龙有其他材质代替吧
 41            return 0;
 42        }

 43    }

 44    return -1// 没有找到相同材质
 45}

 46
 47//--------------------------------------------------------------------------------------------------------
 48void TLBBTerrain::createManualMat(void)
 49{
 50    // 先获得材质模板
 51    MaterialPtr materialTemplate1 = static_cast<MaterialPtr>(MaterialManager::getSingleton().getByName(mTemplateData[1]));
 52    MaterialPtr materialTemplate2 = static_cast<MaterialPtr>(MaterialManager::getSingleton().getByName(mTemplateData[3])); 
 53
 54    int tempIndex = -1;
 55    for (int i = 0; i < mXSize*mZSize; ++ i)
 56    {
 57        // 如果此材质已经存在
 58        if ((tempIndex = findSameMaterial(mGridData[i], i)) >= 0)
 59        {
 60            // 用已有材质存入数组
 61            mManualMatData.push_back(mManualMatData[tempIndex]);
 62        }

 63        else
 64        {    
 65            // 有第二层
 66            if (mGridData[i].nSecondLayer >= 0 && mGridData[i].nFirstLayer >= 0)
 67            
 68                // 拷贝第二层材质
 69                String newMaterialName = "material"+StringConverter::toString(mMaterialNum); // 材质名字
 70                MaterialPtr newMaterial = materialTemplate2->clone(newMaterialName);    // 克隆材质 
 71                AliasTextureNamePairList aliasList;          // 存储纹理别名的二叉树 
 72                String textureName1 = mTextureData[mPixMapData[mGridData[i].nFirstLayer].textureId];
 73                String textureName2 = mTextureData[mPixMapData[mGridData[i].nSecondLayer].textureId];
 74                aliasList["<layer0>"= textureName1;
 75                aliasList["<layer1>"= textureName2;
 76                if (mHasLightMap)
 77                {
 78                    aliasList["<lightmap>"= mLightMapName;
 79                }

 80                newMaterial->applyTextureAliases(aliasList);        // 用纹理别名更改纹理                                  
 81                mManualMatData.push_back(newMaterialName);    // 存入材质数组
 82            }

 83            else if (mGridData[i].nFirstLayer >= 0)
 84            {
 85                // 拷贝第一层材质
 86                String newMaterialName = "material"+StringConverter::toString(mMaterialNum);      // 材质名字
 87                MaterialPtr newMaterial = materialTemplate1->clone(newMaterialName);    // 克隆材质 
 88                AliasTextureNamePairList aliasList;           // 存储纹理别名的二叉树 
 89                String textureName1 = mTextureData[mPixMapData[mGridData[i].nFirstLayer].textureId];
 90                aliasList["<layer0>"= textureName1;
 91                if (mHasLightMap)
 92                {
 93                    aliasList["<lightmap>"= mLightMapName;
 94                }

 95                newMaterial->applyTextureAliases(aliasList);  // 用纹理别名更改纹理                                  
 96                mManualMatData.push_back(newMaterialName);     // 存入材质数组
 97
 98                
 99            }

100
101            ++ mMaterialNum;
102            
103        }

104    }

105}

106
107//--------------------------------------------------------------------------------------------------------
108Vector3 TLBBTerrain::getNormalAt(Real x, Real z) const
109{
110    int flip = 1;
111    int index = x + z*(mXSize+1);
112    Vector3 here(x, mHeightMapData[index], z);
113    Vector3 right;
114    Vector3 down;
115    // 边界
116    if (x >= mXSize)
117    {
118        flip *= -1;
119        right = Vector3(x-1, mHeightMapData[index-1], z);
120    }

121    else
122    {
123        right = Vector3(x+1, mHeightMapData[index+1], z);
124    }

125
126    if (z >= mZSize)
127    {
128        flip *= -1;
129        down = Vector3(x, mHeightMapData[index-mXSize-1], z-1);
130    }

131    else
132    {
133        down = Vector3(x, mHeightMapData[index+mXSize+1], z+1);
134    }

135    // 生成矢量
136    right -= here;
137    down -= here;
138
139    // 矢量正交,注意方向
140    Vector3 normal = flip * down.crossProduct(right);
141    normal.normalise();         // 归一化
142    return normal;
143}

144
145//--------------------------------------------------------------------------------------------------------
146void TLBBTerrain::createTileManualObject(size_t startx, size_t startz, int tileSizeX, int tileSizeZ, const String& matName)
147{
148    StringUtil::StrStreamType entName;
149    entName << "tile[" << startz << "]" << "[" << startx << "]" << matName;
150
151    ManualObject* mo = mSceneMgr->createManualObject(entName.str());
152
153    mo->begin(matName);
154
155    const Real width = 1;
156    int k = 0;
157    bool hasMesh = false;
158    int endx = startx + tileSizeX;
159    int endz = startz + tileSizeZ;
160    for (int z = startz; z < endz; ++ z)
161    {
162        for (int x = startx; x < endx; ++ x)
163        {
164            // 转换成一维数组索引
165            int index = x + z*mXSize; 
166            // 如果存在此材质
167            if (mManualMatData[index] == matName && mGridData[index].nFirstLayer >= 0)
168            {
169                hasMesh = true;
170
171                // 高度图坐标转换
172                int heightIndex = index + z;
173
174                // 第一层纹理坐标
175                int index1 = mGridData[index].nFirstLayer;
176                Real left1 = mPixMapData[index1].left;
177                Real right1 = mPixMapData[index1].right;
178                Real top1 = mPixMapData[index1].top;
179                Real bottom1 = mPixMapData[index1].bottom;
180                Vector2 left_top_1(left1, top1);
181                Vector2 right_top_1(right1, top1);
182                Vector2 right_bottom_1(right1, bottom1);
183                Vector2 left_bottom_1(left1, bottom1);
184                // 图片翻转等操作
185                if (mGridData[index].nFirstLayerOp != 0)
186                {
187                    flipPicture(mGridData[index].nFirstLayerOp, left_top_1, right_top_1, 
188                        left_bottom_1, right_bottom_1, mGridData[index].IndexOrder);
189                }

190
191                // 第二层纹理坐标
192                Vector2 left_top_2;
193                Vector2 right_top_2;
194                Vector2 right_bottom_2;
195                Vector2 left_bottom_2;
196                if (mGridData[index].nSecondLayer >= 0)
197                {
198                    int index2 = mGridData[index].nSecondLayer;
199                    Real left2 = mPixMapData[index2].left;
200                    Real right2 = mPixMapData[index2].right;
201                    Real top2 = mPixMapData[index2].top;
202                    Real bottom2 = mPixMapData[index2].bottom;
203                    left_top_2 = Vector2(left2, top2);
204                    right_top_2 = Vector2(right2, top2);
205                    right_bottom_2 = Vector2(right2, bottom2);
206                    left_bottom_2 = Vector2(left2, bottom2);
207                    if (mGridData[index].nSecondLayerOp != 0)
208                    {
209                        flipPicture(mGridData[index].nSecondLayerOp, left_top_2, right_top_2, 
210                            left_bottom_2, right_bottom_2, mGridData[index].IndexOrder);
211                    }

212                    
213                }

214
215                // 光照图纹理坐标
216                Vector2 left_top_3;
217                Vector2 right_top_3;
218                Vector2 right_bottom_3;
219                Vector2 left_bottom_3;
220                if (mHasLightMap)
221                {
222                    Real left3 = (Real)x / (Real)mXSize;   
223                    Real right3 = left3 + 1/(Real)mXSize;
224                    Real top3 = (Real)z / (Real)mZSize;
225                    Real bottom3 = top3 + 1/(Real)mZSize;
226                    left_top_3 = Vector2(left3, top3);
227                    right_top_3 = Vector2(right3, top3);
228                    right_bottom_3 = Vector2(right3, bottom3);
229                    left_bottom_3 = Vector2(left3, bottom3);
230                }

231
232                // 点0
233                mo->position(x*mScaleX, mHeightMapData[heightIndex]*mScaleY, z*mScaleZ);
234                mo->normal(getNormalAt(x, z));
235                mo->textureCoord(left_top_1);
236                if (mGridData[index].nSecondLayer >= 0)
237                {
238                    mo->textureCoord(left_top_2);
239                }

240                if (mHasLightMap)
241                {
242                    mo->textureCoord(left_top_3);     // 光照图纹理坐标
243                }

244
245                // 点1
246                mo->position((x+width)*mScaleX, mHeightMapData[heightIndex+1]*mScaleY, z*mScaleZ);
247                mo->normal(getNormalAt(x+width, z));
248                mo->textureCoord(right_top_1);
249                if (mGridData[index].nSecondLayer >= 0)
250                {
251                    mo->textureCoord(right_top_2);
252                }

253                if (mHasLightMap)
254                {
255                    mo->textureCoord(right_top_3);   // 光照图纹理坐标
256                }

257
258                // 点2
259                mo->position((x+width)*mScaleX, mHeightMapData[heightIndex+mXSize+2]*mScaleY, (width+z)*mScaleZ);
260                mo->normal(getNormalAt(x+width, z+width));
261                mo->textureCoord(right_bottom_1);
262                if (mGridData[index].nSecondLayer >= 0)
263                {
264                    mo->textureCoord(right_bottom_2);
265                }

266                if (mHasLightMap)
267                {
268                    mo->textureCoord(right_bottom_3);  // 光照图纹理坐标
269                }

270
271
272                // 点3
273                mo->position(x*mScaleX, mHeightMapData[heightIndex+mXSize+1]*mScaleY, (width+z)*mScaleZ);
274                mo->normal(getNormalAt(x, z+width));
275                mo->textureCoord(left_bottom_1);
276                if (mGridData[index].nSecondLayer >= 0)
277                {
278                    mo->textureCoord(left_bottom_2);
279                }

280                if (mHasLightMap)
281                {
282                    mo->textureCoord(left_bottom_3);   // 光照图纹理坐标
283                }

284
285                // 三角形索引顺序
286                int offset = k * 4;
287                if (mGridData[index].IndexOrder == 0)
288                // 正常顺序
289                    mo->triangle(offset+1, offset, offset+3);
290                    mo->triangle(offset+1, offset+3, offset+2);
291                }

292                else
293                {
294                    mo->triangle(offset, offset+3, offset+2);
295                    mo->triangle(offset, offset+2, offset+1);
296                }

297
298                ++ k;
299            }

300        }

301    }

302
303    mo->end();
304
305    // 此tile含有数据才生成
306    if (hasMesh)
307    {
308        mSceneMgr->getRootSceneNode()->createChildSceneNode(mCentre)->attachObject(mo);
309        mo->setCastShadows(false);
310        mo->setQueryFlags(TERRAIN_QUERY_MASK);
311    }

312    else
313    {
314        mSceneMgr->destroyManualObject(entName.str());
315    }

316}

317
318//--------------------------------------------------------------------------------------------------------
319bool TLBBTerrain::createTileMesh(size_t startx, size_t startz, int tileSizeX, int tileSizeZ, const String& matName)
320{
321    const Real width = 1;
322    int k = 0;
323    bool hasMesh = false;
324    int endx = startx + tileSizeX;
325    int endz = startz + tileSizeZ;
326
327    // 先获得mesh顶点的数量
328    size_t vCount = 0;
329    bool hasSecondLayer = false;
330    for (int z = startz; z < endz; ++ z)
331    {
332        for (int x = startx; x < endx; ++ x)
333        {
334            int index = x + z*mXSize; // 转换成一维数组索引
335
336            // 
337            if (mManualMatData[index] == matName && mGridData[index].nFirstLayer >= 0)
338            {
339                vCount += 4;
340                
341                // 此材质是否有第二层
342                if (!hasSecondLayer)
343                {
344                    if (mGridData[index].nSecondLayer >= 0)
345                    {
346                        hasSecondLayer = true;
347                    }

348                }

349            }

350        }

351    }

352
353    if (vCount == 0)
354    {
355        return false;
356    }

357
358    // 生成mesh
359    StringUtil::StrStreamType meshName;
360    meshName << "gridMesh[" << startz << "]" << "[" << startx << "]" << matName;
361    MeshPtr mesh = MeshManager::getSingleton().createManual(meshName.str(), "TLBB");
362    mManualMeshData.push_back(meshName.str());
363
364    // 子mesh
365    SubMesh* sm = mesh->createSubMesh();
366    sm->useSharedVertices = false;   // 不使用共享顶点
367    sm->vertexData = new VertexData();
368    sm->vertexData->vertexCount = vCount;
369
370    // 顶点结构描述
371    VertexDeclaration* decl = sm->vertexData->vertexDeclaration;
372    size_t offset = 0;
373    // 顶点位置
374    decl->addElement(MAIN_BINDING, offset, VET_FLOAT3, VES_POSITION);
375    offset += VertexElement::getTypeSize(VET_FLOAT3);
376    // 法线
377    decl->addElement(MAIN_BINDING, offset, VET_FLOAT3, VES_NORMAL);
378    offset += VertexElement::getTypeSize(VET_FLOAT3);
379    // 纹理坐标
380    decl->addElement(MAIN_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0); 
381    offset += VertexElement::getTypeSize(VET_FLOAT2);
382    if (hasSecondLayer) // 如果有第二层
383    {
384        decl->addElement(MAIN_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 1);
385        offset += VertexElement::getTypeSize(VET_FLOAT2);
386        if (mHasLightMap)
387        {
388            decl->addElement(MAIN_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 2);
389            offset += VertexElement::getTypeSize(VET_FLOAT2);
390        }

391    }

392    else
393    {
394        if (mHasLightMap)
395        {
396            decl->addElement(MAIN_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 1);
397            offset += VertexElement::getTypeSize(VET_FLOAT2);
398        }

399    }

400
401    // 顶点缓存
402    HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton()
403        .createVertexBuffer(offset, vCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
404    // 获得顶点缓存的地址
405    float* pReal = static_cast<float*>(vbuf->lock(HardwareBuffer::HBL_DISCARD));
406
407    // 索引缓存
408    sm->indexData->indexCount = (vCount/2)*3;
409    sm->indexData->indexBuffer = HardwareBufferManager::getSingleton()
410        .createIndexBuffer(HardwareIndexBuffer::IT_16BIT, (vCount/2)*3, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
411    // 获得索引缓存的地址
412    unsigned short* pI = static_cast<unsigned short*>(sm->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
413
414    // 循环写入数据到硬件缓存
415    AxisAlignedBox meshBounds; // AABB绑定盒
416    Real meshRadius = 0;       // 球体半径
417    for (int z = startz; z < endz; ++ z)
418    {
419        for (int x = startx; x < endx; ++ x)
420        {
421            int index = x + z*mXSize; // 转换成一维数组索引
422
423            // 
424            if (mManualMatData[index] == matName && mGridData[index].nFirstLayer >= 0)
425            {
426                // 高度图坐标转换
427                // 因为网格数量是192*192的话,顶点就是193*193
428                int heightIndex = index + z;
429
430                // 第一层纹理坐标
431                int index1 = mGridData[index].nFirstLayer;
432                Real left1 = mPixMapData[index1].left;
433                Real right1 = mPixMapData[index1].right;
434                Real top1 = mPixMapData[index1].top;
435                Real bottom1 = mPixMapData[index1].bottom;
436                Vector2 left_top_1(left1, top1);
437                Vector2 right_top_1(right1, top1);
438                Vector2 right_bottom_1(right1, bottom1);
439                Vector2 left_bottom_1(left1, bottom1);
440                // 图片翻转等操作
441                if (mGridData[index].nFirstLayerOp != 0)
442                {
443                    flipPicture(mGridData[index].nFirstLayerOp, left_top_1, right_top_1, left_bottom_1, right_bottom_1, mGridData[index].IndexOrder);
444                }

445
446                // 第二层纹理坐标
447                Vector2 left_top_2;
448                Vector2 right_top_2;
449                Vector2 right_bottom_2;
450                Vector2 left_bottom_2;
451                if (mGridData[index].nSecondLayer >= 0)
452                {
453                    int index2 = mGridData[index].nSecondLayer;
454                    Real left2 = mPixMapData[index2].left;
455                    Real right2 = mPixMapData[index2].right;
456                    Real top2 = mPixMapData[index2].top;
457                    Real bottom2 = mPixMapData[index2].bottom;
458                    left_top_2 = Vector2(left2, top2);
459                    right_top_2 = Vector2(right2, top2);
460                    right_bottom_2 = Vector2(right2, bottom2);
461                    left_bottom_2 = Vector2(left2, bottom2);
462                    if (mGridData[index].nSecondLayerOp != 0)
463                    {
464                        flipPicture(mGridData[index].nSecondLayerOp, left_top_2, right_top_2, left_bottom_2, right_bottom_2, mGridData[index].IndexOrder);
465                    }

466                }

467
468                // 光照图纹理坐标
469                Vector2 left_top_3;
470                Vector2 right_top_3;
471                Vector2 right_bottom_3;
472                Vector2 left_bottom_3;
473                if (mHasLightMap)
474                {
475                    Real left3 = (Real)x / (Real)mXSize;   
476                    Real right3 = left3 + 1/(Real)mXSize;
477                    Real top3 = (Real)z / (Real)mZSize;
478                    Real bottom3 = top3 + 1/(Real)mZSize;
479                    left_top_3 = Vector2(left3, top3);
480                    right_top_3 = Vector2(right3, top3);
481                    right_bottom_3 = Vector2(right3, bottom3);
482                    left_bottom_3 = Vector2(left3, bottom3);
483                }

484
485                // 对mesh每个网格的个顶点编写数据
486                // 点0
487                // position
488                Vector3 position(x*mScaleX, mHeightMapData[heightIndex]*mScaleY, z*mScaleZ);
489                *pReal++ = position.x;
490                *pReal++ = position.y;
491                *pReal++ = position.z;
492                meshBounds.merge(position);     // update bounds
493                meshRadius = std::max(meshRadius, position.length()); // update bounds
494                // normal
495                Vector3 normal = getNormalAt(x, z);
496                *pReal++ = normal.x;
497                *pReal++ = normal.y;
498                *pReal++ = normal.z;
499                // uv1
500                *pReal++ = left_top_1.x;
501                *pReal++ = left_top_1.y;
502                // uv2
503                if (mGridData[index].nSecondLayer >= 0)
504                {
505                    *pReal++ = left_top_2.x;
506                    *pReal++ = left_top_2.y;
507                }

508                // uv3
509                if (mHasLightMap)
510                {
511                    *pReal++ = left_top_3.x;
512                    *pReal++ = left_top_3.y;
513                }

514
515
516                // 点1
517                // position
518                position = Vector3((x+width)*mScaleX, mHeightMapData[heightIndex+1]*mScaleY, z*mScaleZ);
519                *pReal++ = position.x;
520                *pReal++ = position.y;
521                *pReal++ = position.z;
522                meshBounds.merge(position);     // update bounds
523                meshRadius = std::max(meshRadius, position.length()); // update bounds
524                // normal
525                normal = getNormalAt(x+width, z);
526                *pReal++ = normal.x;
527                *pReal++ = normal.y;
528                *pReal++ = normal.z;
529                // uv1
530                *pReal++ = right_top_1.x;
531                *pReal++ = right_top_1.y;
532                // uv2
533                if (mGridData[index].nSecondLayer >= 0)
534                {
535                    *pReal++ = right_top_2.x;
536                    *pReal++ = right_top_2.y;
537                }

538                // uv3
539                if (mHasLightMap)
540                {
541                    *pReal++ = right_top_3.x;
542                    *pReal++ = right_top_3.y;
543                }

544
545                // 点2
546                // position
547                position = Vector3((x+width)*mScaleX, mHeightMapData[heightIndex+mXSize+2]*mScaleY, (z+width)*mScaleZ);
548                *pReal++ = position.x;
549                *pReal++ = position.y;
550                *pReal++ = position.z;
551                meshBounds.merge(position);     // update bounds
552                meshRadius = std::max(meshRadius, position.length()); // update bounds
553                // normal
554                normal = getNormalAt(x+width, z+width);
555                *pReal++ = normal.x;
556                *pReal++ = normal.y;
557                *pReal++ = normal.z;
558                // uv1
559                *pReal++ = right_bottom_1.x;
560                *pReal++ = right_bottom_1.y;
561                // uv2
562                if (mGridData[index].nSecondLayer >= 0)
563                {
564                    *pReal++ = right_bottom_2.x;
565                    *pReal++ = right_bottom_2.y;
566                }

567                // uv3
568                if (mHasLightMap)
569                {
570                    *pReal++ = right_bottom_3.x;
571                    *pReal++ = right_bottom_3.y;
572                }

573
574                // 点3
575                // position
576                position = Vector3(x*mScaleX, mHeightMapData[heightIndex+mXSize+1]*mScaleY, (z+width)*mScaleZ);
577                *pReal++ = position.x;
578                *pReal++ = position.y;
579                *pReal++ = position.z;
580                meshBounds.merge(position);     // update bounds
581                meshRadius = std::max(meshRadius, position.length()); // update bounds
582                // normal
583                normal = getNormalAt(x, z+width);
584                *pReal++ = normal.x;
585                *pReal++ = normal.y;
586                *pReal++ = normal.z;
587                // uv1
588                *pReal++ = left_bottom_1.x;
589                *pReal++ = left_bottom_1.y;
590                // uv2
591                if (mGridData[index].nSecondLayer >= 0)
592                {
593                    *pReal++ = left_bottom_2.x;
594                    *pReal++ = left_bottom_2.y;
595                }

596                // uv3
597                if (mHasLightMap)
598                {
599                    *pReal++ = left_bottom_3.x;
600                    *pReal++ = left_bottom_3.y;
601                }

602
603                // 索引
604                int off = k * 4;
605                if    (mGridData[index].IndexOrder == 0// 正常索引顺序
606                {
607                    *pI++ = 1 + off;
608                    *pI++ = 0 + off;
609                    *pI++ = 3 + off;
610
611                    *pI++ = 1 + off;
612                    *pI++ = 3 + off;
613                    *pI++ = 2 + off;
614                }

615                else
616                {
617                    *pI++ = 0 + off;
618                    *pI++ = 3 + off;
619                    *pI++ = 2 + off;
620
621                    *pI++ = 0 + off;
622                    *pI++ = 2 + off;
623                    *pI++ = 1 + off;
624                }

625
626                ++ k;
627            }

628        }

629    }

630
631    vbuf->unlock();
632    sm->vertexData->vertexBufferBinding->setBinding(MAIN_BINDING, vbuf);     // 绑定顶点缓存
633
634    sm->indexData->indexBuffer->unlock();
635
636    sm->setMaterialName(matName);
637
638    // 设置绑定盒子和球体半径, 查询裁剪用
639    //Real min = -10*mScaleY;
640    //Real max = 25*mScaleY;
641    //AxisAlignedBox meshBounds(
642    //    (Real)startx*mScaleX, 
643    //    min, 
644    //    (Real)startz*mScaleZ,
645    //    (Real)(endx - 1)*mScaleX, 
646    //    max, 
647    //    (Real)(endz - 1)*mScaleZ);
648
649    //Real meshRadius = Math::Sqrt(
650    //    Math::Sqr(max - min) +
651    //    Math::Sqr((endx - 1 - startx) * mScaleX) +
652    //    Math::Sqr((endz - 1 - startz) * mScaleZ)) / 2;
653
654    mesh->_setBounds(meshBounds);
655    mesh->_setBoundingSphereRadius(meshRadius);
656
657    mesh->load();
658
659    return true;
660}

661
662//--------------------------------------------------------------------------------------------------------
663void TLBBTerrain::createWCollision(const String &fileName , const String &groupName)
664{
665    DataStreamPtr stream = ResourceGroupManager::getSingleton().openResource(fileName , groupName);
666
667    // 读取文件头, 8个字节的结构
668    WCollisionHeader header;
669    stream->read(&header , sizeof(header));
670
671    Vector3 vec3 = Vector3::ZERO;
672    int col = 0;
673    int row = 0;
674    int preCol = 0// 前一个数据块的列
675    int preRow = 0;    // 前一个数据块的行
676    int number = 0;
677    int k = 0;
678    bool firstTime = true// 第一次
679
680    while (!stream->eof())
681    {
682        // 行列坐标, 决定WCollision的分块信息的
683        // 如果把WCOliision做成一个mesh,每次都会全部查询,效率很低
684        stream->read(&col, sizeof(row));
685        stream->read(&row, sizeof(col));
686
687        stream->read(&number, sizeof(number));  // 数据块的三角形数量
688
689        // 读取此数据块的三角形顶点数据
690        for (int i = 0; i < number * 3++ i)
691        {
692            stream->read(&vec3, sizeof(vec3)); 
693            mWCollisionData.push_back(vec3);
694        }

695
696        if (mWCollisionData.size() == 0)
697        {
698            break;
699        }

700
701        // 初始化
702        if (firstTime)
703        {
704            preCol = col;
705            preRow = row;
706            firstTime = false;
707        }
 
708
709        // 行列坐标相连,就做成一个mesh
710        if (col == preCol && (row - preRow) <= 1)
711        {
712            preCol = col;
713            preRow = row;
714        }

715        else
716        {
717            // 生成
718            ManualObject mo("mo");
719            mo.begin("", RenderOperation::OT_TRIANGLE_LIST);
720            for(size_t i = 0; i < mWCollisionData.size(); i += 3)
721            {
722                // 点1
723                mo.position(mWCollisionData[i].x*mScaleX, mWCollisionData[i].y*mScaleY, mWCollisionData[i].z*mScaleZ);
724                mo.colour(ColourValue(001));
725
726                // 点2
727                mo.position(mWCollisionData[i+1].x*mScaleX, mWCollisionData[i+1].y*mScaleY, mWCollisionData[i+1].z*mScaleZ);
728                mo.colour(ColourValue(001));
729
730                // 点3
731                mo.position(mWCollisionData[i+2].x*mScaleX, mWCollisionData[i+2].y*mScaleY, mWCollisionData[i+2].z*mScaleZ);
732                mo.colour(ColourValue(001));
733
734                // 三角形索引顺序
735                mo.triangle(i, i+1, i+2);
736            }

737            mo.end();
738
739            String meshName = "WCollisionMesh"+StringConverter::toString(k);
740            mo.convertToMesh(meshName, "TLBB");
741            mManualMeshData.push_back(meshName);
742
743            Entity* ent = mSceneMgr->createEntity("WCollison"+StringConverter::toString(k), meshName);
744            mWCollisionEntData.push_back(ent); //
745            ent->setCastShadows(false);
746            ent->setQueryFlags(TERRAIN_QUERY_MASK);
747
748            SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(mCentre);
749            node->attachObject(ent);
750
751            mWCollisionData.clear(); // 
752            firstTime = true;
753            ++ k;
754        }

755    }
 // end of while
756}

757
758//--------------------------------------------------------------------------------------------------------
759void TLBBTerrain::createTerrain()
760{
761    // 生成材质
762    LogManager::getSingleton().logMessage(LML_CRITICAL, "开始生成材质");
763    createManualMat();
764
765    // 生成WCollision
766    LogManager::getSingleton().logMessage(LML_CRITICAL, "开始生成WCollsion");
767    vector<String> vec;
768    vec = StringUtil::split(mFileName, "."1);
769    String tempStr = vec[0+ ".WCollision";
770    createWCollision(tempStr, "TLBB");
771
772    // 地形mesh
773    LogManager::getSingleton().logMessage(LML_CRITICAL, "开始生成地形mesh");
774
775    // 判断地形大小是否能被tile整除,不能整除就需要矫正每行每列最后一个tile的大小
776    // 在循环外部判断,就不用每次循环都判断,效率更高
777    if (mXSize % mTileSize != 0 || mZSize % mTileSize != 0)
778    {
779        for (size_t matIndex = 0; matIndex < mMaterialNum; ++ matIndex)
780        {
781            // 材质名字
782            // toString和StrStreamType是用std::ostringstream来做的,非常消耗cpu,尽量减少循环数次
783            // 或者用sprintf来做
784            String matName = "material" + StringConverter::toString(matIndex);
785
786            // 同材质的mesh按tile区域生成
787            for (size_t i = 0; i < mZSize; i += mTileSize)
788            {
789                for (size_t j = 0; j < mXSize; j += mTileSize)
790                {
791                    // 矫正tile大小
792                    int tielSizeZ = mTileSize;
793                    int tileSizeX = mTileSize;
794                    if (mZSize - i < mTileSize)
795                    {
796                        tielSizeZ = mZSize - i;
797                    }

798                    if (mXSize - j < mTileSize)
799                    {
800                        tileSizeX = mXSize - j;
801                    }

802                    
803                    // 第一种方法 
804                    // 现有的地形检测暂时不支持ManualObject,以后考虑添加
805                    //createTileManualObject(j, i, tileSizeX, tielSizeZ, matName);
806                    
807                    // 第二种方法
808                    if (createTileMesh(j, i, tileSizeX, tielSizeZ, matName))
809                    {
810                        StringUtil::StrStreamType entName;
811                        StringUtil::StrStreamType meshName;
812                        entName << "tile[" << i << "]" << "[" << j << "]" << matName;
813                        meshName << "gridMesh[" << i << "]" << "[" << j << "]" << matName;
814                        Entity* entity = mSceneMgr->createEntity(entName.str(), meshName.str());
815                        entity->setCastShadows(false);
816                        entity->setQueryFlags(TERRAIN_QUERY_MASK);
817                        mSceneMgr->getRootSceneNode()->createChildSceneNode(mCentre)->attachObject(entity);
818                    }

819                }

820            }

821        }

822    }

823    else
824    {
825        for (size_t matIndex = 0; matIndex < mMaterialNum; ++ matIndex)
826        {
827            // 材质名字
828            // toString和StrStreamType是用std::ostringstream来做的,非常消耗cpu,尽量减少循环数次
829            // 或者用sprintf来做
830            String matName = "material" + StringConverter::toString(matIndex);
831
832            // 同材质的mesh按tile区域生成
833            for (size_t i = 0; i < mZSize; i += mTileSize)
834            {
835                for (size_t j = 0; j < mXSize; j += mTileSize)
836                {
837                    
838                    // 第一种方法 
839                    // 现有的地形检测暂时不支持ManualObject,以后考虑添加
840                    //createTileManualObject(j, i, mTileSize, mTileSize, matName);
841
842                    // 第二种方法
843                    if (createTileMesh(j, i, mTileSize, mTileSize, matName))
844                    {
845                        StringUtil::StrStreamType entName;
846                        StringUtil::StrStreamType meshName;
847                        entName << "tile[" << i << "]" << "[" << j << "]" << matName;
848                        meshName << "gridMesh[" << i << "]" << "[" << j << "]" << matName;
849                        Entity* entity = mSceneMgr->createEntity(entName.str(), meshName.str());
850                        entity->setCastShadows(false);
851                        entity->setQueryFlags(TERRAIN_QUERY_MASK);
852                        mSceneMgr->getRootSceneNode()->createChildSceneNode(mCentre)->attachObject(entity);
853                    }

854                }

855            }

856        }

857    }

858}
原创粉丝点击