Page 2 of 3

Posted: Wed May 16, 2007 6:01 pm
by jacmoe
funguine wrote:the following is copy-paste from our Mogre-port of your algorithm,
as displayed on the Wiki. Seems to work fine. This version also
reports the normal of the face that was hit.
((code snipped away))

Someone with access to wiki, please feel free ...
You have access to the Wiki, as do all members of the Ogre community.
Feel free to update the code - we appreciate it! :)

Posted: Fri Jun 29, 2007 5:08 am
by smernesto
HI,

anyone has an example for using the code?

I need to know what entity the ray hit.

Thanks

Ernesto

Posted: Thu Jul 19, 2007 7:16 pm
by funguine
smernesto wrote:HI,
anyone has an example for using the code?
I need to know what entity the ray hit.
RaycastFromPoint as displayed on the wiki returns you true if an object
was hit by the ray specified by the parameters 'point' and 'normal' (latter
would be better called 'direction'). In the parameter list are also two (Mogre version) results, 'result' (better 'position') and 'resNormal', which in case true has been returned contain the coordinate where the ray intersects the mesh,
and the normal vector for the surface at that point. To get the name of
the entity that was hit you would need to add a third result parameter,
and set it thus:

Code: Select all

            if (ncf > -1)
            {
                closest_result = ray.GetPoint(closest_distance);
                // if you don't need the normal, comment this out; you'll save some CPU cycles.
                Vector3 v1 = vertices[indices[ncf]] - vertices[indices[ncf + 1]];
                Vector3 v2 = vertices[indices[ncf + 2]] - vertices[indices[ncf + 1]];
                vNormal = v1.CrossProduct(v2);
                name = pentity.Name; // THIS HERE NEW LINE
            }

My version does this and more, I could clean it up a bit and update the Wiki page. Soon :)

The general Raycast test using this function would be something like:

Code: Select all

                Vector3 point = Vector3.ZERO;
                Vector3 direction = -Vector3.UNIT_Z;
                Vector3 pos = Vector3.ZERO;
                Vector3 norm = Vector3.ZERO;
                String name = "";
                if (RaycastFromPoint(point, direction, ref pos, ref norm, ref name))
                { // an object was hit by the ray
                     Console.WriteLine(name + " was hit at " + pos.ToString() + ". Normal: " + norm.ToString());
                } else
                    Console.WriteLine("No object was hit by the ray");
               


Posted: Sat Aug 18, 2007 3:24 am
by smernesto
Will be great if you upload your version of this code to the wiki.

EDIT: thanks , i modified the code and now It works for me, it gives me the name of the entity.

There is any way I can use the code without the unsafe method?

Posted: Mon Oct 01, 2007 5:08 pm
by Minimoi
There is a little bug in the fonction, at line:

// get the mesh information
OgreVE::GetMeshInformation(pentity->getMesh(), vertex_count, vertices, index_count, indices,
pentity->getParentNode()->getWorldPosition(),
pentity->getParentNode()->getWorldOrientation(),
pentity->getParentNode()->getScale());


It 's not pentity->getParentNode()->getScale() but pentity->getParentNode()->_getDerivedScale().

Posted: Wed Oct 24, 2007 8:15 am
by xabila
I found the same bug yesterday, you should update the wiki then ;)

Posted: Sun Jan 06, 2008 5:24 pm
by Pascal
I am trying to raycast mesh created from ManualObject created with option OT_TRIANGLE_STRIP (or OT_TRIANGLE_FAN). I have error at line:

Code: Select all

std::pair<bool, Ogre::Real> hit = Ogre::Math::intersects(ray, vertices[indices[i]], vertices[indices[i+1]], vertices[indices[i+2]], true, false);
It means that only OT_TRIANGLE_LIST is supported? Maybe, the reason is that index count is always 3 * n. Triangle fans or strips don't always have 3 * n indices.

Posted: Wed Jan 09, 2008 1:42 pm
by KuRi
Any sample code on using this with the mouse input to pickup polygons with the mouse?

Thanks!

PD: Self-Solved:

Code: Select all

Ray mouseray = mCamera->getCameraToViewportRay(MouseX,MouseY);
bool ok = RaycastFromPoint(mouseray.getPoint(0),mouseray.getDirection(),obj->Position);

Posted: Thu Feb 14, 2008 1:20 am
by foxmulder900
Sorry for just pasting a bunch of code especially since much of it was pasted above. But I am using this picking method, however, I modified it slightly for my needs. It works i would say 80% of the time however sometimes when It should be returning something it does not.

Code: Select all

		ray = camera->getCameraToMouseRay();
		query->setRay(ray);
		
		results = query->execute();

		float closest_distance = -1;
		Vector3 closest_result;
		Entity* closest_entity = NULL;

		for(unsigned int i=0; i<results.size(); i++)
		{
			
			if(closest_distance >= 0 && closest_distance < results[i].distance)
				break;
			if(results[i].movable && results[i].movable->getName().find("GrassPage") != string::npos)
				continue;
			if(results[i].movable && results[i].movable->getMovableType().compare("Entity") == 0)
			{
				Entity* ent = (Entity*)results[i].movable;
				Node* node = ent->getParentNode();

				// mesh data to retrieve         
				size_t vertex_count;
				size_t index_count;
				Vector3 *vertices;
				unsigned long *indices;

				GetMeshInformation(ent->getMesh(), vertex_count, vertices, index_count, indices, node->getWorldPosition(), node->getWorldOrientation(), node->getScale());
				bool new_closest_found = false;
				for(int j=0; j<(int)index_count; j+=3)
				{
					std::pair<bool, Real> hit = Math::intersects(ray, vertices[indices[j]], vertices[indices[j+1]], vertices[indices[j+2]], true, false);
					if(hit.first)
					{
						if(closest_distance < 0 || hit.second < closest_distance)
						{
							closest_distance = hit.second;
							new_closest_found = true;
						}
					}
				}	
				delete[] vertices;
				delete[] indices;
				
				if(new_closest_found)
				{
					closest_result = ray.getPoint(closest_distance);
					closest_entity = ent;
				}
			}

		}
		if(closest_entity)
			cout << closest_entity->getName() << endl;
		else
			cout << "null" << endl;
I am using my own camera class and I am sure that the getCameraToMouseRay() function is returning the correct ray.

As you can see I put a few cout statements at the end for testing and like I said about 80% of my clicks that should return an entity do, however a few of them are slipping through the code somehow! If anyone sees anything I am missing please let me know! (fyi I did not modify the GetMeshInformation function)

Posted: Thu Feb 14, 2008 9:01 am
by RobG
I'm guessing that your method is relying on hitting the object's bounding box before starting to work out which polygons you are hitting. Switch your bounding box display on and check if your mesh is extending past it's edges. This is what was happening to me when I used an animated mesh.

Posted: Thu Feb 14, 2008 3:15 pm
by foxmulder900
It was my understanding that the fastest way (if not the only way) was to check if a ray collides on the bounding box level - then continue on to check to the polygon level. Maybe I am misunderstanding your suggestion.

Posted: Thu Feb 14, 2008 3:22 pm
by RobG
Yes I agree entirely. I was simply stating that it is possible for a mesh to leave the bounding box. Therefore when you try cast a ray that doesn't go through the bounding box, but does go through the mesh, you will get a NULL result.

Just letting you know that this could potentially be your problem. And the way to fix it would be to make sure all the meshes are fully encompassed in their respective AABBs.

polygon level after animation transform...

Posted: Sun Nov 30, 2008 5:14 am
by CurlyHairedGenius
I know this is kind of an old thread...

I would like to use this method for some collision detection, but I noticed it does not take into account the animation transforms.

Is there a way to raycast to the polygon level at the current animation state.

I think there should be a way to redo the GetMeshInformation function but I'm not exactly sure on the particulars.


I was thinking it could be done at the entity level instead of the mesh level something along the lines of:

Ogre::VertexData * vData = ent->_getHardwareVertexAnimVertexData();

const Ogre::VertexElement* pElem = vData->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);

Ogre::HardwareVertexBufferSharedPtr vBuf = vData->vertexBufferBinding->getBuffer(pElem->getSource());

unsigned char* vert = static_cast<unsigned char*>(vBuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));



I am pretty new to ogre and I feel like I know this is incomplete...

Does anyone have any ideas on how to raycast to the polygon level after the animation transforms?

Posted: Fri Dec 05, 2008 3:34 pm
by mcaden
KuRi wrote:Any sample code on using this with the mouse input to pickup polygons with the mouse?

Thanks!

PD: Self-Solved:

Code: Select all

Ray mouseray = mCamera->getCameraToViewportRay(MouseX,MouseY);
bool ok = RaycastFromPoint(mouseray.getPoint(0),mouseray.getDirection(),obj->Position);
I don't see any problem with this code but I'm having trouble getting this to work. Would using an orthogonal projection skew that mouseray a bit?

Every raycast is returning false. I'm using the mogre code from the wiki and funguine's addition of returning the entity name with KuRi's method of mousePicking.

Code: Select all

if (e.state.ButtonDown(MouseButtonID.MB_Left))
{
    Mogre.Vector3 vec = Mogre.Vector3.ZERO;
    Mogre.Vector3 result = Mogre.Vector3.ZERO;
    String name = "";
    Ray mouseray = ExCamera.getOgreCamera.GetCameraToViewportRay( e.state.X.abs, e.state.Y.abs );

    if (RaycastFromPoint(mouseray.GetPoint(0), mouseray.Direction, ref result, ref vec, ref name))
    {
        LogManager.Singleton.LogMessage(name + " was hit at " + result.ToString() + ". Normal: " + vec.ToString());
    }
    else
    {
        LogManager.Singleton.LogMessage("shootin blanks");
    }
}

Re: polygon level after animation transform...

Posted: Sun Jan 04, 2009 12:22 am
by sms1986
CurlyHairedGenius wrote:I know this is kind of an old thread...

I would like to use this method for some collision detection, but I noticed it does not take into account the animation transforms.

Is there a way to raycast to the polygon level at the current animation state.

I think there should be a way to redo the GetMeshInformation function but I'm not exactly sure on the particulars.


I was thinking it could be done at the entity level instead of the mesh level something along the lines of:

Ogre::VertexData * vData = ent->_getHardwareVertexAnimVertexData();

const Ogre::VertexElement* pElem = vData->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);

Ogre::HardwareVertexBufferSharedPtr vBuf = vData->vertexBufferBinding->getBuffer(pElem->getSource());

unsigned char* vert = static_cast<unsigned char*>(vBuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));



I am pretty new to ogre and I feel like I know this is incomplete...

Does anyone have any ideas on how to raycast to the polygon level after the animation transforms?
I have the same doubt...

Re: Raycasting to the polygon level [solved]

Posted: Mon Aug 10, 2009 3:44 pm
by Rumi
Same problem here... :?
I was using this function for a long time without any problem, until i start using it on animated entities. :(

Re: Raycasting to the polygon level [solved]

Posted: Mon Aug 10, 2009 5:55 pm
by jacmoe
Just update the animation.
Rebuild the information -> You must fetch the mesh information each frame.

Re: Raycasting to the polygon level [solved]

Posted: Mon Aug 10, 2009 6:08 pm
by Rumi
That,s the point. I update my animation each frame, but then my rays keep colliding with the original mesh...
How do i fetch the mesh information every frame? I can't find anything about how to do this...
Doing this will make the rays collide with the animated state of the mesh?

Re: Raycasting to the polygon level [solved]

Posted: Mon Aug 10, 2009 8:42 pm
by jacmoe
Each frame you need to get vertex index mesh information from the animating mesh.
You need to update the animation and the model (IIRC) too, so that the transforms are applied before the frame is over.
It's a bit resource intensive, as you can imagine.

You will need to issue a software animation request, before you use it. Otherwise you won't be able to access the data.

Look here:
http://ogreconglo.svn.sourceforge.net/s ... code/trunk

Look at trunk\src\OgreMeshCollisionShape.cpp
And the demo.

Re: Raycasting to the polygon level [solved]

Posted: Wed Aug 12, 2009 12:38 am
by Rumi
Thanks jacmoe!
I looked the code, and the solution was to insert this code in my geometry checking function:

Code: Select all

...
bool useSoftwareBlendingVertices = entity->hasSkeleton();

for ( unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
{
                Ogre::SubMesh* submesh = mesh->getSubMesh(i);

		//----------------------------------------------------------------
		// GET VERTEXDATA
		//----------------------------------------------------------------
		Ogre::VertexData* vertex_data;

                //THIS IS THE CODE THAT SOLVED THE ANIMATION PROBLEM:
		if(useSoftwareBlendingVertices)
#ifdef BUILD_AGAINST_AZATHOTH
			vertex_data = submesh->useSharedVertices ? entity->_getSharedBlendedVertexData() : entity->getSubEntity(i)->_getBlendedVertexData();
#else
			vertex_data = submesh->useSharedVertices ? entity->_getSkelAnimVertexData() : entity->getSubEntity(i)->_getSkelAnimVertexData();
#endif
		else
			vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;
               //THIS IS THE CODE THAT SOLVED THE ANIMATION PROBLEM
                
                ...
Now i can raycast and pick an entity when it's animated! :D
Thanks again!

Re: Raycasting to the polygon level [solved]

Posted: Wed Sep 09, 2009 1:24 am
by KungFooMasta
Rumi, thanks for sharing your solution. Can you share the function as a whole? Did you adapt the function in the wiki (http://www.ogre3d.org/wiki/index.php/Ra ... ygon_level) or have your own subroutines?

Re: Raycasting to the polygon level [solved]

Posted: Wed Sep 09, 2009 3:16 pm
by Rumi
Yes, i adapted that function. Here is the whole function:

Code: Select all

void GetMeshInformation(const Entity *entity,
                                size_t &vertex_count,
                                Ogre::Vector3* &vertices,
                                size_t &index_count,
                                unsigned long* &indices,
                                const Ogre::Vector3 &position,
                                const Ogre::Quaternion &orient,
                                const Ogre::Vector3 &scale)
{
    bool added_shared = false;
    size_t current_offset = 0;
    size_t shared_offset = 0;
    size_t next_offset = 0;
    size_t index_offset = 0;
    vertex_count = index_count = 0;

	Ogre::MeshPtr mesh = entity->getMesh();


	bool useSoftwareBlendingVertices = entity->hasSkeleton();
	/*
	if (useSoftwareBlendingVertices)
	{
		entity->_updateAnimation();
	}
	*/


    // Calculate how many vertices and indices we're going to need
    for (unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
    {
        Ogre::SubMesh* submesh = mesh->getSubMesh( i );

        // We only need to add the shared vertices once
        if(submesh->useSharedVertices)
        {
            if( !added_shared )
            {
                vertex_count += mesh->sharedVertexData->vertexCount;
                added_shared = true;
            }
        }
        else
        {
            vertex_count += submesh->vertexData->vertexCount;
        }

        // Add the indices
        index_count += submesh->indexData->indexCount;
    }


    // Allocate space for the vertices and indices
    vertices = new Ogre::Vector3[vertex_count];
    indices = new unsigned long[index_count];

    added_shared = false;

    // Run through the submeshes again, adding the data into the arrays
    for ( unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
    {
        Ogre::SubMesh* submesh = mesh->getSubMesh(i);

		//----------------------------------------------------------------
		// GET VERTEXDATA
		//----------------------------------------------------------------

        //Ogre::VertexData* vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;
		Ogre::VertexData* vertex_data;

		//When there is animation:
		if(useSoftwareBlendingVertices)
#ifdef BUILD_AGAINST_AZATHOTH
			vertex_data = submesh->useSharedVertices ? entity->_getSharedBlendedVertexData() : entity->getSubEntity(i)->_getBlendedVertexData();
#else
			vertex_data = submesh->useSharedVertices ? entity->_getSkelAnimVertexData() : entity->getSubEntity(i)->_getSkelAnimVertexData();
#endif
		else
			vertex_data = submesh->useSharedVertices ? 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);

            Ogre::HardwareVertexBufferSharedPtr vbuf =
                vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());

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

            // There is _no_ baseVertexPointerToElement() which takes an Ogre::Real or a double
            //  as second argument. So make it float, to avoid trouble when Ogre::Real will
            //  be comiled/typedefed as double:
            //      Ogre::Real* pReal;
            float* pReal;

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

                Ogre::Vector3 pt(pReal[0], pReal[1], pReal[2]);

                vertices[current_offset + j] = (orient * (pt * scale)) + position;
            }

            vbuf->unlock();
            next_offset += vertex_data->vertexCount;
        }


        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 = (submesh->useSharedVertices)? shared_offset : current_offset;

        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();
        current_offset = next_offset;
    }
} 



Re: Raycasting to the polygon level [solved]

Posted: Wed Sep 09, 2009 11:07 pm
by KungFooMasta
Awesome, thanks Rumi! :D Can I post your code on the wiki page?

On purpose?

Code: Select all

   /*
   if (useSoftwareBlendingVertices)
   {
      entity->_updateAnimation();
   }
   */

Re: Raycasting to the polygon level [solved]

Posted: Thu Sep 10, 2009 2:19 pm
by Rumi
Yes, you can post it. ;)

Ah... that commented lines was for performance issues in my app. But i forgot to uncomment them. In my app i always keep updated the animations, so i don't need to update them again, but i don't know if an animation is already updated then that line doesn't update it again? If so, then you can uncomment that line. ;)

Re: Raycasting to the polygon level [solved]

Posted: Wed Jan 27, 2010 10:24 am
by zakgof
Warning: Morge version fails for 32-bit indices.

Here ulong is used for indices:
ulong* pLong = (ulong*)ibuf.Lock(HardwareBuffer.LockOptions.HBL_READ_ONLY);

However ulong is 64bit and you'll get buffer overrun.
Replace ulong by uint and the code will work fine.