Sunday, May 29, 2011

PhysX3: Picking

In this tutorial, we will use the scene of multiple boxes from a previous tutorial. This tutorial assumes that you have successfully understood the basics of how to create an actor using the scene object. If not, u may want to review the previous tutorials as a refresher. Ok so now lets get started. There are a lot of things similar between this and the previous tutorial.

Picking in PhysX3
We have our matrices setup as in the picking tutorial for the previous PhysX version. We now come on the Pick function. This function takes an x, y screen coordinate, cast a ray into the scene and returns true if there is an intersection. It also stores a sphere object at the hit point, stores reference to the intersected actor and also stores a spring between the hitpoint sphere and the actor. We store the used joint and mouse sphere object pointers globally.
PxDistanceJoint *gMouseJoint = NULL;
PxRigidDynamic* gMouseSphere = NULL;
PxReal gMouseDepth = 0.0f;
PxRigidDynamic* gSelectedActor=NULL;


The pick actor function is defined as follows,

bool PickActor(int x, int y)
{
 LetGoActor();

We first release all previous helpers (the spring and the last intersection sphere.

Ray ray;
ViewUnProject(x,y,0.0f, ray.orig);
ViewUnProject(x,y,1.0f, ray.dir);
ray.dir -= ray.orig; ray.dir.normalize();

The above lines create a ray as given in the previous paragraph. In PhysX3 there is no Ray object so we define our own struct for Ray.

PxRaycastHit hit;
PxShape* closestShape;
gScene->raycastSingle(ray.orig, ray.dir, length, PxSceneQueryFlag::eIMPACT  ,hit);
closestShape = hit.shape;
if (!closestShape) return false;
if (!closestShape->getActor().is(PxActorType::eRIGID_DYNAMIC)) return false;

The above lines are where the ray is cast to find the closest actor. If there is none, we return false.

int hitx, hity;
ViewProject(hit.impact, hitx, hity, gMouseDepth);
gMouseSphere = CreateSphere(hit.impact, 0.1f, 1.0f);
gMouseSphere->setRigidDynamicFlag(PxRigidDynamicFlag::eKINEMATIC, true);  

The above lines project the hit point back to get the world space position. This is done so that the picking cursor (sphere) could be drawn at the intersection point.
The sphere's body flag is raised to kinematic since it will be attached to an actor through a distance joint (see next few lines).

gSelectedActor = (PxRigidDynamic*) &closestShape->getActor();
gSelectedActor->wakeUp();
PxTransform mFrame, sFrame;
mFrame.q = gMouseSphere->getGlobalPose().q;
mFrame.p = gMouseSphere->getGlobalPose().transformInv(hit.impact );
sFrame.q = gSelectedActor->getGlobalPose().q;
sFrame.p = gSelectedActor->getGlobalPose().transformInv(hit.impact );
gMouseJoint = PxDistanceJointCreate(*gPhysicsSDK, gMouseSphere, mFrame, gSelectedActor, sFrame);
gMouseJoint->setDamping(1);
gMouseJoint->setSpring(200);
gMouseJoint->setMinDistance(0);
gMouseJoint->setMaxDistance(0);
gMouseJoint->setDistanceJointFlag(PxDistanceJointFlag::eMAX_DISTANCE_ENABLED, true);
gMouseJoint->setDistanceJointFlag(PxDistanceJointFlag::eSPRING_ENABLED, true);
return true;
}

These lines create a distance joint between the mouse sphere and the picked object; having one end point, our sphere cursor and the other end point our intersected actor.
The object's global pose is used to transform the hit point from world space to object's local space so that the joint could be oriented properly.
Finally, the joint parameters are filled in and a joint is created. Note that on every mouse click, the old cursor (sphere) and joint are released and a new pair is created. The LetGoActorfunction is defined as follows,
void LetGoActor()
{
if (gMouseJoint)
  gMouseJoint->release();
  gMouseJoint = NULL;
if (gMouseSphere)
  gMouseSphere->release();
  gMouseSphere = NULL;
}

Nothing fancy here either. We just release the created objects (the sphere cursor and the joint).

That's it. You need to call the pick function in the mouse function and handle the drag event. Enjoy this snapshot from the demo.

Picking in PhysX3.1

Source code of this tutorial

2 comments:

antonio said...

hi...
I have a question about a collision...
I want to understand the point at which two objects are in contact ...
I used this filter ...


PxFilterFlags filter( PxFilterObjectAttributes attributes0, PxFilterData filterData0, PxFilterObjectAttributes attributes1, PxFilterData filterData1, PxPairFlags& pairFlags, const void* constantBlock,
PxU32 constantBlockSize)
{

globalPose1=actorEndFactor->getGlobalPose();
pairFlags |= PxPairFlag::eCONTACT_DEFAULT;
cout<<"touch"<<endl;
return PxFilterFlags();
}


that I called so, to create the scene:

sceneDesc.filterShader=filter;

well.. I have a little problem..
if I have two actors like a spheres the volume of the contact it is different..
is as if around the sphere exit a box...
I think that the volume of collision, for a sphere is a box...
how I can change this??

thanks

Unknown said...

i have error this code.
PxDefaultCpuDispatcher* mCpuDispatcher = PxDefaultCpuDispatcherCreate(1);

i run program but take access vialotion error.how can i solve this problem...

Popular Posts

Copyright (C) 2011 - Movania Muhammad Mobeen. Awesome Inc. theme. Powered by Blogger.