Creating a custom mesh object

Problems building or running the engine, queries about how to use features etc.
Post Reply
jasonlg3d
Gnoblar
Posts: 15
Joined: Thu Jan 20, 2011 12:14 am

Creating a custom mesh object

Post by jasonlg3d »

*Edited* I had a small light bulb moment that got me a little bit closer i think. New code posted.

I'm working on a terrain engine and am grappling with how to create a custom mesh by writing directly to the hardware vertex buffer. As of now I know my rendering code is working as i can see a normal ogre entity in the window. What Im trying to understand now is how to render the mesh Im attempting to create.

Code: Select all

bool CTPatch::CreatePatch(Ogre::SceneNode* planetNode)
	{
		int numVertices = m_nResolution * m_nResolution;
		
		CDEMChunk demData(m_nResolution);

		Ogre::SubMesh* pSubMesh;
		Ogre::MeshPtr pTerrain;
		Ogre::MeshManager::getSingleton().createManual("terrain", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
		
		pSubMesh = pTerrain->createSubMesh("subMesh");
		pSubMesh->vertexData = new Ogre::VertexData();
		Ogre::VertexData* pVtxData = pSubMesh->vertexData;

		// define the vertex format
		Ogre::VertexDeclaration* pVtxDec = pVtxData->vertexDeclaration;
		size_t currOffset = 0;

		pVtxDec->addElement(0, currOffset, Ogre::VET_FLOAT3, Ogre::VES_POSITION,0);
		currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);

		pVtxData->vertexCount = numVertices;
		Ogre::HardwareVertexBufferSharedPtr vBuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(pVtxDec->getVertexSize(0), numVertices, Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE, false);
		
		Ogre::VertexBufferBinding* pVtxBinding = pVtxData->vertexBufferBinding;
		pVtxBinding->setBinding(0, vBuf);
		
		Ogre::Real* pReal = static_cast<Ogre::Real*>(vBuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
		
		for(int i = 0; i < sizeof(demData.m_vPos); i++)
		{
			*pReal++ = demData.m_vPos->x;
			*pReal++ = demData.m_vPos->y;
			*pReal++ = demData.m_vPos->z;
		}
		pSubMesh->useSharedVertices = false;
		pSubMesh->operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST; 
		vBuf->unlock();

		Ogre::SceneNode* ENode = planetNode->createChildSceneNode("tNode",Ogre::Vector3(0.0,0.0,0.0));
		Ogre::Entity* pEnt;

		return true;
	}
So as you can see, I've created a MeshPtr and a subMesh of that class. Now how the heck to I get that into an Ogre Entity?
jasonlg3d
Gnoblar
Posts: 15
Joined: Thu Jan 20, 2011 12:14 am

Re: Creating a custom mesh object

Post by jasonlg3d »

Well after more experimenting I have managed to attach my mesh to a node (I think) but alas, nothing is rendering.

New code:

Code: Select all

bool CTPatch::CreatePatch(Ogre::SceneNode* planetNode)
	{
		int numVertices = m_nResolution * m_nResolution;
		Ogre::Vector3 pos;
		
		CDEMChunk demData(m_nResolution);

		Ogre::SubMesh* pSubMesh;
		Ogre::MeshPtr pTerrain = Ogre::MeshManager::getSingleton().createManual("terrain", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
		
		pSubMesh = pTerrain->createSubMesh("subMesh");
		pSubMesh->vertexData = new Ogre::VertexData();
		Ogre::VertexData* pVtxData = pSubMesh->vertexData;

		// define the vertex format
		Ogre::VertexDeclaration* pVtxDec = pVtxData->vertexDeclaration;
		size_t currOffset = 0;

		pVtxDec->addElement(0, currOffset, Ogre::VET_FLOAT3, Ogre::VES_POSITION,0);
		currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);

		pVtxData->vertexCount = numVertices;
		Ogre::HardwareVertexBufferSharedPtr vBuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(pVtxDec->getVertexSize(0), numVertices, Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE, false);
		
		Ogre::VertexBufferBinding* pVtxBinding = pVtxData->vertexBufferBinding;
		pVtxBinding->setBinding(0, vBuf);
		
		Ogre::Real* pReal = static_cast<Ogre::Real*>(vBuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
		
		for(int i = 0; i < m_nResolution; i++)
		{
			pos = demData.m_vPos[i];
			*pReal++ = pos.x;
			*pReal++ = pos.y;
			*pReal++ = pos.z;
		}
		pSubMesh->useSharedVertices = false;
		pSubMesh->operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST; 
		vBuf->unlock();
		
		pTerrain->load();
		Ogre::SceneNode* ENode = planetNode->createChildSceneNode("tNode",Ogre::Vector3(0.0,0.0,0.0));
		Ogre::Entity* pEnt = Core::getSingleton().getSceneManager()->createEntity("entTerrain", "terrain");
		ENode->attachObject(pEnt);

		return true;
	}
I know its a bit of a mess at this point, but I'd just like to see something in the window!
jasonlg3d
Gnoblar
Posts: 15
Joined: Thu Jan 20, 2011 12:14 am

Re: Creating a custom mesh object

Post by jasonlg3d »

I'm gonna keep posting in hopes that someone might spot my problem and so that if I do manage to stumble into the solution myself, maybe someone else will benefit from my issues.

Ok so now I am pretty confident that I am properly attaching my mesh to a node. I know that my engine is in fact rendering as I can render a plane to the scene in the same function as I attempt to render my custom object. So now I'm down to the custom object itself and whether or not it is being created properly and completely.

In the interest of detail, I'll describe the entire object in code now.

This function is what is supposed to be doing the actual rendering of the object.

Code: Select all

bool CTPatch::CreatePatch(Ogre::SceneNode* planetNode)
	{
		int numVertices = m_nResolution * m_nResolution;
		Ogre::Vector3 pos;
		
		CDEMChunk demData(m_nResolution);

		Ogre::SubMesh* pSubMesh;
		Ogre::MeshPtr pTerrain = Ogre::MeshManager::getSingleton().createManual("terrain", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
		
		pSubMesh = pTerrain->createSubMesh("subMesh");
		pSubMesh->vertexData = new Ogre::VertexData();
		Ogre::VertexData* pVtxData = pSubMesh->vertexData;

		// define the vertex format
		Ogre::VertexDeclaration* pVtxDec = pVtxData->vertexDeclaration;
		size_t currOffset = 0;

		pVtxDec->addElement(0, currOffset, Ogre::VET_FLOAT3, Ogre::VES_POSITION,0);
		currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);

		pVtxData->vertexCount = numVertices;
		Ogre::HardwareVertexBufferSharedPtr vBuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(pVtxDec->getVertexSize(0), numVertices, Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE, false);
		
		Ogre::VertexBufferBinding* pVtxBinding = pVtxData->vertexBufferBinding;
		pVtxBinding->setBinding(0, vBuf);
		
		Ogre::Real* pReal = static_cast<Ogre::Real*>(vBuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
		
		for(int i = 0; i < m_nResolution; i++)
		{
			pos = demData.m_vPos[i];
			*pReal++ = pos.x;
			*pReal++ = pos.y;
			*pReal++ = pos.z;
		}
		pSubMesh->useSharedVertices = false;
		pSubMesh->operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST; 
		vBuf->unlock();
		
		pTerrain->load();
		Ogre::SceneNode* pNode = planetNode->createChildSceneNode("tNode",Ogre::Vector3(0.0,0.0,0.0));
		Ogre::Entity* pEnt = Core::getSingleton().getSceneManager()->createEntity("entTerrain", "terrain");
		pNode->attachObject(pEnt);

		return true;
	}
This line of code: CDEMChunk demData(m_nResolution); creates the CDEMChunk object, obviously. This object is currently just a bunch of points in space. Here is the constructor.

Code: Select all

CDEMChunk::CDEMChunk(int nRes)
	{
		Ogre::Vector3* points = new Ogre::Vector3[nRes * nRes];

		int i;
		int j;
		int vertCount = 0;

		/* initialize random seed: */
		srand ( time(NULL) );

	
		for (i = 0; i < nRes; i++)
		{
			for (j = 0; j < nRes; j++)
			{
				points[vertCount] = Ogre::Vector3(i*2.0, j*2.0, rand() % 10 + 1);
				vertCount++;
			}
		}

		m_vPos = points;
	}
Now I have debugged that guy and it is working. I get a proper array of 3D points.

So that leaves the problem lying in the first bit of code i posted. I'm not at all confident I have properly built the mesh in the vertex buffer but I really have no idea how to find out. I'll keep banging my head against the already bloody wall and in the mean time, maybe one of you smart cats can point out the error of my ways.
jasonlg3d
Gnoblar
Posts: 15
Joined: Thu Jan 20, 2011 12:14 am

Re: Creating a custom mesh object

Post by jasonlg3d »

Well I made a huge mistake in assuming I knew what I was doing. That said, I was ignoring the index buffer out of ignorance. Now, I have created the index buffer and reworked some of the code and it is now rendering, albeit incorrectly. I'm off to hunt down my algorithm problems now.

The new code for those of you who care.

Code: Select all

Ogre::Entity* CTPatch::CreateMesh(void)
	{
		int nNumVerts = this->m_nPRes * this->m_nPRes;
		
		// Mesh Pointer
		Ogre::MeshPtr msh = Ogre::MeshManager::getSingleton().createManual("terr_mesh", "General");

		// Create one submesh
		Ogre::SubMesh* sub = msh->createSubMesh();
		
		const int sztVertices = this->m_nVRes * this->m_nVRes * 3;
		const size_t sztBufCount = 3*sztVertices;
		
		// Load up the verts
		float* fpVerts = new float[sztVertices];
		
		this->LoadVertices(fpVerts);
		
		// Create the indices
		// Resolution times 2 triagles per quad and 3 verts per triangle
		const int sztIBufCount = this->m_nPRes * this->m_nPRes * 2 * 3;
		unsigned short* fpIndices = new unsigned short[sztIBufCount];
		
		this->LoadIndices(fpIndices);

		/// Create vertex data structure for vertices shared between submeshes
		msh->sharedVertexData = new Ogre::VertexData();
		msh->sharedVertexData->vertexCount = sztVertices;
	 
		/// Create declaration (memory format) of vertex data
		Ogre::VertexDeclaration* decl = msh->sharedVertexData->vertexDeclaration;
		size_t offset = 0;
		// 1st buffer
		decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
		offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);

		/// Allocate vertex buffer of the requested number of vertices (vertexCount) 
		/// and bytes per vertex (offset)
		Ogre::HardwareVertexBufferSharedPtr vbuf = 
			Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
			offset, msh->sharedVertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
		/// Upload the vertex data to the card
		vbuf->writeData(0, vbuf->getSizeInBytes(), fpVerts, true);

		/// Set vertex buffer binding so buffer 0 is bound to our vertex buffer
		Ogre::VertexBufferBinding* bind = msh->sharedVertexData->vertexBufferBinding; 
		bind->setBinding(0, vbuf);

		/// Allocate index buffer of the requested number of vertices (ibufCount) 
		Ogre::HardwareIndexBufferSharedPtr ibuf = Ogre::HardwareBufferManager::getSingleton().
			createIndexBuffer(
			Ogre::HardwareIndexBuffer::IT_16BIT, 
			sztIBufCount, 
			Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
	 
		/// Upload the index data to the card
		ibuf->writeData(0, ibuf->getSizeInBytes(), fpIndices, true);

		/// Set parameters of the submesh
		sub->useSharedVertices = true;
		sub->indexData->indexBuffer = ibuf;
		sub->indexData->indexCount = sztIBufCount;
		sub->indexData->indexStart = 0;
	 
		/// Set bounding information (for culling)
		msh->_setBounds(Ogre::AxisAlignedBox(-100,-100,-100,100,100,100));
		msh->_setBoundingSphereRadius(Ogre::Math::Sqrt(3*100*100));
	 
		/// Notify -Mesh object that it has been loaded
		msh->load();

		Ogre::Entity* thisEntity = Core::getSingleton().getSceneManager()->createEntity("cc", "terr_mesh");
		
		return thisEntity;
	}
User avatar
Jabberwocky
OGRE Moderator
OGRE Moderator
Posts: 2819
Joined: Mon Mar 05, 2007 11:17 pm
Location: Canada
x 218
Contact:

Re: Creating a custom mesh object

Post by Jabberwocky »

jasonlg3d wrote:Well I made a huge mistake in assuming I knew what I was doing.
I make that same mistake all the time. :lol:
Image
Post Reply