Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
I've made a bounce script, but don't know how to optimize
#1
Pregunta 
Hi, the idea is simple, to improve the game feel when character make contact with the softbody.
I would like to have softbody handle OnContact by iterate the contacts and add the incoming contact impulse with a mult value,
so that we can have a squashed feel when character step on a slime.
When it works, it is very cool to look at Gran sonrisa !

But eventually it can be very easy to spiral into a dead performance degradation, since each time you got contact, you have to iterate the contacts, and then iterate the particles to detect which particle is near to add the bounce force.

For example: 10 contact, 1000 particles, that is 10000 iterations each time we got contact. Wow!
How can I optimize this?

Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Obi;
using Unity.Mathematics;

namespace SPIKE.kIntegration
{
    //when got some contact, be squashed by that contact in normal direction
    [RequireComponent(typeof(ObiActor))]
    public class ObiBouncer : MonoBehaviour
    {
        [SerializeField] ObiSolver _solver;
        [SerializeField] float _propagate = 0.5f, _bounceForceMult = 10,_clampBounceForce=10;
        [SerializeField] bool _debug;

        ObiActor actor;

        void Awake()
        {
            actor = GetComponent<ObiActor>();
        }

        void OnEnable()
        {
            _solver.OnCollision += Solver_OnCollision;
        }

        void OnDisable()
        {
            _solver.OnCollision -= Solver_OnCollision;
        }

        void Solver_OnCollision(object sender, ObiSolver.ObiCollisionEventArgs e)
        {
            var world = ObiColliderWorld.GetInstance();

            // just iterate over all contacts in the current frame:
            foreach (Oni.Contact contact in e.contacts)
            {
                // if this one is an actual collision:
                if (contact.distance < 0.01)
                {
                    Vector3 contactOnCollider = contact.pointB;
                    contactOnCollider = _solver.transform.TransformPoint(contactOnCollider);
                    Vector3 contactNm = contact.normal;

#if UNITY_EDITOR
                    if (_debug)
                    {
                        Debug.DrawLine(contactOnCollider, contactOnCollider + contactNm, Color.yellow, 2f);
                    }
#endif
                    //iterate the particles
                    for (int i = 0; i < actor.solverIndices.Length; ++i)
                    {
                        int solverIndex = actor.solverIndices[i];
                        //add bounce force based on the propagate distance
                        if (Vector3.Distance(actor.GetParticlePosition(solverIndex), contactOnCollider)
                            < _propagate)
                        {
                            var squashForce = contact.normal * math.min( contact.normalImpulse * _bounceForceMult,_clampBounceForce);
                            actor.solver.velocities[solverIndex] += squashForce;
                        }
                    }                   
                }
            }
        }
    }
}
Reply
#2
Hi!

Not sure why you need to iterate trough all particles for every contact, just to find which particle is closest to the contact? Contacts already give you the index of the particle involved in the contact, you can use that. See:
http://obi.virtualmethodstudio.com/manua...sions.html

Code:
// get the particle index directly, as all simplices are guaranteed to have size 1:
int particleIndex = solver.simplices[contact.bodyA];

// do something with the particle, for instance get its position:
var position = solver.positions[particleIndex];
Reply
#3
Wow thank you for the prompt reply!

Ah, I have to iterate because I need to add the propagate force to nearby particles, not just the particle involved in the contact.
But given it's very heavy I can consider skipping that propagate effect for now.

Quote:
(01-05-2024, 01:17 PM)josemendez Wrote: Hi!

Not sure why you need to iterate trough all particles for every contact, just to find which particle is closest to the contact? Contacts already give you the index of the particle involved in the contact, you can use that. See:
http://obi.virtualmethodstudio.com/manua...sions.html

Code:
// get the particle index directly, as all simplices are guaranteed to have size 1:
int particleIndex = solver.simplices[contact.bodyA];

// do something with the particle, for instance get its position:
var position = solver.positions[particleIndex];
Reply
#4
Update! 
I reduced the complexity by calling actor.AddForce the negative force that I would add to character (trampoline force).
This iteration no need to query anything.

Code:
        private void FixedUpdate()
        {
            if (bounceForce != default) {
                actor.AddForce(bounceForce, ForceMode.Impulse);
                if (_debug) Debug.Log($"{name} add {bounceForce.ColorMe(kColor.orange)} force to {actor.GetType().Name}!");
                bounceForce = default;
            }
        }


Reply