If you haven't done so already, be sure to visit the Wiki Portal to read about how the wiki works. Especially the Ogre Wiki Overview page.
You could always generate a sphere in your favorite modeller, but given the nature of some of the Ogre exporters, it's not always so easy.
The following code snippet will make a sphere, making full use of hardware vertex and index buffers for performance.
Original credit for this code goes to mcspy0312 from a post of his on the forums, but it looks like he got it from elsewhere too. His initial code was for a "sky sphere," with the faces pointing inwards. I modified it so that the faces had an outwards orientation and fixed a bug in the texture coordinate code.
C# version is also available in MOGRE ManualSphereMeshes.
If you have a screenshot of a sphere, please upload and add it.
Table of contents
Snippet
This code creates a sphere mesh with the given name:
void createSphere(const std::string& strName, const float r, const int nRings = 16, const int nSegments = 16) { MeshPtr pSphere = MeshManager::getSingleton().createManual(strName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); SubMesh *pSphereVertex = pSphere->createSubMesh(); pSphere->sharedVertexData = new VertexData(); VertexData* vertexData = pSphere->sharedVertexData; // define the vertex format VertexDeclaration* vertexDecl = vertexData->vertexDeclaration; size_t currOffset = 0; // positions vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_POSITION); currOffset += VertexElement::getTypeSize(VET_FLOAT3); // normals vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_NORMAL); currOffset += VertexElement::getTypeSize(VET_FLOAT3); // two dimensional texture coordinates vertexDecl->addElement(0, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0); currOffset += VertexElement::getTypeSize(VET_FLOAT2); // allocate the vertex buffer vertexData->vertexCount = (nRings + 1) * (nSegments+1); HardwareVertexBufferSharedPtr vBuf = HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(0), vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); VertexBufferBinding* binding = vertexData->vertexBufferBinding; binding->setBinding(0, vBuf); float* pVertex = static_cast<float*>(vBuf->lock(HardwareBuffer::HBL_DISCARD)); // allocate index buffer pSphereVertex->indexData->indexCount = 6 * nRings * (nSegments + 1); pSphereVertex->indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(HardwareIndexBuffer::IT_16BIT, pSphereVertex->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); HardwareIndexBufferSharedPtr iBuf = pSphereVertex->indexData->indexBuffer; unsigned short* pIndices = static_cast<unsigned short*>(iBuf->lock(HardwareBuffer::HBL_DISCARD)); 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 *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; 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 // Unlock vBuf->unlock(); iBuf->unlock(); // Generate face list pSphereVertex->useSharedVertices = true; // the original code was missing this line: pSphere->_setBounds( AxisAlignedBox( Vector3(-r, -r, -r), Vector3(r, r, r) ), false ); pSphere->_setBoundingSphereRadius(r); // this line makes clear the mesh is loaded (avoids memory leaks) pSphere->load(); }
The parameters are
- strName - The Mesh's name. You'll use this to access it.
- r - The sphere's radius.
- nRings - Number of lines of longitude in the sphere. Defaults to 16.
- nSegments - Number of lines of latitude in the sphere. Also defaults to 16.
Example
Here's an example of how you would use this function and attach the new mesh to a SceneNode:
createSphere("mySphereMesh", 10, 64, 64); Entity* sphereEntity = sceneMgr->createEntity("mySphereEntity", "mySphereMesh"); SceneNode* sphereNode = sceneMgr->getRootSceneNode()->createChildSceneNode(); sphereEntity->setMaterialName("material_name_goes_here"); sphereNode->attachObject(sphereEntity);
Don't forget to replace "material_name_goes_here" with the name of your material.
Creating a sphere with ManualObject
You can also create the mesh with the ManualObject class:
void createSphere(const std::string& strName, const float r, const int nRings = 16, const int nSegments = 16) { 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 manual->end(); MeshPtr mesh = manual->convertToMesh(name); mesh->_setBounds( AxisAlignedBox( Vector3(-r, -r, -r), Vector3(r, r, r) ), false ); mesh->_setBoundingSphereRadius(r); unsigned short src, dest; if (!mesh->suggestTangentVectorBuildParams(VES_TANGENT, src, dest)) { mesh->buildTangentVectors(VES_TANGENT, src, dest); } }
You can use the above example to include it in your code.
Contributors to this page: jacmoe
and
OgreWikiBot
.
Page last modified on Monday 28 of June, 2010 21:46:04 GMT by jacmoe
.
The content on this page is licensed under the terms of the Creative Commons Attribution-ShareAlike License.
As an exception, any source code contributed within the content is released into the Public Domain.

