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


Messages In This Thread
Efficiently determine actor under ray - by 4ringz - 12-06-2024, 11:47 PM