25-08-2025, 11:30 AM
Hi again, I have got several questions to things you mentioned before.
You reffered to rope tearing as example, but there are things that confuse me.
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]?
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;
Forth - why substep time is used here? And this leads to next point:
When to use substepTime and simDelta? If I understand correctly start and end position are positions for single simulation step.
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? 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?
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. The problem is that if we have 5 substeps, then does that mean that we are applying only 1/5 of forces? 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?
In short where to use different delta times, including lambda example above from tearing?
(11-08-2025, 08:31 AM)josemendez Wrote: Most constraint types have a "lambda" value associated to each of them. These are lagrange multipliers, outputted by the simulation, that can be converted to forces dividing by the timestep squared. These lambda values are stored in an array, in each constraint batch. In ObiRope.cs you have an example of this in the ApplyTear() method: it iterates trough all lagrange multipliers for distance constraints, then breaks those constraints whose force exceeds a threshold.
Bend/Twist and Stretch/Shear constraints used in rods also have lambda values, that you can use to calculate deformation. Chain constraints however don't, since they're not really physically based - more of a geometrical constraint.
You reffered to rope tearing as example, but there are things that confuse me.
Code:
var dc = GetConstraintsByType(Oni.ConstraintType.Distance) as ObiConstraints<ObiDistanceConstraintsBatch>;
var sc = this.solver.GetConstraintsByType(Oni.ConstraintType.Distance) as ObiConstraints<ObiDistanceConstraintsBatch>;
if (dc != null && sc != null)
{
// iterate up to the amount of entries in solverBatchOffsets, insteaf of dc.batchCount. This ensures
// the batches we access have been added to the solver, as solver.UpdateConstraints() could have not been called yet on a newly added actor.
for (int j = 0; j < solverBatchOffsets[(int)Oni.ConstraintType.Distance].Count; ++j)
{
var batch = dc.GetBatch(j) as ObiDistanceConstraintsBatch;
var solverBatch = sc.batches[j] as ObiDistanceConstraintsBatch;
for (int i = 0; i < batch.activeConstraintCount; i++)
{
int elementIndex = j + 2 * i;
// divide lambda by squared delta time to get force in newtons:
int offset = solverBatchOffsets[(int)Oni.ConstraintType.Distance][j];
float force = solverBatch.lambdas[offset + i] / sqrTime;
elements[elementIndex].constraintForce = force;
if (-force > tearResistanceMultiplier)
{
tornElements.Add(elements[elementIndex]);
}
}
}
}
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]?
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;
Forth - why substep time is used here? And this leads to next point:
(11-08-2025, 08:31 AM)josemendez Wrote: "startPositions" and "endPositions" are particle positions at the start and end of the whole simulation step, respectively.
"prevPositions" and "positions" are particle positions at the start and end of the current substep, respectively.
When to use substepTime and simDelta? If I understand correctly start and end position are positions for single simulation step.
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? 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?
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. The problem is that if we have 5 substeps, then does that mean that we are applying only 1/5 of forces? 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?
In short where to use different delta times, including lambda example above from tearing?