Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  Emit rope like silly string
#11
(12-02-2026, 02:15 PM)sacb0y Wrote: Okay so i've made some solid progress, but I have a new issue, I can't get consistent collision behavior from characters. It seems like sometimes the colliders don't update with animation at all?

What kind of colliders are you using?
Note that MeshColliders cannot deform at all, so they won't be updated with skeletal meshes.
Also note that primitive colliders like capsules, boxes, etc. have zero velocity when kinematically moved (eg. when parented to an animated transform) so CCD won't work with them.

(12-02-2026, 02:15 PM)sacb0y Wrote: And I'm not 100% sure but the "Animate Physics" setting on the animator seems to have an effect but I'm not sure how exactly. 

This is a must when dealing with physics. Animate Physics updates joint transforms during FixedUpdate(), which allows them to keep in sync with physics calculations (which typically take place in FixedUpdate, not Update). See Unity's manual for details.

kind regards,
Reply
#12
(12-02-2026, 05:22 PM)josemendez Wrote: What kind of colliders are you using?
Note that MeshColliders cannot deform at all, so they won't be updated with skeletal meshes.
Also note that primitive colliders like capsules, boxes, etc. have zero velocity when kinematically moved (eg. when parented to an animated transform) so CCD won't work with them.


This is a must when dealing with physics. Animate Physics updates joint transforms during FixedUpdate(), which allows them to keep in sync with physics calculations (which typically take place in FixedUpdate, not Update). See Unity's manual for details.

kind regards,
I'm using capsules and other primitives, but I have collisions happening as if the character is not animated with animate physics on.

I think i've narrowed down the issue a bit to being related to using playables? Animancer specifically.

It seems like when an animation is playing the colliders aren't where I expect them to be. I can use the physics debugger to see the colliders, and i corrected some behavior, but now I think i'm encountering something invisible that only ObiColliders are facing?
Reply
#13
See because i'm using playables (aka animancer) it seems like my colliders aren't updating normally. 

Unity 6 no longer has "automatically update transforms" as default.

   

So i have to use this function in late update to see updated colliders.

Code:
Physics.SyncTransforms();

but I think obi isn't reading this properly, the position of collisions is different, and even the physics behavior doesn't line up. 

I even see some odd behavior in unity where both the unanimated and animated collier position is factored somehow ?
Reply
#14
(14-02-2026, 03:50 PM)sacb0y Wrote: See because i'm using playables (aka animancer) it seems like my colliders aren't updating normally. 

Unity 6 no longer has "automatically update transforms" as default.



So i have to use this function in late update to see updated colliders.

Code:
Physics.SyncTransforms();

Hi,

What Physics.SyncTransforms() does is it immediately commits any changes done by to collider/rigidbody transforms by the main thread to Unity's physics engine (PhysX). Even if you don't call it manually, Unity does call it automatically right before each FixedUpdate() (see the manual):
https://docs.unity3d.com/6000.3/Document...forms.html

Quote:Unity already syncs transforms automatically before each physics step. * Do use it after Transform changes in Update()/LateUpdate() if you’re immediately performing a physics query. * Don’t overuse it — it’s expensive if called every frame unnecessarily.

So in case your animation system is updating animation before physics (which is the correct approach for anything physics related) then it's not necessary to call Physics.SyncTransforms manually in any case.

(14-02-2026, 03:50 PM)sacb0y Wrote: but I think obi isn't reading this properly, the position of collisions is different, and even the physics behavior doesn't line up. 

I even see some odd behavior in unity where both the unanimated and animated collier position is factored somehow ?

Obi doesn't "read" this at all, since it's a separate, standalone physics engine. Calling Physics.SyncTransforms() has no effect on Obi at all as it only affects Unity's own physics engine.

I've been unable to reproduce this issue using Unity's built-in animation system. I'd need to take a closer look to a project that exhibits this problem in order to help. Would it be possible for you to share your project (or any project that reproduces the same problem) by sending it to support(at)virtualmethodstudio.com so that I can diagnose it?

kind regards
Reply
#15
(16-02-2026, 09:21 AM)josemendez Wrote: Hi,

What Physics.SyncTransforms() does is it immediately commits any changes done by to collider/rigidbody transforms by the main thread to Unity's physics engine (PhysX). Even if you don't call it manually, Unity does call it automatically right before each FixedUpdate() (see the manual):
https://docs.unity3d.com/6000.3/Document...forms.html


So in case your animation system is updating animation before physics (which is the correct approach for anything physics related) then it's not necessary to call Physics.SyncTransforms manually in any case.


Obi doesn't "read" this at all, since it's a separate, standalone physics engine. Calling Physics.SyncTransforms() has no effect on Obi at all as it only affects Unity's own physics engine.

I've been unable to reproduce this issue using Unity's built-in animation system. I'd need to take a closer look to a project that exhibits this problem in order to help. Would it be possible for you to share your project (or any project that reproduces the same problem) by sending it to support(at)virtualmethodstudio.com so that I can diagnose it?

kind regards

From the physics behavior and the physics debugger it seems I do need the sync transforms to get the colliders to follow the character properly, but it seems to vary by config. 

Anyway, yes I'll try isolating this and giving a example project, the issue isn't what I thought from further experimenting. 

Whats giving me the wrong impression is the "attach" behavior I scripted, with certain animations (i believe when the character is heavily offset from the origin or turned around) the collision position is processed wrong.

If the particle sticks to the "Head" collider, the position is offset by a whole unit but it is still following the transform. This only happens during animation, the collision triggers at the right position, but the position it "sticks" to is wrong. This is why I thought the collision was offset. 


Code:
        private static void Global_OnCollision(ObiSolver solver, ObiNativeContactList contacts)
        {
            for (int s = 0; s < activeStrings.Count; s++)
            {
                var str = activeStrings[s];
                if (str.solver == solver)
                    str.Internal_OnCollision(solver, contacts);
            }
        }

        protected virtual void Internal_OnCollision(ObiSolver solverInstance, ObiNativeContactList contacts)
        {
            if (!stickToSurfaces) return;
            if (rope == null || !rope.isLoaded || rope.solverIndices == null || rope.activeParticleCount == 0) return;

            for (int i = 0; i < contacts.count; ++i)
            {
                Oni.Contact contact = contacts[i];
                if (contact.distance < 0.05f)
                {
                    // In Obi 7.1, bodyA is a simplex index. Resolve it to a particle index. (AI fix)
                    int simplexStart = solverInstance.m_SimplexCounts.GetSimplexStartAndSize(contact.bodyA, out int simplexSize);
                    if (simplexSize != 1) continue; // We only care about particle (point) collisions for sticking

                    int solverIndex = solverInstance.simplices[simplexStart];
                   
                    bool belongsToRope = false;
                    for (int j = 0; j < rope.activeParticleCount; ++j)
                    {
                        if (rope.solverIndices[j] == solverIndex)
                        {
                            belongsToRope = true;
                            break;
                        }
                    }

                    if (!belongsToRope) continue;

                    bool alreadyStuck = false;
                    for (int j = 0; j < stuckParticles.Count; ++j)
                    {
                        if (stuckParticles[j].solverIndex == solverIndex)
                        {
                            alreadyStuck = true;
                            break;
                        }
                    }
                    if (alreadyStuck) continue;

                    var colliderHandles = ObiColliderWorld.GetInstance().colliderHandles;
                    if (contact.bodyB >= 0 && contact.bodyB < colliderHandles.Count)
                    {
                        var colHandle = colliderHandles[contact.bodyB];
                        if (colHandle != null && colHandle.owner != null)
                        {
                            Vector3 worldContactPoint = solverInstance.transform.TransformPoint(contact.pointB);
                            Vector3 worldNormal = solverInstance.transform.TransformDirection(contact.normal);

                            AttachToTransform(solverIndex, colHandle.owner.transform, worldContactPoint, worldNormal);
                        }
                    }
                }
            }
        }

        protected virtual void AttachToTransform(int solverIndex, Transform target, Vector3 worldContactPoint, Vector3 worldNormal)
        {
            StuckParticle sp = new StuckParticle();
            sp.solverIndex = solverIndex;
            sp.target = target;
            sp.isVertexStuck = false;
           
            sp.localPoint = target.InverseTransformPoint(worldContactPoint);
            sp.localNormal = target.InverseTransformDirection(worldNormal).normalized;

            FinalizeAttachment(sp);
        }

        protected virtual void FinalizeAttachment(StuckParticle sp)
        {
            sp.shouldSpawnDecal = Random.value < decalSpawnChance;
            stuckParticles.Add(sp);
           
            solver.invMasses[sp.solverIndex] = 0;
            if (solver.invRotationalMasses != null && sp.solverIndex < solver.invRotationalMasses.count)
                solver.invRotationalMasses[sp.solverIndex] = 0;

#if UNITY_EDITOR
            if (showDebugLogs)
            {
                string type = sp.isVertexStuck ? "SkinnedMesh" : "Transform";
                Debug.Log($"[DEBUG_LOG] [{GetType().Name}] Stuck to {type}: {sp.target.name}. SolverIdx: {sp.solverIndex}. LocalNormal: {sp.localNormal}");
            }
#endif
        }
Reply
#16
Here's an example of what I'm seeing, the collision point is at the top, but the point I'm attaching the particle is at the bottom somehow. 

And despite this offset it is still moving based on the animation. 

   

So i'm just doing something wrong here...
Reply
#17
(16-02-2026, 09:15 PM)sacb0y Wrote: Here's an example of what I'm seeing, the collision point is at the top, but the point I'm attaching the particle is at the bottom somehow. 

And despite this offset it is still moving based on the animation. 



So i'm just doing something wrong here...

How are you setting the position of attached particles? your code shows how you detect collisions and how you create instances of StuckParticle, but not how you actually position particles during animation.

kind regards,
Reply
#18
(17-02-2026, 08:51 AM)josemendez Wrote: How are you setting the position of attached particles? your code shows how you detect collisions and how you create instances of StuckParticle, but not how you actually position particles during animation.

kind regards,

This is the portion:

Code:
        protected virtual Vector3 GetTransformWorldPoint(StuckParticle sp)
        {
            return sp.target.TransformPoint(sp.localPoint) + sp.target.TransformDirection(sp.localNormal).normalized * surfaceOffset;
        }

sp.localPoint and sp.localNormal are correct contact points of the particle, but the TransformPoint when the root bone is rotated 180 degrees is wrong. It's heavily offset.

It then applies per frame here.

Code:
            for (int i = 0; i < stuckParticles.Count; ++i)
            {
                var sp = stuckParticles[i];
                if (sp.target == null) continue;

                // Only skip CPU update for vertex-stuck particles if we're in GPU mode
                if (useGPUPath && sp.isVertexStuck) continue;

                Vector3 worldPoint = sp.isVertexStuck ? GetSkinnedMeshWorldPoint(sp) : GetTransformWorldPoint(sp);
                Vector3 solverPoint = solver.transform.InverseTransformPoint(worldPoint);

               
                solver.positions[sp.solverIndex] = solverPoint;
                solver.prevPositions[sp.solverIndex] = solverPoint;
               
                if (solver.velocities != null && sp.solverIndex < solver.velocities.count)
                    solver.velocities[sp.solverIndex] = Vector3.zero;
               
                if (updateRenderablePositions && solver.renderablePositions != null && sp.solverIndex < solver.renderablePositions.count)
                    solver.renderablePositions[sp.solverIndex] = solverPoint;
               
                solver.invMasses[sp.solverIndex] = 0;
                if (solver.invRotationalMasses != null && sp.solverIndex < solver.invRotationalMasses.count)
                    solver.invRotationalMasses[sp.solverIndex] = 0;
            }

I've concluded unity does something weird with euler transforms when a bone with euler rotations is spun around 180 degrees. This causes some kind of transform offset when it should be accurate. 

Undo the rotation and it works perfectly, attach the particle THEN rotate the root bone and it's fine. But attempt to attach the point post rotation it just gets wacky.

Don't rotate, perfectly acurate positions.
   

rotate root bone by animation 180 degrees, the resolved positions are all over the place, but the collision (represented in orange circles here) is fine. 
   
Reply
#19
(18-02-2026, 04:15 PM)sacb0y Wrote: I've concluded unity does something weird with euler transforms when a bone with euler rotations is spun around 180 degrees. This causes some kind of transform offset when it should be accurate. 

Undo the rotation and it works perfectly, attach the particle THEN rotate the root bone and it's fine. But attempt to attach the point post rotation it just gets wacky.

Don't rotate, perfectly acurate positions.

rotate root bone by animation 180 degrees, the resolved positions are all over the place, but the collision (represented in orange circles here) is fine. 

Hi,

Your code looks fine to me, I can't think of anything off the top of my head that would cause incorrect behavior when root bone is rotated. After all, rotation in a transform hierarchy is inherited by children so the code should be the same regardless of rotation values.

If you'd like me to debug the project, you can send it to support(at)virtualmethodstudio.com for me to take a look.

kind regards,
Reply