Ogre 天龙八部地形管理器

最近研究天龙八部的地形管理, 由于地形很大, 很显然Ogre自带的地形管理器没法使用
参考了别人的研究之后, 不打算使用ETM来管理地形
直接写了一个巨大的手工纹理来保存地形所需要的所有图像, 然后根据网格数据一个一个填写纹理坐标,
目前只写了地形第一层的代码, 第二层还没开始
读写速度还是很快的

下面是两张截图

参考他人的文章
修改 ETM,用Ogre实现《天龙八部》地形与部分场景详解(附源码)
纹理的创建方法和该文一样, 只是我打不算用ETM管理器创建地形
自己创建一个mesh来管理地形, 包含顶点数据, 纹理数据

01void TLBBTerrain::createManualMesh()
02{
03    MeshPtr mesh = MeshManager::getSingleton().createManual("mymesh",
04        ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
05    SubMesh* submesh = mesh->createSubMesh();
06    submesh->useSharedVertices = false;
07    // 顶点缓存
08    submesh->vertexData = new VertexData();
09    submesh->vertexData->vertexStart = 0;
10    unsigned int nCount = m_xSize * m_zSize * 4;
11    submesh->vertexData->vertexCount = nCount;
12    VertexDeclaration* decl = submesh->vertexData->vertexDeclaration;
13    VertexBufferBinding* bind = submesh->vertexData->vertexBufferBinding;
14    size_t offset = 0;
15    decl->addElement(MAIN_BINDING, offset, VET_FLOAT3, VES_POSITION);
16    offset += VertexElement::getTypeSize(VET_FLOAT3);
17    decl->addElement(MAIN_BINDING, offset, VET_FLOAT3, VES_NORMAL);
18    offset += VertexElement::getTypeSize(VET_FLOAT3);
19    decl->addElement(MAIN_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
20    offset += VertexElement::getTypeSize(VET_FLOAT2);
21    decl->addElement(MAIN_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 1);
22    offset += VertexElement::getTypeSize(VET_FLOAT2);
23    decl->addElement( MAIN_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 2);
24    offset += VertexElement::getTypeSize(VET_FLOAT2);
25    HardwareVertexBufferSharedPtr vertexBuffer = HardwareBufferManager::getSingleton().createVertexBuffer(
26        decl->getVertexSize(MAIN_BINDING), nCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
27    bind->setBinding(MAIN_BINDING, vertexBuffer);
28    float* pBase = static_cast<float*>(vertexBuffer->lock(HardwareBuffer::HBL_DISCARD));
29    TexureInfo info;
30    for (int j = 0; j < m_zSize; ++j)
31    {
32        for (int i = 0; i < m_xSize; ++i)
33        {
34            info = handleTexture(i, j);
35            // 点0
36            fillVertexData(i, j, pBase, info.firstleft, info.firsttop, info.secondleft, info.secondtop);
37            pBase += 12;
38            // 点1
39            fillVertexData(i, j+1, pBase, info.firstleft, info.firstbottom, info.secondleft, info.secondbottom);
40            pBase += 12;
41            // 点2
42            fillVertexData(i+1, j+1, pBase, info.firstright, info.firstbottom, info.secondright, info.secondbottom);
43            pBase += 12;
44            // 点3
45            fillVertexData(i+1, j, pBase, info.firstright, info.firsttop, info.secondright, info.secondtop);
46            pBase += 12;
47        }
48    }
49    vertexBuffer->unlock();
50    HardwareIndexBufferSharedPtr indexBuffer =
51        HardwareBufferManager::getSingleton().createIndexBuffer(
52        HardwareIndexBuffer::IT_32BIT,
53        m_xSize * m_zSize * 6,
54        HardwareBuffer::HBU_STATIC, true);
55    submesh->indexData->indexBuffer = indexBuffer;
56    submesh->indexData->indexStart = 0;
57    submesh->indexData->indexCount = m_xSize * m_zSize * 6;
58    unsigned int* indexBuff = (unsigned int*)indexBuffer->lock(HardwareBuffer::HBL_NORMAL);
59    int indexFirstNum = 0;
60    for (int j = 0; j < m_zSize; ++j)
61    {
62        for (int i = 0; i < m_xSize; ++i)
63        {
64            *indexBuff++ = indexFirstNum;
65            *indexBuff++ = indexFirstNum + 1;
66            *indexBuff++ = indexFirstNum + 2;
67            *indexBuff++ = indexFirstNum;
68            *indexBuff++ = indexFirstNum + 2;
69            *indexBuff++ = indexFirstNum + 3;
70            indexFirstNum += 4;
71        }
72    }
73    indexBuffer->unlock();
74    AxisAlignedBox meshBounds(0, m_minHeight * m_scale.y, 0,
75        m_xSize * m_scale.x, m_maxHeight * m_scale.y, m_zSize * m_scale.z);
76    mesh->_setBounds(meshBounds);
77    mesh->load();
78    mesh->touch();
79    // 设置相机位置
80    mSceneMgr->getCamera("PlayerCam")->setPosition(0, m_maxHeight * m_scale.y, 0);
81}

其实我认为, 可以根据主角在场景的位置创建小范围的mesh, 可以将该mesh分成tile*tile大小, 根据主角位置创建周围四个tile的mesh就可以了. 不需要写这么大的mesh.等以后写入主角怪物的时候在写这段代码

加载静态对象的时候出现了很多问题, 经过分析, 发现天龙八部游戏新版本的很多mesh不能够直接使用, 主要是Model目录里面的0灌木, 0树木, 0物品三个文件夹里面的mesh文件
直接拷贝老天龙的数据就可以了
不过加载的时候读取skeleton数据会出现错误, 查找一些资料后发现需要直接修改Ogre源码, 这些数据主要用于实现骨骼动画的时候会出现
对OgreSkeletonSerializer.cpp文件里面的SkeletonSerializer::readAnimationTrack 函数进行修改.然后编译出ogremain.dll, ogremain_d.lib, 覆盖OgreSDK/bin文件里面的同名文件

01void   SkeletonSerializer::readAnimationTrack(DataStreamPtr  &   stream, Animation  *   anim,
02       Skeleton *  pSkel)
03   {
04        //  unsigned short boneIndex     : Index of bone to apply to
05       unsigned  short  boneHandle;
06       readShorts(stream,  & boneHandle,  1 );
07        //  Find bone
08       Bone  * targetBone  =  pSkel -> getBone(boneHandle);
09        //  Create track
10       NodeAnimationTrack *  pTrack  =  anim -> createNodeTrack(boneHandle, targetBone);
11        //  Keep looking for nested keyframes
12        if  ( ! stream -> eof())
13       {
14           unsigned  short  streamID  =  readChunk(stream);
15            // while(streamID == SKELETON_ANIMATION_TRACK_KEYFRAME && !stream->eof())
16            while ((streamID  ==  SKELETON_ANIMATION_TRACK_KEYFRAME  ||  streamID  ==   0x4120 )  &&   ! stream -> eof())
17           {
18                if  (streamID  ==   0x4120 )
19               {
20                   unsigned  short  len;
21                   readShorts(stream,  & len,  1 );
22                   unsigned  short  flags;
23                   readShorts(stream,  & flags,  1 );
24                    int  count  =  (mCurrentstreamLen  -   4   -   4 )  /   4 ;
25                    if  (len  !=  count  /   8 )
26                       len  =  len;
27                    float  time;
28                    for  ( int  i  =   0 ; i  <  len; i  +=   1 )
29                   {
30                       readFloats(stream,  & time,  1 );
31                       TransformKeyFrame  * kf  =  pTrack -> createNodeKeyFrame(time);
32                       Quaternion rot  =  Quaternion::IDENTITY;
33                        if  (flags  &   1 )
34                       {
35                           readObject(stream, rot);
36                       }
37                       kf -> setRotation(rot);
38                       Vector3 trans  =  Vector3::ZERO;
39                        if  (flags  &   2 )
40                       {
41                           readObject(stream, trans);
42                       }
43                       kf -> setTranslate(trans);
44                   }
45               }
46                else
47                   readKeyFrame(stream, pTrack, pSkel);
48                if  ( ! stream -> eof())
49               {
50                    //  Get next stream
51                   streamID  =  readChunk(stream);
52               }
53           }
54            if  ( ! stream -> eof())
55           {
56                //  Backpedal back to start of this stream if we've found a non-keyframe
57               stream -> skip( - STREAM_OVERHEAD_SIZE);
58           }
59       }
60   }

显示场景图如下

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值