1.10 to 1.11 textures on animated mesh scrambled

Problems building or running the engine, queries about how to use features etc.
Post Reply
glennr
Greenskin
Posts: 113
Joined: Thu Jun 05, 2008 3:26 am
Location: Thames, New Zealand
x 3

1.10 to 1.11 textures on animated mesh scrambled

Post by glennr » Thu Feb 14, 2019 8:15 am

Ogre Version: :1.11.6:
Operating System: :Windows 10:
Render System: :D3D9, OpenGL:

I have an animated mesh that has a generated texture image applied like this:

Code: Select all

	{
		// Use the original material as a template, clone it and update the texture image
		// http://www.ogre3d.org/forums/viewtopic.php?f=21&t=64635

        Ogre::MaterialManager &mm = Ogre::MaterialManager::getSingleton();

        // Get an existing material
        Ogre::MaterialPtr mat = mm.getByName(materialName);
        if(!mat)
        {
            Ogre::MaterialPtr templateMat = mm.getByName(templateMaterialName);
            assert(templateMat);
            mat = templateMat->clone(materialName);
            m_materialNames.push_back(materialName);

            bool ok = mat->applyTextureAliases(texNameList);
            assert(ok);

            Ogre::TextureManager &tm = Ogre::TextureManager::getSingleton();

            Ogre::AliasTextureNamePairList::iterator iend = texNameList.end();
            for(Ogre::AliasTextureNamePairList::iterator i = texNameList.begin(); i != iend; ++i)
            {
                tm.unload(i->second);
            }
            mat->load();
This code works for meshes that don't have animation, but on animated meshes I see results like this:

Image

This was working on 1.10.

Reading through the notes at https://github.com/OGRECave/ogre/blob/m ... 1-Notes.md there doesn't seem to be anything that is relevant, but I may be misunderstanding it.

Any ideas what might be going wrong?
Last edited by glennr on Thu Feb 14, 2019 10:59 pm, edited 1 time in total.
0 x

rpgplayerrobin
Gremlin
Posts: 151
Joined: Wed Mar 18, 2009 3:03 am
x 16

Re: 1.10 to 1.11 textures on animated mesh scrambled

Post by rpgplayerrobin » Thu Feb 14, 2019 9:33 pm

There are many variables that can make this happen, I would suggest you to create a small sample code that can reproduce the error, which is usually what I do, and that almost always solves my problem since I start understanding what is actually happening.
But I can still try to help you through this!

1. You only posted the image when it has errors on it, how should it look like?
2. How does the material look like? What shaders does it use? Is it a post-process shader or is it just using normal vertex/fragment shaders?
3. What does the generated textures look like, can you upload one of them?
4. What if you export your generated textures and manually create a material without using a code to create that material/textures? Does the same error still happen? If the same error still happens, can you upload that manual material with textures and its shaders?
1 x

glennr
Greenskin
Posts: 113
Joined: Thu Jun 05, 2008 3:26 am
Location: Thames, New Zealand
x 3

Re: 1.10 to 1.11 textures on animated mesh scrambled

Post by glennr » Thu Feb 14, 2019 10:58 pm

Thanks rpgplayerrobin I guess I'll have to go through that process now. Was hoping it would be something simple related to the 1.10 to 1.11 update.

To answer your questions as best I can:
1. It should look like a regular guy wearing sunglasses and a T-shirt
This is what it looks like using 1.10: Image
2. It's just a plain 'diffusemap' texture, no shaders
3. I'd prefer not to do that as it's a commercial product but you get the idea from the above image
4. Will do that and post the outcome
0 x

rpgplayerrobin
Gremlin
Posts: 151
Joined: Wed Mar 18, 2009 3:03 am
x 16

Re: 1.10 to 1.11 textures on animated mesh scrambled

Post by rpgplayerrobin » Fri Feb 15, 2019 3:12 am

It can also be good to see if there is something wrong in the log (Ogre.log).

Here is some code to easily export textures and materials:

Code: Select all

void ExportTexture(TexturePtr texture, std::string toDirectory)
{
	Image tmpImage;
	texture->convertToImage(tmpImage);
	tmpImage.save(toDirectory + "/" + texture->getName() + ".png");
}

void ExportMaterial(MaterialPtr material, std::string toDirectory)
{
	MaterialSerializer tmpMaterialSerializer;
	tmpMaterialSerializer.exportMaterial(material, toDirectory + "/" + material->getName() + ".material");
}
The material export might look a bit messy though, as it exports stuff that are not always needed (like filtering, texture_alias, max_anisotropy, etc), but that won't really matter much for the test.
1 x

glennr
Greenskin
Posts: 113
Joined: Thu Jun 05, 2008 3:26 am
Location: Thames, New Zealand
x 3

Re: 1.10 to 1.11 textures on animated mesh scrambled

Post by glennr » Fri Feb 15, 2019 3:50 am

rpgplayerrobin wrote:
Thu Feb 14, 2019 9:33 pm
4. What if you export your generated textures and manually create a material without using a code to create that material/textures? Does the same error still happen? If the same error still happens, can you upload that manual material with textures and its shaders?
If I manually create the material that is referenced in the mesh file I can see in the log that the texture images are loaded correctly but I still get the same error. Also disabling the animation has no effect.
0 x

rpgplayerrobin
Gremlin
Posts: 151
Joined: Wed Mar 18, 2009 3:03 am
x 16

Re: 1.10 to 1.11 textures on animated mesh scrambled

Post by rpgplayerrobin » Fri Feb 15, 2019 4:34 am

Can you do a material, texture and mesh that you get the same error with, and then upload those for me to take a look at?
You can of course alter the texture and mesh to be something completely ridiculous (like a cube mesh and just a flat texture with one color), as long as you get the same error for them.

Another thought, what if you create a simple png file with just some arbitrary shape in the texture and then apply that to a mesh, does the same error occur, or is this only happening with the generated textures?
1 x

glennr
Greenskin
Posts: 113
Joined: Thu Jun 05, 2008 3:26 am
Location: Thames, New Zealand
x 3

Re: 1.10 to 1.11 textures on animated mesh scrambled

Post by glennr » Fri Feb 15, 2019 5:23 am

I won't be able to create an example until Monday, but here's what I've found by querying the material and texture.

This is the material definition for the head.

Code: Select all

material male_head
{
    technique
    {
        pass
        {
            ambient 1 1 1 1
            diffuse 1 1 1 1
            specular 0 0 0 1 128
            emissive 0 0 0 1

            texture_unit
            {
                texture male_head_color.png
            }
        }
    }
}

Exported the material and texture using this code based on the code you posted above:

Code: Select all

				Ogre::MaterialPtr m = model->getSubEntity(0)->getMaterial();
				MaterialSerializer tmpMaterialSerializer;
				tmpMaterialSerializer.exportMaterial(m, m->getName() + ".material");

				Ogre::TextureManager &tm = Ogre::TextureManager::getSingleton();
				Ogre::Pass *pass = m->getTechnique(0)->getPass(0);
				Ogre::TextureUnitState* t = pass->getTextureUnitState(0);
				Ogre::TexturePtr tp = tm.getByName(t->getTextureName());

				Image tmpImage;
				tp->convertToImage(tmpImage);
				tmpImage.save(tp->getName() + ".png");

The exported png is correct.
The exported material looks like this:

Code: Select all

material male_head
{
	technique
	{
		pass 
		{
			specular 0 0 0 1 128

			texture_unit
			{
			}
		}

	}

}
As you can see the texture_unit clause is empty. I would have expected it to contain "texture male_head_color.png".
1 x

rpgplayerrobin
Gremlin
Posts: 151
Joined: Wed Mar 18, 2009 3:03 am
x 16

Re: 1.10 to 1.11 textures on animated mesh scrambled

Post by rpgplayerrobin » Fri Feb 15, 2019 7:59 am

That is a bit weird. When I export the same material (with a different texture of course) I get that texture name inside the texture_unit in the exported material.
If you can go into the exporting function (tmpMaterialSerializer.exportMaterial), check why it is not entering the function MaterialSerializer::writeTextureUnit. Something seems to be a bit strange there for you.

But I guess we will have to see on Monday then for the real test.
1 x

rpgplayerrobin
Gremlin
Posts: 151
Joined: Wed Mar 18, 2009 3:03 am
x 16

Re: 1.10 to 1.11 textures on animated mesh scrambled

Post by rpgplayerrobin » Mon Feb 18, 2019 9:49 pm

I got the files and edited the material to show all the parts of the character.
I get exactly the same visual bug as you do, though my visual bug can vary from time to time (each startup seems to be a bit different).

When I add a simple shader to the materials, the same result is given at a core. Since per-pixel lighting works with the new shader means that the material is not the issue, that get rendered correctly.
Because I added a shader, I could now debug the shader in Visual Studio 2017 with the Graphics Debugging tool, which in turn shows me that the UV from TEXCOORD0 in the vertex shader is always [0, 0]. It never gets sent to the shader (at least not correctly).

This means that the UV gets messed up somehow, and I have not been able to track where it has gone wrong (and yes, I tried it in the materials also with "tex_address_mode wrap").
I have tried getting the UV data directly from the mesh, but that data always seems to be fine.

But I know for a fact that it has to do with animations as you suggested, as the code below shows the mesh when it works and then when the bug happens (add this code to a key press if you want to try it):

Code: Select all

if (ent->getMesh()->getSkeletonName() == "")
	ent->getMesh()->setSkeletonName("male_rower_tripled.skeleton");
else
	ent->getMesh()->setSkeletonName("");
The data for the position, normal and UV seems to be the same even if I enable/disable the bug with the code above. This means that the data is actually correct, but it does not get bound correctly for rendering somewhere.

Another weird thing is also that when I build tangents for the mesh (just for a test), the tangent also gets sent into the shader as [0, 0, 0], even though the code that built it shows that it has valid values (like the UV shows).



Things you could try:

1. Simplify the skeleton, try to only use one or two bones. That way we know for sure that every vertex only has weight from less than 5 bones at a time (a maximum of 4 bones per vertex are actually weighted, might be a bug because it might be more than that).

2. Make sure the 3D mesh does not have any strange faces, for example, the mesh might show in the 3D program that it has double the triangles needed, and those triangles might always have a UV of [0, 0]. These strange faces could possibly randomly be drawn before the others when using animation.

3. Try exporting the mesh with only one submesh. The current one has 3 submeshes and that might also have something to do with the bug.

4. Check through all options in the 3D program when exporting the mesh and its skeleton. Also check the UV editor that the mesh actually seems to be correct there (I know for a fact that the UV is minus in Y in your mesh, you could try fixing that also to the range of 0-1).
0 x

glennr
Greenskin
Posts: 113
Joined: Thu Jun 05, 2008 3:26 am
Location: Thames, New Zealand
x 3

Re: 1.10 to 1.11 textures on animated mesh scrambled

Post by glennr » Wed Feb 27, 2019 4:17 am

I have narrowed down the problem a bit.

The .mesh files we use are generated from XML that was exported from Lightwave. We first use OgreXMLconverter to create a .mesh file and then use MeshMagick to rotate the meshes by 90 degrees. On visual inspection of the XML the meshes appear to be valid.

An additional issue that I didn't mention before, in order to deal with one thing at a time, is that these meshes with animation get distorted when rotated by MeshMagick.

The problem only occurs when using these tools (XMLConverter and MeshMagick) built using Ogre 1.10 or later. When using XMLConverter from Ogre 1.9 and MeshMagick built against 1.9 the problem does not occur. However an application using Ogre version 1.10 or 1.11 is able to correctly display these meshes that were converted using the 1.9 tools.

So it appears that there is an issue that was introduced between 1.9 and 1.10 that is causing XMLConverter and MeshMagick to incorrectly process meshes with skeletal animation.
0 x

paroj
OGRE Team Member
OGRE Team Member
Posts: 794
Joined: Sun Mar 30, 2014 2:51 pm
x 126
Contact:

Re: 1.10 to 1.11 textures on animated mesh scrambled

Post by paroj » Wed Feb 27, 2019 12:30 pm

with 1.11 there were some changes that could break converters, however you say that this already breaks with 1.10. Are you using strict mode there?

Try to narrow down the issue further; verify that the meshes still reference the Material they should and take a look at the uv coordinates. Possibly load the mesh after each processing step for visual inspection. (with e.g OgreMeshy)
1 x

rpgplayerrobin
Gremlin
Posts: 151
Joined: Wed Mar 18, 2009 3:03 am
x 16

Re: 1.10 to 1.11 textures on animated mesh scrambled

Post by rpgplayerrobin » Wed Feb 27, 2019 2:00 pm

Since he sent me the mesh and material with textures, I can say for 100% sure that the UV coordinates works (just not when applying a skeleton to the mesh for some reason as stated in my above reply).

The material also works. I debugged the material (by adding a shader to it) as stated in that above reply also, and the only error there is that the UV coordinates are always [0, 0].
But those UV coordinates are good in the mesh when I checked it there. Also, when not using the skeleton, the UV coordinates are correct in the shader.

I debugged the mesh in several ways for a couple of hours, but I could still not find where everything goes wrong. The mesh has valid UV, but for some reason they come out as [0, 0] when rendered using a skeleton (with or without a shader).
0 x

paroj
OGRE Team Member
OGRE Team Member
Posts: 794
Joined: Sun Mar 30, 2014 2:51 pm
x 126
Contact:

Re: 1.10 to 1.11 textures on animated mesh scrambled

Post by paroj » Wed Feb 27, 2019 3:07 pm

for skeletal animation the geometry is copied to separate buffers. Did you take a look at that step already?

Specifically "prepareTempBlendBuffers" and "mSkelAnimVertexData"? But how comes that the exporter makes a difference?

If there are two .mesh files out of which only one works with Ogre 1.11 we should find the difference there.
0 x

rpgplayerrobin
Gremlin
Posts: 151
Joined: Wed Mar 18, 2009 3:03 am
x 16

Re: 1.10 to 1.11 textures on animated mesh scrambled

Post by rpgplayerrobin » Wed Feb 27, 2019 4:43 pm

It seems that the UV is indeed messed up during the process you mentioned.
When I checked the UV, I just took it directly from the mesh vertex data, now with your input I use getVertexDataForBinding instead.

All the UV elements becomes [-431602080., -431602080.] after the the skeleton has been set to the mesh.

I will debug this a bit more but I am still not sure where the UV stops working.

I tried it with this code (the code is called when I press a button, it toggles the error on and off):

Code: Select all

if (ent->getMesh()->getSkeletonName() == "")
{
	class CTemporaryClass
	{
	public:
		static void ExtractFromVertexData(Ogre::VertexData* vertexData, std::vector<Vector3>& positions, std::vector<Vector3>& normals, std::vector<Vector2>& textureCoordinates)
		{
			positions.clear();
			normals.clear();
			textureCoordinates.clear();

			{
				float* tmpElement;
				const VertexElement* tmpVertexPositions = vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
				HardwareVertexBufferSharedPtr tmpVertexBuffer = vertexData->vertexBufferBinding->getBuffer(tmpVertexPositions->getSource());
				unsigned char* tmpVertex = static_cast<unsigned char*>(tmpVertexBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
				for (size_t j = 0; j < vertexData->vertexCount; ++j, tmpVertex += tmpVertexBuffer->getVertexSize())
				{
					tmpVertexPositions->baseVertexPointerToElement(tmpVertex, &tmpElement);

					positions.push_back(Vector3(tmpElement[0], tmpElement[1], tmpElement[2]));
				}
				tmpVertexBuffer->unlock();
			}
			{
				float* tmpElement;
				const VertexElement* tmpVertexPositions = vertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL);
				HardwareVertexBufferSharedPtr tmpVertexBuffer = vertexData->vertexBufferBinding->getBuffer(tmpVertexPositions->getSource());
				unsigned char* tmpVertex = static_cast<unsigned char*>(tmpVertexBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
				for (size_t j = 0; j < vertexData->vertexCount; ++j, tmpVertex += tmpVertexBuffer->getVertexSize())
				{
					tmpVertexPositions->baseVertexPointerToElement(tmpVertex, &tmpElement);

					normals.push_back(Vector3(tmpElement[0], tmpElement[1], tmpElement[2]));
				}
				tmpVertexBuffer->unlock();
			}
			{
				float* tmpElement;
				const VertexElement* tmpVertexPositions = vertexData->vertexDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES);
				HardwareVertexBufferSharedPtr tmpVertexBuffer = vertexData->vertexBufferBinding->getBuffer(tmpVertexPositions->getSource());
				unsigned char* tmpVertex = static_cast<unsigned char*>(tmpVertexBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
				for (size_t j = 0; j < vertexData->vertexCount; ++j, tmpVertex += tmpVertexBuffer->getVertexSize())
				{
					tmpVertexPositions->baseVertexPointerToElement(tmpVertex, &tmpElement);

					textureCoordinates.push_back(Vector2(tmpElement[0], tmpElement[1]));
				}
				tmpVertexBuffer->unlock();
			}
		}
	};

	std::vector<Vector3> tmpPositions;
	std::vector<Vector3> tmpNormals;
	std::vector<Vector2> tmpTextureCoordinates;
	for (int n = 0; n < ent->getMesh()->getNumSubMeshes(); n++)
	{
		SubMesh* tmpSubMesh = ent->getMesh()->getSubMesh(n);
		CTemporaryClass::ExtractFromVertexData(tmpSubMesh->vertexData, tmpPositions, tmpNormals, tmpTextureCoordinates);
	}

	for (int n = 0; n < ent->getNumSubEntities(); n++)
	{
		SubEntity* tmpSubEntity = ent->getSubEntity(n);
		VertexData* tmpVertexData = tmpSubEntity->getVertexDataForBinding();
		CTemporaryClass::ExtractFromVertexData(tmpVertexData, tmpPositions, tmpNormals, tmpTextureCoordinates);
	}

	ent->getMesh()->setSkeletonName("male_rower_tripled.skeleton");
	app->m_Root->renderOneFrame();

// THE UV DATA HERE BECOMES INVALID
	for (int n = 0; n < ent->getNumSubEntities(); n++)
	{
		SubEntity* tmpSubEntity = ent->getSubEntity(n);
		VertexData* tmpVertexData = tmpSubEntity->getVertexDataForBinding();
		CTemporaryClass::ExtractFromVertexData(tmpVertexData, tmpPositions, tmpNormals, tmpTextureCoordinates);
	}
}
else
{
	ent->getMesh()->setSkeletonName("");
}
0 x

rpgplayerrobin
Gremlin
Posts: 151
Joined: Wed Mar 18, 2009 3:03 am
x 16

Re: 1.10 to 1.11 textures on animated mesh scrambled

Post by rpgplayerrobin » Wed Feb 27, 2019 9:55 pm

I found a solution.

Your mesh looks like this with the vertex declarations:
Semantic / Source (offset does not matter in this scenario)
Position / 0
Normal / 0
Texture Coordinates / 0

While my animated meshes looks like this:
Position / 0
Normal / 0
Texture Coordinates / 1

It might be a simple thing as exporting it correctly that solves this, as it seems that maybe the first source (0) is discarded completely when using animations (since Position/Normal is blended by bones then instead).
Since I don't have that file to export it again, I tried it in code and moving the texture coordinate to source 1 instead of 0 fixes everything.

But, instead of exporting it, you could also do it by code. I made a function to fix it for you:

Code: Select all

// Moves texture coordinates of the mesh to source 1 instead of 0
void FixMesh(std::string meshName)
{
	// Get the source mesh
	MeshPtr tmpSourceMesh = MeshManager::getSingleton().getByName(meshName);

	// Create a new mesh
	MeshPtr tmpNewMesh = MeshManager::getSingleton().createManual("NewFixedMesh", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

	class CTemporaryHelperClass
	{
	public:
		static void baseVertexPointerToElement(void* pBase, float** pElem)
		{
			*pElem = static_cast<float*>(static_cast<void*>(static_cast<unsigned char*>(pBase)));
		}

		static void AddData(char* vertexData, size_t& vertexDataIndex, const Vector2& x)
		{
			const size_t tmpSizeInBytes = 4 * 2;

			float* tmpFloat;
			baseVertexPointerToElement(vertexData + vertexDataIndex, &tmpFloat);
			*tmpFloat++ = x.x;
			*tmpFloat++ = x.y;
			vertexDataIndex += tmpSizeInBytes;
		}

		static void AddData(char* vertexData, size_t& vertexDataIndex, const Vector3& x)
		{
			const size_t tmpSizeInBytes = 4 * 3;

			float* tmpFloat;
			baseVertexPointerToElement(vertexData + vertexDataIndex, &tmpFloat);
			*tmpFloat++ = x.x;
			*tmpFloat++ = x.y;
			*tmpFloat++ = x.z;
			vertexDataIndex += tmpSizeInBytes;
		}
	};

	// Loop through all sub meshes
	for (int i = 0; i < tmpSourceMesh->getNumSubMeshes(); i++)
	{
		// Get all vertex information we need
		SubMesh* tmpSourceSubMesh = tmpSourceMesh->getSubMesh(i);
		size_t tmpNumberOfVertices = tmpSourceSubMesh->vertexData->vertexCount;
		Vector3* tmpPositions = new Vector3[tmpNumberOfVertices];
		Vector3* tmpNormals = new Vector3[tmpNumberOfVertices];
		Vector2* tmpTextureCoordinates = new Vector2[tmpNumberOfVertices];
		{
			float* tmpElement;
			const VertexElement* tmpVertexElement = tmpSourceSubMesh->vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
			HardwareVertexBufferSharedPtr tmpVertexBuffer = tmpSourceSubMesh->vertexData->vertexBufferBinding->getBuffer(tmpVertexElement->getSource());
			unsigned char* tmpVertex = static_cast<unsigned char*>(tmpVertexBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
			for (size_t j = 0; j < tmpSourceSubMesh->vertexData->vertexCount; ++j, tmpVertex += tmpVertexBuffer->getVertexSize())
			{
				tmpVertexElement->baseVertexPointerToElement(tmpVertex, &tmpElement);

				tmpPositions[j] = Vector3(tmpElement[0], tmpElement[1], tmpElement[2]);
			}
			tmpVertexBuffer->unlock();
		}
		{
			float* tmpElement;
			const VertexElement* tmpVertexElement = tmpSourceSubMesh->vertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL);
			HardwareVertexBufferSharedPtr tmpVertexBuffer = tmpSourceSubMesh->vertexData->vertexBufferBinding->getBuffer(tmpVertexElement->getSource());
			unsigned char* tmpVertex = static_cast<unsigned char*>(tmpVertexBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
			for (size_t j = 0; j < tmpSourceSubMesh->vertexData->vertexCount; ++j, tmpVertex += tmpVertexBuffer->getVertexSize())
			{
				tmpVertexElement->baseVertexPointerToElement(tmpVertex, &tmpElement);

				tmpNormals[j] = Vector3(tmpElement[0], tmpElement[1], tmpElement[2]);
			}
			tmpVertexBuffer->unlock();
		}
		{
			float* tmpElement;
			const VertexElement* tmpVertexElement = tmpSourceSubMesh->vertexData->vertexDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES);
			HardwareVertexBufferSharedPtr tmpVertexBuffer = tmpSourceSubMesh->vertexData->vertexBufferBinding->getBuffer(tmpVertexElement->getSource());
			unsigned char* tmpVertex = static_cast<unsigned char*>(tmpVertexBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
			for (size_t j = 0; j < tmpSourceSubMesh->vertexData->vertexCount; ++j, tmpVertex += tmpVertexBuffer->getVertexSize())
			{
				tmpVertexElement->baseVertexPointerToElement(tmpVertex, &tmpElement);

				tmpTextureCoordinates[j] = Vector2(tmpElement[0], tmpElement[1]);
			}
			tmpVertexBuffer->unlock();
		}

		// Create a new submesh
		SubMesh* tmpNewSubMesh = tmpNewMesh->createSubMesh();
		tmpNewSubMesh->useSharedVertices = false;
		tmpNewSubMesh->setMaterialName(tmpSourceSubMesh->getMaterialName());
		tmpNewSubMesh->vertexData = new VertexData();
		tmpNewSubMesh->vertexData->vertexCount = 0;
		tmpNewSubMesh->operationType = tmpSourceSubMesh->operationType;

		// Setup the vertex declaration to how we want it (texture coordinates moved to source 1 instead of 0)
		VertexDeclaration* tmpVertexDeclaration = tmpNewSubMesh->vertexData->vertexDeclaration;
		size_t tmpNewSubMesh_VertexSize_Source0 = 0;
		size_t tmpNewSubMesh_VertexSize_Source1 = 0;

		tmpVertexDeclaration->addElement(0, tmpNewSubMesh_VertexSize_Source0, VET_FLOAT3, VES_POSITION);
		tmpNewSubMesh_VertexSize_Source0 += VertexElement::getTypeSize(VET_FLOAT3);

		tmpVertexDeclaration->addElement(0, tmpNewSubMesh_VertexSize_Source0, VET_FLOAT3, VES_NORMAL);
		tmpNewSubMesh_VertexSize_Source0 += VertexElement::getTypeSize(VET_FLOAT3);

		tmpVertexDeclaration->addElement(1, tmpNewSubMesh_VertexSize_Source1, VET_FLOAT2, VES_TEXTURE_COORDINATES);
		tmpNewSubMesh_VertexSize_Source1 += VertexElement::getTypeSize(VET_FLOAT2);

		bool tmpUseIndices = tmpSourceSubMesh->indexData != NULL;
		if (tmpUseIndices)
		{
			tmpNewSubMesh->indexData = new IndexData();
			tmpNewSubMesh->indexData->indexCount = 0;
		}

		tmpNewSubMesh->vertexData->vertexCount = tmpNumberOfVertices;
		VertexBufferBinding* tmpVertexBufferBinding = tmpNewSubMesh->vertexData->vertexBufferBinding;

		// Add the vertex data needed to source 0
		size_t tmpVertexDataIndex = 0;
		size_t tmpBytesToWrite = tmpNumberOfVertices * tmpNewSubMesh_VertexSize_Source0;
		char* tmpVertexData = new char[tmpBytesToWrite];
		for (size_t n = 0; n < tmpNumberOfVertices; n++)
		{
			CTemporaryHelperClass::AddData(tmpVertexData, tmpVertexDataIndex, tmpPositions[n]);
			CTemporaryHelperClass::AddData(tmpVertexData, tmpVertexDataIndex, tmpNormals[n]);
		}

		HardwareVertexBufferSharedPtr tmpVertexBuffer = HardwareBufferManager::getSingleton().createVertexBuffer(tmpNewSubMesh_VertexSize_Source0,
			tmpNumberOfVertices, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
		tmpVertexBuffer->writeData(0, tmpBytesToWrite, tmpVertexData, true);
		tmpVertexBufferBinding->setBinding(0, tmpVertexBuffer);

		delete[] tmpVertexData;



		// Add the vertex data needed to source 1
		tmpVertexDataIndex = 0;
		tmpBytesToWrite = tmpNumberOfVertices * tmpNewSubMesh_VertexSize_Source1;
		tmpVertexData = new char[tmpBytesToWrite];
		for (size_t n = 0; n < tmpNumberOfVertices; n++)
			CTemporaryHelperClass::AddData(tmpVertexData, tmpVertexDataIndex, tmpTextureCoordinates[n]);

		tmpVertexBuffer = HardwareBufferManager::getSingleton().createVertexBuffer(tmpNewSubMesh_VertexSize_Source1,
			tmpNumberOfVertices, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
		tmpVertexBuffer->writeData(0, tmpBytesToWrite, tmpVertexData, true);
		tmpVertexBufferBinding->setBinding(1, tmpVertexBuffer);

		delete[] tmpVertexData;




		// Add the indices data
		if (tmpUseIndices)
		{
			tmpNewSubMesh->indexData->indexCount = tmpSourceSubMesh->indexData->indexBuffer->getNumIndexes();

			if (tmpSourceSubMesh->indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT)
			{
				uint32* tmpIndexData = new uint32[tmpSourceSubMesh->indexData->indexBuffer->getNumIndexes()];

				uint32* p32 = static_cast<uint32*>(tmpSourceSubMesh->indexData->indexBuffer->lock(HardwareBuffer::HBL_NORMAL));
				for (size_t n = 0; n < tmpSourceSubMesh->indexData->indexBuffer->getNumIndexes(); n++)
					tmpIndexData[n] = p32[n];
				tmpSourceSubMesh->indexData->indexBuffer->unlock();

				HardwareIndexBufferSharedPtr tmpNewIndexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(tmpSourceSubMesh->indexData->indexBuffer->getType(),
					tmpSourceSubMesh->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
				tmpNewIndexBuffer->writeData(0, tmpSourceSubMesh->indexData->indexBuffer->getSizeInBytes(), tmpIndexData, true);
				tmpNewSubMesh->indexData->indexBuffer = tmpNewIndexBuffer;

				delete[] tmpIndexData;
			}
			else
			{
				uint16* tmpIndexData = new uint16[tmpSourceSubMesh->indexData->indexBuffer->getNumIndexes()];

				uint16* p16 = static_cast<uint16*>(tmpSourceSubMesh->indexData->indexBuffer->lock(HardwareBuffer::HBL_NORMAL));
				for (size_t n = 0; n < tmpSourceSubMesh->indexData->indexBuffer->getNumIndexes(); n++)
					tmpIndexData[n] = p16[n];
				tmpSourceSubMesh->indexData->indexBuffer->unlock();

				HardwareIndexBufferSharedPtr tmpNewIndexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(tmpSourceSubMesh->indexData->indexBuffer->getType(),
					tmpSourceSubMesh->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
				tmpNewIndexBuffer->writeData(0, tmpSourceSubMesh->indexData->indexBuffer->getSizeInBytes(), tmpIndexData, true);
				tmpNewSubMesh->indexData->indexBuffer = tmpNewIndexBuffer;

				delete[] tmpIndexData;
			}
		}

		delete[] tmpPositions;
		delete[] tmpNormals;
		delete[] tmpTextureCoordinates;
	}

	// Set the bounds
	tmpNewMesh->_setBounds(tmpSourceMesh->getBounds());
	tmpNewMesh->_setBoundingSphereRadius(tmpSourceMesh->getBoundingSphereRadius());

	// Set the skeleton
	tmpNewMesh->setSkeletonName(tmpSourceMesh->getSkeletonName());

	// Copy all bone assignments
	for (int i = 0; i < tmpSourceMesh->getNumSubMeshes(); i++)
	{
		SubMesh* tmpSourceSubMesh = tmpSourceMesh->getSubMesh(i);
		SubMesh* tmpNewSubMesh = tmpNewMesh->getSubMesh(i);

		for (Mesh::VertexBoneAssignmentList::const_iterator tmpItr = tmpSourceSubMesh->getBoneAssignments().begin(); tmpItr != tmpSourceSubMesh->getBoneAssignments().end(); ++tmpItr)
			tmpNewSubMesh->addBoneAssignment(tmpItr->second);

		for (size_t n = 0; n < tmpSourceSubMesh->blendIndexToBoneIndexMap.size(); n++)
			tmpNewSubMesh->blendIndexToBoneIndexMap.push_back(tmpSourceSubMesh->blendIndexToBoneIndexMap[n]);
	}

	for (Mesh::VertexBoneAssignmentList::const_iterator tmpItr = tmpSourceMesh->getBoneAssignments().begin(); tmpItr != tmpSourceMesh->getBoneAssignments().end(); ++tmpItr)
		tmpNewMesh->addBoneAssignment(tmpItr->second);

	for (size_t n = 0; n < tmpSourceMesh->sharedBlendIndexToBoneIndexMap.size(); n++)
		tmpNewMesh->sharedBlendIndexToBoneIndexMap.push_back(tmpSourceMesh->sharedBlendIndexToBoneIndexMap[n]);

	// Remove the old mesh
	std::string tmpName = tmpSourceMesh->getName();
	tmpSourceMesh.reset();
	MeshManager::getSingleton().unload(tmpName);
	MeshManager::getSingleton().remove(tmpName);

	// Clone the new mesh with the same name as the old mesh
	tmpNewMesh->clone(meshName);

	// Remove the new mesh now that we have cloned it to the right name
	tmpName = tmpNewMesh->getName();
	tmpNewMesh.reset();
	MeshManager::getSingleton().unload(tmpName);
	MeshManager::getSingleton().remove(tmpName);
}
Simply just use this code after you have loaded the meshes (but before you have started to use them of course):

Code: Select all

FixMesh("male_rower_tripled.mesh");
If you feel that function is slow, you could always export the mesh after using that function and only use that function "offline":

Code: Select all

std::string tmpMeshName = "male_rower_tripled.mesh";
FixMesh(tmpMeshName);
MeshPtr tmpMesh = MeshManager::getSingleton().getByName(tmpMeshName);
MeshSerializer tmpMeshExport;
tmpMeshExport.exportMesh(tmpMesh.get(), outputPath);
1 x

glennr
Greenskin
Posts: 113
Joined: Thu Jun 05, 2008 3:26 am
Location: Thames, New Zealand
x 3

Re: 1.10 to 1.11 textures on animated mesh scrambled

Post by glennr » Wed Feb 27, 2019 10:20 pm

Thanks very much for that.

I'm not that familiar with the binary mesh format, but in the XML I don't see any "source" definition for the texture coords. The XML looks like this:

Code: Select all

<mesh>
    <submeshes>
        <submesh material="male_head" usesharedvertices="false" use32bitindexes="false" operationtype="triangle_list">
            <geometry vertexcount="1490">
                <vertexbuffer positions="true" normals="true" colours_diffuse="false" colours_specular="false" texture_coords="1" texture_coord_dimensions_0="2" texture_coord_dimensions_1="2">
                    <vertex>
                        <position x="0.00789926201" y="1.77843344" z="0.0869925246" />
                        <normal x="-0.355634838" y="-0.846924424" z="-0.395275712" />
                        <texcoord u="0.426453948" v="-0.718836248" />
                    </vertex>
		    ... etc
                </vertexbuffer>
            </geometry>
            <faces count="1830">
                <face v1="0" v2="1" v3="2" />
		... etc
            </faces>
            <boneassignments>
                <vertexboneassignment vertexindex="0" boneindex="5" weight="1" />
		... etc
            </boneassignments>
        </submesh>
	... etc
    </submeshes>
    <skeletonlink name="male.skeleton" />
</mesh>
Rather than adapting my application code, would it be better to modify XMLConverter in 1.11 to produce 'correct' meshes like XMLConverter in 1.9 does?

For now I have worked around the problem by using XMLConverter from 1.9 in my media build system.
0 x

rpgplayerrobin
Gremlin
Posts: 151
Joined: Wed Mar 18, 2009 3:03 am
x 16

Re: 1.10 to 1.11 textures on animated mesh scrambled

Post by rpgplayerrobin » Wed Feb 27, 2019 10:58 pm

I have never actually used the xml format. But it seems like it should be pretty easy to do by just adding another vertex buffer (like I do in the code)?

Code: Select all

<geometry vertexcount="1490">
	<vertexbuffer positions="true" normals="true" colours_diffuse="false" colours_specular="false" texture_coords="0" texture_coord_dimensions_0="2" texture_coord_dimensions_1="2">
		<vertex>
			<position x="0.00789926201" y="1.77843344" z="0.0869925246" />
			<normal x="-0.355634838" y="-0.846924424" z="-0.395275712" />
		</vertex>
		... etc
	</vertexbuffer>

	<vertexbuffer positions="false" normals="false" colours_diffuse="false" colours_specular="false" texture_coords="1" texture_coord_dimensions_0="2" texture_coord_dimensions_1="2">
		<vertex>
			<texcoord u="0.426453948" v="-0.718836248" />
		</vertex>
		... etc
	</vertexbuffer>
</geometry>
0 x

rpgplayerrobin
Gremlin
Posts: 151
Joined: Wed Mar 18, 2009 3:03 am
x 16

Re: 1.10 to 1.11 textures on animated mesh scrambled

Post by rpgplayerrobin » Thu Feb 28, 2019 5:43 am

If you want to solve the chain instead, I just remembered that you mentioned MeshMagick and how it only became an error when using that and XMLConverter.

Can't you just check for each stage of that how the mesh looks like?
At export from Lightwave, does the XML have valid data?
When using OgreXMLconverter on that, is that mesh actually correct? Check if it has one or two vertex buffers (source 0 and 1). Is there only position/normal in source 0 and then only texture coordinates in source 1?
When using MeshMagick on that, is that mesh actually correct? Check if it has one or two vertex buffers (source 0 and 1). Is there only position/normal in source 0 and then only texture coordinates in source 1?

Since I do not use any of those 3 things myself, there is nothing more than that I can help with, but knowing when it actually happens is how you solve it, if you delve deep into those programs and compile them yourself.
Also, if that fails or if you just want to skip that, you can just add another stage by calling my function and exporting the mesh as a part of the chain of exporting those meshes with errors.
0 x

Post Reply