[2.1] Assimp, try loading asset for v2.1 mesh ..

Discussion area about developing with Ogre-Next (2.1, 2.2 and beyond)


Post Reply
riveranb
Gnoblar
Posts: 7
Joined: Tue Sep 26, 2017 1:35 am

[2.1] Assimp, try loading asset for v2.1 mesh ..

Post by riveranb »

I followed the threads about mesh importing and assimp.

http://forums.ogre3d.org/viewtopic.php?f=2&t=93553
http://forums.ogre3d.org/viewtopic.php?f=1&t=93145
http://www.ogre3d.org/tikiwiki/OgreAssi ... ture=Tools

I found OgreAssimpConverter very useful, and I decided to start from it and give a try for OGRE v2.1 mesh.
Currently my codes only work for static mesh (vertex buffer + index buffer).
But I have encountered problems with created mesh coming with glitches (broken triangles, and not everytime!).
It seems the index buffer I created may have some bugs to let this bug happen.
But now I just can't find where the bug is (I also still can't fully understand how to create/access OGRE_SIMD_MALLOC buffers).

So wanna anyone can help view/debug my codes, any helps are really appreciated.

Here is one successful asset case.
https://imgur.com/a/QwqV7
Here is asset with glitches case.
https://imgur.com/a/DXpa8

My test sample is using Assimp library (v3.3.1). I modify Sample_V2Mesh project for my quick test.
Test file is one STL file.

And I posted codes here, cause I have not upload them onto internet yet. Not sure if its a good idea to post too much codes here..

(codes about the mesh and submeshes are generated)

Code: Select all

bool AssimpLoader::genSubMeshV2(const Ogre::String& name, int index, const aiNode* node, const aiMesh* mesh, 
	const aiMaterial* mat, Ogre::MeshPtr pmeshv2)
{
	// if animated all submeshes must have bone weights
	if (mBonesByName.size() && !mesh->HasBones())
	{
		if (!mQuietMode)
		{
			Ogre::LogManager::getSingleton().logMessage("Skipping Mesh " + Ogre::String(mesh->mName.data) + "with no bone weights");
		}
		return false;
	}

	// TODO: Material for v1::Mesh conversion still have problems now.
	/*
	Ogre::MaterialPtr matptr;
	if((mLoaderParams & LP_GENERATE_MATERIALS_AS_CODE) == 0)
	{
	matptr = createMaterial(mesh->mMaterialIndex, mat, dir);
	}
	else
	{
	matptr = createMaterialByScript(mesh->mMaterialIndex, mat);
	}
	*/

	Ogre::VaoManager *vaoManager = Ogre::Root::getSingleton().getRenderSystem()->getVaoManager();
	// create vertex buffer
	unsigned short numreal = 3;
	unsigned short posBytes = 0, normBytes = 0, uvBytes = 0, colBytes = 0;
	posBytes = sizeof(Ogre::Real) * 3;
	Ogre::VertexElement2Vec velements;
	velements.push_back(Ogre::VertexElement2(Ogre::VET_FLOAT3, Ogre::VES_POSITION));
	if (mesh->HasNormals())
	{
		normBytes = sizeof(Ogre::Real) * 3;
		numreal += 3;
		velements.push_back(Ogre::VertexElement2(Ogre::VET_FLOAT3, Ogre::VES_NORMAL));
	}
	if (mesh->HasTextureCoords(0)) // currently consider first uv only
	{
		uvBytes = sizeof(Ogre::Real) * 2;
		numreal += 2;
		velements.push_back(Ogre::VertexElement2(Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES));
	}
	if (mesh->HasVertexColors(0)) // assume first color set as diffuse color
	{
		// TODO: can it be uint32 (RGBA)?
		colBytes = sizeof(Ogre::Real) * 3;
		numreal += 3;
		velements.push_back(Ogre::VertexElement2(Ogre::VET_FLOAT3, Ogre::VES_DIFFUSE));
	}

	Ogre::Real *vertexdata = reinterpret_cast<Ogre::Real *> (OGRE_MALLOC_SIMD(
								sizeof(Ogre::Real) * numreal * mesh->mNumVertices, Ogre::MEMCATEGORY_GEOMETRY));
	// fill vertexdata manually
	// prime pointers to vertex related data
	aiVector3D *vec = mesh->mVertices;
	aiVector3D *norm = mesh->mNormals;
	aiVector3D *uv = mesh->mTextureCoords[0];
	aiColor4D *col = mesh->mColors[0];
	Ogre::Aabb subAABB(Ogre::Vector3(vec[0].x, vec[0].y, vec[0].z), Ogre::Vector3::UNIT_SCALE);
#if defined _DEBUG && 0
	Ogre::LogManager::getSingleton().logMessage("  = Parsed vertuces (positions):");
#endif
	for (unsigned int i = 0, offset = 0; i < mesh->mNumVertices; ++i)
	{
		// position
		memcpy(vertexdata + offset, &vec[i].x, posBytes);
		//vertexdata[offset + 0] = vec[i].x;
		//vertexdata[offset + 1] = vec[i].y;
		//vertexdata[offset + 2] = vec[i].z;
		offset += 3;
		subAABB.merge(Ogre::Vector3(vec[i].x, vec[i].y, vec[i].z));
#if defined _DEBUG && 0
		Ogre::LogManager::getSingleton().logMessage(Ogre::StringConverter::toString(i) + ": " +
											Ogre::StringConverter::toString(vec[i].x) + ",  " +
											Ogre::StringConverter::toString(vec[i].y) + ",  " +
											Ogre::StringConverter::toString(vec[i].z));
#endif

		// normal
		if (mesh->HasNormals())
		{
			memcpy(vertexdata + offset, &norm[i].x, normBytes);
			//vertexdata[offset + 0] = norm[i].x;
			//vertexdata[offset + 1] = norm[i].y;
			//vertexdata[offset + 2] = norm[i].z;
			offset += 3;
		}
		// uv
		if (mesh->HasTextureCoords(0))
		{
			memcpy(vertexdata + offset, &uv[i].x, uvBytes);
			//vertexdata[offset + 0] = uv[i].x;
			//vertexdata[offset + 1] = uv[i].y;
			offset += 2;
		}
		// color
		if (mesh->HasVertexColors(0))
		{
			memcpy(vertexdata + offset, &col[i].r, colBytes);
			//vertex[offset + 0] = col[i].r;
			//vertex[offset + 1] = col[i].g;
			//vertex[offset + 2] = col[i].b;
			offset += 3;
		}
	}

	Ogre::VertexBufferPacked *vertexBuffer = 0;
	try
	{
		//Create the actual vertex buffer.
		vertexBuffer = vaoManager->createVertexBuffer(velements, mesh->mNumVertices,
			Ogre::BT_IMMUTABLE,
			vertexdata, false);
	}
	catch (Ogre::Exception &e)
	{
		// When keepAsShadow = true, the memory will be freed when the index buffer is destroyed.
		// However if for some weird reason there is an exception raised, the memory will
		// not be freed, so it is up to us to do so.
		// The reasons for exceptions are very rare. But we're doing this for correctness.
		OGRE_FREE_SIMD(vertexBuffer, Ogre::MEMCATEGORY_GEOMETRY);
		vertexBuffer = 0;
		throw e;
	}
	//We'll just use one vertex buffer source (multi-source not working yet)
	Ogre::VertexBufferPackedVec vertexBuffers;
	vertexBuffers.push_back(vertexBuffer);

	// currently consider 16-bit indices array only
	Ogre::uint16 * indexdata = reinterpret_cast<Ogre::uint16 *>(OGRE_MALLOC_SIMD(
									sizeof(Ogre::uint16) * 3 * mesh->mNumFaces, Ogre::MEMCATEGORY_GEOMETRY));
	// fill indexdata manually
#if defined _DEBUG && 0
	Ogre::LogManager::getSingleton().logMessage("  = Parsed indices:");
#endif
	for (unsigned int i = 0, offset = 0; i < mesh->mNumFaces; ++i)
	{
		indexdata[offset + 0] = (Ogre::uint16)mesh->mFaces[i].mIndices[0];
		indexdata[offset + 1] = (Ogre::uint16)mesh->mFaces[i].mIndices[1];
		indexdata[offset + 2] = (Ogre::uint16)mesh->mFaces[i].mIndices[2];
#if defined _DEBUG && 0
		Ogre::LogManager::getSingleton().logMessage(Ogre::StringConverter::toString(i) + ": " +
											Ogre::StringConverter::toString(mesh->mFaces[i].mIndices[0]) + ", " +
											Ogre::StringConverter::toString(mesh->mFaces[i].mIndices[1]) + ", " +
											Ogre::StringConverter::toString(mesh->mFaces[i].mIndices[2]));
#endif

		offset += 3;
	}

	Ogre::IndexBufferPacked *indexBuffer = 0;
	try
	{
		indexBuffer = vaoManager->createIndexBuffer(Ogre::IndexBufferPacked::IT_16BIT,
			sizeof(Ogre::uint16) * 3 * mesh->mNumFaces,
			Ogre::BT_IMMUTABLE,
			indexdata, false);
	}
	catch (Ogre::Exception &e)
	{
		// When keepAsShadow = true, the memory will be freed when the index buffer is destroyed.
		// However if for some weird reason there is an exception raised, the memory will
		// not be freed, so it is up to us to do so.
		// The reasons for exceptions are very rare. But we're doing this for correctness.
		OGRE_FREE_SIMD(indexBuffer, Ogre::MEMCATEGORY_GEOMETRY);
		indexBuffer = 0;
		throw e;
	}
	
	Ogre::SubMesh * submesh = pmeshv2->createSubMesh(index);
	Ogre::VertexArrayObject *vao = vaoManager->createVertexArrayObject(
		vertexBuffers, indexBuffer, Ogre::OT_TRIANGLE_LIST);

	//Each Vao pushed to the vector refers to an LOD level.
	//Must be in sync with mesh->mLodValues & mesh->mNumLods if you use more than one level
	submesh->mVao[Ogre::VpNormal].push_back(vao);
	//Use the same geometry for shadow casting.
	submesh->mVao[Ogre::VpShadow].push_back(vao);

	// AABB
	if (index > 0) // not first
	{
		subAABB.merge(_sV2mesh->getAabb());
	}
	pmeshv2->_setBounds(subAABB);
	pmeshv2->_setBoundingSphereRadius(subAABB.getRadius());

	return true;
}

EDIT: Complete codes on my github: https://github.com/riveranb/ogre-assimp


EDIT: Bug fixed.

Code: Select all

      indexBuffer = vaoManager->createIndexBuffer(Ogre::IndexBufferPacked::IT_16BIT,
         sizeof(Ogre::uint16) * 3 * mesh->mNumFaces,
         Ogre::BT_IMMUTABLE,
         indexdata, false);
createIndexBuffer(), 2nd argument I passed the wrong number (not number of bytes, should be number of indices!)
Last edited by riveranb on Fri Nov 17, 2017 10:32 am, edited 3 times in total.
riveranb
Gnoblar
Posts: 7
Joined: Tue Sep 26, 2017 1:35 am

Re: [2.1] Assimp, try loading asset for v2.1 mesh, with glitches

Post by riveranb »

I forked from kenkit/ogre-assimp on github,
And I put my developing codes on my github now.

Anyone wanna view codes can go to
https://github.com/riveranb/ogre-assimp
riveranb
Gnoblar
Posts: 7
Joined: Tue Sep 26, 2017 1:35 am

Re: [2.1] Assimp, try loading asset for v2.1 mesh, with glitches

Post by riveranb »

After several days debugging.
I have to say I'm really frustrated.

My final try is dump vertex buffer (position + normal) and index buffer.
And directly declare these buffers as global const arrays, then use memcpy() to copy the content.
And the result still the same.
Generated meshes keep creating new (different) glitches everytime.
I'm not sure if there's actually some bug in OGRE creating vao.
But I just tried everything I can to debug this issue.

Here I dump my mesh buffers. (6779 vertices + 2646 triangles, quiet a bit large buffer ...)
Is there some limit on vertex number or triangle number for one single submesh?
Could anyone please help? or any options/advice?

https://github.com/riveranb/ogre-assimp ... shBuffer.h
al2950
OGRE Expert User
OGRE Expert User
Posts: 1227
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 157

Re: [2.1] Assimp, try loading asset for v2.1 mesh, with glitches

Post by al2950 »

I am about 3 days off implementing exactly this my self. And to be honest I have been contemplating just creating a V1 mesh, and then converting it to V2, for 2 reasons.

1) V1 has the create tangent code that can be quite useful (although I think assimp can do all that),
2) When you convert a v1 mesh it will do all the optimisations, like QTangents and arrangeEfficient, as well as filling in optimised shadow buffers.

Obviously these could be done separately but the V1 mesh to V2 mesh is a reasonably well tested code path.
riveranb
Gnoblar
Posts: 7
Joined: Tue Sep 26, 2017 1:35 am

Re: [2.1] Assimp, try loading asset for v2.1 mesh, with glitches

Post by riveranb »

V1 mesh to V2 mesh is a reasonably well tested code path.
Well, it's really another way worth trying.
I will try it, though I think the codes generating v2 mesh/submesh should work....


EDIT: damn!
I really made a silly mistake!
The bug is I misunderstand the input arguments of createIndexBuffer();

Code: Select all

      indexBuffer = vaoManager->createIndexBuffer(Ogre::IndexBufferPacked::IT_16BIT,
         sizeof(Ogre::uint16) * 3 * mesh->mNumFaces,
         Ogre::BT_IMMUTABLE,
         indexdata, false);
2nd argument should be "number of indices", but I passed "number of bytes"....
So of course gpu seeks for non-existing triangles for rendering...
Bug fixed! Thanks for your help!
User avatar
Aiden
Halfling
Posts: 54
Joined: Fri Jul 14, 2017 3:16 pm
x 5

Re: [2.1] Assimp, try loading asset for v2.1 mesh, with glitches

Post by Aiden »

Nice work, I will try to catch up a bit later on the 2.1 branch. My repo is pretty messed up and would also need some work as I rushed it and haven't had the time to really work with ogre.
riveranb
Gnoblar
Posts: 7
Joined: Tue Sep 26, 2017 1:35 am

Re: [2.1] Assimp, try loading asset for v2.1 mesh, with glitches

Post by riveranb »

Aiden wrote: Fri Nov 03, 2017 7:55 am Nice work, I will try to catch up a bit later on the 2.1 branch. My repo is pretty messed up and would also need some work as I rushed it and haven't had the time to really work with ogre.
Thanks for all your previous works too!
I have a chance to use OGRE on my work, which is quite lucky thing I think.
But now I'm also been assigned other jobs/stuff.
So the integration work here I think will also be slow.

There are still a lot of contents need to be filled and tested (material/skeleton/animation/LOD ...).
I hope I can have more progress achieved on this interesting topic, though first need to have more time on it.
Post Reply