Changing Coordinate Handedness

From Ogre Wiki

Jump to: navigation, search

This function will change the handedness of a loaded mesh. For this to work, the mesh must have read- and writeable hardware buffers (which is the default, if you load the model using SceneManager::createEntity(String, String)). This snippet will reverse the Z axis, although reversing any axis would be enough to change handedness, inverting z should be the most common use case.

Furthermore, the LOD levels will be removed, since they are no longer correct.

void invertZ(Ogre::MeshPtr mesh)
{
	bool added_shared = false;
	size_t current_offset = 0;
	size_t shared_offset = 0;
	size_t next_offset = 0;
	// foreach SubMesh
	for (unsigned short i = 0; i < mesh->getNumSubMeshes(); i++)
	{
		Ogre::SubMesh* submesh = mesh->getSubMesh(i);
		Ogre::VertexData* vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;
		if ((!submesh->useSharedVertices) || (submesh->useSharedVertices && !added_shared))
		{
			if (submesh->useSharedVertices)
			{
				added_shared = true;
				shared_offset = current_offset;
			}
			// the real vertex data is wrapped into lots of classes
			const Ogre::VertexElement* posElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
			Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());
			unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
			float* pReal;
			for (size_t j = 0; j < vertex_data->vertexCount; j++, vertex += vbuf->getVertexSize())
			{
				// get vertex data
				posElem->baseVertexPointerToElement(vertex, &pReal);
				// reverse Z
				pReal[2] = -pReal[2];
			}
			vbuf->unlock();
			next_offset += vertex_data->vertexCount;
		}
		// reverse the triangles, otherwise they will be facing the wrong direction
		// again we need to unwrap the data
		Ogre::IndexData* index_data = submesh->indexData;
		size_t numTris = index_data->indexCount / 3;
		Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;
		bool use32bitindexes = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT);
		unsigned long* pLong = static_cast<unsigned long*>(ibuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
		unsigned short* pShort = reinterpret_cast<unsigned short*>(pLong);
		// the data is ready, do the swapping
		if (use32bitindexes)
		{
			for (size_t k = 0; k < numTris * 3; k += 3)
			{
				unsigned long swapSpace = pLong[k + 2];
				pLong[k + 2] = pLong[k + 1];
				pLong[k + 1] = swapSpace;
			}
		}
		else
		{
			for (size_t k = 0; k < numTris * 3; k += 3)
			{
				unsigned short swapSpace = pShort[k + 2];
				pShort[k + 2] = pShort[k + 1];
				pShort[k + 1] = swapSpace;
			}
		}
		ibuf->unlock();
		current_offset = next_offset;
	}
	// Adjust the bounding box
	Ogre::AxisAlignedBox box = mesh->getBounds();
	Ogre::Vector3 min = box.getMinimum();
	Ogre::Vector3 max = box.getMaximum();
	box.setExtents(min.x, min.y, -max.z, max.x, max.y, -min.z);
	mesh->_setBounds(box);
	// Remove LOD Levels
	mesh->removeLodLevels();
}

Personal tools
administration