Page 1 of 1

Find the color of a vertex?

Posted: Mon Apr 20, 2009 10:41 am
by Quark
Is it possible to retrieve the color of a specific vertex? The base color, determined by the material, without any light influence?
I got the x,y float2 texture coordinates, found by retrieving VES_TEXTURE_COORDINATES alright, but how do I perform the texture lookup?

Re: Find the color of a vertex?

Posted: Wed Apr 22, 2009 8:40 am
by ming.zhu
You already have the texture-coords right? Then just lock the texture and you can get the pixel data~

Re: Find the color of a vertex?

Posted: Wed Apr 22, 2009 8:51 am
by Quark
Could you point me in the right direction? How do I lock the texture and get the pixel data? Which class allows me to do so?

Re: Find the color of a vertex?

Posted: Mon Apr 27, 2009 7:45 am
by Quark
*bump*

Could anyone tell me exactly how to do a texture lookup in Ogre3D?
How do I lock the texture and get the pixel data?

Re: Find the color of a vertex?

Posted: Mon May 04, 2009 9:00 am
by Quark
Sorry to bump again, but I'm still a bit stuck on this.

Re: Find the color of a vertex?

Posted: Mon May 04, 2009 7:10 pm
by madmarx
There is an example of locking a texture, accessing the pixel data of the texture in the ogre demo called "dyn_tex" (for "dynamic texture").
From my head : get the texture from the texture manager, then ask for a pixel buffer (I can't remember if I had to create a pixel buffer to receive the texture last time I used this feature), and then call lock() on the pixel buffer. The lock will give you a pointer to the data of the texture (be careful of the data format anyway, not everything is RGB24).

Hope this help! :D

Good luck!


EDIT:
in OgreTexture :
HardwarePixelBufferSharedPtr getBuffer (size_t face=0, size_t mipmap=0)=0
then T * get () const
then virtual void * lock (size_t offset, size_t length, LockOptions options)
then unlock.
For example (NEVER write it like that of course !).
TextureManager::getSingletonPtr()->getByName("myTex")->getBuffer().get()->lock(size of the texture, ...);

Re: Find the color of a vertex?

Posted: Tue Jul 07, 2009 11:50 am
by Quark
It's been a while since my post. I've been working on other stuff and I couldn't return to this before.

I found the dynamic texture example at Wiki - Creating_dynamic_textures. This seems to be what you meant.

Also, I can use vertexDeclaration->findElementBySemantic(Ogre::VES_TEXTURE_COORDINATES) to find the texture coordinates alright.

However, how do I get a TexturePtr to the texture to use? For my specific submesh..

Re: Find the color of a vertex?

Posted: Tue Jul 07, 2009 12:27 pm
by Kencho
TextureManager::getByName() is one way. TextureUnitState::_getTexturePtr() is other.

Re: Find the color of a vertex?

Posted: Wed Jul 08, 2009 11:15 am
by Quark
Ok, this is how I'm planning to do it, do you guys spot any problems with it?

Code: Select all

SubMesh* submesh; 	// Initialized elsewhere

Ogre::VertexData* vertex_data = submesh->useSharedVertices ? data.mesh->sharedVertexData : submesh->vertexData;
if((!submesh->useSharedVertices)||(submesh->useSharedVertices && !added_shared))
{
	if(submesh->useSharedVertices) {
		added_shared = true;
		shared_offset = current_offset;
	}

	const Ogre::VertexElement* posElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
	const Ogre::VertexElement* norElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_NORMAL);
	const Ogre::VertexElement* texElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_TEXTURE_COORDINATES, 0);
	Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());
	unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
	float* pReal;
	float* nReal;
	float* tReal;

	for(size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize()) {
		posElem->baseVertexPointerToElement(vertex, &pReal);
		norElem->baseVertexPointerToElement(vertex, &nReal);
		texElem->baseVertexPointerToElement(vertex, &tReal);

		// What I'm trying to do here is find the (base) color of the current vertex
		Pass* pass = ((MaterialPtr) MaterialManager::getSingleton().getByName(submesh->getMaterialName()))->getTechnique(0)->getPass(0);
		if (pass->getNumTextureUnitStates() > 0) {
			TextureUnitState* texunit = pass->getTextureUnitStateIterator().getNext();
			TexturePtr texture = texunit->_getTexturePtr();

			// Get the pixel buffer
			HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer();

			// Lock the pixel buffer and get a pixel box
			pixelBuffer->lock(HardwareBuffer::HBL_DISCARD);
			const PixelBox& pixelBox = pixelBuffer->getCurrentLock();

			int width = pixelBox.getWidth();
			int height = pixelBox.getHeight();
			std::cout << "width=" << width << " height=" << height << "\n";
			uint8* pDest = static_cast<uint8*>(pixelBox.data);

			// pDest contains our RGBA data (considering color format)

			pixelBuffer->unlock();
		}
	}
}
I assume that pDest contains all pixels.

However, how can I retrieve the color for the current vertex? Tex.x and tex.y contains floats from a wide range (including negative floats), so I assume I'm doing something wrong.

Re: Find the color of a vertex?

Posted: Mon Jul 13, 2009 8:46 am
by Quark
*bump*

How do I use the texture_coordinates properly? What's the correct range (from 0.0f to 1.0f?)?

Code: Select all

uint8* pDest = static_cast<uint8*>(pixelBox.data);
This holds the texture_coordinates, but in my current model this can range from -10.0f to 110.0f, I can't really use it properly.

Re: Find the color of a vertex?

Posted: Mon Jul 13, 2009 8:53 am
by Kencho
I'm afraid you're mixing concepts here...
First of all, pixel boxes are "raw" images. The "uint8" data type should hint that the possible values are integers in the range [0, 255]. Then, they only store colour information, not texture coordinates.

Now, assuming you meant that you want to obtain the texture colour at positions outside the [0, 1] range, it all depends on the texture addressing mode. If you use clamping, then values below 0 are the values at 0 and above 1 are the values at 1. Wrapping results in repeating the whole cycle of [0, 1] (as with the modulus of a division), and so on.

Re: Find the color of a vertex?

Posted: Mon Jul 13, 2009 10:01 am
by Quark
Oh sorry, I'm indeed mixing things up. I posted too soon without thinking right.
The pixelbox indeed holds the raw texture.

In my case tReal[0] and tReal[1] hold the x,y texture coordinates. And these values range from -10.0f to 110.0f in this case.

I'm wondering how to use these correctly. Must I clamp them to the range [0.0 .. 1.0]?

Re: Find the color of a vertex?

Posted: Mon Jul 13, 2009 1:19 pm
by Kencho
That's up to you. Sometimes you will want to clamp it, and sometimes you'll want to wrap it. Would you tile that texture? If so, wrap it. Otherwise, clamp it ;)

Re: Find the color of a vertex?

Posted: Fri Jul 17, 2009 3:15 pm
by Quark
I just can't seem to get any vertex color data using the above code.
Could any of you gurus please check if I'm doing anything wrong?

(Both using clamping and wrapping I'm not getting any color data)

Re: Find the color of a vertex?

Posted: Thu Jul 23, 2009 4:41 am
by ming.zhu
You tried to get tex_coord data from the same vertex buffer source that stores the position data. However they may be of different sources.

Btw don't do lock/unlock in the vertex loop.

Re: Find the color of a vertex?

Posted: Thu Jul 23, 2009 4:53 am
by ming.zhu
Just have a look at my comment.

Code: Select all

SubMesh* submesh; 	// Initialized elsewhere

Ogre::VertexData* vertex_data = submesh->useSharedVertices ? data.mesh->sharedVertexData : submesh->vertexData;
if((!submesh->useSharedVertices)||(submesh->useSharedVertices && !added_shared))
{
	if(submesh->useSharedVertices) {
		added_shared = true;
		shared_offset = current_offset;
	}

	const Ogre::VertexElement* posElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
	const Ogre::VertexElement* norElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_NORMAL);

/* the texElem may be of a different source from the posElem. You could try getSource to check it */
	const Ogre::VertexElement* texElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_TEXTURE_COORDINATES, 0);

/* the vbuf is the buffer for the position data, you can pass in texElem->getSource() as the param to get tex_coord data */
	Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());

	unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
	float* pReal;
	float* nReal;
	float* tReal;

	for(size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize()) {
		posElem->baseVertexPointerToElement(vertex, &pReal);
		norElem->baseVertexPointerToElement(vertex, &nReal);

/* after you get the tReal for the texture UV data, you could use it to get the color info from the texture( pixel box )
    usually the UV data should be two floats of the range [0.0, 1.0] */
		texElem->baseVertexPointerToElement(vertex, &tReal);

/* don't do lock/unlock here. move it out of the loop. */
		// What I'm trying to do here is find the (base) color of the current vertex
		Pass* pass = ((MaterialPtr) MaterialManager::getSingleton().getByName(submesh->getMaterialName()))->getTechnique(0)->getPass(0);
		if (pass->getNumTextureUnitStates() > 0) {
			TextureUnitState* texunit = pass->getTextureUnitStateIterator().getNext();
			TexturePtr texture = texunit->_getTexturePtr();

			// Get the pixel buffer
			HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer();

/* don't use HBL_DISCARD since you want to read but not change the texture data. Try HBL_READ_ONLY */
			// Lock the pixel buffer and get a pixel box
			pixelBuffer->lock(HardwareBuffer::HBL_DISCARD);
			const PixelBox& pixelBox = pixelBuffer->getCurrentLock();

			int width = pixelBox.getWidth();
			int height = pixelBox.getHeight();
			std::cout << "width=" << width << " height=" << height << "\n";
/* you may need to check the format for the pixel box. uint8 is not always the case. */
			uint8* pDest = static_cast<uint8*>(pixelBox.data);

			// pDest contains our RGBA data (considering color format)

			pixelBuffer->unlock();
		}
	}
}