Sorry to bother you. I want to create a system where when a cloth net collides with a rigid body, it indicates whether a collision has occurred. If a collision occurs, the scene should be reinitialized. However, with the current code, even though collisions appear to happen on screen, there is no indication of a collision being detected.
Here is the code attached to the obi solver,
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Obi;
[RequireComponent(typeof(ObiSolver))]
public class CollisionEventHandlerchuang : MonoBehaviour
{
ObiSolver solver;
public int contactCount;
private bool collisionOccurred = false;
// just iterate over all contacts in the current frame:
foreach (Oni.Contact contact in e.contacts)
{
// if this one is an actual collision:
Debug.Log("no bang chuang");
if (contact.distance < 0.01)
{
ObiColliderBase col = world.colliderHandles[contact.bodyB].owner;
if (col != null)
{
Debug.Log("bang chuang");
collisionOccurred = true;
contactCount++;
}
}
}
}
public bool IsCollisionOccurred()
{
return collisionOccurred;
}
public int GetContactCount()
{
return contactCount;
}
if (collisionHandlerchuang == null)
{
Debug.LogError("CollisionEventHandlerchuang not found in the scene.");
}
if (collisionHandler == null)
{
Debug.LogError("CollisionEventHandler not found in the scene.");
}
}
void FixedUpdate()
{
if (collisionHandlerchuang != null)
{
bool collisionOccurred = collisionHandlerchuang.IsCollisionOccurred();
int contactCount = collisionHandlerchuang.GetContactCount();
Dev environment: Obi Rope version 6.5.4 / Windows 10 / Unity 2021
Hello, sorry to bother you. I am working on a puzzle game and need to save the data of twisted ropes into a JSON file, then read the JSON during gameplay to restore the ropes to their previous twisted state. ()
I have implemented the save and load functions and can confirm that the saved data is correct because I have tested the vectors' paths of the ropes, and they match what was saved.
However, when I apply the data to the instantiated ropes, I cannot restore the ropes to their previous state. When I use the vectors stored in JSON to restore the positions of the rope's particles, the ropes can never maintain their previous twissted state. The ropes are always spread out or lying there alone.
I found some posts in the forum:
https://obi.virtualmethodstudio.com/foru...-116.html?
The first post from 2017 mentioned frequently calling ObiRopeCursor.ChangeLength() to restore the shape of the ropes, but this method does not work for me, and I am also unable to call the PushDataToSolver method mentioned in the post. (This method only implemented in class ObiStitcher) However, I understand the reason for calling ObiRopeCursor.ChangeLength(). Calling this method can increase the activeParticleCount. The number of actor.activeParticleCount may be much smaller than the number of actor.particleCount, but the number of actor.particleCount is limited by the particleCount in ObiActorBlueprint.
https://obi.virtualmethodstudio.com/foru...4112.html?
The second post was updated in February 2024, which is very recent and provides sample code. The save and load code in the post is very similar to mine, with the only difference being that the loop code during restoration ignores the legality of solver.positions[particlesIndices[i]]. During actual operation, the number of _rope.solverIndices may be much smaller than the total amount of data stored in JSON, resulting in either loss of some data or array out-of-bounds errors.
Here is the code I used to instantiate the rope / saving and restoring the ropes.
JSONObject GetRopeParticleData()
{
var rope = gameObject.GetComponent<ObiRope>();
var solver = rope.solver;
var particlesIndices = rope.solverIndices;
var positions = new List<Vector3>();
for (int i = 0; i < particlesIndices.Length; i++)
{
//if (rope.IsParticleActive(i)) // I was considering save active particles only.
{
positions.Add(solver.positions[particlesIndices[i]]);
}
}
var positionsArray = JSONObject.emptyArray;
for (int i = 0; i < positions.Count; i++)
{
positionsArray.Add((JSONNode)positions[i]);
}
var ropeObject = JSONObject.emptyObject;
ropeObject.AddField("positions", positionsArray);
//ropeObject.AddField("velocities", velocitiesArray); // Velocities are all zero, so I didn't save.
return ropeObject;
}
Load the positions of the particles from JSON and set to particles in the rope:
public void Actor_OnBlueprintLoaded(ObiActor actor, ObiActorBlueprint blueprint)
{
if (particleDataToRestore == null)
return;
var solver = actor.solver;
var particlesIndices = actor.solverIndices;
/*for (int i = 0; i < actor.solverIndices.Length; ++i)
solver.invMasses[actor.solverIndices[i]] = 0;*/
var positionsJsonArray = particleDataToRestore["positions"];
if (positionsJsonArray != null && positionsJsonArray.type == JSONObject.Type.Array)
{
for (int i = 0; i < positionsJsonArray.list.Count; i++)
{
if (i < particlesIndices.Length)
{
solver.positions[particlesIndices[i]] = positionsJsonArray[i].ToVector3();
// actor.ActivateParticle(i);
}
}
}
/*for (int i = 0; i < actor.solverIndices.Length; ++i)
solver.invMasses[actor.solverIndices[i]] = 1f;*/
In this post https://obi.virtualmethodstudio.com/foru...-3520.html you helped Locque create particles with a solid white color using the Built-In Pipeline.
But how can I do this in URP?
I tried taking the shader file you gave him and splicing the changes into a copy of ParticleShaderURP.shader but couldn't get it to work.
The pipelines are just too different.
I'm new to ObiFluid and I'm currently working on a 2D bartender game where you can grab glasses with fluid, move them around and pour the fluids into other glasses (or onto the shelves).
For example, I'd like this to work:
Drag and drop the red fluid glass from below through the upper shelf collider and through the blue and green glasses without affecting the liquids at all - it should just pass through it.
Rotate the red fluid glass so the red fluid pours out. Once the red fluid has left its glass it should be stopped by any other glass (i.e. fill those glasses and mix with any fluids inside) or the shelf.
So, in short, I'd need a *grabbed glass with liquid* ignore all non-grabbed-glass colliders/liquids, and *liquid that has left a grabbed glass* to normally interact with the world.
Liquids can mix, so I don't think I could do anything like "liquid from the red emitter behaves differently" - it might be glass mixed with red and blue liquid that is grabbed, while other glasses also already have red or blue liquid.
I see two ways this could happen:
If I make the simulation 3D with very flat models, it would still look 2D in an orthographic camera and I could use the Z-axis to make a grabbed glass and its contents ignore any other collider. When the fluid leaves the grabbed glass trigger volume because it is poured I could adjust the Z-position of those now-outside-the-glass fluid particles back to the Z-position that everything non-grabbed is on.
If there is a way to have multiple simulations and to transfer colliders/fluids between simulations, I could temporary make a grabbed glass and its fluid a separate "grabbed glass" simulation and return any fluid that leaves the grabbed glass to the "main" simulation.
Do those ways sound possible? Is there any other (maybe better?) way to achieve this?
Hi, I played around with Obi Rope (and rod) for a bit, but I'm not sure if I can simulate a sort of ball of noodles/yarn like this picture. From what I've tried, I tried to use rods and bent them into a U, and then just spawned a bunch of them. However it seems with just 10 of them (each being relatively long), my FPS would drop a lot. I'm trying to use these in a VR game, where users can pick up this ball of noodles and drop them into a pot of boiling water etc. Not sure if this is achievable?
Hi,
Please check this video. when a shape with obicollider collides with the rope, rope goes inside the table ignoring collision.
Shape ObiCollider rigidbody has constraints x and z rotation locked and y position locked. Attached rigidbody, collider, solver and rope config snapshots.
// Setup a blueprint for the rope:
var blueprint = ScriptableObject.CreateInstance<ObiRopeBlueprint>();
blueprint.resolution = 0.65f;
blueprint.thickness = 0.07f;
blueprint.pooledParticles = 5;
Vector3 point = Vector3.zero;
blueprint.path.Clear();
int filter = ObiUtils.MakeFilter(ObiUtils.CollideWithEverything, 0);
float mass = 1;
for (int i = 0; i < points.Length; i++)
{
if (i == 0 || i == points.Length - 1)
{
mass = .001f;
filter = ObiUtils.MakeFilter(ObiUtils.CollideWithEverything, 2);
}
else
{
mass = .002f;
filter = ObiUtils.MakeFilter(ObiUtils.CollideWithEverything, 0);
}
if( i == 0 )
{
point = rope.transform.InverseTransformPoint(points[i].position);
blueprint.path.AddControlPoint(point, -Vector3.zero, Vector3.zero, Vector3.up, mass, 0.5f, 1, filter, Color.white, "A");
continue;
}
// convert both points to the rope's local space:
/*pointA = rope.transform.InverseTransformPoint(pointA);
pointB = rope.transform.InverseTransformPoint(pointB);
// access the distance constraints currently simulated by the solver:
var solverConstraints = rope.GetConstraintsByType(Oni.ConstraintType.Distance)
as ObiConstraints<ObiDistanceConstraintsBatch>;
int batches = solverConstraints.batches.Count;
for (int k = 0; k < batches; k++)
{
int cnt = solverConstraints.batches[k].constraintCount;
for (int i = 0; i < cnt; i++)
{
solverConstraints.batches[k].restLengths[i] = length;
}
}
Once a cursor is added to a rope (and the length is altered) it looks like the index of the particles no longer returns in a nice order using the below method:
Code:
// first particle in the rope is the first particle of the first element:
int firstParticle = rope.elements[0].particle1;
// last particle in the rope is the second particle of the last element:
int lastParticle = rope.elements[rope.elements.Count-1].particle2;
// now get their positions (expressed in solver space):
var firstPos = rope.solver.positions[firstParticle];
var lastPos = rope.solver.positions[lastParticle];
Instead, I have found I'll get the index of the first particle correct, and the last particle index will be at the first cursor spawn position, and then after that, I can't spy an order to the particles.
I'm using two cursors both facing inward in case that context matters, though I've found the same issue with just one cursor in the crane demo scene also.
Any clues/advice from folks for how to get a nice ordered index of them?
I've been working on a caving simulator for some time now. Obi has become an integral part to get rope climbing, guidelines and hoses interactive! It's incredible what it can do :O
I'm seeing some performance issues from the high fidelity of the rope, but hopefully the new GPU accelerated version can improve on that!
I've set up Obi solver to Use Burst, I have a TONE of work for it - the game is running at 1 FPS in editor, but when I go to Profiler, it shows fully occupied main thread with ObiFixedUpdater.FixedUpdate() while every Job.Worker thread is Idle
Have I made a mistake somewhere?