Jump to content

Adhere to surface normal on collision


Fenix Eldritch
 Share

You are about to reply to a thread that has been inactive for 3446 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

I'm working on small thrown object. The idea is that when the user "throws" it, the object will fake attach itself to the surface it collided with. In practice, it will shoot out a ray, grab the normal and then re-orient itself based on the surface normal and it's own rotation, and then re-position itself to be right up against the surface.

I've got it working well enough in controlled tests. The problem I have is during live tests. The object doesn't seem to stop itself fast enough in the collision_start event. It bounces off, or even clips through the impact surface before the ray can be cast, and thus it finds nothing to adhere to.

I've tried lowering the initial rez velocity to 5 m/s, and adding a larger child prim for a slightly bigger collision buffer. Even with this, it still messes up half the time.

 

collision_start(integer count)
{
    llSetStatus(STATUS_PHYSICS, FALSE);

    vector startUp = llGetPos();    //will reuse these two vectors for llAxes2Rot below
    vector endFwd = startUp - (<0.0,0.0,0.3>*llGetRot());
    
    list results = llCastRay(startUp, endFwd, [
        RC_DATA_FLAGS, RC_GET_NORMAL,
        RC_REJECT_TYPES, RC_REJECT_AGENTS|RC_REJECT_PHYSICAL,
        RC_MAX_HITS, 1] );
    
    if(llList2Integer(results, -1) == 0){llOwnerSay("no target!"); return;}
    
    llOwnerSay("hit object: "+ llKey2Name(llList2Key(results,0))); //debug object hit name
    
    //Given our rotation, and the vector normal of the face we hit, combine the two to make us perpendicular.
    startUp = llList2Vector(results,2);   //reuse the start vector for "UP"
    endFwd  = llRot2Fwd(llGetRot());      //reuse the end vector for "FWD
    llSetLinkPrimitiveParamsFast(LINK_THIS,[
        PRIM_ROTATION, llAxes2Rot(endFwd, startUp%endFwd, startUp),
        PRIM_POSITION, llList2Vector(results,1) + <0.0,0.0,0.016>*llGetRot()
    ]);
}

 

The very first thing I do is disable physics! How is that not fast enough? Any ideas on how to halt thig this the instant it collides? Trying to predict the impact surface by ray casting on_rez isn't an option because the thrown object is physical and is to be affected by gravity...

Link to comment
Share on other sites

When the moving object is an arrow  shot at an archery target, you have more leeway than you do when it's a ball. The arrow can bury itself partway in the target before it stops and still look right.  A ball can't do that. I think I'd be tempted to put a transparent collision surface in front of your actual one.  Make it thin enough that the ball is almost certain to go all the way through before it realizes that it has collided and place it far enough from the real target that you still have time to cast a ray  at the real target.

Link to comment
Share on other sites

Thanks for the suggestions, Rolig and Innula!

The actual object is a very small <0.14, 0.14, 0.03> cube. I tried increasing the depth of the child prim for the collision shape, but the results wern't much better than before. It did occur to me though, that I can probably scrap the child prim and instead  make the rayCast start further back (relative to the object) and go a tad deeper. This seems to improve the detection rate a little bit - if the object buries itself in the surface, there's a good chance the ray  will still start outside to compensate.

I think a lot of the remaining error is boiling down to the elasticity of the object. If I can make it less bouncy, I think it would help a great deal. I've spent a while this afternoon experimenting with the gravity/friction/density/restitution parameters. Not much info on the wiki, but a restitution of 0 seems like a good first step.

I did consider doing a series of raycasts while in flight, but was reluctant to go that route because I wanted to put as little stress on the server as possible. But then again, doing a short range cast on a reasonably paced timer and aborting the iteration if nothing is detected probably wouldn't be that big a load. And I suppose that would be the most accurate solution, detecting the surface and acting before the collision itself has a chance to alter the projectile and thus make its ray miss after the fact.

Raycasts are pretty lightweight, right?

Link to comment
Share on other sites

Yes, especially if you reject things you aren't looking for, restrict hits to 1 or 2, and keep the range relatively short.  So, the scheme could be something like

1. Launch object toward target

2. Hit and penetrate collision surface, trigger cast ray

3. Cast ray at target, get target vector and normal

4. Reach target, go non-physical, adjust rotation as necessary.

Link to comment
Share on other sites

So I've been having more success with the casting-while-in-flight approach. Still not perfect, but I'm getting there. I'd like to backtrack a little and ask another question: Looking at my code in the original post, does anyone see problems with the alignment process? I did originally say it's working "well enough" but I wonder if it could be better.

Even in controlled tests (using a touch_start to align instead of being in physical motion) I would find that the object isn't perfectly aligned with the target surface normal. Depending on the orientation of the projectile, it sometimes is very noticeably misaligned with the target surface. I am using default prim cubes at various rotations for my test targets, though I can often see this with non-rotated targets too.

The projectile is created such that at zero rotation, its top faces positive Z and its left faces negative X. When fired, it is rezed moving "bottom first" and the ray always shoots out the bottom for alignment purposes. I assumed that the normal of the target would effectively be perfect to use as the new UP vector and I could just use the current FWD to calculate the rest for llAxes2Rot. Is there something else I need to compensate for?

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 3446 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...