How to access 2nd UV layer? Topic is solved

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 to access 2nd UV layer?

Post by slapin »

Hi, all!
I try to get access to second layer of UV coordinates in my mesh. How can I do this?
It looks like doc lacks explanation about geometry access :(
All I was able to find was

Code: Select all

	const Ogre::VertexElement *uvElem =
		vertex_data->vertexDeclaration->findElementBySemantic(
			Ogre::VES_TEXTURE_COORDINATES);

but there is nothing about additional layers :(
@paroj

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

Re: How to access 2nd UV layer?

Post by slapin »

Managed to make it work with the following code:

Code: Select all

void getSubmeshNormals(const Ogre::Mesh *mesh, const Ogre::SubMesh *submesh,
		       size_t &vertex_count, Ogre::Vector3 **normals)
{
	int j;
	float *pReal;
	vertex_count = 0;
	if (submesh->useSharedVertices)
		vertex_count += mesh->sharedVertexData->vertexCount;
	else
		vertex_count += submesh->vertexData->vertexCount;
	Ogre::HardwareVertexBufferSharedPtr vbuf;
	Ogre::VertexData *vertex_data = submesh->useSharedVertices ?
						mesh->sharedVertexData :
						submesh->vertexData;
	const Ogre::VertexElement *normalsElem =
		vertex_data->vertexDeclaration->findElementBySemantic(
			Ogre::VES_NORMAL);
	*normals = nullptr;
	if (!normalsElem)
		return;
	*normals = new Ogre::Vector3[vertex_count];
	vbuf = vertex_data->vertexBufferBinding->getBuffer(
		normalsElem->getSource());
	unsigned char *vertex = static_cast<unsigned char *>(
		vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
	for (j = 0; j < vertex_data->vertexCount;
	     ++j, vertex += vbuf->getVertexSize()) {
		normalsElem->baseVertexPointerToElement(vertex, &pReal);
		(*normals)[j] = Ogre::Vector3(pReal[0], pReal[1], pReal[2]);
	}
	vbuf->unlock();
}
void getSubmeshUVs(const Ogre::Mesh *mesh, const Ogre::SubMesh *submesh,
		   size_t &vertex_count, Ogre::Vector2 **uvs, int index)
{
	int j;
	float *pReal;
	Ogre::HardwareVertexBufferSharedPtr vbuf;
	Ogre::VertexData *vertex_data = submesh->useSharedVertices ?
						mesh->sharedVertexData :
						submesh->vertexData;
	const Ogre::VertexElement *uvElem =
		vertex_data->vertexDeclaration->findElementBySemantic(
			Ogre::VES_TEXTURE_COORDINATES, index);
	vertex_count = 0;
	*uvs = nullptr;
	if (submesh->useSharedVertices)
		vertex_count += mesh->sharedVertexData->vertexCount;
	else
		vertex_count += submesh->vertexData->vertexCount;
	if (!uvElem)
		return;
	*uvs = new Ogre::Vector2[vertex_count];
	vbuf = vertex_data->vertexBufferBinding->getBuffer(uvElem->getSource());
	unsigned char *uv = static_cast<unsigned char *>(
		vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
	for (j = 0; j < vertex_data->vertexCount; ++j) {
		uvElem->baseVertexPointerToElement(uv, &pReal);
		(*uvs)[j] = Ogre::Vector2(pReal[0], pReal[1]);
		uv += vbuf->getVertexSize();
	}
	vbuf->unlock();
}
void getSubmeshVertices(const Ogre::Mesh *mesh, const Ogre::SubMesh *submesh,
			size_t &vertex_count, Ogre::Vector3 **vertices)
{
	int j;
	float *pReal;
	vertex_count = 0;
	if (submesh->useSharedVertices)
		vertex_count += mesh->sharedVertexData->vertexCount;
	else
		vertex_count += submesh->vertexData->vertexCount;
	Ogre::HardwareVertexBufferSharedPtr vbuf;
	Ogre::VertexData *vertex_data = submesh->useSharedVertices ?
						mesh->sharedVertexData :
						submesh->vertexData;
	const Ogre::VertexElement *posElem =
		vertex_data->vertexDeclaration->findElementBySemantic(
			Ogre::VES_POSITION);
	*vertices = nullptr;
	if (!posElem)
		return;
	*vertices = new Ogre::Vector3[vertex_count];
	vbuf = vertex_data->vertexBufferBinding->getBuffer(
		posElem->getSource());
	unsigned char *vertex = static_cast<unsigned char *>(
		vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
	for (j = 0; j < vertex_data->vertexCount;
	     ++j, vertex += vbuf->getVertexSize()) {
		posElem->baseVertexPointerToElement(vertex, &pReal);
		(*vertices)[j] = Ogre::Vector3(pReal[0], pReal[1], pReal[2]);
	}
	vbuf->unlock();
}
void getSubmeshIndices(const Ogre::Mesh *mesh, const Ogre::SubMesh *submesh,
		       size_t &index_count, unsigned long **indices)
{
	index_count = 0;
	index_count += submesh->indexData->indexCount;
	int index_offset = 0;
	*indices = new unsigned long[index_count];

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_READ_ONLY));
unsigned short *pShort = reinterpret_cast<unsigned short *>(pLong);

size_t offset = 0;

if (use32bitindexes) {
	for (size_t k = 0; k < numTris * 3; ++k) {
		(*indices)[index_offset++] =
			pLong[k] + static_cast<unsigned long>(offset);
	}
} else {
	for (size_t k = 0; k < numTris * 3; ++k) {
		(*indices)[index_offset++] =
			static_cast<unsigned long>(pShort[k]) +
			static_cast<unsigned long>(offset);
	}
}

ibuf->unlock();
}

void getSubMeshInformation(const Ogre::Mesh *mesh, const Ogre::SubMesh *submesh,
			   size_t &vertex_count, Ogre::Vector3 **vertices,
			   size_t &index_count, unsigned long **indices,
			   Ogre::Vector2 **uvs, Ogre::Vector2 **uv2s)
{
	getSubmeshIndices(mesh, submesh, index_count, indices);
	getSubmeshVertices(mesh, submesh, vertex_count, vertices);
	size_t vc = vertex_count;
	getSubmeshUVs(mesh, submesh, vertex_count, uvs, 0);
	OgreAssert(vc == vertex_count, "bad vertex count ");
	getSubmeshUVs(mesh, submesh, vertex_count, uv2s, 1);
	OgreAssert(vc == vertex_count, "bad vertex count");
}

I wonder if I really need to access each element separately... but it works.