(21-02-2020, 11:18 AM)josemendez Wrote: Haven't been able to reproduce this yet on any Unity version or platform (tried 2019.3.0f6, 2019.2.9f1, 2018.4.10f1 and 2017.4.2.0f2, Windows, Mac and Linux). Also haven't had any other reports regarding this, I'd think at least some other user would have run into it. Here's video of my attempts to get it to happen: new scene, add a rope, play, exit, set up a rope blueprint, play, exit, same but disabling components... no luck.
Maybe you can record a video of the exact steps that trigger it?
Moreover, no component of the rope object (or the solver, or the updater) tries to remove the ObiRope component at any point during execution, so as far as I can think of, there's literally no way for that "Can't remove ObiRope (script)" error to show up. It's really weird.
That's fine - right now its not breaking anything important so I can live with it for now.
I was thinking more about the earlier comment:
Do you have any recommendations for increasing performance/simulation other than simulation?
More specifically; is there any way to disable the solver ones all actors have entered sleep mode? Since in my app only playerinput (or narratively scripted event) will re-awaken the rope.
My current solution is to have each rope in a single solver, and then manually disabling and enabling the solver - this way I save a ton of performance because I'm only simulating the ropes I need to, but they are all still being rendered. I can't seem to find a function for checking if the rope has reached it's sleep thresh-hold. This way I could make sure the rope is not moving when I disable the solver.
21-02-2020, 01:36 PM (This post was last modified: 21-02-2020, 01:38 PM by josemendez.)
(21-02-2020, 12:15 PM)TheMunk Wrote: That's fine - right now its not breaking anything important so I can live with it for now.
I was thinking more about the earlier comment:
Do you have any recommendations for increasing performance/simulation other than simulation?
More specifically; is there any way to disable the solver ones all actors have entered sleep mode? Since in my app only playerinput (or narratively scripted event) will re-awaken the rope.
My current solution is to have each rope in a single solver, and then manually disabling and enabling the solver - this way I save a ton of performance because I'm only simulating the ropes I need to, but they are all still being rendered. I can't seem to find a function for checking if the rope has reached it's sleep thresh-hold. This way I could make sure the rope is not moving when I disable the solver.
A sleep threshold is basically low kinetic energy. Kinetic energy of a body is defined as: 1/2 * mass * velocity^2. If that value is lower than a threshold for all particles, you know the rope isnt moving. Since you’re only interested in visual movement (not energy) you can drop the mass term:
1/2 * velocity^2.
The 1/2 is just a constant, that you can fold it over to the threshold value. Also the square.
So it all boils down to iterating over all particles in the rope and checking if their velocity is smaller than a threshold. If it is, you can disable the solver. If you find a single particle whose velocity is over the threshold, you must keep the solver enabled, so in most cases it’s an early out.
(21-02-2020, 01:36 PM)josemendez Wrote: A sleep threshold is basically low kinetic energy. Kinetic energy of a body is defined as: 1/2 * mass * velocity^2. If that value is lower than a threshold for all particles, you know the rope isnt moving. Since you’re only interested in visual movement (not energy) you can drop the mass term:
1/2 * velocity^2.
The 1/2 is just a constant, that you can fold it over to the threshold value. Also the square.
So it all boils down to iterating over all particles in the rope and checking if their velocity is smaller than a threshold. If it is, you can disable the solver. If you find a single particle whose velocity is over the threshold, you must keep the solver enabled, so in most cases it’s an early out.
(21-02-2020, 01:36 PM)josemendez Wrote: A sleep threshold is basically low kinetic energy. Kinetic energy of a body is defined as: 1/2 * mass * velocity^2. If that value is lower than a threshold for all particles, you know the rope isnt moving. Since you’re only interested in visual movement (not energy) you can drop the mass term:
1/2 * velocity^2.
The 1/2 is just a constant, that you can fold it over to the threshold value. Also the square.
So it all boils down to iterating over all particles in the rope and checking if their velocity is smaller than a threshold. If it is, you can disable the solver. If you find a single particle whose velocity is over the threshold, you must keep the solver enabled, so in most cases it’s an early out.
I'm sorry but without 5.1 API docs it's hard to figure out how to iterate over all particles. Do I get them through the Obi rope or the solver? What is an element vs a particle? An element is a connection between two particles? but i cannot get the velocity of a single particle?
25-02-2020, 12:35 PM (This post was last modified: 25-02-2020, 12:36 PM by josemendez.)
(25-02-2020, 12:22 PM)TheMunk Wrote: I'm sorry but without 5.1 API docs it's hard to figure out how to iterate over all particles. Do I get them through the Obi rope or the solver? What is an element vs a particle? An element is a connection between two particles? but i cannot get the velocity of a single particle?
Hi,
Elements are a logic "connection" between two particles. You don't need to use them at all, not for your purpose. They're mostly used to change the topology of the rope, when resizing a rope or tearing it.
In your particular case, you only have one actor (rope) per solver, so it does not really matter if you iterate over the actor's solverIndices array, or over the solver data arrays directly. So you could either do what's done in the manual:
Code:
// Iterate over all particles in an actor:
for (int i = 0; i < actor.solverIndices.Length; ++i){
// retrieve the particle index in the solver:
int solverIndex = actor.solverIndices[i];
// look up the particle velocity:
if (actor.solver.velocities[solverIndex] ...etc)
{
}
}
or
Code:
// Iterate over all particles in the solver:
for (int i = 0; i < actor.solver.velocities.Length; ++i){
// look up the particle velocity:
if (actor.solver.velocities[i] ...etc)
{
}
}
This last method will only work correctly if there's exactly one actor in the solver, though. As you add/remove actors from a solver, particles are reassigned to different actors and the actor's solverIndices array is the only consistent way to access solver data arrays. (You can think of Obi as an ECS system, where particles are entities, and the constraint groups are components.)
So all that's left to do is check if the velocity magnitude of each particle is over a threshold. If you find that all particles are under the threshold, you can disable the solver.
25-02-2020, 04:09 PM (This post was last modified: 25-02-2020, 04:15 PM by TheMunk.)
(25-02-2020, 12:35 PM)josemendez Wrote: Hi,
Elements are a logic "connection" between two particles. You don't need to use them at all, not for your purpose. They're mostly used to change the topology of the rope, when resizing a rope or tearing it.
In your particular case, you only have one actor (rope) per solver, so it does not really matter if you iterate over the actor's solverIndices array, or over the solver data arrays directly. So you could either do what's done in the manual:
Code:
// Iterate over all particles in an actor:
for (int i = 0; i < actor.solverIndices.Length; ++i){
// retrieve the particle index in the solver:
int solverIndex = actor.solverIndices[i];
// look up the particle velocity:
if (actor.solver.velocities[solverIndex] ...etc)
{
}
}
or
Code:
// Iterate over all particles in the solver:
for (int i = 0; i < actor.solver.velocities.Length; ++i){
// look up the particle velocity:
if (actor.solver.velocities[i] ...etc)
{
}
}
This last method will only work correctly if there's exactly one actor in the solver, though. As you add/remove actors from a solver, particles are reassigned to different actors and the actor's solverIndices array is the only consistent way to access solver data arrays. (You can think of Obi as an ECS system, where particles are entities, and the constraint groups are components.)
So all that's left to do is check if the velocity magnitude of each particle is over a threshold. If you find that all particles are under the threshold, you can disable the solver.
Thanks - got me a bit further although not the entire way.
I'm doing this on Fixed Update;
Code:
highestParticleMagnitude = 0;
highestVelocity = new Vector4(0, 0, 0, 0);
// Iterate over all particles in an actor:
for (int i = 0; i < rope.solverIndices.Length; ++i)
{
// retrieve the particle index in the solver:
int solverIndex = rope.solverIndices[i];
// look up the particle velocity:
if ((rope.solver.velocities[solverIndex] * Time.fixedDeltaTime).magnitude > highestVelocity.magnitude)
{
highestVelocity = (rope.solver.velocities[solverIndex] * Time.fixedDeltaTime);
highestParticleMagnitude = rope.solver.velocities[solverIndex].magnitude;
}
}
But it looks like the velocities stops updating after some time even though the rope is still moving (see here):
As you can see the VelocityVisualizer from your documentation seems to work fine though, so why isn't mine updating?
Changing sleep threshold in the solver doesn't help.
EDIT:
It seems to work right until I shorten the rope, then it breaks... Without errors.
25-02-2020, 04:35 PM (This post was last modified: 25-02-2020, 04:47 PM by josemendez.)
(25-02-2020, 04:09 PM)TheMunk Wrote: Thanks - got me a bit further although not the entire way.
I'm doing this on Fixed Update;
Code:
highestParticleMagnitude = 0;
highestVelocity = new Vector4(0, 0, 0, 0);
// Iterate over all particles in an actor:
for (int i = 0; i < rope.solverIndices.Length; ++i)
{
// retrieve the particle index in the solver:
int solverIndex = rope.solverIndices[i];
// look up the particle velocity:
if ((rope.solver.velocities[solverIndex] * Time.fixedDeltaTime).magnitude > highestVelocity.magnitude)
{
highestVelocity = (rope.solver.velocities[solverIndex] * Time.fixedDeltaTime);
highestParticleMagnitude = rope.solver.velocities[solverIndex].magnitude;
}
}
But it looks like the velocities stops updating after some time even though the rope is still moving (see here):
As you can see the VelocityVisualizer from your documentation seems to work fine though, so why isn't mine updating?
Changing sleep threshold in the solver doesn't help.
EDIT:
It seems to work right until I shorten the rope, then it breaks... Without errors.
Hi,
It's hard to tell, but in your video the highest velocity seems to stop updating right when the rope particles stop moving. Isn't this the expected result?
Also, multiplying velocities by the delta time converts them to position deltas. I'm not sure if this is intended, but most likely not. Velocities are expressed in meters/second, so you don't need to multiply them by anything (unless you want to use a threshold expressed in meters, but then it wouldn't be independent of the timestep)
Edit: I just realized that you might have copied the "actor.solver.velocities[solverIndex] * Time.fixedDeltaTime" from the documentation. I did this because the sample visualizer draws a line between two positions (the particle position, and the position where it will move to the next frame, due to its velocity) so I need to integrate velocity over time to get a position, hence the * Time.fixedDeltaTime. Remember from basic physics that velocity = distance/time, so distance = velocity * time. You don't want to work with distances but with velocities.
26-02-2020, 09:31 AM (This post was last modified: 26-02-2020, 04:50 PM by TheMunk.)
(25-02-2020, 04:35 PM)josemendez Wrote: Hi,
It's hard to tell, but in your video the highest velocity seems to stop updating right when the rope particles stop moving. Isn't this the expected result?
I'm sorry for the ambiguity of that gif, but its the very thin line which the script is attached to, not the one with the big particles. I basically thinned the line renderer and disabled the particle renderer in order to show you the velocity gizmos of the rope.
EDIT: also, this script runs on fixed update - shouldn't the velocity be set to 0 if the rope is not moving instead of not updating?
On a completely still rope, this;
(21-02-2020, 11:18 AM)josemendez Wrote: Moreover, no component of the rope object (or the solver, or the updater) tries to remove the ObiRope component at any point during execution, so as far as I can think of, there's literally no way for that "Can't remove ObiRope (script)" error to show up. It's really weird.
Btw, I solved this - apparently the Unity Substance plugin does some weird stuff when ending playmode, which was what was trying to destroy the ropes.
So while I fixed the in-editor errors I'm still occasionally getting some crashes when entering playmode, and I found this in the error.log of the crash:
Code:
libOni.dll caused an Access Violation (0xc0000005)
in module libOni.dll at 0033:421a4549.