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.
Second:
Giving up on modelling a sphere, I went on to look for a way to generate one programmatically...it 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
vBuf->unlock();
iBuf->unlock();
// Generate face list
pSphereVertex->useSharedVertices = true;
pSphere->_setBoundingSphereRadius(r);
// the original code was missing this line:
pSphere->_setBounds( AxisAlignedBox( Vector3(-r, -r, -r), Vector3(r, r, r) ), false );
}
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?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.
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?