天龙八部生成地形mesh的源码
2011-09-17 14:27
288 查看
有个网友说他把我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
{
69
public:
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
{
92
public:
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
139
protected:
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
208
protected:
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
}
真的蛮辛苦的....天龙的地形用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
{
69
public:
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
{
92
public:
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
139
protected:
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
208
protected:
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
}
相关文章推荐
- OGRESE 地形Tile材质的生成 源码以及详细注释 所有源码出自OGRESE,注释部分出自OGRESE
- (转)修改ETM,用Ogre实现《天龙八部》地形与部分场景详解(附源码)
- 初级3D地形随机生成算法源码(Ogre实现)放出
- 修改ETM,用Ogre实现《天龙八部》地形与部分场景详解(附源码)
- Ogre天龙八部地形mesh部分的C++源码
- unity 程序生成mesh并实现2D山丘地形
- 修改ETM,用Ogre实现《天龙八部》地形与部分场景详解(附源码)
- 修改ETM,用Ogre实现《天龙八部》地形与部分场景详解(附源码)
- 修改ETM,用Ogre实现《天龙八部》地形与部分场景详解(附源码)
- 修改ETM,用Ogre实现《天龙八部》地形与部分场景详解(附源码)
- 修改ETM,用Ogre实现《天龙八部》地形与部分场景详解(附源码)
- unity3d 随机生成地形之随机山脉
- 共享生成静态页面并分页源码
- 微信小程序定制开发工具,自动生成前端源码
- 淘宝数据库OceanBase SQL编译器部分 源码阅读--生成逻辑计划
- 学习用 doxygen 生成源码文档
- FreeMarker教你如何生成html静态页面源码
- jfreechart各种图表生成源码练习
- jQuery插件echarts实现的循环生成图效果示例【附demo源码下载】
- Windows 源码编译Hadoop 2.7.4生成X64