公告
-
博主简介:1982年生,2006年毕业于华南理工大学电子专业,毕业后在某知名企业从事电路硬件研发工作,2008年底决定转行做游戏程序开发,至今还在转行中.......现居成都,求游戏开发工作一份:D. 技术交流加QQ:18052887
日历
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
---|
24 | 25 | 26 | 27 | 28 | 29 | 30 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 1 | 2 | 3 | 4 |
|
统计
- 随笔 - 2
- 文章 - 1
- 评论 - 6
- 引用 - 0
导航
常用链接
留言簿
随笔分类
随笔档案
文章档案
搜索
最新评论
阅读排行榜
评论排行榜
|
有个网友说他把我csdn博客的零落代码拼起来搞了一周都没能够载入场景....
真的蛮辛苦的....天龙的地形用mesh自己做就好的,
以前我的部分源码效率有问题,因为我低估了tostring函数的开销,
这函数很变态....用io输出流来实现的,代码优雅但是效率就....
如果需要多次循环就不要使用它.
好了,发源码,随便说一句,csdn很烂.....提交老是失败,实在受不了~~~
头文件:
1/**//* 2************************************************************************************************************** 3@fileName Terrain.h 4@remarks 用来创建地形,和保存地形相关信息 5@author LYN 2009.10.1 6*************************************************************************************************************** 7*/ 8#pragma once 9 10#include "TLBB.h" 11#include <vector> 12using namespace Ogre; 13using std::vector; 14 15const uint TERRAIN_QUERY_MASK = 0x00000001; // 地形查询掩码 16const unsigned short MAIN_BINDING = 0; // 主绑定 17 18/**//* 网格操作标志的枚举*/ 19enum Operate 20{ 21 FLIP_HORIZINTAL = 1, // 图片水平翻转,即左右翻转 22 FLIP_VERTICAL = 2, // 图片垂直翻转,即上下翻转 23 ANTICLOCKWISE_90 = 4, // 逆时针旋转90度 24 FLIP_DIAGONAL = 8 // 三角形的对角线镜像,IndexOrder==0时就把左上的纹理坐标复制到右下,否则右上到左下 25}; 26 27/**//* 像素图信息 28@remarks 保存的是每个网格的纹理图片ID和纹理坐标 29*/ 30struct PixMap 31{ 32 int textureId; 33 Real left; 34 Real top; 35 Real right; 36 Real bottom; 37}; 38 39/**//* 高度图文件头信息*/ 40struct HeightMapHeader 41{ 42 DWORD nMagic; 43 DWORD nVersion; // 版本号 44 int nWidth; 45 int nHeight; 46}; 47 48/**//* 碰撞图文件头*/ 49struct WCollisionHeader 50{ 51 DWORD nVersion; 52 DWORD nNumber; // 三角形数量 53}; 54 55/**//* 网格文件头信息*/ 56struct GridHeader 57{ 58 DWORD nMagic; 59 DWORD nVersion; 60 int nWidth; 61 int nHeight; 62}; 63 64/**//* 单个网格类 65@remarks 1个网格就是一个正方,天龙八部的地形是根据网格信息拼接而成,但没有共享顶点,这样可以做很多层uv 66*/ 67class GridInfo 68{ 69public: 70 // 第一层pixelmap的索引, 如果是7字节版本,读取后需交换高8位与低8位的值, 71 // 需做如下操作 nFirstLayer = (nFirstLayer<<8)|(nFirstLayer>>8) 72 short nFirstLayer; 73 74 // 对nFirstLayer的操作, 取值是上面几个定义的宏, 可以互相组合 75 BYTE nFirstLayerOp; 76 77 // 第二层pixelmap的索引, 天龙八部的地表不算光照图有两层UV来融合 78 short nSecondLayer; 79 80 // 对nSecondLayer的操作,取值同nFirstLayerOp 81 BYTE nSecondLayerOp; 82 83 // 对格子的三角形的操作,可能取值如下, 0正常三角形索引, 1不同于正常的三角形索引 84 BYTE IndexOrder; 85}; 86 87/**//* TLBBTerrain类 88@remarks 用来生成地形 89*/ 90class TLBBTerrain 91{ 92public: 93 /**//* 构造函数 94 @param filename 地形文件名 95 @param sceneMgr 场景管理器 96 */ 97 TLBBTerrain(const String& filename, SceneManager* sceneMgr); 98 ~TLBBTerrain(void); 99 100 /**//* 生成地形 101 @remarks 生成地形,直接调用此方法直接可以生成地形. 102 */ 103 void createTerrain(void); 104 105 /**//* 获得地图X方向的缩放*/ 106 int getScaleX(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//-------------------------------------------------------------------------------------------------------- 2int TLBBTerrain::findSameMaterial(GridInfo& gridinfo, int endIndex) 3{ 4 // 网格比较 5 for (int i = 0; i < endIndex; ++ i) 6 { 7 8 if (mGridData[i].nFirstLayer < 0 ) 9 { 10 continue; 11 } 12 13 // 如果有第一层 14 if (gridinfo.nFirstLayer >= 0) 15 { 16 // 第一层的纹理图片相同 17 if (mPixMapData[gridinfo.nFirstLayer].textureId == mPixMapData[mGridData[i].nFirstLayer].textureId) 18 { 19 // 如果有第二层 20 if (gridinfo.nSecondLayer >= 0) 21 { 22 if (mGridData[i].nSecondLayer >= 0) 23 { 24 // 第二层的纹理图片相同 25 if (mPixMapData[gridinfo.nSecondLayer].textureId == mPixMapData[mGridData[i].nSecondLayer].textureId) 26 { 27 return i; // 一,二层的纹理图片都相同 28 } 29 } 30 } 31 else if (mGridData[i].nSecondLayer < 0) 32 { 33 return i; // 第一层的纹理图片相同 34 } 35 } 36 } 37 else 38 { 39 // 如果第一层都没有纹理图片.用第0个网格的材质代替,不清楚为什么会没有纹理 40 // 可能天龙有其他材质代替吧 41 return 0; 42 } 43 } 44 return -1; // 没有找到相同材质 45} 46 47//-------------------------------------------------------------------------------------------------------- 48void TLBBTerrain::createManualMat(void) 49{ 50 // 先获得材质模板 51 MaterialPtr materialTemplate1 = static_cast<MaterialPtr>(MaterialManager::getSingleton().getByName(mTemplateData[1])); 52 MaterialPtr materialTemplate2 = static_cast<MaterialPtr>(MaterialManager::getSingleton().getByName(mTemplateData[3])); 53 54 int tempIndex = -1; 55 for (int i = 0; i < mXSize*mZSize; ++ i) 56 { 57 // 如果此材质已经存在 58 if ((tempIndex = findSameMaterial(mGridData[i], i)) >= 0) 59 { 60 // 用已有材质存入数组 61 mManualMatData.push_back(mManualMatData[tempIndex]); 62 } 63 else 64 { 65 // 有第二层 66 if (mGridData[i].nSecondLayer >= 0 && mGridData[i].nFirstLayer >= 0) 67 { 68 // 拷贝第二层材质 69 String newMaterialName = "material"+StringConverter::toString(mMaterialNum); // 材质名字 70 MaterialPtr newMaterial = materialTemplate2->clone(newMaterialName); // 克隆材质 71 AliasTextureNamePairList aliasList; // 存储纹理别名的二叉树 72 String textureName1 = mTextureData[mPixMapData[mGridData[i].nFirstLayer].textureId]; 73 String textureName2 = mTextureData[mPixMapData[mGridData[i].nSecondLayer].textureId]; 74 aliasList["<layer0>"] = textureName1; 75 aliasList["<layer1>"] = textureName2; 76 if (mHasLightMap) 77 { 78 aliasList["<lightmap>"] = mLightMapName; 79 } 80 newMaterial->applyTextureAliases(aliasList); // 用纹理别名更改纹理 81 mManualMatData.push_back(newMaterialName); // 存入材质数组 82 } 83 else if (mGridData[i].nFirstLayer >= 0) 84 { 85 // 拷贝第一层材质 86 String newMaterialName = "material"+StringConverter::toString(mMaterialNum); // 材质名字 87 MaterialPtr newMaterial = materialTemplate1->clone(newMaterialName); // 克隆材质 88 AliasTextureNamePairList aliasList; // 存储纹理别名的二叉树 89 String textureName1 = mTextureData[mPixMapData[mGridData[i].nFirstLayer].textureId]; 90 aliasList["<layer0>"] = textureName1; 91 if (mHasLightMap) 92 { 93 aliasList["<lightmap>"] = mLightMapName; 94 } 95 newMaterial->applyTextureAliases(aliasList); // 用纹理别名更改纹理 96 mManualMatData.push_back(newMaterialName); // 存入材质数组 97 98 99 } 100 101 ++ mMaterialNum; 102 103 } 104 } 105} 106 107//-------------------------------------------------------------------------------------------------------- 108Vector3 TLBBTerrain::getNormalAt(Real x, Real z) const 109{ 110 int flip = 1; 111 int index = x + z*(mXSize+1); 112 Vector3 here(x, mHeightMapData[index], z); 113 Vector3 right; 114 Vector3 down; 115 // 边界 116 if (x >= mXSize) 117 { 118 flip *= -1; 119 right = Vector3(x-1, mHeightMapData[index-1], z); 120 } 121 else 122 { 123 right = Vector3(x+1, mHeightMapData[index+1], z); 124 } 125 126 if (z >= mZSize) 127 { 128 flip *= -1; 129 down = Vector3(x, mHeightMapData[index-mXSize-1], z-1); 130 } 131 else 132 { 133 down = Vector3(x, mHeightMapData[index+mXSize+1], z+1); 134 } 135 // 生成矢量 136 right -= here; 137 down -= here; 138 139 // 矢量正交,注意方向 140 Vector3 normal = flip * down.crossProduct(right); 141 normal.normalise(); // 归一化 142 return normal; 143} 144 145//-------------------------------------------------------------------------------------------------------- 146void TLBBTerrain::createTileManualObject(size_t startx, size_t startz, int tileSizeX, int tileSizeZ, const String& matName) 147{ 148 StringUtil::StrStreamType entName; 149 entName << "tile[" << startz << "]" << "[" << startx << "]" << matName; 150 151 ManualObject* mo = mSceneMgr->createManualObject(entName.str()); 152 153 mo->begin(matName); 154 155 const Real width = 1; 156 int k = 0; 157 bool hasMesh = false; 158 int endx = startx + tileSizeX; 159 int endz = startz + tileSizeZ; 160 for (int z = startz; z < endz; ++ z) 161 { 162 for (int x = startx; x < endx; ++ x) 163 { 164 // 转换成一维数组索引 165 int index = x + z*mXSize; 166 // 如果存在此材质 167 if (mManualMatData[index] == matName && mGridData[index].nFirstLayer >= 0) 168 { 169 hasMesh = true; 170 171 // 高度图坐标转换 172 int heightIndex = index + z; 173 174 // 第一层纹理坐标 175 int index1 = mGridData[index].nFirstLayer; 176 Real left1 = mPixMapData[index1].left; 177 Real right1 = mPixMapData[index1].right; 178 Real top1 = mPixMapData[index1].top; 179 Real bottom1 = mPixMapData[index1].bottom; 180 Vector2 left_top_1(left1, top1); 181 Vector2 right_top_1(right1, top1); 182 Vector2 right_bottom_1(right1, bottom1); 183 Vector2 left_bottom_1(left1, bottom1); 184 // 图片翻转等操作 185 if (mGridData[index].nFirstLayerOp != 0) 186 { 187 flipPicture(mGridData[index].nFirstLayerOp, left_top_1, right_top_1, 188 left_bottom_1, right_bottom_1, mGridData[index].IndexOrder); 189 } 190 191 // 第二层纹理坐标 192 Vector2 left_top_2; 193 Vector2 right_top_2; 194 Vector2 right_bottom_2; 195 Vector2 left_bottom_2; 196 if (mGridData[index].nSecondLayer >= 0) 197 { 198 int index2 = mGridData[index].nSecondLayer; 199 Real left2 = mPixMapData[index2].left; 200 Real right2 = mPixMapData[index2].right; 201 Real top2 = mPixMapData[index2].top; 202 Real bottom2 = mPixMapData[index2].bottom; 203 left_top_2 = Vector2(left2, top2); 204 right_top_2 = Vector2(right2, top2); 205 right_bottom_2 = Vector2(right2, bottom2); 206 left_bottom_2 = Vector2(left2, bottom2); 207 if (mGridData[index].nSecondLayerOp != 0) 208 { 209 flipPicture(mGridData[index].nSecondLayerOp, left_top_2, right_top_2, 210 left_bottom_2, right_bottom_2, mGridData[index].IndexOrder); 211 } 212 213 } 214 215 // 光照图纹理坐标 216 Vector2 left_top_3; 217 Vector2 right_top_3; 218 Vector2 right_bottom_3; 219 Vector2 left_bottom_3; 220 if (mHasLightMap) 221 { 222 Real left3 = (Real)x / (Real)mXSize; 223 Real right3 = left3 + 1/(Real)mXSize; 224 Real top3 = (Real)z / (Real)mZSize; 225 Real bottom3 = top3 + 1/(Real)mZSize; 226 left_top_3 = Vector2(left3, top3); 227 right_top_3 = Vector2(right3, top3); 228 right_bottom_3 = Vector2(right3, bottom3); 229 left_bottom_3 = Vector2(left3, bottom3); 230 } 231 232 // 点0 233 mo->position(x*mScaleX, mHeightMapData[heightIndex]*mScaleY, z*mScaleZ); 234 mo->normal(getNormalAt(x, z)); 235 mo->textureCoord(left_top_1); 236 if (mGridData[index].nSecondLayer >= 0) 237 { 238 mo->textureCoord(left_top_2); 239 } 240 if (mHasLightMap) 241 { 242 mo->textureCoord(left_top_3); // 光照图纹理坐标 243 } 244 245 // 点1 246 mo->position((x+width)*mScaleX, mHeightMapData[heightIndex+1]*mScaleY, z*mScaleZ); 247 mo->normal(getNormalAt(x+width, z)); 248 mo->textureCoord(right_top_1); 249 if (mGridData[index].nSecondLayer >= 0) 250 { 251 mo->textureCoord(right_top_2); 252 } 253 if (mHasLightMap) 254 { 255 mo->textureCoord(right_top_3); // 光照图纹理坐标 256 } 257 258 // 点2 259 mo->position((x+width)*mScaleX, mHeightMapData[heightIndex+mXSize+2]*mScaleY, (width+z)*mScaleZ); 260 mo->normal(getNormalAt(x+width, z+width)); 261 mo->textureCoord(right_bottom_1); 262 if (mGridData[index].nSecondLayer >= 0) 263 { 264 mo->textureCoord(right_bottom_2); 265 } 266 if (mHasLightMap) 267 { 268 mo->textureCoord(right_bottom_3); // 光照图纹理坐标 269 } 270 271 272 // 点3 273 mo->position(x*mScaleX, mHeightMapData[heightIndex+mXSize+1]*mScaleY, (width+z)*mScaleZ); 274 mo->normal(getNormalAt(x, z+width)); 275 mo->textureCoord(left_bottom_1); 276 if (mGridData[index].nSecondLayer >= 0) 277 { 278 mo->textureCoord(left_bottom_2); 279 } 280 if (mHasLightMap) 281 { 282 mo->textureCoord(left_bottom_3); // 光照图纹理坐标 283 } 284 285 // 三角形索引顺序 286 int offset = k * 4; 287 if (mGridData[index].IndexOrder == 0) 288 { // 正常顺序 289 mo->triangle(offset+1, offset, offset+3); 290 mo->triangle(offset+1, offset+3, offset+2); 291 } 292 else 293 { 294 mo->triangle(offset, offset+3, offset+2); 295 mo->triangle(offset, offset+2, offset+1); 296 } 297 298 ++ k; 299 } 300 } 301 } 302 303 mo->end(); 304 305 // 此tile含有数据才生成 306 if (hasMesh) 307 { 308 mSceneMgr->getRootSceneNode()->createChildSceneNode(mCentre)->attachObject(mo); 309 mo->setCastShadows(false); 310 mo->setQueryFlags(TERRAIN_QUERY_MASK); 311 } 312 else 313 { 314 mSceneMgr->destroyManualObject(entName.str()); 315 } 316} 317 318//-------------------------------------------------------------------------------------------------------- 319bool TLBBTerrain::createTileMesh(size_t startx, size_t startz, int tileSizeX, int tileSizeZ, const String& matName) 320{ 321 const Real width = 1; 322 int k = 0; 323 bool hasMesh = false; 324 int endx = startx + tileSizeX; 325 int endz = startz + tileSizeZ; 326 327 // 先获得mesh顶点的数量 328 size_t vCount = 0; 329 bool hasSecondLayer = false; 330 for (int z = startz; z < endz; ++ z) 331 { 332 for (int x = startx; x < endx; ++ x) 333 { 334 int index = x + z*mXSize; // 转换成一维数组索引 335 336 // 337 if (mManualMatData[index] == matName && mGridData[index].nFirstLayer >= 0) 338 { 339 vCount += 4; 340 341 // 此材质是否有第二层 342 if (!hasSecondLayer) 343 { 344 if (mGridData[index].nSecondLayer >= 0) 345 { 346 hasSecondLayer = true; 347 } 348 } 349 } 350 } 351 } 352 353 if (vCount == 0) 354 { 355 return false; 356 } 357 358 // 生成mesh 359 StringUtil::StrStreamType meshName; 360 meshName << "gridMesh[" << startz << "]" << "[" << startx << "]" << matName; 361 MeshPtr mesh = MeshManager::getSingleton().createManual(meshName.str(), "TLBB"); 362 mManualMeshData.push_back(meshName.str()); 363 364 // 子mesh 365 SubMesh* sm = mesh->createSubMesh(); 366 sm->useSharedVertices = false; // 不使用共享顶点 367 sm->vertexData = new VertexData(); 368 sm->vertexData->vertexCount = vCount; 369 370 // 顶点结构描述 371 VertexDeclaration* decl = sm->vertexData->vertexDeclaration; 372 size_t offset = 0; 373 // 顶点位置 374 decl->addElement(MAIN_BINDING, offset, VET_FLOAT3, VES_POSITION); 375 offset += VertexElement::getTypeSize(VET_FLOAT3); 376 // 法线 377 decl->addElement(MAIN_BINDING, offset, VET_FLOAT3, VES_NORMAL); 378 offset += VertexElement::getTypeSize(VET_FLOAT3); 379 // 纹理坐标 380 decl->addElement(MAIN_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0); 381 offset += VertexElement::getTypeSize(VET_FLOAT2); 382 if (hasSecondLayer) // 如果有第二层 383 { 384 decl->addElement(MAIN_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 1); 385 offset += VertexElement::getTypeSize(VET_FLOAT2); 386 if (mHasLightMap) 387 { 388 decl->addElement(MAIN_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 2); 389 offset += VertexElement::getTypeSize(VET_FLOAT2); 390 } 391 } 392 else 393 { 394 if (mHasLightMap) 395 { 396 decl->addElement(MAIN_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 1); 397 offset += VertexElement::getTypeSize(VET_FLOAT2); 398 } 399 } 400 401 // 顶点缓存 402 HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton() 403 .createVertexBuffer(offset, vCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY); 404 // 获得顶点缓存的地址 405 float* pReal = static_cast<float*>(vbuf->lock(HardwareBuffer::HBL_DISCARD)); 406 407 // 索引缓存 408 sm->indexData->indexCount = (vCount/2)*3; 409 sm->indexData->indexBuffer = HardwareBufferManager::getSingleton() 410 .createIndexBuffer(HardwareIndexBuffer::IT_16BIT, (vCount/2)*3, HardwareBuffer::HBU_STATIC_WRITE_ONLY); 411 // 获得索引缓存的地址 412 unsigned short* pI = static_cast<unsigned short*>(sm->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD)); 413 414 // 循环写入数据到硬件缓存 415 AxisAlignedBox meshBounds; // AABB绑定盒 416 Real meshRadius = 0; // 球体半径 417 for (int z = startz; z < endz; ++ z) 418 { 419 for (int x = startx; x < endx; ++ x) 420 { 421 int index = x + z*mXSize; // 转换成一维数组索引 422 423 // 424 if (mManualMatData[index] == matName && mGridData[index].nFirstLayer >= 0) 425 { 426 // 高度图坐标转换 427 // 因为网格数量是192*192的话,顶点就是193*193 428 int heightIndex = index + z; 429 430 // 第一层纹理坐标 431 int index1 = mGridData[index].nFirstLayer; 432 Real left1 = mPixMapData[index1].left; 433 Real right1 = mPixMapData[index1].right; 434 Real top1 = mPixMapData[index1].top; 435 Real bottom1 = mPixMapData[index1].bottom; 436 Vector2 left_top_1(left1, top1); 437 Vector2 right_top_1(right1, top1); 438 Vector2 right_bottom_1(right1, bottom1); 439 Vector2 left_bottom_1(left1, bottom1); 440 // 图片翻转等操作 441 if (mGridData[index].nFirstLayerOp != 0) 442 { 443 flipPicture(mGridData[index].nFirstLayerOp, left_top_1, right_top_1, left_bottom_1, right_bottom_1, mGridData[index].IndexOrder); 444 } 445 446 // 第二层纹理坐标 447 Vector2 left_top_2; 448 Vector2 right_top_2; 449 Vector2 right_bottom_2; 450 Vector2 left_bottom_2; 451 if (mGridData[index].nSecondLayer >= 0) 452 { 453 int index2 = mGridData[index].nSecondLayer; 454 Real left2 = mPixMapData[index2].left; 455 Real right2 = mPixMapData[index2].right; 456 Real top2 = mPixMapData[index2].top; 457 Real bottom2 = mPixMapData[index2].bottom; 458 left_top_2 = Vector2(left2, top2); 459 right_top_2 = Vector2(right2, top2); 460 right_bottom_2 = Vector2(right2, bottom2); 461 left_bottom_2 = Vector2(left2, bottom2); 462 if (mGridData[index].nSecondLayerOp != 0) 463 { 464 flipPicture(mGridData[index].nSecondLayerOp, left_top_2, right_top_2, left_bottom_2, right_bottom_2, mGridData[index].IndexOrder); 465 } 466 } 467 468 // 光照图纹理坐标 469 Vector2 left_top_3; 470 Vector2 right_top_3; 471 Vector2 right_bottom_3; 472 Vector2 left_bottom_3; 473 if (mHasLightMap) 474 { 475 Real left3 = (Real)x / (Real)mXSize; 476 Real right3 = left3 + 1/(Real)mXSize; 477 Real top3 = (Real)z / (Real)mZSize; 478 Real bottom3 = top3 + 1/(Real)mZSize; 479 left_top_3 = Vector2(left3, top3); 480 right_top_3 = Vector2(right3, top3); 481 right_bottom_3 = Vector2(right3, bottom3); 482 left_bottom_3 = Vector2(left3, bottom3); 483 } 484 485 // 对mesh每个网格的个顶点编写数据 486 // 点0 487 // position 488 Vector3 position(x*mScaleX, mHeightMapData[heightIndex]*mScaleY, z*mScaleZ); 489 *pReal++ = position.x; 490 *pReal++ = position.y; 491 *pReal++ = position.z; 492 meshBounds.merge(position); // update bounds 493 meshRadius = std::max(meshRadius, position.length()); // update bounds 494 // normal 495 Vector3 normal = getNormalAt(x, z); 496 *pReal++ = normal.x; 497 *pReal++ = normal.y; 498 *pReal++ = normal.z; 499 // uv1 500 *pReal++ = left_top_1.x; 501 *pReal++ = left_top_1.y; 502 // uv2 503 if (mGridData[index].nSecondLayer >= 0) 504 { 505 *pReal++ = left_top_2.x; 506 *pReal++ = left_top_2.y; 507 } 508 // uv3 509 if (mHasLightMap) 510 { 511 *pReal++ = left_top_3.x; 512 *pReal++ = left_top_3.y; 513 } 514 515 516 // 点1 517 // position 518 position = Vector3((x+width)*mScaleX, mHeightMapData[heightIndex+1]*mScaleY, z*mScaleZ); 519 *pReal++ = position.x; 520 *pReal++ = position.y; 521 *pReal++ = position.z; 522 meshBounds.merge(position); // update bounds 523 meshRadius = std::max(meshRadius, position.length()); // update bounds 524 // normal 525 normal = getNormalAt(x+width, z); 526 *pReal++ = normal.x; 527 *pReal++ = normal.y; 528 *pReal++ = normal.z; 529 // uv1 530 *pReal++ = right_top_1.x; 531 *pReal++ = right_top_1.y; 532 // uv2 533 if (mGridData[index].nSecondLayer >= 0) 534 { 535 *pReal++ = right_top_2.x; 536 *pReal++ = right_top_2.y; 537 } 538 // uv3 539 if (mHasLightMap) 540 { 541 *pReal++ = right_top_3.x; 542 *pReal++ = right_top_3.y; 543 } 544 545 // 点2 546 // position 547 position = Vector3((x+width)*mScaleX, mHeightMapData[heightIndex+mXSize+2]*mScaleY, (z+width)*mScaleZ); 548 *pReal++ = position.x; 549 *pReal++ = position.y; 550 *pReal++ = position.z; 551 meshBounds.merge(position); // update bounds 552 meshRadius = std::max(meshRadius, position.length()); // update bounds 553 // normal 554 normal = getNormalAt(x+width, z+width); 555 *pReal++ = normal.x; 556 *pReal++ = normal.y; 557 *pReal++ = normal.z; 558 // uv1 559 *pReal++ = right_bottom_1.x; 560 *pReal++ = right_bottom_1.y; 561 // uv2 562 if (mGridData[index].nSecondLayer >= 0) 563 { 564 *pReal++ = right_bottom_2.x; 565 *pReal++ = right_bottom_2.y; 566 } 567 // uv3 568 if (mHasLightMap) 569 { 570 *pReal++ = right_bottom_3.x; 571 *pReal++ = right_bottom_3.y; 572 } 573 574 // 点3 575 // position 576 position = Vector3(x*mScaleX, mHeightMapData[heightIndex+mXSize+1]*mScaleY, (z+width)*mScaleZ); 577 *pReal++ = position.x; 578 *pReal++ = position.y; 579 *pReal++ = position.z; 580 meshBounds.merge(position); // update bounds 581 meshRadius = std::max(meshRadius, position.length()); // update bounds 582 // normal 583 normal = getNormalAt(x, z+width); 584 *pReal++ = normal.x; 585 *pReal++ = normal.y; 586 *pReal++ = normal.z; 587 // uv1 588 *pReal++ = left_bottom_1.x; 589 *pReal++ = left_bottom_1.y; 590 // uv2 591 if (mGridData[index].nSecondLayer >= 0) 592 { 593 *pReal++ = left_bottom_2.x; 594 *pReal++ = left_bottom_2.y; 595 } 596 // uv3 597 if (mHasLightMap) 598 { 599 *pReal++ = left_bottom_3.x; 600 *pReal++ = left_bottom_3.y; 601 } 602 603 // 索引 604 int off = k * 4; 605 if (mGridData[index].IndexOrder == 0) // 正常索引顺序 606 { 607 *pI++ = 1 + off; 608 *pI++ = 0 + off; 609 *pI++ = 3 + off; 610 611 *pI++ = 1 + off; 612 *pI++ = 3 + off; 613 *pI++ = 2 + off; 614 } 615 else 616 { 617 *pI++ = 0 + off; 618 *pI++ = 3 + off; 619 *pI++ = 2 + off; 620 621 *pI++ = 0 + off; 622 *pI++ = 2 + off; 623 *pI++ = 1 + off; 624 } 625 626 ++ k; 627 } 628 } 629 } 630 631 vbuf->unlock(); 632 sm->vertexData->vertexBufferBinding->setBinding(MAIN_BINDING, vbuf); // 绑定顶点缓存 633 634 sm->indexData->indexBuffer->unlock(); 635 636 sm->setMaterialName(matName); 637 638 // 设置绑定盒子和球体半径, 查询裁剪用 639 //Real min = -10*mScaleY; 640 //Real max = 25*mScaleY; 641 //AxisAlignedBox meshBounds( 642 // (Real)startx*mScaleX, 643 // min, 644 // (Real)startz*mScaleZ, 645 // (Real)(endx - 1)*mScaleX, 646 // max, 647 // (Real)(endz - 1)*mScaleZ); 648 649 //Real meshRadius = Math::Sqrt( 650 // Math::Sqr(max - min) + 651 // Math::Sqr((endx - 1 - startx) * mScaleX) + 652 // Math::Sqr((endz - 1 - startz) * mScaleZ)) / 2; 653 654 mesh->_setBounds(meshBounds); 655 mesh->_setBoundingSphereRadius(meshRadius); 656 657 mesh->load(); 658 659 return true; 660} 661 662//-------------------------------------------------------------------------------------------------------- 663void TLBBTerrain::createWCollision(const String &fileName , const String &groupName) 664{ 665 DataStreamPtr stream = ResourceGroupManager::getSingleton().openResource(fileName , groupName); 666 667 // 读取文件头, 8个字节的结构 668 WCollisionHeader header; 669 stream->read(&header , sizeof(header)); 670 671 Vector3 vec3 = Vector3::ZERO; 672 int col = 0; 673 int row = 0; 674 int preCol = 0; // 前一个数据块的列 675 int preRow = 0; // 前一个数据块的行 676 int number = 0; 677 int k = 0; 678 bool firstTime = true; // 第一次 679 680 while (!stream->eof()) 681 { 682 // 行列坐标, 决定WCollision的分块信息的 683 // 如果把WCOliision做成一个mesh,每次都会全部查询,效率很低 684 stream->read(&col, sizeof(row)); 685 stream->read(&row, sizeof(col)); 686 687 stream->read(&number, sizeof(number)); // 数据块的三角形数量 688 689 // 读取此数据块的三角形顶点数据 690 for (int i = 0; i < number * 3; ++ i) 691 { 692 stream->read(&vec3, sizeof(vec3)); 693 mWCollisionData.push_back(vec3); 694 } 695 696 if (mWCollisionData.size() == 0) 697 { 698 break; 699 } 700 701 // 初始化 702 if (firstTime) 703 { 704 preCol = col; 705 preRow = row; 706 firstTime = false; 707 } 708 709 // 行列坐标相连,就做成一个mesh 710 if (col == preCol && (row - preRow) <= 1) 711 { 712 preCol = col; 713 preRow = row; 714 } 715 else 716 { 717 // 生成 718 ManualObject mo("mo"); 719 mo.begin("", RenderOperation::OT_TRIANGLE_LIST); 720 for(size_t i = 0; i < mWCollisionData.size(); i += 3) 721 { 722 // 点1 723 mo.position(mWCollisionData[i].x*mScaleX, mWCollisionData[i].y*mScaleY, mWCollisionData[i].z*mScaleZ); 724 mo.colour(ColourValue(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//-------------------------------------------------------------------------------------------------------- 759void TLBBTerrain::createTerrain() 760{ 761 // 生成材质 762 LogManager::getSingleton().logMessage(LML_CRITICAL, "开始生成材质"); 763 createManualMat(); 764 765 // 生成WCollision 766 LogManager::getSingleton().logMessage(LML_CRITICAL, "开始生成WCollsion"); 767 vector<String> vec; 768 vec = StringUtil::split(mFileName, ".", 1); 769 String tempStr = vec[0] + ".WCollision"; 770 createWCollision(tempStr, "TLBB"); 771 772 // 地形mesh 773 LogManager::getSingleton().logMessage(LML_CRITICAL, "开始生成地形mesh"); 774 775 // 判断地形大小是否能被tile整除,不能整除就需要矫正每行每列最后一个tile的大小 776 // 在循环外部判断,就不用每次循环都判断,效率更高 777 if (mXSize % mTileSize != 0 || mZSize % mTileSize != 0) 778 { 779 for (size_t matIndex = 0; matIndex < mMaterialNum; ++ matIndex) 780 { 781 // 材质名字 782 // toString和StrStreamType是用std::ostringstream来做的,非常消耗cpu,尽量减少循环数次 783 // 或者用sprintf来做 784 String matName = "material" + StringConverter::toString(matIndex); 785 786 // 同材质的mesh按tile区域生成 787 for (size_t i = 0; i < mZSize; i += mTileSize) 788 { 789 for (size_t j = 0; j < mXSize; j += mTileSize) 790 { 791 // 矫正tile大小 792 int tielSizeZ = mTileSize; 793 int tileSizeX = mTileSize; 794 if (mZSize - i < mTileSize) 795 { 796 tielSizeZ = mZSize - i; 797 } 798 if (mXSize - j < mTileSize) 799 { 800 tileSizeX = mXSize - j; 801 } 802 803 // 第一种方法 804 // 现有的地形检测暂时不支持ManualObject,以后考虑添加 805 //createTileManualObject(j, i, tileSizeX, tielSizeZ, matName); 806 807 // 第二种方法 808 if (createTileMesh(j, i, tileSizeX, tielSizeZ, matName)) 809 { 810 StringUtil::StrStreamType entName; 811 StringUtil::StrStreamType meshName; 812 entName << "tile[" << i << "]" << "[" << j << "]" << matName; 813 meshName << "gridMesh[" << i << "]" << "[" << j << "]" << matName; 814 Entity* entity = mSceneMgr->createEntity(entName.str(), meshName.str()); 815 entity->setCastShadows(false); 816 entity->setQueryFlags(TERRAIN_QUERY_MASK); 817 mSceneMgr->getRootSceneNode()->createChildSceneNode(mCentre)->attachObject(entity); 818 } 819 } 820 } 821 } 822 } 823 else 824 { 825 for (size_t matIndex = 0; matIndex < mMaterialNum; ++ matIndex) 826 { 827 // 材质名字 828 // toString和StrStreamType是用std::ostringstream来做的,非常消耗cpu,尽量减少循环数次 829 // 或者用sprintf来做 830 String matName = "material" + StringConverter::toString(matIndex); 831 832 // 同材质的mesh按tile区域生成 833 for (size_t i = 0; i < mZSize; i += mTileSize) 834 { 835 for (size_t j = 0; j < mXSize; j += mTileSize) 836 { 837 838 // 第一种方法 839 // 现有的地形检测暂时不支持ManualObject,以后考虑添加 840 //createTileManualObject(j, i, mTileSize, mTileSize, matName); 841 842 // 第二种方法 843 if (createTileMesh(j, i, mTileSize, mTileSize, matName)) 844 { 845 StringUtil::StrStreamType entName; 846 StringUtil::StrStreamType meshName; 847 entName << "tile[" << i << "]" << "[" << j << "]" << matName; 848 meshName << "gridMesh[" << i << "]" << "[" << j << "]" << matName; 849 Entity* entity = mSceneMgr->createEntity(entName.str(), meshName.str()); 850 entity->setCastShadows(false); 851 entity->setQueryFlags(TERRAIN_QUERY_MASK); 852 mSceneMgr->getRootSceneNode()->createChildSceneNode(mCentre)->attachObject(entity); 853 } 854 } 855 } 856 } 857 } 858}
|