Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  Scripting rod forces
#10
(25-08-2025, 11:30 AM)Qriva0 Wrote: First of all why constraint is accessed twice in two ways? Are those constraint batches different?
Second, why first batch is accesed differently? Is there difference between GetBatch(j) and batches[j]?

Yes, there's solver and actor constraint batches. These are completely different. When you create an actor, its constraints are grouped into batches. When you add an actor to a solver (so it becomes part of the simulation), a copy of each constraint batch in the actor is created and merged with *all other existing constraints in the solver*, including those belonging to other actors to maximize parallelism.

As a result:
- Actor batches contain constraint data at rest for a specific actor.
- Solver batches contain current constraint data for all constraints in the simulation, at any point during simulation.
- The number of solver batches and the number of constraints in each solver batch is different than its actor counterparts, and are accessed differently.

See: https://obi.virtualmethodstudio.com/manu...aints.html

Quote:Very much like particle data, constraint data isn't laid out in the solver the same way it is in an actor. When an actor gets added to a solver, all its constraints are merged with the existing constraints in the solver to maximize performance. This means each constraint batch in the solver contains constraints belonging to different actors, so if we want to access data for a certain actor in particular, we need to know the offset of that actor's constraints inside the solver batch.

As the manual mentions, this mirrors how particle data is laid out: actor.positions and solver.positions are not the same thing, do not have the same amount of entries, and are not accessed the same way.


(25-08-2025, 11:30 AM)Qriva0 Wrote: Third, how to read lambda? In case of strech constraint lambda has 3 components, I guess one for each "axis", so do I need to multiply by 3?
float force = solverBatch.lambdas[offset + i * 3] / sqrTime;

How to access lambdas depends on the specific constraint type. Some constraints have only 1 lambda, since they only have 1 gradient direction. Some have 2, 3, or more lambda values. Stretch/shear constraints have 3 lambdas: one for stretch, one for  the first shear axis, and another for the second shear axis. So you have to multiply the current index by 3 when iterating, and add an offset ranging from 0 to 2 depending on which lambda you want to access for each constraint:

Code:
float shearForce1 = solverBatch.lambdas[(offset + i) * 3] / sqrTime;
float shearForce2 = solverBatch.lambdas[(offset + i) * 3 + 1] / sqrTime;
float stretchForce = solverBatch.lambdas[(offset + i) * 3 + 2] / sqrTime;

Note this is just one way of doing it. You could also reinterpret the memory as Vector3/float3 and access it that way.

(25-08-2025, 11:30 AM)Qriva0 Wrote: Forth - why substep time is used here? And this leads to next point:

Because lagrange multipliers (lambdas) in XPBD are positional deltas, calculated and applied during each substep, so to convert them to forces you divide by substep duration squared.

(25-08-2025, 11:30 AM)Qriva0 Wrote: When to use substepTime and simDelta?

Entirely depends on what you're using them for. Just like in Unity you sometimes use deltaTime, but some other times you use fixedDeltaTime.

(25-08-2025, 11:30 AM)Qriva0 Wrote: If I understand correctly start and end position are positions for single simulation step.

Correct. These are used to interpolate physics state between frames, since rendering happens between full steps (substeps are just chained back to back) they store data for full steps instead of susbteps.

(25-08-2025, 11:30 AM)Qriva0 Wrote: There are also substeps and those are run as group of jobs - there is no way to do anything between substeps, so is prevPositions and positions just data from the last substep?

Correct. A single simulation step is comprised of multiple substeps, and each substep is comprised of multiple iterations. During solver callbacks (and Unity's events like Update(), LateUpdate(), etc), all information you get belongs to the last executed substep.

(25-08-2025, 11:30 AM)Qriva0 Wrote: If that is the case, then in the code above is substepDelta used because we have access only to the last one? I think I understand it wrong, because lambda is accumulated, so can you clarify how that actually work?

Lambda values are set to zero at the start of each substep, and accumulated between iterations. However, while time advances from one substep to the next, it does not advance between iterations: iterations simply refine the solution for the current substep.

The rope tearing code uses the lambda values from the last substep, using the substep time delta to get a force value, and tears the rope if the force exceeds a threshold. It's possible for the constraint force to briefly go over the tear threshold during an intermediate substep, but these sudden "spikes" are ignored: we're only interested in forces that are sustained over at least one full simulation step.

(25-08-2025, 11:30 AM)Qriva0 Wrote: I found example here about adding forces (Using Burst/Jobs to process particles) https://obi.virtualmethodstudio.com/manu...icles.html
It does not work, it uses undeclared variable stepTime, but I guess it would be substepTime.

That should be timeToSimulate, which is the total amount of time passed between steps (substeps * substepTime). I've corrected it in the example, thanks for reporting the issue!

(25-08-2025, 11:30 AM)Qriva0 Wrote: The problem is that if we have 5 substeps, then does that mean that we are applying only 1/5 of forces?

We're applying the full force (since it's multiplied by substep*substepTime), but only changing its direction/magnitude every N substeps.

(25-08-2025, 11:30 AM)Qriva0 Wrote: For example I wanted to create script that uses onSimulationStart to move particles, velocity or position delta is 5 per second, so in such a case should I use timeToSimulate or substepTime as delta? 

This happens over an entire step, so you should use timeToSimulate.

I'd recommend reading the "how it works" section of the manual, as it goes in-depth about timesteps, substeps and iterations:
https://obi.virtualmethodstudio.com/manu...gence.html

These articles are also useful for reference:
https://matthias-research.github.io/page...s/XPBD.pdf
https://mmacklin.com/smallsteps.pdf

let me know if I can be of further help,

kind regards
Reply


Messages In This Thread
Scripting rod forces - by Qriva0 - 08-08-2025, 06:33 PM
RE: Scripting rod forces - by chenji - 11-08-2025, 03:18 AM
RE: Scripting rod forces - by josemendez - 11-08-2025, 08:31 AM
RE: Scripting rod forces - by Qriva0 - 11-08-2025, 11:14 AM
RE: Scripting rod forces - by josemendez - 11-08-2025, 11:26 AM
RE: Scripting rod forces - by Qriva0 - 11-08-2025, 12:25 PM
RE: Scripting rod forces - by josemendez - 11-08-2025, 12:48 PM
RE: Scripting rod forces - by Qriva0 - 11-08-2025, 03:24 PM
RE: Scripting rod forces - by Qriva0 - 25-08-2025, 11:30 AM
RE: Scripting rod forces - by josemendez - 25-08-2025, 12:12 PM
RE: Scripting rod forces - by Qriva0 - 25-08-2025, 02:11 PM
RE: Scripting rod forces - by josemendez - 25-08-2025, 02:36 PM
RE: Scripting rod forces - by Qriva0 - 25-08-2025, 03:59 PM