Lotes de Geometria de Bajo-Nivel usando Buferes Hardware y motor de Geometria Paginada



Este articulo da un codigo de demostracion practico del uso de los buferes hardware y permite comprender como el motor de Geometria paginada funciona para los anyadidos de ogre.
Este tutorial no trata de reemplazar al Manual de Ogre pero da un codigo practico para ayudar con estas clases.

Como notaras cuando estudies en motor de Geometria paginada el codigo de debajo es un extracto del motor. Estoy agradecido a JohnJ sin este codigo no podria haber entendido los conceptos.


¿Qué es un Lote de Geometría?


Los lotes son procesos de renderizado enviando cantidades masivas de mallas accediendo directamente a la memoria grafica. Para un uso simple usando Geometria estatica. Sin embargo algunas veces necesitas ser capaz de usar mas metodos fundamentales (como si quieres crear un manejador de escena especifico, tener mas control sobre el detalle de las mallas basadas en -LOD, ...). La Geometria paginada es un buen ejemplo.

Estructura de Vertices y de Búferes

TODO Un bonito diagrama UML :-D


VertexData

VertexDeclaration* vertexDeclaration;
VertexBufferBinding* vertexBufferBinding;
size_t vertexStart; size_t vertexCount;
HardwareAnimationDataList hwAnimationDataList;
size_t hwAnimationItemUsed;
Colección de información de fuentes de vértices. vertexCount es el número de vértices. hwAnimationDataList es usado para la animación de forma/poses.

IndexData

size_t indexStart;
size_t indexCount;
indexStart: posición en el búfer para comenzar desde una operación.
indexCount: número de índices a usar desde un búfer.

HardwareVertexBuffer
size_t mNumVertices;
size_t mVertexSize;
mVertexSize: tamaño de un vértice single en este búfer.

HardwareIndexBuffer

enum IndexType;
enum Usage;
enum LockOptions;
...

VertexBufferBinding

std::map<ushort,
HardwareVertexBufferSharedPtr> &nbsp; &nbsp; &nbsp; &nbsp; VertexBufferBindingMap;
VertexBufferBindingMap mBindingMap;
ushort mHightIndex;
...

VertexDeclaration

typedef std::list<VertexElement>
VertexElementList;
VertexElementList mElementList;
VertexElement debería ser añadido en un orden preciso: mirar debajo.

VertexElement

ushort mSource;
size_t mOffset;
VertexElementType mType;
VertexElementSemantic mSemantics;
ushort mIndex;
por hacer.


Algunos puntos importantes tienen que tenerse en consideracion cuando se implementa una declaracion de Vertices:

Deberias tener cuidado del orden y estructura de la declaracion de vertices que podria ser importante en DirectX con tarjetas antiguas, asi que si quieres mantener la maxima compatibilidad con todos los sistemas de renderizado y todas las tarjetas deberias tener cuidado con las siguientes reglas:

  1. Los VertexElements (elementos de vertice) deberian ser anyadidos en el orden siguiente, y el orden de los elementos dentro de un bufer compartido deberia ser asi: posicion, mezclado de pesos, normales, colores difusos, colores especulares, coordenadas de textura (en orden, sin saltos)
  2. No debes tener saltos sin usar en tus buferes que no esten referenciados por ningun VertexElement
  3. No debes permitir que los ajustes de bufer y desplazamiento(offset) de 2 Elementos de vertice se superpongan.

Uso del Codigo de Ejemplo


El codigo de debajo demostrara como hacer un Objeto movil que use gemetria por lotes. El codigo puede estar compilado con una libreria estatica usada de manera muy simple. Mostrara un cubo simple (sin textura, sin color).
El anyadido de una textura y del color deberia hacerse en una segunda parte.
Ogre::SceneNode* sn = sceneManager->getRootSceneNode()
->createChildSceneNode(Ogre::Vector3(0,0,0));
 
Ogre::BatchedGeometry* object =
new Ogre::BatchedGeometry(sceneManager, sn);
 
object->addObject(Ogre::Vector3::ZERO);
object->build();
Para anyadir nuestra geometria necesitas modificar el codigo entre:
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Nota: El codigo es un extracto del fuente del Motor de Geometria Paginada tambien conocido como el enlace de anyadidos.



Estructura de Codigo



El codigo esta solo compuesto de dos clases: BatchedGeometry y Batch.


BatchedGeometry deriva de MovableObject lo que significa que puedes manipularlo facilmente en tus escenas. Su proposito es agrupar varios de las subpartes que componen la geometria que tu quieres poner por lotes.


Un punto muy importante a notar es que los lotes deberian estar agrupados juntos para usar el hardware a su maximo potencial. Esta es la razon del metodo BatchedGeometry::getFormatString() en el motor de Geometria Paginada. No implemente esto (todavia) guarda el codigo ... es simple.


Batch deriva de un Renderable. Esta es la calse que accede al bufer hardware durante la fase de renderizado.


Codigo Fuente

OgreBatchedGeometry.h



#ifndef OGE_BATCHEDGEOMETRY_H
#define OGE_BATCHEDGEOMETRY_H
 
#include "OgreBatch.h"
#include "OGRE/OgrePrerequisites.h"
#include "OGRE/OgreMovableObject.h"
 
namespace Ogre
{
   /**
   */
   class BatchedGeometry: public MovableObject
   {
   private:
      Vector3 mCenter;
      Real mRadius;
      AxisAlignedBox mBounds;
      bool mBoundsUndefined;
 
      Real mMinDistanceSquared;
      // Por que no estamos usando MovableObject::mBeyondFarDistance ?
      bool mWithinFarDistance;
 
      /// Guarda una lista de Batchs(lotes), usando un formato de cadena
      /// (generado con getGeometryFormatString()) como el valor clave
      typedef std::map<String, Batch*> BatchMap;
      BatchMap mBatchs;
 
      bool mIsBuilt;
 
      SceneManager* mSceneManager;
      SceneNode* mSceneNode;
      SceneNode* mParentSceneNode;
 
public:
      typedef Ogre::MapIterator<BatchMap> BatchIterator;
 
public:
      BatchedGeometry(SceneManager* mgr, SceneNode* parentSceneNode);
      virtual ~BatchedGeometry();
 
      // ---- Metodo abstracto que necesita ser implementado ----
      const String& getMovableType() const {
      static String s = "BatchedGeometry"; return s; }
      const AxisAlignedBox& getBoundingBox() const { return mBounds; }
      Real getBoundingRadius() const { return mRadius; }
      const Vector3& getCenter() const { return mCenter; }
      const SceneNode* getSceneNode() const { return mSceneNode; }
 
      void _updateRenderQueue(RenderQueue* queue);
      void visitRenderables(Renderable::Visitor* visitor, bool debugRenderables) {}
 
      // ------------------------------------------------------
 
      void clear();
      void build();
 
      bool isVisible();
 
      /** Metodo interno para notificar que el objeto de la camara
       * sera usado para la siguiente operacion de renderizado
       */
      void _notifyCurrentCamera(Camera* cam);
 
      void addSelfToRenderQueue(RenderQueue* queue, uint8 group);
      inline Real const getMinDistanceSquared() const {
           return mMinDistanceSquared; }
 
      /// Convierte desde la posicion global a la local
      /// en el sistema de coordenadas del nodo padre de la escena
      Vector3 convertToLocal(const Vector3& globalVec) const;
 
      BatchIterator getBatchIterator() const;
 
      // El metodo principal de la clase!
      void addObject(const Vector3& position,
           const Quaternion& orientation = Quaternion::IDENTITY,
           const Vector3& scale = Vector3::UNIT_SCALE);
 
      /// Genera un formato de cadena unico que identifica
      /// a este material y al formato de vertice/indices
      // TODO String getFormatString(Ogre::SubEntity* ent);
};
}
#endif

OgreBatchedGeometry.cpp


#include "OgreBatchedGeometry.h"
 
#include "OGRE/OgreCamera.h"
#include "OGRE/OgreSceneNode.h"
#include "OGRE/OgreSceneManager.h"
 
namespace Ogre
{
// -----------------------------------------------------------------------------
BatchedGeometry::BatchedGeometry(SceneManager* mgr,
SceneNode* parentSceneNode)
: mBoundsUndefined(true),
mMinDistanceSquared(0),
mWithinFarDistance(false),
mSceneManager(mgr),
mSceneNode(0),
mParentSceneNode(parentSceneNode)
{
    clear();
    COUT("BatchedGeometry created")
}
// -----------------------------------------------------------------------------
 
BatchedGeometry::~BatchedGeometry()
{
    clear();
    COUT("BatchedGeometry destroyed")
}
// -----------------------------------------------------------------------------
 
void BatchedGeometry::clear()
{
    // Elimina el lote de la escena
    if (mSceneNode)
    {
        mSceneNode->removeAllChildren();
        mSceneManager->destroySceneNode(mSceneNode->getName());
        mSceneNode = 0;
    }
 
    // Reestablece los limites de la informacion
    mBoundsUndefined = true;
    // mBounds = AxisAlignedBox::BOX_NULL; why not?
    mCenter = Vector3::ZERO;
    mRadius = 0;
 
    // Elimina cada lote
    for (BatchMap::iterator i = mBatchs.begin(); i != mBatchs.end(); ++i)
    {
        delete i->second;
    }
    mBatchs.clear();
 
    mIsBuilt = false;
}
// -----------------------------------------------------------------------------
 
void BatchedGeometry::build()
{
    if (mIsBuilt)
        OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, "Invalid call to build() - celestial object is already batched (call clear() first)", "BatchedGeometry::build()");
 
    if (mBatchs.size() != 0)
    {
        // Finaliza los limites de la informacion
        mCenter = mBounds.getCenter();
        // Centra la caja de limite
        mBounds.setMinimum(mBounds.getMinimum() - mCenter);
        mBounds.setMaximum(mBounds.getMaximum() - mCenter);
        // Calcula el radio BB
        mRadius = mBounds.getMaximum().length();
 
        // Crea el nodo de escena
        mSceneNode = mParentSceneNode->createChildSceneNode(mCenter);
 
        // Construye cada lote
        for (BatchMap::iterator i = mBatchs.begin(); i != mBatchs.end(); ++i)
        {
            i->second->build();
        }
     }
 
     // Acopla el lote al nodo de escena
     mSceneNode->attachObject(this);
 
     // Depuracion
     mSceneNode->showBoundingBox(true); // TODO param
 
     mIsBuilt = true;
  }
  // -----------------------------------------------------------------------------
 
  void BatchedGeometry::_updateRenderQueue(RenderQueue* queue)
  {
     if (isVisible())
     {
          // Si cada lote se anyade a si mismo
          // a la cola de renderizado
          for (BatchMap::iterator i = mBatchs.begin(); i != mBatchs.end(); ++i)
          {
               i->second->addSelfToRenderQueue(queue,
                  getRenderQueueGroup());
          }
     }
  }
   // -----------------------------------------------------------------------------
 
  bool BatchedGeometry::isVisible()
  {
      // mVisible es un atributo MovableObject
      return mVisible && mWithinFarDistance;
  }
  // -----------------------------------------------------------------------------
 
  void BatchedGeometry::_notifyCurrentCamera(Camera* cam)
  {
      if (getRenderingDistance() == 0)
      {
          mWithinFarDistance = true;
      }
      else
      {
          // Calcula la distancia de la camara
          Vector3 camVec = convertToLocal(
             cam->getDerivedPosition()) - mCenter;
          Real centerDistanceSquared = camVec.squaredLength();
          mMinDistanceSquared = std::max(0.0f,
             centerDistanceSquared - (mRadius * mRadius));
 
          // Nota: centerDistanceSquared mide la distancia
          // entre la camara y el centro del lote,
          // mientras minDistanceSquared mide la distancia de cercania
          // entre la camara y el filo mas cercano a la esfera del limite de la geometria.
          // Determina si el BatchedGeometry esta dentro / de la distancia de renderizado lejana.
          mWithinFarDistance =
               mMinDistanceSquared <= Math::Sqr(getRenderingDistance());
       }
   }
 
   // -----------------------------------------------------------------------------
 
   Ogre::Vector3 BatchedGeometry::convertToLocal(const Vector3& globalVec) const
   {
       assert(mParentSceneNode);
       // Convierte de la posicion global al
       // sistema de coordenadas local del nodo de escena padre.
       return (mParentSceneNode->getOrientation().Inverse() * globalVec);
   }
   // -----------------------------------------------------------------------------
 
   BatchedGeometry::BatchIterator BatchedGeometry::getBatchIterator() const
   {
       return BatchIterator((BatchMap&)mBatchs);
   }
   // -----------------------------------------------------------------------------
 
   void BatchedGeometry::addObject(const Vector3& position,
const Quaternion& orientation, const Vector3& scale)
   {
        // Crea la geometria
        // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        String format = "aa"; TODO = getFormatString(...)
        // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
        Batch* batch;
 
        /* TODO
        BatchIterator iter = mBatchs.find(format);
        if (iter != mBatchs.end())
            batch = iter->second;
        else
        { */
            batch = new Batch(this);
            mBatchs.insert(std::pair<String, Batch*>(format, batch));
         // }
 
         // cf. PagedGeometry addSubEntity()
         batch->addSub( position, orientation, scale );
 
         // Actualiza la caja de limites
         Matrix4 mat(orientation);
         mat.setScale(scale);
         AxisAlignedBox entBounds;
 
         // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         // entBounds = ent->getBoundingBox();
         entBounds.setMinimum(Vector3(-100,-100,-100));
         entBounds.setMaximum(Vector3( 100, 100, 100));
         // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
         entBounds.transform(mat);
 
         if (mBoundsUndefined)
         {
             mBounds.setMinimum(entBounds.getMinimum() + position);
             mBounds.setMaximum(entBounds.getMaximum() + position);
             mBoundsUndefined = false;
         }
         else
         {
             Vector3 min = mBounds.getMinimum();
             Vector3 max = mBounds.getMaximum();
             min.makeFloor(entBounds.getMinimum() + position);
             max.makeCeil(entBounds.getMaximum() + position);
             mBounds.setMinimum(min);
             mBounds.setMaximum(max);
         }
     }
     // -----------------------------------------------------------------------------
}



OgreBatch.h


#ifndef __OGRE_BATCH_H__
#define __OGRE_BATCH_H__
 
#include "OGRE/OgrePrerequisites.h"
#include "OGRE/OgreMovableObject.h"
#include "OGRE/OgreMaterialManager.h"
 
#define COUT(x) std::cout << x << std::endl;
 
namespace Ogre
{
    // Siguiente definicion
    class BatchedGeometry;
 
    /*
     *
     */
    class Batch : public Renderable
    {
    private:
        bool mIsBuilt;
 
        VertexData* mVertexData;
        IndexData* mIndexData;
 
        BatchedGeometry* mParent;
        MaterialPtr mMaterial;
 
        // NOTA : Esto deberia recalcularse cada frame
        Technique* mBestTechnique;
 
        // Deberia ser esto parte de una estructura?
        Vector3 mPosition;
        Quaternion mOrientation;
        Vector3 mScale;
        ColourValue mColour;
 
    public:
        Batch(BatchedGeometry* parent); , SubEntity* ent);
        ~Batch();
 
        void build();
        void clear();
 
        void setMaterial(MaterialPtr& mat) { mMaterial = mat; }
        void setMaterialName(const String& mat) {
        mMaterial = MaterialManager::getSingleton().getByName(mat); }
        inline String getMaterialName() const {
          return mMaterial->getName(); }
        const MaterialPtr& getMaterial() const { return mMaterial; }
 
        Technique* getTechnique() const { return mBestTechnique; }
 
        void getWorldTransforms(Matrix4* xform) const;
        const Quaternion& getWorldOrientation() const;
        const Vector3& getWorldPosition() const;
 
        bool castsShadows() const;
        const LightList& getLights() const;
 
        void addSelfToRenderQueue(RenderQueue* queue, uint8 group);
        void getRenderOperation(RenderOperation& operation);
        Real getSquaredViewDepth(const Camera* cam) const;
 
        /**
         * Esta funcion es usada para hacer un clon unico de los materiales,
         * ya que los materiales seran modificados por el sistema de lotes
         * (y no deberia ser bueno modificar los materiales originales
         * que el usuario podria usar en otro lugar).
         */
 
        Material* getMaterialClone(Material* material);
        // cf. Metodo de Geometria Paginada
        // void BatchedGeometry::SubBatch::addSubEntity(
        // SubEntity *ent, ....);
        void addSub(const Vector3& position,
            const Quaternion& orientation, const Vector3& scale,
            const ColourValue& color = ColourValue::White);
    };
}
#endif

OgreBatch.cpp


#include "OgreBatch.h"
#include "OgreBatchedGeometry.h"
 
#include "OGRE/OgreCamera.h"
#include "OGRE/OgreSceneNode.h"
#include "OGRE/OgreHardwareBufferManager.h"
#include "OGRE/OgreTechnique.h"
#include "OGRE/OgreRoot.h"
#include "OGRE/OgreRenderSystem.h"
#include "OGRE/OgreColourValue.h"
 
namespace Ogre
{
    // -----------------------------------------------------------------------------
    Batch::Batch(BatchedGeometry* parent) :
      mParent(parent)
    {
      mIsBuilt = false;
 
      // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      // Mirar PagedGeometry BatchedGeometry::SubBatch::SubBatch()
      // Material *origMat =
      //
((MaterialPtr)MaterialManager::getSingleton().getByName(
      // ent->getMaterialName())).getPointer();
      // mMaterial =
      // MaterialManager::getSingleton().getByName(
      // getMaterialClone(origMat)->getName());
      // mMaterial = MaterialManager::getSingleton().create(
      // "Test/ColourTest",
      // ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
      mMaterial->getTechnique(0)->getPass(0)->setVertexColourTracking(TVC_AMBIENT);
 
      mMaterial->getTechnique(0)->getPass(0)->setSpecular(0,0,0,1);
      // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
      // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      // Mirar Geometria Paginada para ver como clonar partes de los datos de la entidad
      mVertexData = new VertexData();
      mIndexData = new IndexData();
      // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
      // Reestablecer la cuenta de vertices/indices
      mVertexData->vertexStart = 0;
      mVertexData->vertexCount = 0;
      mIndexData->indexStart = 0;
      mIndexData->indexCount = 0;
     }
     // -----------------------------------------------------------------------------
     Batch::~Batch()
     {
        clear();
        delete mVertexData;
        delete mIndexData;
     }
     // -----------------------------------------------------------------------------
     void Batch::addSelfToRenderQueue(RenderQueue* queue, uint8 group)
     {
         if (mIsBuilt)
         {
              // Actualiza la tecnica del material basandose en la distancia a la camara
              assert(!mMaterial.isNull());
              mBestTechnique = mMaterial->getBestTechnique(
                  mMaterial->getLodIndexSquaredDepth(
                      mParent->getMinDistanceSquared()));
              queue->addRenderable(this, group);
         }
     }
     // -----------------------------------------------------------------------------
     bool Batch::castsShadows() const
     {
         return mParent->getCastShadows();
     }
     // -----------------------------------------------------------------------------
     void Batch::clear()
     {
         // Si se construye, borralo
         if (mIsBuilt)
         {
              // Borrar buferes
              mIndexData->indexBuffer.setNull();
              mVertexData->vertexBufferBinding->unsetAllBindings();
 
              // NOTA: Si estas anyadiendo los elementos cada vez
              // debes eliminar el anterior antes
              // mVertexData->vertexDeclaration->removeAllElements();
 
              // Reestablecer la cuenta de vertices/indices
              mVertexData->vertexStart = 0;
              mVertexData->vertexCount = 0;
              mIndexData->indexStart = 0;
              mIndexData->indexCount = 0;
         }
         mIsBuilt = false;
     }
     // -----------------------------------------------------------------------------
     Material* Batch::getMaterialClone(Material* material)
     {
         String name = material->getName() + "_Batch";
         MaterialPtr clone = MaterialManager::getSingleton().getByName( name );
 
         if (clone.isNull())
              clone = material->clone(name);
         return clone.getPointer();
     }
     // -----------------------------------------------------------------------------
     void Batch::getRenderOperation(RenderOperation& operation)
     {
         operation.operationType = RenderOperation::OT_TRIANGLE_LIST;
         operation.srcRenderable = this;
         operation.useIndexes = true;
         operation.vertexData = mVertexData;
         operation.indexData = mIndexData;
 
         /* depurar
         COUT(" 1 " << mVertexData->vertexCount)
         COUT(" 1 " << mVertexData->vertexCount)
         COUT(" 2 " << mVertexData->vertexDeclaration->getElementCount())
         COUT(" 3 " << mVertexData->vertexDeclaration->getVertexSize(0))
         COUT(" 4 " << mVertexData->vertexDeclaration->getElement(1)->getIndex())
         COUT(" 5 " << mVertexData->vertexDeclaration->getElement(1)->getSource())
         COUT(" 5 " << mIndexData->indexCount)
         COUT(" 6 " << mIndexData->indexBuffer->getIndexSize())
         COUT(" 7 " << mIndexData->indexBuffer->getNumIndexes())
         */
      }
      // -----------------------------------------------------------------------------
      Real Batch::getSquaredViewDepth(const Camera *camera) const
      {
         Vector3 pos = mParent->convertToLocal(
            camera->getDerivedPosition()) - mParent->getCenter();
 
         return pos.squaredLength();
      }
      // -----------------------------------------------------------------------------
      const LightList& Batch::getLights() const
      {
         return mParent->queryLights();
      }
      // -----------------------------------------------------------------------------
      void Batch::getWorldTransforms(Matrix4* xform) const
      {
         *xform = mParent->_getParentNodeFullTransform();
      }
      // -----------------------------------------------------------------------------
      const Quaternion& Batch::getWorldOrientation() const
      {
         return mParent->getSceneNode()->_getDerivedOrientation();
      }
      // -----------------------------------------------------------------------------
      const Vector3& Batch::getWorldPosition() const
      {
         return mParent->getSceneNode()->_getDerivedPosition();
      }
      // -----------------------------------------------------------------------------
      void Batch::addSub(const Vector3& position, const Quaternion& orientation,
      const Vector3& scale, const ColourValue& color)
      {
         assert(!mIsBuilt);
 
         // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         // Usa una estructura de datos de geometria para pasar los datos
         mVertexData->vertexCount = 8;
         mIndexData->indexCount = 36;
         // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
         mPosition = position;
         mOrientation = orientation;
         mScale = scale;
         mColour = color;
 
         VertexElementType format = Root::getSingleton().getRenderSystem()->getColourVertexElementType();
 
         switch (format)
         {
             case VET_COLOUR_ARGB:
                 std::swap(mColour.r, mColour.b);
                 break;
             case VET_COLOUR_ABGR:
                 break;
             default:
                 OGRE_EXCEPT(0, "Unknown RenderSystem color format", "Batch::addSub()");
                 break;
         }
     }
     // -----------------------------------------------------------------------------
     void Batch::build()
     {
         assert(!mIsBuilt);
 
         Vector3 batchCenter = mParent->getCenter();
 
         // Mirar PagedGeometry::BatchedGeometry para como establecer IT_32BIT
         // Si he comprendido correctamente es dependiente
         // del numero de vertices que quieras en el lote
         HardwareIndexBuffer::IndexType destIndexType;
         destIndexType = HardwareIndexBuffer::IT_16BIT;
 
         // Los datos de vertice
         // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         VertexBufferBinding *vertBinding =
              mVertexData->vertexBufferBinding;
         VertexDeclaration *vertDecl = mVertexData->vertexDeclaration;
 
         // Reservar y cerrar los buferes de vertice
         HardwareVertexBufferSharedPtr buffer =
             HardwareBufferManager::getSingleton()
             .createVertexBuffer(24, 8,
                  HardwareBuffer::HBU_STATIC_WRITE_ONLY);
 
         vertBinding->setBinding(0, buffer);
 
         float* destPtr = static_cast<float*>(buffer->lock(HardwareBuffer::HBL_DISCARD));
 
         // Mirar los Ogre Samples/CubeMapping/include/CubeMapping.h !
         VertexDeclaration* dec = mVertexData->vertexDeclaration;
         size_t offset = 0;
 
         dec->addElement(0, offset, VET_FLOAT3, VES_POSITION);
         offset += VertexElement::getTypeSize(VET_FLOAT3);
         dec->addElement(0, offset, VET_FLOAT3, VES_NORMAL);
 
         const float sqrt13 = 0.577350269f;
 
         *destPtr++ = -100; *destPtr++ = 100; *destPtr++ = -100;
         *destPtr++ = -sqrt13; *destPtr++ = sqrt13; *destPtr++ = -sqrt13;
         *destPtr++ = 100; *destPtr++ = 100; *destPtr++ = -100;
         *destPtr++ = sqrt13; *destPtr++ = sqrt13; *destPtr++ = -sqrt13;
         *destPtr++ = 100; *destPtr++ = -100; *destPtr++ = -100;
         *destPtr++ = sqrt13; *destPtr++ = -sqrt13; *destPtr++ = -sqrt13;
         *destPtr++ = -100; *destPtr++ = -100; *destPtr++ = -100;
         *destPtr++ = -sqrt13; *destPtr++ = -sqrt13; *destPtr++ = -sqrt13;
         *destPtr++ = -100; *destPtr++ = 100; *destPtr++ = 100;
         *destPtr++ = -sqrt13; *destPtr++ = sqrt13; *destPtr++ = sqrt13;
         *destPtr++ = 100; *destPtr++ = 100; *destPtr++ = 100;
         *destPtr++ = sqrt13; *destPtr++ = sqrt13; *destPtr++ = sqrt13;
         *destPtr++ = 100; *destPtr++ = -100; *destPtr++ = 100;
         *destPtr++ = sqrt13; *destPtr++ = -sqrt13; *destPtr++ = sqrt13;
         *destPtr++ = -100; *destPtr++ = -100; *destPtr++ = 100;
         *destPtr++ = -sqrt13; *destPtr++ = -sqrt13; *destPtr++ = sqrt13;
 
         // Reservar el bufer de indice
         mIndexData->indexBuffer = HardwareBufferManager::getSingleton()
         .createIndexBuffer(HardwareIndexBuffer::IT_16BIT, 36,
             HardwareBuffer::HBU_STATIC_WRITE_ONLY);
 
         // Como una alternativa puedes bloquear el bufer por ti mismo.
         // y copiar el data "manualmente"
         // uint16* indexBuffer16 = static_cast<uint16*>
         // (mIndexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
 
         uint16 faces[36] = {
                 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
         };
 
         // for (int i=0; i<36; ++i)
         // {
         //    *indexBuffer16++ = static_cast<uint16>(faces[i]);
         // }
 
         COUT(mIndexData->indexBuffer->getSizeInBytes());
         COUT(sizeof(faces));
         mIndexData->indexBuffer->writeData(0, mIndexData->indexBuffer->getSizeInBytes(), faces, true);
 
         // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
         // mIndexData->indexBuffer->unlock();
         buffer->unlock();
 
         mMaterial->load(); TODO No estoy seguro de esto
         mIsBuilt = true;
    }
    // -----------------------------------------------------------------------------
}
Eso es todo!.