有个网友说他把我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 >
12 using namespace Ogre;
13 using std::vector;
14
15 const uint TERRAIN_QUERY_MASK = 0x00000001 ; // 地形查询掩码
16 const unsigned short MAIN_BINDING = 0 ; // 主绑定
17
18 /**/ /* 网格操作标志的枚举*/
19 enum 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*/
30 struct PixMap
31 {
32 int textureId;
33 Real left;
34 Real top;
35 Real right;
36 Real bottom;
37} ;
38
39 /**/ /* 高度图文件头信息*/
40 struct HeightMapHeader
41 {
42 DWORD nMagic;
43 DWORD nVersion; // 版本号
44 int nWidth;
45 int nHeight;
46} ;
47
48 /**/ /* 碰撞图文件头*/
49 struct WCollisionHeader
50 {
51 DWORD nVersion;
52 DWORD nNumber; // 三角形数量
53} ;
54
55 /**/ /* 网格文件头信息*/
56 struct GridHeader
57 {
58 DWORD nMagic;
59 DWORD nVersion;
60 int nWidth;
61 int nHeight;
62} ;
63
64 /**/ /* 单个网格类
65@remarks 1个网格就是一个正方,天龙八部的地形是根据网格信息拼接而成,但没有共享顶点,这样可以做很多层uv
66*/
67 class 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*/
90 class 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(void) const;
107
108 /**//* 获得地图Y方向的缩放*/
109 int getScaleY(void) const;
110
111 /**//* 获得地图Z方向的缩放*/
112 int getScaleZ(void) const;
113
114 /**//* 获得地图X方向的大小*/
115 int getXSize(void) const;
116
117 /**//* 获得地图Z方向的大小*/
118 int getZSize(void) const;
119
120 /**//* 获得地图中心点*/
121 const Vector3& getCentre(void) const;
122
123 /**//* 获得高度图数据*/
124 const vector<Real>& getHeightMapData(void) const;
125
126 /**//* 获得手工材质的名字数组
127 @remarks 手动生成的材质换图的时候需要手工清除,所以保留他们的名字
128 */
129 const vector<String>& getManualMatData(void) const;
130
131 /**//* 获得手工mesh的名字数组
132 @remarks 手动生成的mesh换图的时候需要手工清除,所以保留他们的名字
133 */
134 const vector<String>& getManualMeshData(void) const;
135
136 /**//* 获得WCollision实体指针数组*/
137 const vector<Entity*>& getmWCollisionEntData(void) const;
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
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 >
12 using namespace Ogre;
13 using std::vector;
14
15 const uint TERRAIN_QUERY_MASK = 0x00000001 ; // 地形查询掩码
16 const unsigned short MAIN_BINDING = 0 ; // 主绑定
17
18 /**/ /* 网格操作标志的枚举*/
19 enum 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*/
30 struct PixMap
31 {
32 int textureId;
33 Real left;
34 Real top;
35 Real right;
36 Real bottom;
37} ;
38
39 /**/ /* 高度图文件头信息*/
40 struct HeightMapHeader
41 {
42 DWORD nMagic;
43 DWORD nVersion; // 版本号
44 int nWidth;
45 int nHeight;
46} ;
47
48 /**/ /* 碰撞图文件头*/
49 struct WCollisionHeader
50 {
51 DWORD nVersion;
52 DWORD nNumber; // 三角形数量
53} ;
54
55 /**/ /* 网格文件头信息*/
56 struct GridHeader
57 {
58 DWORD nMagic;
59 DWORD nVersion;
60 int nWidth;
61 int nHeight;
62} ;
63
64 /**/ /* 单个网格类
65@remarks 1个网格就是一个正方,天龙八部的地形是根据网格信息拼接而成,但没有共享顶点,这样可以做很多层uv
66*/
67 class 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*/
90 class 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(void) const;
107
108 /**//* 获得地图Y方向的缩放*/
109 int getScaleY(void) const;
110
111 /**//* 获得地图Z方向的缩放*/
112 int getScaleZ(void) const;
113
114 /**//* 获得地图X方向的大小*/
115 int getXSize(void) const;
116
117 /**//* 获得地图Z方向的大小*/
118 int getZSize(void) const;
119
120 /**//* 获得地图中心点*/
121 const Vector3& getCentre(void) const;
122
123 /**//* 获得高度图数据*/
124 const vector<Real>& getHeightMapData(void) const;
125
126 /**//* 获得手工材质的名字数组
127 @remarks 手动生成的材质换图的时候需要手工清除,所以保留他们的名字
128 */
129 const vector<String>& getManualMatData(void) const;
130
131 /**//* 获得手工mesh的名字数组
132 @remarks 手动生成的mesh换图的时候需要手工清除,所以保留他们的名字
133 */
134 const vector<String>& getManualMeshData(void) const;
135
136 /**//* 获得WCollision实体指针数组*/
137 const vector<Entity*>& getmWCollisionEntData(void) const;
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
//
--------------------------------------------------------------------------------------------------------
2 int 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 // --------------------------------------------------------------------------------------------------------
48 void 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 // --------------------------------------------------------------------------------------------------------
108 Vector3 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 // --------------------------------------------------------------------------------------------------------
146 void 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 // --------------------------------------------------------------------------------------------------------
319 bool 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 // --------------------------------------------------------------------------------------------------------
663 void 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(0, 0, 1));
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(0, 0, 1));
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(0, 0, 1));
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 // --------------------------------------------------------------------------------------------------------
759 void 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}
2 int 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 // --------------------------------------------------------------------------------------------------------
48 void 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 // --------------------------------------------------------------------------------------------------------
108 Vector3 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 // --------------------------------------------------------------------------------------------------------
146 void 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 // --------------------------------------------------------------------------------------------------------
319 bool 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 // --------------------------------------------------------------------------------------------------------
663 void 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(0, 0, 1));
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(0, 0, 1));
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(0, 0, 1));
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 // --------------------------------------------------------------------------------------------------------
759 void 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}