Terrain Collisions?

Is there a way to collide CollisionRays to Mesh Polygons? I need to extract the normal and collisionPoint out of the mesh triangle to be used in terrain following. Just want to know if the engine supports it already, or should I plan on extending the source to handle it?

I have been knocking my brain on this problem for weeks. Any help would be greatly appreciated.

Thanks in advance,

Ryan
RimLine - Studio 44

Not sure exactly what you mean by “Mesh Polygons”, but CollisionRays do make intersections tests with polygons and the intersection returns an intersection point and a surface normal.

Lemme start over. :astonished:

 We are loading terrain and I need to get a collision sphere around the player to clamp to the ground while moving.  We are using Maya to create the terrain, and making a low rez copy of it for collision data.  

My Questions are:

  1. How would I setup a Collision Sphere and Ray to only collide with the terrains collision geometry, if possible within a given radius. Just to cut down on collision checks.

  2. Is there a way to get the subset of polygons within a given area at runtime? Used for time based orientation of physical bodies.

Thanks again,

Ryan
Dedicated and Driven

RimLine - Studio 44

Use the collide mask to restrict the set of geometry that a particular CollisionSphere or CollisionRay with test for collisions. Specifically, declare a bit that corresponds to your terrain, and ensure that bit is set on the “into” collide mask of your terrain, and not on any other collision data. Also ensure that the bit is the only bit in the “from” collide mask of the CollisionSphere and CollisionRay that will be testing this terrain.

You can automatically set the “into” collide mask with an egg-object-type declaration something like this:

egg-object-type-terrain collide-mask { 0x04 } { Polyset descend }

Then flag the terrain with the “terrain” egg object type in Maya.

For clamping an object to the ground, you may find the CollisionHandlerFloor object useful (if you’re not using this already). This requires just a CollisionRay, not a CollisionSphere.

There is no automatic way in Panda to get a subset of polygons within a given volume. The inverse question can be answered: you can easily ask for a bounding volume for a particular subset of polygons. To implement the former, you will need to create your own data structures, or traverse the scene graph testing bounding volumes, in a mechanism similar to Panda’s collision traversal.

David

Thanks David, I will try what you suggested. I appreciate the quick response. Keep up the good work.

Ryan

One more quick question. Is there a special way I should add the flag to the object in maya; should I just add an attribute called terrain?

Also, should I export differently than this “maya2egg testCollision.mb -p -ptol 0.01 testCollision.egg” to extract the flags out of it?

Hehe, I guess that makes 2 questions.

The maya2egg program looks for an attribute called “eggObjectTypes” (or “eggObjectTypes1”, “eggObjectTypes2”, etc.) on a Maya node, which should be a string value. If such an attribute is found, it writes an entry to the egg file for that node.

We use a mel script similar to the attached to add the eggObjectTypes attributes to nodes as desired. Feel free to take the script and modify it to suit your needs (e.g. by removing unneeded object types and adding your own).

This should be made part of the Panda distribution. I’ll see about putting it in the pandatool/src/maya directory.

David

global proc vrsEggObjectFlags()
{       
string $sel[] =`ls -sl`;
for ($i in $sel)
  {
  string $attrName = "eggObjectTypes";
  
  string $object = ($i + ".eggObjectTypes");
  
    if( `objExists ($object + "1")` ) 
    {
    
      if( `objExists ($object + "2")` ) 
      {
      
        if( `objExists ($object + "3")` ) 
        {
        warning("No More Egg Object Types Supported");
        } 
         else 
        {
        addAttr -ln ($attrName + "3") -k 1 -at "enum" -en "none:model:dcs:barrier:cambarrier:camcollide:shground:bbpoint:trigger:floor:sphere:backstage:decal:decalbase:shadow:billboard:double-sided:tube:ouch1:ouch2:ouch3:ouch4:ouch5:portal:pets:polylight:shipcollide:shipbarrier:indexed:seq12:seq24:lod"  $i;
        }
      
      } 
       else 
      {
      addAttr -ln ($attrName + "2") -k 1 -at "enum" -en "none:model:dcs:barrier:cambarrier:camcollide:shground:bbpoint:trigger:floor:sphere:backstage:decal:decalbase:shadow:billboard:double-sided:tube:ouch1:ouch2:ouch3:ouch4:ouch5:portal:pets:polylight:shipcollide:shipbarrier:indexed:seq12:seq24:lod"  $i;
      }
    } 
     else 
    {
    addAttr -ln ($attrName + "1")  -k 1 -at "enum" -en "none:model:dcs:barrier:cambarrier:camcollide:shground:bbpoint:trigger:floor:sphere:backstage:decal:decalbase:shadow:billboard:double-sided:tube:ouch1:ouch2:ouch3:ouch4:ouch5:portal:pets:polylight:shipcollide:shipbarrier:indexed:seq12:seq24:lod"  $i;
    }
 
  
  }
}

Thanks for clearing that up. The help is very much appreciated, and thanks for the script.

Ryan

RimLine - Studio 44

Sorry David,
One more question and this thread is done.

Is there documentation on all of the egg-object-types that are already implemented in the engine besides looking in all the source files?

If not, then I will try to find all of em and post it. :slight_smile:

Ryan

Hi Ryan,

Yes: the built-in egg object types are listed beginning at around line 1200 of panda/src/doc/eggSyntax.txt.

There are a few more that are not built-in, but are implemented in panda/src/configfiles/20_panda.prc (which is generated from panda.prc.pp). This file is a relatively recent addition to the source codebase, and may not exist in the 2004-04-27 version.

David

I got it all working. One last question since we are on the subject. How would I get the current polygon that a Collision Ray is colliding with, and its normal. Currently I am making the collision ray like so… for testing purposes.

Any Suggestions?

MyEvent=CollisionHandlerFloor()
MyEvent.setReach(100)
MyEvent.setOffset(15.0)

aNode = CollisionNode("TheRay")
ray = CollisionRay()
ray.setOrigin( camera.getPos() )
ray.setDirection( Vec3(0, 0, -1) ) 

aNode.addSolid(ray)
aNodePath = MyModel.attachNewNode( aNode )

base.cTrav.addCollider( aNodePath.node() , MyEvent )
MyEvent.addCollider( aNodepath, camera, base.drive.node() )

Collision = ( aNode, "TheRay" )
Collision[0].setFromCollideMask( BitMask32.bit( 1 ) )

All of the detailed collision information–polygon, intersection point, surface normal, etc.–is stored in the CollisionEntry object that is generated for the collision. In order to query this data, you will need to get a pointer to this CollisionEntry.

The problem is that a CollisionHandlerFloor doesn’t save the CollisionEntries it is given; it just examines them all to find the highest intersection point, and sets its controlling object to that height. Then it throws them away.

There are therefore several choices:

(1) Assign an in_pattern and again_pattern event string to the CollisionHandlerFloor, and listen for this event. Since CollisionHandlerFloor inherits from CollisionHandlerEvent, you can assign event strings for the various kinds of collision events. If you assign an in_pattern event string, that event will be generated each time a new collision is detected, and an again_pattern event is generated each time the same collision is detected on subsequent frames (they can be the same string if you don’t care to differentiate). You can then have a Python function that is listening for this event. The Python function will receive the CollisionEntry associated with that event as a parameter.

Downside: there may be a frame of latency associated with the event; in general, events thrown in C++ (like collision events) are not processed immediately by Python. Also, you will get multiple CollisionEntries if your object is over multiple layers of floors; it is up to you to figure out which one is the highest.

(2) Replace CollisionHandlerFloor with CollisionHandlerQueue. This is a special handler that does nothing but save up the list of CollisionEntries each frame. Then write a Python task that checks this list each frame and duplicates the logic of CollisionHandlerFloor, but also saves the surface normal where you can get to it. The CollisionHandlerQueue.sortEntries() method will be especially helpful here.

Downside: not much. You have to duplicate some existing C++ logic in Python.

(3) Extend the C++ code of CollisionHandlerFloor to save its topmost CollisionEntry for purposes such as this. Provide a new method to retrieve this object.

Downside: requires modifying C++. May be more involved than you care to get.

David

After that said, I think I will be modifying the c++ code because it might speed up the app due to not having to query the queue every frame in Python to retrieve the top-most collison. Doesnt seem much more work in C++ for me. I am more comfortable in C++ anyways. :slight_smile: Plus Wigs already got the source compiling.

Thanks for all the great work man. You really know your Panda :slight_smile:

Well back to work for me. Have a great Turkey Day

Ryan