Vega-strike-engine-source: Collision resolution (physics modeling issues, metric confusion, config variable override)

Created on 1 Feb 2021  路  11Comments  路  Source: vegastrike/Vega-Strike-Engine-Source

All comments pertain to https://github.com/vegastrike/Vega-Strike-Engine-Source/blob/master/engine/src/cmd/collision.cpp as of 1/31/2021

Minor issue first, then major issues, then enhancement suggestion for additional feature properties.

Minor
_(config variable ignored/overriden + sense flip)_:
Line 298: float elasticity = 0.8f;
is used as a hard-code in lieu of
Line 42: static float inelastic_scale = GameConfig::GetVariable( "physics", "inelastic_scale", 0.8f);

Also, note the sense flip from 0.8/0.2 inelastic/elastic (old model) to 0.2/0.8 inelastic/elastic -- if it's set to use the config var, the default is secondary, but we should be consistent in naming-meaning.

Major
_(1] - unit mismatch (m/s vs Kg-m/s^2) in application of force;
2] - Current physics modeling of inelasticity of collision can lead to undesired/substantially incorrect/catastrophic outputs wrt post-collision velocity )_

  1. Apply force passed a velocity, not a force

Lines 261-271:

    float& m1 = mass;
    Vector& v1 = velocity;

    // Perfectly elastic result
    Vector new_velocity = v1*(m1-m2)/(m1+m2) + v2*2*m2/(m1+m2);

    // Apply ratio
    new_velocity = new_velocity * elasticity;

    // Apply force
    unit->ApplyForce(new_velocity);

unit->ApplyForce should be applying the force required to achieve the new velocity at the end of the current sim_atom, not the new velocity - the units are fundamentally mismatched (newtons vs meters/second) and will lead to unintended results, especially for more massive objects.

  1. The elasticity scaling is scaling between a fully-elastic collision and zero velocity relative to system, rather than between a fully-elastic and fully-inelastic collision velocity outcome, which makes the delta-v proportional to absolute system-relative velocity rather than the delta-v between the colliding objects.

Line 267,268:

  // Apply ratio
  new_velocity = new_velocity * elasticity;

To see how this is problematic (and to see how we might construct a unit test to validate this) consider the following thought experiment:

Without loss of generality(for the elasticity consideration), consider two point objects A and B with identical mass traveling in the X,Y plane. Assume that both A and B have identical, very large, velocities V in the X direction. Assume that A and B are initially separated by K meters in the Y dimension and have the same initial X coordinate. B has a velocity of 0 in the Y dimension, and A has a velocity of epsilon << V in the Y dimension.

When A and B collide, there should be no effect on the X component of the post-collision velocities and the total energy change should be small (because epsilon is small)

Using momentum conservation,
In a fully elastic collision, B will have velocity and A will have velocity
In a fully inelastic collision, A and B will both have velocity

With the current code, all dimensions are just uniformly scaled, which is going to lead to unexpected/undesired behaviors (consider, for instance, what happens as V --> inf).

The original use of the inelastic_scale coefficient was to blend the two closed form computable (fully elastic, fully inelastic) collision outcome velocities.
Applying a 0.8 inelastic scale to the above would result in
A: 0.2 + 0.8 -->
B: 0.2
+ 0.8 -->

We can do unit testing fairly easily for this 1st-order correctness of outcomes in resultant velocity by doing these simple particle collisions with highly structured examples like the above where it would be easy to sense (large V, small epsilon) whether things are matching physical system expectations. Potential issues in testing: mixed sim_atom issues between the two objects/drft due to iterative method calculation of acceleration from force vs. resultant velocity -- may take a couple of passes to make sure we're covering the end-to-end actual expected outcome velocity from the collision to set floating point error bounds for passing results appropriately.

Enhancement
The current code computes the collision using only the center-of-mass velocity of the unit. This does not take into account the rotational velocity components of the points on the two objects that are actually colliding (note that this is separate from considerations of resultant torque, as will be shown in the example).

Consider the following example:
There are two units, A and B, both cylinders with length L, mass M, and radius R (R << L, R~=0+).
Both have <0,0,0> translational velocities for their center of mass.
The center of mass for A is at <0,0,0> and the center of mass for B is at
B is oriented with length perpendicular to the X,Y plane.
A is oriented in the X,Y plane with L along the Y axis.
A is rotating within the X,Y plane with initial velocity at the center of the tip (0,-L/2,0), in the X direction, of .

Using the R~=0 approximation, the tip of A will impact the center of mass of B with velocity <0,V,0>
Despite there being no relative velocity between the center of masses, the resulting collision should propel B in the Y direction with (some) resultant velocity. Note that, for B, there is no concern with respect to torque, as the impact is at the center of mass. (Torque is clearly an issue for A). Thus, collision should take into account (in some fashion) the velocity of the point of impact, not just the translational velocity of the center of mass (this actually came up frequently in small-craft + station interactions in the days of yore, so I am convinced that this is not a purely academic concern).

Computing the velocity of the points of impact on each object is straightforward. Figuring out how we want to do any mass adjustment for the impacting piece vs. the whole object is less trivial (the old collision code didn't bother and used the whole object mass as if it were present at the point of impact - any number of simplifications could be reasonably applied with respect to effective mass and then adjusted at a later date)

Again, this is something we should eventually be able to create unit testing for by constructing appropriate values for the above example or other simple geometries for which the expected outcomes can be verified.

bug enhancement

All 11 comments

Oh boy a kinematic's issue this is going to be tricky to resolve properly.

The two major and one minor bit will be easy to resolve - computing the inelastic velocity is trivial, as is going between F=ma and deltaV (ignoring numerical integration for the latter). Adding in unit tests to validate this will take more work though.

The old codebase had the point-of-impact velocity calculations, but it never did anything sane with the effective mass. Moreover I doubt that the fundamental VS physics issue of moment of inertia being specified as a scalar (rather than a multidimensional) property was ever upgraded, so I suspect that getting the torques to really be right will require non-trivial work (although a 1st order approximation using implied simple geometries with uniform density shouldn't be too bad to implement) - I'll have to maybe go hit my old physics textbooks again and look at the Step KDE code Loki mentioned on Gitter to see what's been done there and if relevant bits can be extracted.

Step is one of the apps in KDE's educational suite it models springs,linear motion,circular motion on gases and soft bodies. There are a couple examples that are of interest ATM 2.4,8 pendulums and soft body it's been around for a while from what I can see from the docs I have uses Euler's method for 1st order integration.

Looked at the Step code - it's relatively straightforward, but I think we're probably overthinking it a bit for rigid body collisions if we're hunting in other codebases (also, Step uses a scalar moment of inertia, fwiw) -- less so if we start looking at springs and other modeling. I think we'd be reasonably served to observe how some of those models are put together from an organizational (and edge-case checking) perspective

I say we shouldn't have to go digging through other codebases because https://en.wikipedia.org/wiki/Collision_response#Impulse-based_reaction_model has everything we need, given what our collision detection currently gets us ... except an easy means of deriving the 3x3 tensors for moment-of-inertia for all of the elements of the dataset. This would require a tool to A) do the decomposition of meshes into simple geometric approximations and B) combine them into a net moment of inertia tensor, given information about total mass and its expected distribution for a given mesh (the latter of which we could simplify into a small number of fixed cases to specify, e.g. treat a dome mesh as having all its mass in thin layer,, a turret as a uniform density rectangular block, and a thruster or antennae assembly as a non-uniform gradient density block, etc.).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nabaco picture nabaco  路  4Comments

viktorradnai picture viktorradnai  路  3Comments

stephengtuggy picture stephengtuggy  路  5Comments

stephengtuggy picture stephengtuggy  路  5Comments

BenjamenMeyer picture BenjamenMeyer  路  3Comments