Vertex and Index Buffers在OGRE中的应用

  本文主要介绍些在OGRE中创建Vertex Buffer和Index Buffer的主要流程。Vertex Buffer主要用来保存一组数据,这些数据可以包括顶点,顶点颜色,顶点法线或贴图坐标等等。Index Buffer是用来保存Vertex Buffer中对应顶点的索引。通过Vertex Buffer 和IndexBuffer 可以创建自己的Mesh并载入,以下是基本流程:

首先:定义你自己的顶点数据(Mesh的坐标数据)和对应的顶点索引(注意三角形顶点顺序)

例如:

复制代码
float vertices[vbufCount] = {
            -100.0,100.0,-100.0,        //0 position
            -sqrt13,sqrt13,-sqrt13,     //0 normal
            100.0,100.0,-100.0,         //1 position
            sqrt13,sqrt13,-sqrt13,      //1 normal
            100.0,-100.0,-100.0,        //2 position
            sqrt13,-sqrt13,-sqrt13,     //2 normal
            -100.0,-100.0,-100.0,       //3 position
            -sqrt13,-sqrt13,-sqrt13,    //3 normal
            -100.0,100.0,100.0,         //4 position
            -sqrt13,sqrt13,sqrt13,      //4 normal
            100.0,100.0,100.0,          //5 position
            sqrt13,sqrt13,sqrt13,       //5 normal
            100.0,-100.0,100.0,         //6 position
            sqrt13,-sqrt13,sqrt13,      //6 normal
            -100.0,-100.0,100.0,        //7 position
            -sqrt13,-sqrt13,sqrt13,     //7 normal
    };
复制代码

复制代码
    unsigned short faces[indexCount] = {
            0,2,3,
            0,1,2,
            1,6,2,
            1,5,6,
            4,6,5,
            4,7,6,
            0,7,4,
            0,3,7,
            0,5,1,
            0,4,5,
            2,7,3,
            2,6,7
    };
复制代码

其次,创建Mesh,此处有两种方法,首先介绍下用MeshManager来创建的方法(用ManualObject的方法,在本文的最后涉及)

 Ogre::MeshPtr msh = MeshManager::getSingleton().createManual("Name", "General");

 SubMesh* sub = msh->createSubMesh();

根据你的顶点数据和索引数据的信息,来确定msh参数的值,如下:

msh->sharedVertexData = new VertexData();
msh->sharedVertexData->vertexCount = nVertices;

然后,声明每个点在你的Buffer中的具有的内部分布结构,也就是除了点坐标,还具有的其他能描述该点的信息。例如是法线信息,还是位置信息,还是纹理坐标等等。注意在Buffer中要使用正确的偏移量。

VertexDeclaration* decl = msh->sharedVertexData->vertexDeclaration;
 size_t offset = 0;
 decl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
 offset += VertexElement::getTypeSize(VET_FLOAT3);
 decl->addElement(0, offset, VET_FLOAT3, VES_NORMAL);
 offset += VertexElement::getTypeSize(VET_FLOAT3);

接下来,就该创建和绑定这个Vertex Buffer了。

   HardwareVertexBufferSharedPtr vbuf = 
   HardwareBufferManager::getSingleton().createVertexBuffer(
              offset, msh->sharedVertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
    vbuf->writeData(0, vbuf->getSizeInBytes(), vertices, true);
    VertexBufferBinding* bind = msh->sharedVertexData->vertexBufferBinding; 
    bind->setBinding(0, vbuf);

这里详细介绍下createVertexBuffer的参数,offset是指在VertexBuffer中每个顶点间的偏移量,第二个参数指顶点的数量,第三个参数HBU_STATIC_WRITE_ONLY,是指你不需要经常更新缓存,并且你从不需要从缓存读取数据。然后writeData函数将vertices的数据写入vbuf,true参数的设置允许在写的时候,丢弃整个buffer的原有内容。最后将VB进行绑定。此处也可用另一种方法读取数据(用指针的方法填充VertexBuffer),而不是通过writeData。现在去掉writeData这行函数,加入如下代码。一下引用Snippet中的一些代码作为说明示例。

复制代码
     float* pVertex = static_cast<float*>(vBuf->lock(HardwareBuffer::HBL_DISCARD));
 
          for( int ring = 0; ring <= nRings; ring++ ) {
         float r0 = r * sinf (ring * fDeltaRingAngle);
         float y0 = r * cosf (ring * fDeltaRingAngle);
 
         // Generate the group of segments for the current ring
         for(int seg = 0; seg <= nSegments; seg++) {
             float x0 = r0 * sinf(seg * fDeltaSegAngle);
             float z0 = r0 * cosf(seg * fDeltaSegAngle);
 
             // Add one vertex to the strip which makes up the sphere
             *pVertex++ = x0;
             *pVertex++ = y0;
             *pVertex++ = z0;
 
             Vector3 vNormal = Vector3(x0, y0, z0).normalisedCopy();
             *pVertex++ = vNormal.x;
             *pVertex++ = vNormal.y;
             *pVertex++ = vNormal.z;
 
             *pVertex++ = (float) seg / (float) nSegments;
             *pVertex++ = (float) ring / (float) nRings;
 }

vBuf->unlock();
复制代码

这种方法需要给缓冲区加锁。

 

以上是我们对于VertexBuffer的创建过程。IndexBuffer的创建如出一辙。

复制代码
    HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton().
        createIndexBuffer(
        HardwareIndexBuffer::IT_16BIT, 
        ibufCount, 
        HardwareBuffer::HBU_STATIC_WRITE_ONLY);

     ibuf->writeData(0, ibuf->getSizeInBytes(), faces, true);

    /// Set parameters of the submesh
    sub->useSharedVertices = true;
    sub->indexData->indexBuffer = ibuf;
    sub->indexData->indexCount = ibufCount;
    sub->indexData->indexStart = 0;
复制代码

同样,也可以用指针的方法确定IndexBuffer中的内容。

复制代码
  unsigned short* pIndices = static_cast<unsigned short*>(iBuf->lock(HardwareBuffer::HBL_DISCARD));
 // Generate the group of rings for the sphere
     for( int ring = 0; ring <= nRings; ring++ ) {
         float r0 = r * sinf (ring * fDeltaRingAngle);
         float y0 = r * cosf (ring * fDeltaRingAngle);
 
         // Generate the group of segments for the current ring
         for(int seg = 0; seg <= nSegments; seg++) {
             float x0 = r0 * sinf(seg * fDeltaSegAngle);
             float z0 = r0 * cosf(seg * fDeltaSegAngle);
 
             if (ring != nRings) {
                                // each vertex (except the last) has six indices pointing to it
                 *pIndices++ = wVerticeIndex + nSegments + 1;
                 *pIndices++ = wVerticeIndex;               
                 *pIndices++ = wVerticeIndex + nSegments;
                 *pIndices++ = wVerticeIndex + nSegments + 1;
                 *pIndices++ = wVerticeIndex + 1;
                 *pIndices++ = wVerticeIndex;
                 wVerticeIndex ++;
             }
         }; // end for seg
     } // end for ring
  vBuf->unlock();
复制代码

最后,应该来确定你的创建的Mesh的包围盒,这样当你的Mesh处于相机之外的时候,将被裁减掉。包围和的创建要根据你的具体的mesh来确定,最后因为你的模型是自建的,需要load将模型载入,此处只给出snippet中一段简单的示例

 pSphere->_setBounds( AxisAlignedBox( Vector3(-r, -r, -r), Vector3(r, r, r) ), false );
     pSphere->_setBoundingSphereRadius(r);
         pSphere->load();

刚才提到用另种方法创建Mesh。应用ManualObject,思想与前面一样。代码如下:

复制代码
     ManualObject * manual = sceneMgr->createManualObject(strName);
     manual->begin("BaseWhiteNoLighting", RenderOperation::OT_TRIANGLE_LIST);
         
     float fDeltaRingAngle = (Math::PI / nRings);
     float fDeltaSegAngle = (2 * Math::PI / nSegments);
     unsigned short wVerticeIndex = 0 ;
 
     // Generate the group of rings for the sphere
     for( int ring = 0; ring <= nRings; ring++ ) {
         float r0 = r * sinf (ring * fDeltaRingAngle);
         float y0 = r * cosf (ring * fDeltaRingAngle);
 
         // Generate the group of segments for the current ring
         for(int seg = 0; seg <= nSegments; seg++) {
             float x0 = r0 * sinf(seg * fDeltaSegAngle);
             float z0 = r0 * cosf(seg * fDeltaSegAngle);
 
             // Add one vertex to the strip which makes up the sphere
             manual->position( x0, y0, z0);
             manual->normal(Vector3(x0, y0, z0).normalisedCopy());
             manual->textureCoord((float) seg / (float) nSegments, (float) ring / (float) nRings);
 
             if (ring != nRings) {
                 // each vertex (except the last) has six indicies pointing to it
                 manual->index(wVerticeIndex + nSegments + 1);
                 manual->index(wVerticeIndex);               
                 manual->index(wVerticeIndex + nSegments);
                 manual->index(wVerticeIndex + nSegments + 1);
                 manual->index(wVerticeIndex + 1);
                 manual->index(wVerticeIndex);
                 wVerticeIndex ++;
                 }
         }; // end for seg
     } // end for ring
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值