How can I reproduce loaded mesh in manual one? How to get bone weight data and animations to the manual mesh?

Problems building or running the engine, queries about how to use features etc.
slapin
Bronze Sponsor
Bronze Sponsor
Posts: 250
Joined: Fri May 23, 2025 5:04 pm
x 16

How can I reproduce loaded mesh in manual one? How to get bone weight data and animations to the manual mesh?

Post by slapin »

Hi, all!

Googling on the forum and reading the docs and source for Ogre I composed myself a function which loads
the mesh and creates manual one which looks the same and displays it:

Code: Select all

/* this code is taken from various places on forum and does not belong to me */
	void meshProcessing()
	{
		std::vector<Ogre::MeshPtr> m_Meshes;

	m_Meshes.push_back(Ogre::MeshManager::getSingleton().load(
		"male/normal-male.glb", "Characters"));

	std::string m_ModelId = "MergedMesh";
	Ogre::MeshPtr m_BaseMesh =
		Ogre::MeshManager::getSingleton().createManual(
			m_ModelId, Ogre::ResourceGroupManager::
					   DEFAULT_RESOURCE_GROUP_NAME);
	//Lets add some submeshes
	std::vector<Ogre::MeshPtr>::iterator itr = m_Meshes.begin();
	std::vector<Ogre::MeshPtr>::iterator itr_e = m_Meshes.end();
	int i = 0, j;
	Ogre::String skelName;
	for (; itr != itr_e; ++itr) {
		if (skelName.length() == 0) {
			skelName = m_Meshes[i]->getSkeletonName();
			std::cout << "skeleton: " << skelName;
		}
		Ogre::Mesh::SubMeshList mlist =
			m_Meshes[i]->getSubMeshes();
		i++;
		Ogre::SubMesh *in = 0, *out = 0;
		Ogre::VertexBoneAssignment vbass;
		for (j = 0; j < mlist.size(); j++) {
			in = mlist[j];
			const Ogre::String mn = in->getMaterialName();
			out = m_BaseMesh->createSubMesh();
			out->indexData = in->indexData->clone();
			out->mLodFaceList = in->mLodFaceList;
			out->operationType = in->operationType;
			out->parent = m_BaseMesh.get();
			out->useSharedVertices = false;
			out->vertexData = in->vertexData->clone();
			out->clearBoneAssignments();
			for (size_t x = 0;
			     x < in->vertexData->vertexCount; ++x) {
				vbass.vertexIndex = i;
				vbass.weight = 1.0f;
				out->addBoneAssignment(vbass);
			}
			out->setMaterialName(mn);
		}
	}

	//define a extreme boundary values
	Ogre::Real max_x = -1e+8;
	Ogre::Real min_x = 1e+8;
	Ogre::Real max_y = -1e+8;
	Ogre::Real min_y = 1e+8;
	Ogre::Real max_z = -1e+8;
	Ogre::Real min_z = +1e+8;
	// Setting bounding box
	Ogre::Mesh::SubMeshList mlist = m_BaseMesh->getSubMeshes();
	for (j = 0; j < mlist.size(); j++) {
		Ogre::SubMesh *in = mlist[j];
		Ogre::VertexData *vertex_data = in->vertexData;
		const Ogre::VertexElement *posElem =
			vertex_data->vertexDeclaration
				->findElementBySemantic(
					Ogre::VES_POSITION);
		Ogre::HardwareVertexBufferSharedPtr hwvb =
			in->vertexData->vertexBufferBinding->getBuffer(
				posElem->getSource());
		unsigned char *hbuff =
			static_cast<unsigned char *>(hwvb->lock(
				Ogre::HardwareBuffer::HBL_READ_ONLY));
		Ogre::Real *pValue;
		Ogre::Real value;

		for (size_t idx = 0; idx < vertex_data->vertexCount;
		     ++idx, hbuff += hwvb->getVertexSize()) {
			posElem->baseVertexPointerToElement(hbuff,
							    &pValue);
			value = (*pValue++);
			if (value > max_x)
				max_x = value;
			if (value < min_x)
				min_x = value;
			value = (*pValue++);

			if (value > max_y)
				max_y = value;
			if (value < min_y)
				min_y = value;
			value = (*pValue++);

			if (value > max_z)
				max_z = value;
			if (value < min_z)
				min_z = value;
		}
		hwvb->unlock();
	}
#ifdef ANIM
		m_BaseMesh->setSkeletonName(skelName);
#endif
		m_BaseMesh->_setBounds(Ogre::AxisAlignedBox(
			min_x, min_y, min_z, max_x, max_y, max_z));
		Ogre::Entity *ent =
			mScnMgr->createEntity("entName", m_BaseMesh->getName());
		Ogre::SceneNode *thisSceneNode =
			mScnMgr->getRootSceneNode()->createChildSceneNode();
		thisSceneNode->attachObject(ent);
#ifdef ANIM
		mIdle = ent->getAnimationState("idle");
		mIdle->setEnabled(true);
		mIdle->setLoop(true);
		mIdle->setWeight(1.0f);
#endif
	}

if I compile it with ANIM defined, the skeletal mesh becomes invisible because it seems weight data are missing.
otherwise everything works.
So the question is how can I add missing data to the manual mesh?

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 250
Joined: Fri May 23, 2025 5:04 pm
x 16

Re: How can I reproduce loaded mesh in manual one? How to get bone weight data and animations to the manual mesh?

Post by slapin »

made it work.
The working version looks like:

Code: Select all

	void meshProcessing()
	{
		std::vector<Ogre::MeshPtr> m_Meshes;

	// Creating the character from parts
	m_Meshes.push_back(Ogre::MeshManager::getSingleton().load(
		"male/normal-male.glb", "Characters"));
	m_Meshes.push_back(Ogre::MeshManager::getSingleton().load(
		"male/clothes/suit.glb", "Characters"));

	std::string m_ModelId = "MergedMesh";
	Ogre::MeshPtr m_BaseMesh =
		Ogre::MeshManager::getSingleton().createManual(
			m_ModelId, Ogre::ResourceGroupManager::
					   DEFAULT_RESOURCE_GROUP_NAME);
	std::vector<Ogre::MeshPtr>::iterator itr = m_Meshes.begin();
	std::vector<Ogre::MeshPtr>::iterator itr_e = m_Meshes.end();
	int i = 0, j;
	Ogre::String skelName;
	for (; itr != itr_e; ++itr) {
		if (skelName.length() == 0) {
			skelName = m_Meshes[i]->getSkeletonName();
			std::cout << "skeleton: " << skelName
				  << std::endl;
		}
		Ogre::Mesh::SubMeshList mlist =
			m_Meshes[i]->getSubMeshes();
		i++;
		Ogre::SubMesh *in = 0, *out = 0;
		Ogre::VertexBoneAssignment vbass;
		for (j = 0; j < mlist.size(); j++) {
			in = mlist[j];
			const Ogre::String mn = in->getMaterialName();
			out = m_BaseMesh->createSubMesh();
			out->indexData = in->indexData->clone();
			out->mLodFaceList = in->mLodFaceList;
			out->operationType = in->operationType;
			out->parent = m_BaseMesh.get();
			out->useSharedVertices = false;
			out->vertexData = in->vertexData->clone();
			out->clearBoneAssignments();
			Ogre::Mesh::VertexBoneAssignmentList blist =
				in->getBoneAssignments();
			auto vbass_it = blist.begin();
			while (vbass_it != blist.end()) {
				out->addBoneAssignment(
					vbass_it->second);
				vbass_it++;
			}
			out->setMaterialName(mn);
		}
	}

	//define a extreme boundary values
	Ogre::Real max_x = -1e+8;
	Ogre::Real min_x = 1e+8;
	Ogre::Real max_y = -1e+8;
	Ogre::Real min_y = 1e+8;
	Ogre::Real max_z = -1e+8;
	Ogre::Real min_z = +1e+8;
	// Setting bounding box
	Ogre::Mesh::SubMeshList mlist = m_BaseMesh->getSubMeshes();
	for (j = 0; j < mlist.size(); j++) {
		Ogre::SubMesh *in = mlist[j];
		Ogre::VertexData *vertex_data = in->vertexData;
		const Ogre::VertexElement *posElem =
			vertex_data->vertexDeclaration
				->findElementBySemantic(
					Ogre::VES_POSITION);
		Ogre::HardwareVertexBufferSharedPtr hwvb =
			in->vertexData->vertexBufferBinding->getBuffer(
				posElem->getSource());
		unsigned char *hbuff =
			static_cast<unsigned char *>(hwvb->lock(
				Ogre::HardwareBuffer::HBL_READ_ONLY));
		Ogre::Real *pValue;
		Ogre::Real value;

		for (size_t idx = 0; idx < vertex_data->vertexCount;
		     ++idx, hbuff += hwvb->getVertexSize()) {
			posElem->baseVertexPointerToElement(hbuff,
							    &pValue);
			value = (*pValue++);
			if (value > max_x)
				max_x = value;
			if (value < min_x)
				min_x = value;
			value = (*pValue++);

			if (value > max_y)
				max_y = value;
			if (value < min_y)
				min_y = value;
			value = (*pValue++);

			if (value > max_z)
				max_z = value;
			if (value < min_z)
				min_z = value;
		}
		hwvb->unlock();
	}
	m_BaseMesh->setSkeletonName(skelName);
	m_BaseMesh->_setBounds(Ogre::AxisAlignedBox(
		min_x, min_y, min_z, max_x, max_y, max_z));
	Ogre::Entity *ent =
		mScnMgr->createEntity("entName", m_BaseMesh->getName());
	Ogre::SceneNode *thisSceneNode =
		mScnMgr->getRootSceneNode()->createChildSceneNode();
	thisSceneNode->attachObject(ent);
#if 0
// test using animation
// use addTime() each frame to make it work
		mIdle = ent->getAnimationState("idle");
		mIdle->setEnabled(true);
		mIdle->setLoop(true);
		mIdle->setWeight(1.0f);
#endif
	}