Page 1 of 1

fun with spheres and lod

Posted: Wed Feb 02, 2005 8:52 pm
by snowblind
Working on a space sim (oh no not another one)...

First of all, I can not for the life of me figure out a way to export texture uv coords with the lwo2mesh.exe utility.

I've been trying to texture a simple sphere with an Earth texture, and during runtime it's just a flat blue color all the way around.

So I opened the .mesh up with the GUI mesh tool and exported to XML to have a look at what was going on...the texcoord entries were all zero!

I've tried various combinations of smoothing, not smoothing, and surfaces in Lightwave, but to no avail...if anyone has any good Lightwave->Ogre tips, please let me know.


Giving up on modelling a sphere, I went on to look for a way to generate one should be pretty simple. I found some SkySphere code here in the forums that works pretty nicely:

Code: Select all

void CreateSkySphere(const std::string& strName, const float r, const int nRings = 16, const int nSegments = 16)
      Mesh* pSphere = MeshManager::getSingleton().createManual(strName);
      SubMesh *pSphereVertex = pSphere->createSubMesh();

      pSphere->sharedVertexData = new VertexData();
      VertexData* vertexData = pSphere->sharedVertexData;

      // Definite vertex format
      VertexDeclaration* vertexDecl = vertexData->vertexDeclaration;
      size_t currOffset = 0;
      // We always need 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);
      // Assumes 2D texture coords
      vertexDecl->addElement(0, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
      currOffset += VertexElement::getTypeSize(VET_FLOAT2);

      // Allocate vertex buffer
      vertexData->vertexCount = (nRings + 1) * nSegments;
      HardwareVertexBufferSharedPtr vBuf = HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(0), vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
      VertexBufferBinding* binding = vertexData->vertexBufferBinding;
      binding->setBinding(0, vBuf);
      Real* pVertex = static_cast<Real*>(vBuf->lock(HardwareBuffer::HBL_DISCARD));

      // Allocate index buffer
      pSphereVertex->indexData->indexCount = 6 * nRings * nSegments;
      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));

      // fill vertex
      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 vertices 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) {
               if (seg == nSegments - 1) {
                  *pIndices++ = wVerticeIndex + 1;
                  *pIndices++ = wVerticeIndex + nSegments;
                  *pIndices++ = wVerticeIndex;
                  *pIndices++ = wVerticeIndex + 1;
                  *pIndices++ = wVerticeIndex;
                  *pIndices++ = wVerticeIndex - nSegments + 1;
               } else {
                  *pIndices++ = wVerticeIndex + nSegments + 1;
                  *pIndices++ = wVerticeIndex + nSegments;
                  *pIndices++ = wVerticeIndex;               
                  *pIndices++ = wVerticeIndex + nSegments + 1;
                  *pIndices++ = wVerticeIndex;
                  *pIndices++ = wVerticeIndex + 1;
               wVerticeIndex ++;
         }; // end for seg
      } // end for ring

      // 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 );
But the problem is, the sphere is "inside out" since it's meant to be an enclosing sky sphere. Sinbad responded to the question of how to fix this with:
Face culling has nothing to do with vertex normals. Vertex normals only affect lighting. The 'front' of a face is derived from the vertex winding - whether the vertices are listed in clockwise or anticlockwise order as viewed from the camera. So to invert the faces, you have to reverse the order of 2 of the vertex indices.
I tried flipping y's and x's in the code, but I can't get it to look quite right. Does anyone have any nice sphere generating code?

And finally, if I wanted to give the sphere mesh several levels of detail, what would be the best way to do it, and if I just used Mesh::createManualLodLevel with lower values of my sphere function, would the scene manager use them automatically, or do I need to work that into the code manually somehow?

Posted: Wed Feb 02, 2005 10:26 pm
by sinbad
I said exchange 2 of the indexes in each face, not exchange the vertex components.

Ie if you would have done this:

Code: Select all

*pindex++ = face[i];
*pindex++ = face[i+1];
*pindex++ = face[i+2];
do this instead..

Code: Select all

*pindex++ = face[i];
*pindex++ = face[i+2];
*pindex++ = face[i+1];

Posted: Fri Mar 11, 2005 11:04 am
by dennis
I hope you didn't use spherical mapping for your globe ... You'll have to use UV texturing for your sphere. Which leads to another problem ... discontinuous vertex maps.