12-06-2024, 11:47 PM
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!
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;