Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  Efficiently determine actor under ray
#1
Hi,

I'd appreciate some quick advice re: whether there's a more performant way to accomplish what I'm trying to do OOTB. For a first-person "grabbing" system I need to get the particle and related Actor (specifically softbody, but right now code works w/ all actors) closest to an origin point with a given ray.

My current code (adapted crudely from the particle picker example scripts) works, but as it's iterating through A) all particle positions and then B) an undetermined number of softbodies and each of their particles again to relate the particle to an Actor, it's quite inefficient, as I may need many softbodies as well as non-softbody particles in my scenes.

If there are cached bounds/extents per Obi actor I could cluster them into volumes, cast the ray through volumes, and then only iterate over each of their particles, but if those structures exist in ObiActor I can't seem to locate them.

Appreciate any help, thanks!

Code:
    public ObiActor GetActor(ObiSolver solver, int particleIndex){
        foreach (ObiActor actor in solver.actors){
            for (int i = 0; i < actor.solverIndices.count; i++){
                if (actor.solverIndices[i] == particleIndex){
                    return actor;
                }
            }
        }
        return null;
    }

    public int Raycast(ObiSolver solver, Ray ray, float radiusScale, float maxDistance, Vector3 origin){
        if (solver == null) return 1;

        int hitParticle = -1;
        float closestMu = float.MaxValue;
        float closestDistance = float.MaxValue;
        Matrix4x4 solver2World = solver.transform.localToWorldMatrix;

        // Find the closest particle hit by the ray
        for (int i = 0; i < solver.positions.count; ++i){

            Vector3 worldPos = solver2World.MultiplyPoint3x4(solver.positions[i]);

            if (Vector3.Distance(worldPos, origin) > maxDistance) continue;

            float mu;
            Vector3 projected = ObiUtils.ProjectPointLine(ray.origin, ray.origin + ray.direction, worldPos, out mu, false);
            float distanceToRay = Vector3.SqrMagnitude(worldPos - projected);

            // Disregard particles behind the camera:
            mu = Mathf.Max(0, mu);

            float radius = solver.principalRadii[i][0] * radiusScale;
            if (distanceToRay <= radius * radius && distanceToRay < closestDistance && mu < closestMu){
                closestMu = mu;
                closestDistance = distanceToRay;
                hitParticle = i;
            }
        }

        return hitParticle;
Reply
#2
Hi!

There's built-in raycast queries (as well as box and sphere overlap queries) that run in parallel across all particles using specialized spatial subdivision structures. See spatial queries in the manual. Also see the SoftbodyRaycast sample scene for an example use case:

[Image: KcYlGg0.png]

Additionally, you also have contact callbacks, which work with both regular colliders and triggers. None of these require to iterate trough all actors & particles.

Also note that anytime you have the index of a particle (be it returned by spatial quieries, contacts, or manually obtained any other way), you can get a direct reference to the actor it belongs to using the solver.particleToActor array. See "retrieving the actor involved in a contact": http://obi.virtualmethodstudio.com/manua...sions.html
Reply
#3
(13-06-2024, 07:52 AM)josemendez Wrote: Hi!

There's built-in raycast queries (as well as box and sphere overlap queries) that run in parallel across all particles using specialized spatial subdivision structures. See spatial queries in the manual. Also see the SoftbodyRaycast sample scene for an example use case:

[Image: KcYlGg0.png]

Additionally, you also have contact callbacks, which work with both regular colliders and triggers. None of these require to iterate trough all actors & particles.

Also note that anytime you have the index of a particle (be it returned by spatial quieries, contacts, or manually obtained any other way), you can get a direct reference to the actor it belongs to using the solver.particleToActor array. See "retrieving the actor involved in a contact": http://obi.virtualmethodstudio.com/manua...sions.html


Thank you, that's extremely helpful and gives me exactly what I needed. I hadn't realized what simplices were and somehow missed that raycast example. Cheers!
Reply