Implement restitution, better hack for static friction
This commit is contained in:
parent
9f6d57b5ea
commit
66f42c3cee
16
assets/cube.obj
Normal file
16
assets/cube.obj
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Blender 3.5.0 Alpha
|
||||||
|
# www.blender.org
|
||||||
|
v 1 1 -1
|
||||||
|
v 1 -1 -1
|
||||||
|
v 1 1 1
|
||||||
|
v 1 -1 1
|
||||||
|
v -1 1 -1
|
||||||
|
v -1 -1 -1
|
||||||
|
v -1 1 1
|
||||||
|
v -1 -1 1
|
||||||
|
f 1 5 7 3
|
||||||
|
f 4 3 7 8
|
||||||
|
f 8 7 5 6
|
||||||
|
f 6 2 4 8
|
||||||
|
f 2 1 3 4
|
||||||
|
f 6 5 1 2
|
@ -67,9 +67,9 @@ Car :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SOLVER_CONFIG :: physics.Solver_Config {
|
SOLVER_CONFIG :: physics.Solver_Config {
|
||||||
timestep = 1.0 / 120,
|
timestep = 1.0 / 60,
|
||||||
gravity = rl.Vector3{0, -9.8, 0},
|
gravity = rl.Vector3{0, -9.8, 0},
|
||||||
substreps_minus_one = 2 - 1,
|
substreps_minus_one = 4 - 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
Game_Memory :: struct {
|
Game_Memory :: struct {
|
||||||
@ -270,14 +270,14 @@ update_runtime_world :: proc(runtime_world: ^Runtime_World, dt: f32) {
|
|||||||
|
|
||||||
if true {
|
if true {
|
||||||
|
|
||||||
for x in -3 ..< 3 {
|
for x in 0 ..< 1 {
|
||||||
for y in -3 ..< 3 {
|
for y in -3 ..< 4 {
|
||||||
physics.immediate_body(
|
physics.immediate_body(
|
||||||
&world.physics_scene,
|
&world.physics_scene,
|
||||||
&runtime_world.solver_state,
|
&runtime_world.solver_state,
|
||||||
hash.fnv32a(slice.to_bytes([]int{(x | y << 8)})),
|
hash.fnv32a(slice.to_bytes([]int{(x | y << 8)})),
|
||||||
physics.Body_Config {
|
physics.Body_Config {
|
||||||
initial_pos = {f32(x) * 3 + 20, 5 + f32(y) * 2, 0},
|
initial_pos = {f32(x) * 3 - 10, 5 + f32(y) * 3, 0},
|
||||||
initial_rot = linalg.QUATERNIONF32_IDENTITY,
|
initial_rot = linalg.QUATERNIONF32_IDENTITY,
|
||||||
shape = physics.Shape_Box{size = 1},
|
shape = physics.Shape_Box{size = 1},
|
||||||
mass = 10,
|
mass = 10,
|
||||||
|
@ -444,7 +444,7 @@ create_face_contact_manifold :: proc(
|
|||||||
for i in 0 ..< vert_count {
|
for i in 0 ..< vert_count {
|
||||||
d := signed_distance_plane(src_polygon[i], ref_plane)
|
d := signed_distance_plane(src_polygon[i], ref_plane)
|
||||||
|
|
||||||
if d <= EPS {
|
if d <= 1e-03 {
|
||||||
clipped_polygon[j] = src_polygon[i] - d * ref_plane.normal
|
clipped_polygon[j] = src_polygon[i] - d * ref_plane.normal
|
||||||
j += 1
|
j += 1
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,8 @@ simulate :: proc(scene: ^Scene, state: ^Solver_State, config: Solver_Config, dt:
|
|||||||
|
|
||||||
Body_Sim_State :: struct {
|
Body_Sim_State :: struct {
|
||||||
prev_x: rl.Vector3,
|
prev_x: rl.Vector3,
|
||||||
|
prev_v: rl.Vector3,
|
||||||
|
prev_w: rl.Vector3,
|
||||||
prev_q: rl.Quaternion,
|
prev_q: rl.Quaternion,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,13 +79,15 @@ GLOBAL_PLANE :: collision.Plane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Contact_Pair :: struct {
|
Contact_Pair :: struct {
|
||||||
a, b: Body_Handle,
|
a, b: Body_Handle,
|
||||||
prev_x_a, prev_x_b: rl.Vector3,
|
prev_x_a, prev_x_b: rl.Vector3,
|
||||||
prev_q_a, prev_q_b: rl.Quaternion,
|
prev_q_a, prev_q_b: rl.Quaternion,
|
||||||
manifold: collision.Contact_Manifold,
|
manifold: collision.Contact_Manifold,
|
||||||
applied_corrections: int,
|
applied_corrections: int,
|
||||||
lambda_normal: [4]f32,
|
lambda_normal: [4]f32,
|
||||||
lambda_tangent: [4]f32,
|
lambda_tangent: [4]f32,
|
||||||
|
applied_static_friction: [4]bool,
|
||||||
|
applied_normal_correction: [4]f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
|
simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
|
||||||
@ -103,11 +107,13 @@ simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
|
|||||||
for &body, i in scene.bodies {
|
for &body, i in scene.bodies {
|
||||||
if body.alive {
|
if body.alive {
|
||||||
body_states[i].prev_x = body.x
|
body_states[i].prev_x = body.x
|
||||||
|
body_states[i].prev_v = body.v
|
||||||
|
body_states[i].prev_w = body.w
|
||||||
|
body_states[i].prev_q = body.q
|
||||||
|
|
||||||
body.v += config.gravity * dt * (body.inv_mass == 0 ? 0 : 1) // special case for gravity, TODO
|
body.v += config.gravity * dt * (body.inv_mass == 0 ? 0 : 1) // special case for gravity, TODO
|
||||||
body.x += body.v * dt
|
body.x += body.v * dt
|
||||||
|
|
||||||
body_states[i].prev_q = body.q
|
|
||||||
|
|
||||||
// NOTE: figure out how this works https://fgiesen.wordpress.com/2012/08/24/quaternion-differentiation/
|
// NOTE: figure out how this works https://fgiesen.wordpress.com/2012/08/24/quaternion-differentiation/
|
||||||
q := body.q
|
q := body.q
|
||||||
|
|
||||||
@ -197,6 +203,8 @@ simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
|
|||||||
p2,
|
p2,
|
||||||
)
|
)
|
||||||
if ok {
|
if ok {
|
||||||
|
contact_pair.applied_normal_correction[point_idx] =
|
||||||
|
-separation
|
||||||
contact_pair.applied_corrections += 1
|
contact_pair.applied_corrections += 1
|
||||||
contact_pair.lambda_normal[point_idx] = lambda_norm
|
contact_pair.lambda_normal[point_idx] = lambda_norm
|
||||||
|
|
||||||
@ -214,8 +222,7 @@ simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
|
|||||||
{
|
{
|
||||||
tracy.ZoneN("simulate_step::static_friction")
|
tracy.ZoneN("simulate_step::static_friction")
|
||||||
|
|
||||||
if true {
|
if false {
|
||||||
|
|
||||||
context = context
|
context = context
|
||||||
context.user_ptr = scene
|
context.user_ptr = scene
|
||||||
slice.sort_by(
|
slice.sort_by(
|
||||||
@ -253,9 +260,7 @@ simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
|
|||||||
body, body2 := get_body(scene, contact_pair.a), get_body(scene, contact_pair.b)
|
body, body2 := get_body(scene, contact_pair.a), get_body(scene, contact_pair.b)
|
||||||
i, j := int(contact_pair.a) - 1, int(contact_pair.b) - 1
|
i, j := int(contact_pair.a) - 1, int(contact_pair.b) - 1
|
||||||
|
|
||||||
lambda_tangent: f32
|
|
||||||
for point_idx in 0 ..< manifold.points_len {
|
for point_idx in 0 ..< manifold.points_len {
|
||||||
|
|
||||||
lambda_norm := contact_pair.lambda_normal[point_idx]
|
lambda_norm := contact_pair.lambda_normal[point_idx]
|
||||||
if lambda_norm != 0 {
|
if lambda_norm != 0 {
|
||||||
p1 := body_local_to_world(body, manifold.points_a[point_idx])
|
p1 := body_local_to_world(body, manifold.points_a[point_idx])
|
||||||
@ -287,18 +292,17 @@ simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
|
|||||||
body,
|
body,
|
||||||
body2,
|
body2,
|
||||||
0,
|
0,
|
||||||
-tangent_diff_len / f32(contact_pair.applied_corrections),
|
-tangent_diff_len / max(f32(contact_pair.applied_corrections) * 0.5, 1),
|
||||||
-tangent_diff_normalized,
|
-tangent_diff_normalized,
|
||||||
p1,
|
p1,
|
||||||
p2,
|
p2,
|
||||||
)
|
)
|
||||||
contact_pair.lambda_tangent[point_idx] = lambda_tangent
|
|
||||||
|
|
||||||
new_lambda_tangent := lambda_tangent + delta_lambda_tangent
|
STATIC_FRICTION :: 0.6
|
||||||
|
|
||||||
STATIC_FRICTION :: 0.7
|
|
||||||
if ok_tangent && delta_lambda_tangent < STATIC_FRICTION * lambda_norm {
|
if ok_tangent && delta_lambda_tangent < STATIC_FRICTION * lambda_norm {
|
||||||
lambda_tangent = new_lambda_tangent
|
contact_pair.applied_static_friction[point_idx] = true
|
||||||
|
contact_pair.lambda_tangent[point_idx] = delta_lambda_tangent
|
||||||
|
|
||||||
apply_correction(body, corr1_tangent, p1)
|
apply_correction(body, corr1_tangent, p1)
|
||||||
apply_correction(body2, corr2_tangent, p2)
|
apply_correction(body2, corr2_tangent, p2)
|
||||||
}
|
}
|
||||||
@ -343,6 +347,69 @@ simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
|
|||||||
|
|
||||||
solve_velocities(scene, body_states, inv_dt)
|
solve_velocities(scene, body_states, inv_dt)
|
||||||
|
|
||||||
|
// Restituion
|
||||||
|
{
|
||||||
|
tracy.ZoneN("simulate_step::restitution")
|
||||||
|
|
||||||
|
for &pair in scene.contact_pairs[:scene.contact_pairs_len] {
|
||||||
|
i, j := int(pair.a) - 1, int(pair.b) - 1
|
||||||
|
manifold := &pair.manifold
|
||||||
|
|
||||||
|
body, body2 := get_body(scene, pair.a), get_body(scene, pair.b)
|
||||||
|
s1, s2 := body_states[i], body_states[j]
|
||||||
|
prev_q1, prev_q2 := s1.prev_q, s2.prev_q
|
||||||
|
|
||||||
|
for point_idx in 0..<manifold.points_len {
|
||||||
|
if pair.lambda_normal == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
prev_r1 :=
|
||||||
|
lg.quaternion_mul_vector3(
|
||||||
|
prev_q1,
|
||||||
|
manifold.points_a[point_idx],
|
||||||
|
)
|
||||||
|
prev_r2 :=
|
||||||
|
lg.quaternion_mul_vector3(
|
||||||
|
prev_q2,
|
||||||
|
manifold.points_b[point_idx],
|
||||||
|
)
|
||||||
|
|
||||||
|
r1 := lg.quaternion_mul_vector3(body.q, manifold.points_a[point_idx])
|
||||||
|
r2 := lg.quaternion_mul_vector3(body2.q, manifold.points_b[point_idx])
|
||||||
|
|
||||||
|
prev_v := (s1.prev_v + lg.cross(s1.prev_w, prev_r1)) - (s2.prev_v + lg.cross(s2.prev_w, prev_r2))
|
||||||
|
v := (body.v + lg.cross(body.w, r1)) - (body2.v + lg.cross(body2.w, r2))
|
||||||
|
|
||||||
|
prev_v_normal := lg.dot(prev_v, manifold.normal)
|
||||||
|
v_normal := lg.dot(v, manifold.normal)
|
||||||
|
|
||||||
|
RESTITUTION :: 0.5
|
||||||
|
|
||||||
|
restitution := f32(RESTITUTION)
|
||||||
|
|
||||||
|
if abs(v_normal) <= 2 * abs(lg.dot(manifold.normal, -config.gravity) * dt) {
|
||||||
|
restitution = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
delta_v := manifold.normal * (-v_normal + min(-RESTITUTION * prev_v_normal, 0))
|
||||||
|
|
||||||
|
w1 := get_body_inverse_mass(body, manifold.normal, r1 + body.x)
|
||||||
|
w2 := get_body_inverse_mass(body2, manifold.normal, r2 + body.x)
|
||||||
|
w := w1 + w2
|
||||||
|
|
||||||
|
if w != 0 {
|
||||||
|
p := delta_v / w
|
||||||
|
|
||||||
|
body.v += p * body.inv_mass
|
||||||
|
body2.v -= p * body2.inv_mass
|
||||||
|
|
||||||
|
body.w += multiply_inv_intertia(body, lg.cross(r1, p))
|
||||||
|
body2.w -= multiply_inv_intertia(body2, lg.cross(r2, p))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if true {
|
if true {
|
||||||
tracy.ZoneN("simulate_step::dynamic_friction")
|
tracy.ZoneN("simulate_step::dynamic_friction")
|
||||||
|
|
||||||
@ -352,6 +419,9 @@ simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
|
|||||||
body2 := get_body(scene, pair.b)
|
body2 := get_body(scene, pair.b)
|
||||||
|
|
||||||
for point_idx in 0 ..< pair.manifold.points_len {
|
for point_idx in 0 ..< pair.manifold.points_len {
|
||||||
|
if pair.applied_static_friction[point_idx] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
p1, p2 :=
|
p1, p2 :=
|
||||||
body_local_to_world(body1, manifold.points_a[point_idx]),
|
body_local_to_world(body1, manifold.points_a[point_idx]),
|
||||||
body_local_to_world(body2, manifold.points_b[point_idx])
|
body_local_to_world(body2, manifold.points_b[point_idx])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user