Search Forums

(Advanced Search)

Latest Threads
Stretching verts uniforml...
Forum: Obi Softbody
Last Post: Aroosh
Yesterday, 05:32 AM
» Replies: 0
» Views: 71
Scripting rod forces
Forum: Obi Rope
Last Post: chenji
11-09-2025, 01:15 PM
» Replies: 25
» Views: 2,777
Burst error causing crash...
Forum: Obi Rope
Last Post: josemendez
10-09-2025, 07:03 AM
» Replies: 1
» Views: 190
Controlling speed of emit...
Forum: Obi Fluid
Last Post: josemendez
06-09-2025, 06:29 AM
» Replies: 1
» Views: 440
Looks nice on editor but ...
Forum: Obi Fluid
Last Post: josemendez
04-09-2025, 07:20 AM
» Replies: 3
» Views: 693
How to Shorten or Scale t...
Forum: Obi Rope
Last Post: josemendez
02-09-2025, 09:53 AM
» Replies: 5
» Views: 781
The Limitation of Using O...
Forum: Obi Rope
Last Post: josemendez
01-09-2025, 10:30 PM
» Replies: 1
» Views: 519
Bug Where a Straight Segm...
Forum: Obi Rope
Last Post: josemendez
01-09-2025, 08:46 PM
» Replies: 1
» Views: 492
Having an issue with obi ...
Forum: Obi Rope
Last Post: Ben_bionic
29-08-2025, 04:23 PM
» Replies: 4
» Views: 990
Non-uniform particle dist...
Forum: Obi Rope
Last Post: chenji
29-08-2025, 09:05 AM
» Replies: 4
» Views: 836

 
  ObiSkinnedCloth.SetTargetSkin Jobification
Posted by: ThoughtMango - 04-06-2021, 03:19 PM - Forum: Obi Cloth - Replies (3)

posting this here so it can be verified and hopefully merged into the project (unless supersed already by better code):
Modifications in ObiSkinnedCloth.cs:

Code:
//Top of file:
using Unity.Jobs;
using Unity.Collections;
using Unity.Burst;
using Unity.Mathematics;

...

//replaces existing sortedPoints/Normals
private NativeArray<Vector4> sortedPoints;
private NativeArray<Vector4> sortedNormals;
private NativeArray<int> actorIndices;

...

//Changing LoadBlueprint to init native arrays
public override void LoadBlueprint(ObiSolver solver)
{
    base.LoadBlueprint(solver);
    SetupRuntimeConstraints();

    var skinConstraints = GetConstraintsByType(Oni.ConstraintType.Skin) as ObiConstraints<ObiSkinConstraintsBatch>;
    if (skinConstraints != null && skinConstraints.GetBatchCount() > 0)
    {
        var batch = skinConstraints.batches[0] as ObiSkinConstraintsBatch;
        if(sortedPoints.IsCreated)
        {
            sortedPoints.Dispose();
        }
        sortedPoints = new NativeArray<Vector4>(batch.constraintCount, Allocator.Persistent);

        if(sortedNormals.IsCreated)
        {
            sortedNormals.Dispose();
        }
        sortedNormals = new NativeArray<Vector4>(batch.constraintCount, Allocator.Persistent);

        if(actorIndices.IsCreated)
        {
            actorIndices.Dispose();
        }
        actorIndices = new NativeArray<int>(batch.constraintCount, Allocator.Persistent);
    }
}

...

//Adding on destroy to cleanup native arrays
private void OnDestroy()
{
    if(sortedPoints.IsCreated)
    {
        sortedPoints.Dispose();
    }

    if(sortedNormals.IsCreated)
    {
        sortedNormals.Dispose();
    }

    if(actorIndices.IsCreated)
    {
        actorIndices.Dispose();
    }
}


private void SetTargetSkin()
{
    using (m_SetTargetSkinPerfMarker.Auto())
    {

        var skinConstraints = GetConstraintsByType(Oni.ConstraintType.Skin) as ObiConstraints<ObiSkinConstraintsBatch>;
        var batch = skinConstraints.batches[0] as ObiSkinConstraintsBatch;

        using (m_SortSkinInputsPerfMarker.Auto())
        {
            int pointCount = bakedVertices.Count;
            for (int i = 0; i < pointCount; ++i)
            {
                int welded = m_SkinnedClothBlueprint.topology.rawToWelded[i];
                sortedPoints[welded] = bakedVertices[i];
                sortedNormals[welded] = bakedNormals[i];
            }
        }

        using (m_SetSkinInputsPerfMarker.Auto())
        {
            for(int i = 0; i < batch.activeConstraintCount; ++i)
            {
                int solverIndex = batch.particleIndices[i];
                actorIndices[i] = solver.particleToActor[solverIndex].indexInActor;
            }

            setSkinInputsJob.approxValue = Mathf.Epsilon * 8f;
            setSkinInputsJob.skinToSolver = actorLocalToSolverMatrix;

            setSkinInputsJob.sortedPoints = sortedPoints;
            setSkinInputsJob.sortedNormals = sortedNormals;

            setSkinInputsJob.particleIndices = batch.particleIndices.AsNativeArray<int>();
            setSkinInputsJob.actorIndices = actorIndices;

            setSkinInputsJob.skinCompliance = batch.skinCompliance.AsNativeArray<float>();
            setSkinInputsJob.skinRadiiBackstop = batch.skinRadiiBackstop.AsNativeArray<float>();

            setSkinInputsJob.skinPoints = batch.skinPoints.AsNativeArray<Vector4>();
            setSkinInputsJob.skinNormals = batch.skinNormals.AsNativeArray<Vector4>();

            setSkinInputsJob.invMasses = solver.invMasses.AsNativeArray<float>();
            setSkinInputsJob.positions = solver.positions.AsNativeArray<Vector4>();

            setSkinInputsJob.Run();
        }
    }
}

SetSkinInputsJob setSkinInputsJob = new SetSkinInputsJob();

[BurstCompile(FloatMode = FloatMode.Deterministic)]
struct SetSkinInputsJob : IJob
{
    public float approxValue;
    public Matrix4x4 skinToSolver;

    [ReadOnly]
    public NativeArray<Vector4> sortedPoints;
    [ReadOnly]
    public NativeArray<Vector4> sortedNormals;

    [ReadOnly]
    public NativeArray<int> particleIndices;
    [ReadOnly]
    public NativeArray<int> actorIndices;

    [ReadOnly]
    public NativeArray<float> skinRadiiBackstop;
    [ReadOnly]
    public NativeArray<float> skinCompliance;

    //[WriteOnly]
    public NativeArray<Vector4> skinPoints;
    [WriteOnly]
    public NativeArray<Vector4> skinNormals;

    [WriteOnly]
    public NativeArray<float> invMasses;
    [WriteOnly]
    public NativeArray<Vector4> positions;

    public void Execute()
    {
        for(int i = 0; i < particleIndices.Length; ++i)
        {
            int solverIndex = particleIndices[i];
            int actorIndex = actorIndices[i];

            skinPoints[i] = skinToSolver.MultiplyPoint3x4(sortedPoints[actorIndex]);
            skinNormals[i] = skinToSolver.MultiplyVector(sortedNormals[actorIndex]);

            // Rigidly transform particles with zero skin radius and zero compliance:                   
            if(math.abs(skinRadiiBackstop[i * 3]) <= approxValue && math.abs(skinCompliance[i]) <= approxValue)
            {
                invMasses[solverIndex] = 0;
                positions[solverIndex] = skinPoints[i];
            }
        }
    }
}
I assume there's some potential optimisation by switching to float4x4s and float4s across the board, but I've had no luck implementing that, and the job is already very fast
You could also reduce some of the job data assignment calls probs.

For me it reduced the task from ~0.03-0.04ms per SkinnedCloth with about 50-80 vertices down to ~0.02-0.025ms

Print this item

  Ropes and cloth with guaranteed no tunnelling?
Posted by: Hatchling - 03-06-2021, 12:06 AM - Forum: Obi Rope - Replies (1)

I don't really need something like this for my project, but I've been following SIGGRAPH papers that deal with rope and cloth simulation and I think some of them managed to write their simulations such that, a knot for example, will never become untied by pulling on the two ends with any amount of force. Or if you tried to pull a cloth through another, it will never poke through.

Have you looked into any of these solutions? I'm guessing most of them are not realtime.

A method I had used to ensure tunnelling doesn't occur in some of my earlier simulation projects was fairly simple, though the content being simulated was also simple:

  • A particle was in an 2D environment. In the environment were horizontal line segments that the particles would collide with.
  • For simplicity, assume the particle and line segments have 0 radius.
  • The space around a line segment was divided into 6 parts: above to the right, above, above to the left, below to the right, below, and below to the left. (I'll abbreviate these as AR, A, AL, BR, B, and BL.)
  • If the particle passed through from one region to another suggesting a collision occurred, like A to B, it'd add a force that pushes the particle into region A (a point on the line segment).
  • If, at the end of frame 1, after summing all forces acting on the particle still resulted in the particle being in region B, it'd remember that the particle is "supposed" to be in region A and continue pushing the particle into it on the next frame.
  • If the particle passed through from, for example, AR to BR, the line segment would now remember that the particle switched from "supposed to be above" to "supposed to be below" and no longer try to push the particle above it.
Another way to describe it:

Code:
for each line segment L
    for each particle P
        P.Zone[L] is the current zone around L that P resides despite collision
        L.Zone[P] is the zone that L remembers P residing in last frame
        
        if a comparison of the two zones, P.Zone[L] and L.Zone[P] suggest a collision occurred
            newZone is the zone closest to P.Zone[L] that doesn't suggest a collision:
                For example, if P.Zone[L] is BL and L.Zone[P] is A, newZone would be AL.
                
            Apply a force to P that pushes it into zone newZone.
            L.Zone[P] <= newZone
        
        else
            L.Zone[P] <= P.Zone[L]



This approach could be made more accurrate by checking if the path of the particle intersected the line, rather than just comparing the 6-mode states for an invalid zone passing. Also, instead of just remembering the "last valid zone", it could remember the "last valid state", that is where the particle WOULD be if its collision force was the only force acting on it; the state resulting from projecting the particle.
Also, this approach does permit the particle to "poke through" the line segment, but it will always try to push the particle above it unless the particle makes a "legal" collision-free path around it. If there were a heavy object trying to pull the particle through the line segment, it wouldn't pass through freely; it'd likely reach equilibrium somewhere under the line but prevent it from falling.

This approach could be generalized to all simplices, but would require temporary memory that is freed when the collision is resolved. E.g. a list of collisions that is populated when a collision is detected, which are then removed from the list when the collision resolves.
Another challenge of this approach would be allowing adjacent simplices to "pass on" the knowledge that a collision is occurring to their neighbors, otherwise the particle could pass between two joined simplices.

This is to my knowledge the "fastest" way to ensure tunnelling-free collision, though the collision would be "soft" and not prevent interprenetration.

Another interesting approach I've seen was to create a Deluaney triangulation of the scene, where vertex points are the corners of collision shapes. If an inversion of any of the triangles occurred from frame 1 to frame 2, it'd check whether the inversion involves a collision. (E.g. a triangle's top vertex passing through its bottom edge, which is marked as a collision boundary.) If it did, it'd apply forces to correct the inversion by pushing the vertices opposite to a collision edge through to the correct side. Otherwise, it'd re-mesh the region around the inversion. (I think it continuously improves mesh quality by performing greedy edge flips, excluding edges that involve a collision boundary, or if it'd cause a false negative.) This also prevents falling through, since the inverted triangle will not get remeshed if it is collision-related, and the only way to fix the inversion is to push the particle back through the collision boundary.
I'm guessing this could be generalized to "thick" collisions by biasing edges of the triangle towards an inversion. It could also be sped up by selectively including elements in the mesh based on AABB overlap and using the beginning-of-frame state to construct the mesh of newly added elements.
(On second thought, I think I might like this approach better because it doesn't require remembering projected states or passing collision knowledge between connected simplices.)

Print this item

  Obiparticleattachment
Posted by: mayaeraky - 02-06-2021, 07:26 PM - Forum: Obi Cloth - Replies (5)

Hi there, I am trying to grab my obi cloth in VR using steamVR. I tried attaching the cloth to the hand after any contact between the hand and any particle of the cloth using contact event handler and obi particle attachment but there is a huge gap between the hand and the particles attached. They’re attached correctly movement wise but they are not overlapping which makes it look weird. 
Thank you

Print this item

  Obi Rope Collider
Posted by: Glenicus - 01-06-2021, 03:58 PM - Forum: Obi Rope - Replies (3)

Hello there,

Currently I am working on a game. In this game I have a rope and ball. Basically I want to do drag rope and push ball. But I've a problem with colliders I believe. When I added box collider it affects shape of my rope.

[Image: Qdy21GD.png]

After I edited box collider I solved that problem but I want to push ball with Rope drag but also ball needs to follow rope when It dragged. But it stays on box collider and I cannot push up.

I dont know If I need to add something else or there are another ways to do it.

[Image: 48KC8FN.png]
[Image: ZIMKLWR.png]

Print this item

  Obi Fluid + Trail Renderer
Posted by: ary1111 - 01-06-2021, 03:34 PM - Forum: Obi Fluid - Replies (1)

I was wondering if there was a way to show a trail renderer attached to the particles, either using Unity's built-in system or using something like Ara Trails?

Print this item

  Basic Rope Grabbing
Posted by: eddy_vr - 31-05-2021, 11:05 AM - Forum: Obi Rope - Replies (4)

Hello,

I am trying to set up a basic rope grabbing with a simple box collider. I added ObiContactGrabber to the box collider and a script RopeGrabber.cs which calls Grab() function. When the box collider is in contact with the particles it seems not working. What am I doing wrong ?

Here is the full sample project https://www.dropbox.com/s/a358ydt1gy2qk2...n.rar?dl=0

Thanks 
Eddy

Print this item

  Runtime repin rope to new controll point
Posted by: yeronimovr - 30-05-2021, 02:39 PM - Forum: Obi Rope - Replies (1)

Hello, let`s say there are A and B points between which i`m generating a rope. Then i want to add a 3rd C point and then move/repin constraint rope to new C point. Below steps:

1. spawn rope between A-B: two controll points and 2 pin constraints 
2. spawn new game object and adding on his transform new controll point using InsertControlPoint

Code:
 Vector3 pointPos = GetSolverLocalPos(hooks[GetLastHookIndex].transform.position);
 rope.path.InsertControlPoint(rope.path.ControlPointCount - 1 ,pointPos, -startHook.position.normalized, pointPos.normalized, Vector3.up, .1f, 0.1f, colliderThickness, 0, Color.red, "Hook");

3. unsap (remove constraint) rope from B: getting rope consraint, getting first batch, removing from batch. set batch to solver, setDirtyConstraints
Code:
  var pinConstraints = rope.GetConstraintsByType(Oni.ConstraintType.Pin) as ObiConstraints<ObiPinConstraintsBatch>;
  var batch = pinConstraints.GetFirstBatch();
  int index = batch.constraintCount - 1;
           
  pinConstraints.RemoveFromSolver();
  batch.RemoveConstraint(index);
  pinConstraints.AddToSolver(solver);
  rope.SetConstraintsDirty(Oni.ConstraintType.Pin);

and now where im stuck:
4. i want to move rope (all particles to new C point position) forward C - it works
Code:
for (int i = 0; i < blueprint.activeParticleCount; i++)
        {
            rope.TeleportParticle(rope.solverIndices[i], GetSolverLocalPos(hooks[GetLastHookIndex].transform.position));
            rope.solver.velocities[i] = Vector4.zero;
            rope.solver.angularVelocities[i] = Vector4.zero;
        }
        rope.UpdateParticleProperties();
        rope.RecalculateRestPositions();
        rope.RecalculateRestLength();

5. when i want to pin last particle to C rope the constraint doesnt work and rope is going back with all forces working on particles - stuck here.
Code:
var pinConstraints = rope.GetConstraintsByType(Oni.ConstraintType.Pin) as ObiConstraints<ObiPinConstraintsBatch>;
        var batch = pinConstraints.GetFirstBatch();

        pinConstraints.RemoveFromSolver();

        batch.AddConstraint(rope.solverIndices[blueprint.activeParticleCount - 1], lastHook.AttachCollider, Vector3.zero, Quaternion.identity, 0, 0, float.PositiveInfinity);
        batch.activeConstraintCount = 2;

        pinConstraints.AddBatch(batch);
        pinConstraints.AddToSolver(solver);

        rope.SetConstraintsDirty(Oni.ConstraintType.Pin);

My target is to attach rope to new C point, set there cursor, change rope length that i can again attach rope to B point getting: A-C-B connections.

Which steps i`m missing (some update on some component) or what im doing wrong ? Thanks for any help in advance

Print this item

  What Asset to Buy (if any) for Fishing Net style effect?
Posted by: mpbeau - 30-05-2021, 10:19 AM - Forum: General - Replies (1)

Hi everyone,

I am trying to create a mobile game that involves having a net in which objects are placed inside. The net grows over the course of the game. The net also doesn't need to look super realistic or have a lot of density, but should sway a little bit and behave/look relatively satisfying/interesting.

I have been looking at Obi Cloth or Obi Rope to potentially implement this, as I am not getting far with the basic Unity toolset.

Is there any recommendations on what I should look at? Is what I am doing even possible with the current state of Unity and mobile hardware (especially in a way that it is performant on most devices)?

Appreciate any information - thanks!

Print this item

  Rope Knot
Posted by: Gamify3D - 29-05-2021, 04:49 AM - Forum: Obi Rope - Replies (1)

We are using obi rope with the hope we will be able to tie knots for one of our projects.

Obi rope is working for most of what we need so far... However we have run into difficulty when trying to prevent knots from "slipping" through? 

Based on other forum posts on here you've suggested increasing resolution. Which still yields us the same results.


Any suggestions on other properties to try?


Please and thank you!

https://imgur.com/aFZnNee

https://imgur.com/Awos2Lp



Attached Files Thumbnail(s)
           
Print this item

  Setting instances of rope mesh renderer at runtime
Posted by: luvjungle - 28-05-2021, 11:07 PM - Forum: Obi Rope - Replies (1)

Hi! 
I want to constantly changle length with cursor and adjust instances amount at runtime. But every time when I change instances amount, my rope teleports to some point and becomes straight, then cursor updates it and rope teleports back and becomes normal.
Is it a bug or setup issue or anything else?

Print this item