Posts: 6
Threads: 5
Joined: Jan 2022
Reputation:
0
29-08-2024, 11:37 AM
I’m trying to get the position of a particle at runtime using
Code: for (int i = 0; i < actor.activeParticleCount; i++)
{
var solverIndex = actor.solverIndices[i];
var particlePos = actor.GetParticlePosition(solverIndex);
}
However, when the solver backend is set to GPU, it returns the position from the blueprint instead of the current position in the simulation.
Is this a bug?
If not, how can I retrieve the particle's position using the GPU (and is it even possible)?
Posts: 17
Threads: 3
Joined: Jan 2024
Reputation:
0
(29-08-2024, 11:37 AM)PlatonSk Wrote: I’m trying to get the position of a particle at runtime using
Code: for (int i = 0; i < actor.activeParticleCount; i++)
{
var solverIndex = actor.solverIndices[i];
var particlePos = actor.GetParticlePosition(solverIndex);
}
However, when the solver backend is set to GPU, it returns the position from the blueprint instead of the current position in the simulation.
Is this a bug?
If not, how can I retrieve the particle's position using the GPU (and is it even possible)?
Try this instead
Code: actor.solver.positions[solverIndex];
Posts: 6,512
Threads: 27
Joined: Jun 2017
Reputation:
423
Obi Owner:
29-08-2024, 12:02 PM
(This post was last modified: 29-08-2024, 12:07 PM by josemendez.)
(29-08-2024, 11:37 AM)PlatonSk Wrote: I’m trying to get the position of a particle at runtime using
Code: for (int i = 0; i < actor.activeParticleCount; i++)
{
var solverIndex = actor.solverIndices[i];
var particlePos = actor.GetParticlePosition(solverIndex);
}
However, when the solver backend is set to GPU, it returns the position from the blueprint instead of the current position in the simulation.
Is this a bug?
If not, how can I retrieve the particle's position using the GPU (and is it even possible)?
Hi,
Not a bug. See "Modifying data in the CPU when using the Compute backend" in the manual:
Quote:Obi will automatically upload particle data to the GPU at the start of every simulation step (only those data lists that have been modified by the CPU since the last time they were uploaded). However, it will only automatically read positions and velocities back from the GPU at the end of each step for performance reasons. If you want to read any other data from the CPU (eg. colors or user data) you need to manually ask Obi to read this data back from the GPU. Note this is also necessary if you're going to modify this data on the CPU, otherwise you would be working with stale data.
GetParticlePosition() returns data from the solver.renderablePositions array, which is used for rendering on the GPU and not read back to the CPU by default as it's not necessary for the normal simulation cycle (the difference with solver.positions is that solver.renderablePositions includes any interpolation/extrapolation performed during frames where a simulation step does not take place). As mentioned above, only solver.positions and solver.velocities are read back by default.
- If you're retrieving the particle position for simulation purposes, read from solver.positions instead.
- If you want to read renderable positions (either by using solver.renderablePositions or GetParticlePosition()), call Readback() and WaitForReadback() as explained in the link above:
Code: Readbacks in Obi are an asynchronous operation. To start reading data back from the GPU, call Readback() on the desired particle data list. You can then use WaitForReadback() to make the CPU wait for the current readback to be complete.
It is advisable to call WaitForReadback() as far away from Readback() as possible, to avoid long waits while the requested data travels from GPU to CPU. Ideally, Readback() should be called right after a simulation step has been dispatched to the GPU, and WaitForReadback() right after a step has been completed. ObiSolver provides two callback events for this purpose: OnRequestReadback and OnSimulationEnd. ObiActors expose two virtual methods for the same purpose: RequestReadback() and SimulationEnd().
let me know if you need further help!
kind regards
Posts: 17
Threads: 5
Joined: Jul 2024
Reputation:
0
Hello, i am having the same issue and i tried all the methods suggested here.
this is my code snippet
if (rope.isLoaded)
{
for (int i = 0; i < rope.solverIndices.count; ++i)
{
int solverIndex = rope.solverIndices[i];
Vector3 particlePos = rope.solver.renderablePositions[solverIndex]; //rope.solver.positions[solverIndex];
Debug.Log($"particle{solverIndex} position {particlePos}");
}
}
and the output is always the same position for all the particles with both methods.
Any other suggestion??
Posts: 6,512
Threads: 27
Joined: Jun 2017
Reputation:
423
Obi Owner:
10-06-2025, 06:23 AM
(This post was last modified: 10-06-2025, 06:27 AM by josemendez.)
(09-06-2025, 04:33 PM)alicecatalano Wrote: and the output is always the same position for all the particles with both methods.
Any other suggestion??
Hi!
The only situation in which the content of renderablePositions and positions arrays will differ is when your ObiSolver component has interpolation/extrapolation enabled, and no physics update has taken place in the current frame. As explained in the manual:
Quote:If the solver's interpolation mode is set to interpolate or extrapolate, solver.renderablePositions and solver.renderableOrientations will contain temporally smoothed-out data that won´t coincide with the physical particle positions/orientations at the end of the simulation step. That's why they are called "renderable": they are only used for smooth rendering, but they aren't fed back into the simulation.
This behavior is the same as Unity's transform.position (which is the GameObject equivalent to renderablePosition) and rigidbody.position (which is the GameObject equivalent to Obi's position).
Now, if the position returned is the same for all particles, that either means you're calling this code from the wrong place, or there's some other issue causing this. Would help us to know the context in which this code is being used.
kind regards,
Posts: 17
Threads: 5
Joined: Jul 2024
Reputation:
0
(10-06-2025, 06:23 AM)josemendez Wrote: Hi!
The only situation in which the content of renderablePositions and positions arrays will differ is when your ObiSolver component has interpolation/extrapolation enabled, and no physics update has taken place in the current frame. As explained in the manual:
This behavior is the same as Unity's transform.position (which is the GameObject equivalent to renderablePosition) and rigidbody.position (which is the GameObject equivalent to Obi's position).
Now, if the position returned is the same for all particles, that either means you're calling this code from the wrong place, or there's some other issue causing this. Would help us to know the context in which this code is being used.
kind regards, Hello,
thank you for the answer. I want to correct myself, i don'g get the same position for all the partciles, but each particle keeps the same position as output. so if particle 1 is in 0,0,0 and 2 is in 0,0,1 they keep otuputting this for all the game duration.
tha context is that in the Update() i am calling a method that checks if any of the particle positions falls in a certain area
bool IsRopeInsideCrossArea()
{
bool inBound = false;
if (rope.isLoaded)
{
for (int i = 0; i < rope.solverIndices.count; ++i)
{
int solverIndex = rope.solverIndices[i];
Vector3 particlePos = rope.solver.positions[solverIndex]; // GetParticlePosition(solverIndex);
Debug.Log($"particle {solverIndex} position {particlePos}");
if (crossArea.bounds.Contains(particlePos))
{
inBound = true;
}
else
{
inBound = false;
}
}
}
return inBound;
}
and this is always false, even when visually i can see it happens. Morevoer, I used the same code structure that i used to check if the particle were near enoguh to a grasping point to be grasped. and i don't understand why in that case the output was right while now it isn't. I am sure I am missing something but I can't wrap my head around it.
Posts: 6,512
Threads: 27
Joined: Jun 2017
Reputation:
423
Obi Owner:
10-06-2025, 08:47 AM
(This post was last modified: 10-06-2025, 09:15 AM by josemendez.)
(10-06-2025, 08:31 AM)alicecatalano Wrote: this is always false, even when visually i can see it happens. Morevoer, I used the same code structure that i used to check if the particle were near enoguh to a grasping point to be grasped. and i don't understand why in that case the output was right while now it isn't. I am sure I am missing something but I can't wrap my head around it.
Keep in mind that all solver data is expressed in the solver's local space. This means particle positions are unchanged when the solver moves around:
Quote:Each ObiSolver has a list for each one of these properties (solver.positions, solver.principalRadii, solver.velocities, solver.colors and so on), that stores the particle data for all actors currently being simulated by the solver. All spatial properties (positions, orientations, velocities, vorticities, etc) are expressed in the solver's local space.
So if crossArea.bounds is expressed in world space, your code won't work.
You must either convert the bounds to solver space, or convert the positions to world space.
Posts: 1
Threads: 0
Joined: May 2025
Reputation:
0
(10-06-2025, 08:31 AM)alicecatalano Wrote:
int solverIndex = rope.solverIndices[i];
Vector3 particlePos = rope.solver.positions[solverIndex]; // GetParticlePosition(solverIndex);
Debug.Log($"particle {solverIndex} position {particlePos}");
1. You get the wrong particle (though it may work in your case sometimes, your code is actually an unstable way, or a wrong way). See https://obi.virtualmethodstudio.com/manu...ropes.html. You must use something like this to get particle position:
int firstParticle = rope.elements[0].particle1;
var firstPos = rope.solver.positions[firstParticle];
2. You get the wrong position. You're getting the local position. If you need world position you must transform local to world.
Posts: 6,512
Threads: 27
Joined: Jun 2017
Reputation:
423
Obi Owner:
10-06-2025, 10:16 AM
(This post was last modified: 10-06-2025, 10:19 AM by josemendez.)
(10-06-2025, 09:40 AM)chenji Wrote: 1. You get the wrong particle (though it may work in your case sometimes, your code is actually an unstable way, or a wrong way). See https://obi.virtualmethodstudio.com/manu...ropes.html. You must use something like this to get particle position:
[size=small]int firstParticle = rope.elements[0].particle1;
[size=small]var firstPos = rope.solver.positions[firstParticle];
[color=#000000][font=Arial]
Thanks for your input chenji!
Just to clarify, elements are only needed in case you want to iterate particles in the same order they're laid out in the rope. For instance, when you want to move an object along the rope.
Alicecatalano just wants to know whether particles are inside a box, so there's no need to use elements: checking particles in any order is completely fine.
Posts: 17
Threads: 5
Joined: Jul 2024
Reputation:
0
10-06-2025, 10:18 AM
(This post was last modified: 10-06-2025, 10:33 AM by alicecatalano.)
(10-06-2025, 09:40 AM)chenji Wrote: 1. You get the wrong particle (though it may work in your case sometimes, your code is actually an unstable way, or a wrong way). See https://obi.virtualmethodstudio.com/manu...ropes.html. You must use something like this to get particle position:
int firstParticle = rope.elements[0].particle1;
var firstPos = rope.solver.positions[firstParticle];
2. You get the wrong position. You're getting the local position. If you need world position you must transform local to world. Thaks you chenji and jose,
my rope is a closed loop rope, so i son't know if i have an exact first particle.
seems like i have no idea on how to convert from solver to world space. my corss areas are in the solver hierarchy.
i move them scene by scene using the usual code for moving objects
Vector3 crossPos = GetCrossAreaPositionForRepetition(repetition);
crossArea.transform.position = crossPos;
can you tell me where can i find the lines to change the output frame of the particles so that i know wher they are in the world space? thank you
|