Collisions for the convex shape
This commit is contained in:
parent
999a7a4631
commit
25ff57168b
@ -35,7 +35,7 @@ esac
|
||||
|
||||
# Build the game.
|
||||
echo "Building game$DLL_EXT"
|
||||
odin build game -extra-linker-flags:"$EXTRA_LINKER_FLAGS" -define:RAYLIB_SHARED=true -define:TRACY_ENABLE=true -collection:libs=./libs -collection:common=./common -collection:game=./game -build-mode:dll -out:game_tmp$DLL_EXT -strict-style -vet -debug
|
||||
odin build game -extra-linker-flags:"$EXTRA_LINKER_FLAGS" -define:RAYLIB_SHARED=true -define:TRACY_ENABLE=true -collection:libs=./libs -collection:common=./common -collection:game=./game -build-mode:dll -out:game_tmp$DLL_EXT -strict-style -vet -debug -o:speed
|
||||
|
||||
# Need to use a temp file on Linux because it first writes an empty `game.so`, which the game will load before it is actually fully written.
|
||||
mv game_tmp$DLL_EXT game$DLL_EXT
|
||||
|
@ -453,6 +453,7 @@ get_convex :: proc(assetman: ^Asset_Manager, path: cstring) -> (result: Loaded_C
|
||||
}
|
||||
}
|
||||
log.infof("inertia tensor: %v", inertia_tensor)
|
||||
inertia_tensor = inertia_tensor * lg.Matrix3f32(1.0 / total_volume)
|
||||
|
||||
return {mesh = mesh, center_of_mass = center_of_mass, inertia_tensor = inertia_tensor}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ Car :: struct {
|
||||
SOLVER_CONFIG :: physics.Solver_Config {
|
||||
timestep = 1.0 / 120,
|
||||
gravity = rl.Vector3{0, -9.8, 0},
|
||||
substreps_minus_one = 2 - 1,
|
||||
substreps_minus_one = 1 - 1,
|
||||
}
|
||||
|
||||
Game_Memory :: struct {
|
||||
@ -246,6 +246,8 @@ update_runtime_world :: proc(runtime_world: ^Runtime_World, dt: f32) {
|
||||
},
|
||||
)
|
||||
|
||||
car_convex := assets.get_convex(&g_mem.assetman, "assets/car_convex.obj")
|
||||
|
||||
runtime_world.car_handle = physics.immediate_body(
|
||||
&world.physics_scene,
|
||||
&runtime_world.solver_state,
|
||||
@ -257,12 +259,16 @@ update_runtime_world :: proc(runtime_world: ^Runtime_World, dt: f32) {
|
||||
rl.Vector3{0, 1, 0},
|
||||
),
|
||||
initial_ang_vel = {0, 0, 0},
|
||||
shape = physics.Shape_Box{size = car_bounds.max - car_bounds.min},
|
||||
shape = physics.Shape_Convex {
|
||||
mesh = car_convex.mesh,
|
||||
center_of_mass = car_convex.center_of_mass,
|
||||
inertia_tensor = auto_cast car_convex.inertia_tensor,
|
||||
},
|
||||
mass = 100,
|
||||
},
|
||||
)
|
||||
|
||||
if false {
|
||||
if true {
|
||||
|
||||
for x in -3 ..< 3 {
|
||||
for y in -3 ..< 3 {
|
||||
@ -271,9 +277,9 @@ update_runtime_world :: proc(runtime_world: ^Runtime_World, dt: f32) {
|
||||
&runtime_world.solver_state,
|
||||
hash.fnv32a(slice.to_bytes([]int{(x | y << 8)})),
|
||||
physics.Body_Config {
|
||||
initial_pos = {f32(x), 5, f32(y)},
|
||||
initial_pos = {f32(x) * 2, 5, f32(y) * 2},
|
||||
initial_rot = linalg.QUATERNIONF32_IDENTITY,
|
||||
shape = physics.Shape_Box{size = 0.5},
|
||||
shape = physics.Shape_Box{size = 1.5},
|
||||
mass = 10,
|
||||
},
|
||||
)
|
||||
@ -302,20 +308,22 @@ update_runtime_world :: proc(runtime_world: ^Runtime_World, dt: f32) {
|
||||
}
|
||||
|
||||
// 1.6 is a good value
|
||||
wheel_extent_x := f32(2)
|
||||
wheel_y := f32(-1)
|
||||
wheel_extent_x := f32(1.7)
|
||||
wheel_y := f32(-0.5)
|
||||
rest := f32(1)
|
||||
suspension_stiffness := f32(2000)
|
||||
compliance := 1.0 / suspension_stiffness
|
||||
damping := f32(0.01)
|
||||
radius := f32(0.6)
|
||||
wheel_front_z := f32(3.05)
|
||||
wheel_back_z := f32(-2.45)
|
||||
|
||||
wheel_fl := physics.immediate_suspension_constraint(
|
||||
&world.physics_scene,
|
||||
&runtime_world.solver_state,
|
||||
#hash("FL", "fnv32a"),
|
||||
{
|
||||
rel_pos = {-wheel_extent_x, wheel_y, 2.9},
|
||||
rel_pos = {-wheel_extent_x, wheel_y, wheel_front_z},
|
||||
rel_dir = {0, -1, 0},
|
||||
radius = radius,
|
||||
rest = rest,
|
||||
@ -329,7 +337,7 @@ update_runtime_world :: proc(runtime_world: ^Runtime_World, dt: f32) {
|
||||
&runtime_world.solver_state,
|
||||
#hash("FR", "fnv32a"),
|
||||
{
|
||||
rel_pos = {wheel_extent_x, wheel_y, 2.9},
|
||||
rel_pos = {wheel_extent_x, wheel_y, wheel_front_z},
|
||||
rel_dir = {0, -1, 0},
|
||||
radius = radius,
|
||||
rest = rest,
|
||||
@ -343,7 +351,7 @@ update_runtime_world :: proc(runtime_world: ^Runtime_World, dt: f32) {
|
||||
&runtime_world.solver_state,
|
||||
#hash("RL", "fnv32a"),
|
||||
{
|
||||
rel_pos = {-wheel_extent_x, wheel_y, -2.6},
|
||||
rel_pos = {-wheel_extent_x, wheel_y, wheel_back_z},
|
||||
rel_dir = {0, -1, 0},
|
||||
radius = radius,
|
||||
rest = rest,
|
||||
@ -357,7 +365,7 @@ update_runtime_world :: proc(runtime_world: ^Runtime_World, dt: f32) {
|
||||
&runtime_world.solver_state,
|
||||
#hash("RR", "fnv32a"),
|
||||
{
|
||||
rel_pos = {wheel_extent_x, wheel_y, -2.6},
|
||||
rel_pos = {wheel_extent_x, wheel_y, wheel_back_z},
|
||||
rel_dir = {0, -1, 0},
|
||||
radius = radius,
|
||||
rest = rest,
|
||||
@ -552,12 +560,6 @@ draw :: proc() {
|
||||
rad = 0.5,
|
||||
}
|
||||
|
||||
car_convex := assets.get_convex(&g_mem.assetman, "assets/car_convex.obj")
|
||||
|
||||
halfedge.debug_draw_mesh_wires(car_convex.mesh, rl.RED)
|
||||
rl.DrawSphereWires(car_convex.mesh.center, 0.0, 8, 8, rl.BLUE)
|
||||
rl.DrawSphereWires(car_convex.center_of_mass, 0.5, 8, 8, rl.RED)
|
||||
|
||||
box1_convex := collision.box_to_convex(box1, context.temp_allocator)
|
||||
box2_convex := collision.box_to_convex(box2, context.temp_allocator)
|
||||
|
||||
@ -617,12 +619,7 @@ draw :: proc() {
|
||||
car_matrix := rl.QuaternionToMatrix(car_body.q)
|
||||
car_model.transform = car_matrix
|
||||
|
||||
rl.DrawModel(
|
||||
car_model,
|
||||
physics.body_local_to_world(car_body, -runtime_world.car_com),
|
||||
1,
|
||||
rl.WHITE,
|
||||
)
|
||||
rl.DrawModel(car_model, physics.body_get_shape_pos(car_body), 1, rl.WHITE)
|
||||
} else {
|
||||
// rl.DrawModel(car_model, 0, 1, rl.WHITE)
|
||||
}
|
||||
|
@ -193,6 +193,24 @@ iterate_next_edge :: proc(
|
||||
|
||||
Vec4 :: [4]f32
|
||||
|
||||
copy_mesh :: proc(
|
||||
mesh: Half_Edge_Mesh,
|
||||
allocator := context.allocator,
|
||||
) -> (
|
||||
result: Half_Edge_Mesh,
|
||||
) {
|
||||
result.center = mesh.center
|
||||
result.vertices = make([]Vertex, len(mesh.vertices), allocator)
|
||||
result.faces = make([]Face, len(mesh.faces), allocator)
|
||||
result.edges = make([]Half_Edge, len(mesh.edges), allocator)
|
||||
|
||||
copy(result.vertices, mesh.vertices)
|
||||
copy(result.faces, mesh.faces)
|
||||
copy(result.edges, mesh.edges)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
transform_mesh :: proc(mesh: ^Half_Edge_Mesh, mat: lg.Matrix4f32) {
|
||||
mesh_center_avg_factor := 1.0 / f32(len(mesh.vertices))
|
||||
new_center: Vec3
|
||||
|
@ -177,8 +177,27 @@ query_separation_edges :: proc(
|
||||
separating_plane_p: Vec3
|
||||
success_step: int
|
||||
|
||||
Edge_Pair :: [2]halfedge.Edge_Index
|
||||
checked_pairs := make(map[Edge_Pair]bool, context.temp_allocator)
|
||||
|
||||
for edge_a, edge_a_idx in a.edges {
|
||||
for edge_b in b.edges {
|
||||
for edge_b, edge_b_idx in b.edges {
|
||||
pair := Edge_Pair{halfedge.Edge_Index(edge_a_idx), halfedge.Edge_Index(edge_b_idx)}
|
||||
if checked_pairs[pair] {
|
||||
continue
|
||||
}
|
||||
|
||||
checked_pairs[pair] = true
|
||||
if edge_a.twin >= 0 {
|
||||
checked_pairs[{edge_a.twin, halfedge.Edge_Index(edge_b_idx)}] = true
|
||||
}
|
||||
if edge_b.twin >= 0 {
|
||||
checked_pairs[{halfedge.Edge_Index(edge_a_idx), edge_b.twin}] = true
|
||||
}
|
||||
if edge_a.twin >= 0 && edge_b.twin >= 0 {
|
||||
checked_pairs[{edge_a.twin, edge_b.twin}] = true
|
||||
}
|
||||
|
||||
edge_a_dir := halfedge.get_edge_direction_normalized(a, edge_a)
|
||||
edge_b_dir := halfedge.get_edge_direction_normalized(b, edge_b)
|
||||
|
||||
|
@ -4,6 +4,7 @@ import "core:log"
|
||||
import "core:math"
|
||||
import lg "core:math/linalg"
|
||||
import "game:debug"
|
||||
import "game:halfedge"
|
||||
import "libs:tracy"
|
||||
import rl "vendor:raylib"
|
||||
import "vendor:raylib/rlgl"
|
||||
@ -18,29 +19,27 @@ draw_debug_shape :: proc(
|
||||
rot: rl.Quaternion,
|
||||
color: rl.Color,
|
||||
) {
|
||||
mat := lg.matrix4_from_trs(pos, rot, 1)
|
||||
|
||||
rlgl.PushMatrix()
|
||||
defer rlgl.PopMatrix()
|
||||
|
||||
rlgl.Begin(rlgl.LINES)
|
||||
defer rlgl.End()
|
||||
rlgl.LoadIdentity()
|
||||
rlgl.MultMatrixf(cast([^]f32)&mat)
|
||||
|
||||
switch s in shape {
|
||||
case Shape_Sphere:
|
||||
rl.DrawSphere(pos, s.radius, color)
|
||||
case Shape_Box:
|
||||
mat := lg.matrix4_from_trs(pos, rot, 1)
|
||||
|
||||
rlgl.LoadIdentity()
|
||||
rlgl.MultMatrixf(cast([^]f32)&mat)
|
||||
|
||||
rl.DrawCubeWiresV(0, s.size, color)
|
||||
rl.DrawCubeV(0, s.size, color)
|
||||
case Shape_Convex:
|
||||
halfedge.debug_draw_mesh_wires(s.mesh, color)
|
||||
}
|
||||
}
|
||||
|
||||
draw_debug_scene :: proc(scene: ^Scene) {
|
||||
tracy.Zone()
|
||||
|
||||
for &body, i in scene.bodies {
|
||||
for _, i in scene.bodies {
|
||||
body := &scene.bodies_slice[i]
|
||||
if body.alive {
|
||||
pos := body.x
|
||||
|
||||
@ -53,7 +52,12 @@ draw_debug_scene :: proc(scene: ^Scene) {
|
||||
rl.DrawLine3D(pos, pos + y, rl.GREEN)
|
||||
rl.DrawLine3D(pos, pos + z, rl.BLUE)
|
||||
|
||||
draw_debug_shape(body.shape, body.x, body.q, debug.int_to_color(i32(i + 1)))
|
||||
draw_debug_shape(
|
||||
body.shape,
|
||||
body_get_shape_pos(body),
|
||||
body.q,
|
||||
debug.int_to_color(i32(i + 2)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,7 +87,7 @@ draw_debug_scene :: proc(scene: ^Scene) {
|
||||
rl.RED,
|
||||
)
|
||||
|
||||
rl.DrawLine3D(wheel_pos, wheel_pos + right * 10, rl.RED)
|
||||
// rl.DrawLine3D(wheel_pos, wheel_pos + right * 10, rl.RED)
|
||||
|
||||
if wheel.hit {
|
||||
// rl.DrawLine3D(
|
||||
@ -99,7 +103,7 @@ draw_debug_scene :: proc(scene: ^Scene) {
|
||||
}
|
||||
}
|
||||
|
||||
if false {
|
||||
if true {
|
||||
for &contact, contact_idx in scene.contact_pairs[:scene.contact_pairs_len] {
|
||||
points_a := contact.manifold.points_a[:contact.manifold.points_len]
|
||||
points_b := contact.manifold.points_b[:contact.manifold.points_len]
|
||||
|
@ -1,6 +1,8 @@
|
||||
package physics
|
||||
|
||||
import "collision"
|
||||
import lg "core:math/linalg"
|
||||
import "game:halfedge"
|
||||
import rl "vendor:raylib"
|
||||
|
||||
inertia_tensor_sphere :: proc(radius: f32) -> (tensor: Matrix3) {
|
||||
@ -23,10 +25,11 @@ inertia_tensor_box :: proc(size: rl.Vector3) -> (tensor: Matrix3) {
|
||||
|
||||
inertia_tensor_collision_shape :: proc(shape: Collision_Shape) -> (tensor: Matrix3) {
|
||||
switch s in shape {
|
||||
case Shape_Sphere:
|
||||
tensor = inertia_tensor_sphere(s.radius)
|
||||
case Shape_Box:
|
||||
tensor = inertia_tensor_box(s.size)
|
||||
case Shape_Convex:
|
||||
// TODO: assuming precomputed
|
||||
tensor = s.inertia_tensor
|
||||
}
|
||||
|
||||
return
|
||||
@ -72,3 +75,38 @@ wheel_get_right_vec :: #force_inline proc(
|
||||
)
|
||||
return body_local_to_world_vec(body, local_right)
|
||||
}
|
||||
|
||||
body_get_shape_offset_local :: proc(body: Body_Ptr) -> (offset: rl.Vector3) {
|
||||
#partial switch s in body.shape {
|
||||
case Shape_Convex:
|
||||
offset = -s.center_of_mass
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Returns the shape's world position
|
||||
// Shape can be offset from COM
|
||||
body_get_shape_pos :: proc(body: Body_Ptr) -> rl.Vector3 {
|
||||
offset := body_get_shape_offset_local(body)
|
||||
return body_local_to_world(body, offset)
|
||||
}
|
||||
|
||||
body_get_convex_shape_world :: proc(
|
||||
body: Body_Ptr,
|
||||
allocator := context.temp_allocator,
|
||||
) -> (
|
||||
mesh: collision.Convex,
|
||||
) {
|
||||
switch s in body.shape {
|
||||
case Shape_Box:
|
||||
mesh = collision.box_to_convex(collision.Box{rad = s.size * 0.5}, allocator)
|
||||
case Shape_Convex:
|
||||
mesh = halfedge.copy_mesh(s.mesh, context.temp_allocator)
|
||||
}
|
||||
|
||||
transform :=
|
||||
lg.matrix4_translate(body_get_shape_pos(body)) * lg.matrix4_from_quaternion(body.q)
|
||||
halfedge.transform_mesh(&mesh, transform)
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package physics
|
||||
|
||||
import "collision"
|
||||
import rl "vendor:raylib"
|
||||
|
||||
MAX_CONTACTS :: 1024
|
||||
@ -49,11 +50,16 @@ Shape_Box :: struct {
|
||||
size: rl.Vector3,
|
||||
}
|
||||
|
||||
Shape_Convex :: struct {}
|
||||
// TODO: Assuming mesh is generated and reinserted every frame for now, make it persistent yada yada
|
||||
Shape_Convex :: struct {
|
||||
mesh: collision.Convex,
|
||||
center_of_mass: rl.Vector3,
|
||||
inertia_tensor: Matrix3,
|
||||
}
|
||||
|
||||
Collision_Shape :: union {
|
||||
Shape_Sphere,
|
||||
Shape_Box,
|
||||
Shape_Convex,
|
||||
}
|
||||
|
||||
Suspension_Constraint :: struct {
|
||||
|
@ -4,7 +4,6 @@ import "collision"
|
||||
import "core:fmt"
|
||||
import "core:math"
|
||||
import lg "core:math/linalg"
|
||||
import "game:halfedge"
|
||||
import "libs:tracy"
|
||||
import rl "vendor:raylib"
|
||||
|
||||
@ -139,27 +138,12 @@ simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
|
||||
if i != j &&
|
||||
body2.alive &&
|
||||
!handled_pairs[{a = min(i, j), b = max(i, j)}] {
|
||||
s1, s2 := body.shape.(Shape_Box), body2.shape.(Shape_Box)
|
||||
|
||||
box1 := collision.box_to_convex(
|
||||
collision.Box{rad = s1.size * 0.5},
|
||||
context.temp_allocator,
|
||||
)
|
||||
box2 := collision.box_to_convex(
|
||||
collision.Box{rad = s2.size * 0.5},
|
||||
context.temp_allocator,
|
||||
)
|
||||
|
||||
mat1 :=
|
||||
lg.matrix4_translate(body.x) * lg.matrix4_from_quaternion(body.q)
|
||||
mat2 :=
|
||||
lg.matrix4_translate(body2.x) * lg.matrix4_from_quaternion(body2.q)
|
||||
|
||||
halfedge.transform_mesh(&box1, mat1)
|
||||
halfedge.transform_mesh(&box2, mat2)
|
||||
m1, m2 :=
|
||||
body_get_convex_shape_world(body),
|
||||
body_get_convex_shape_world(body2)
|
||||
|
||||
// Raw manifold has contact points in world space
|
||||
raw_manifold, collision := collision.convex_vs_convex_sat(box1, box2)
|
||||
raw_manifold, collision := collision.convex_vs_convex_sat(m1, m2)
|
||||
|
||||
if collision {
|
||||
contact_pair := &scene.contact_pairs[scene.contact_pairs_len]
|
||||
@ -327,7 +311,7 @@ simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
|
||||
v_normal := lg.dot(manifold.normal, v) * manifold.normal
|
||||
v_tangent := v - v_normal
|
||||
|
||||
DYNAMIC_FRICTION :: 0.1
|
||||
DYNAMIC_FRICTION :: 0.2
|
||||
v_tangent_len := lg.length(v_tangent)
|
||||
if v_tangent_len > 0 {
|
||||
delta_v :=
|
||||
|
Loading…
x
Reference in New Issue
Block a user