Remove unnecessary rl dependency in physics engine

This commit is contained in:
sergeypdev 2025-03-01 13:30:25 +04:00
parent c2b831a4d6
commit c91018fec8
5 changed files with 90 additions and 78 deletions

View File

@ -16,8 +16,8 @@ _ :: debug
draw_debug_shape :: proc(
sim_state: ^Sim_State,
shape: Collision_Shape,
pos: rl.Vector3,
rot: rl.Quaternion,
pos: Vec3,
rot: Quat,
color: rl.Color,
) {
mat := lg.matrix4_from_trs(pos, rot, 1)
@ -48,9 +48,9 @@ draw_debug_scene :: proc(scene: ^Scene) {
pos := body.x
q := body.q
x := lg.quaternion_mul_vector3(q, rl.Vector3{1, 0, 0})
y := lg.quaternion_mul_vector3(q, rl.Vector3{0, 1, 0})
z := lg.quaternion_mul_vector3(q, rl.Vector3{0, 0, 1})
x := lg.quaternion_mul_vector3(q, Vec3{1, 0, 0})
y := lg.quaternion_mul_vector3(q, Vec3{0, 1, 0})
z := lg.quaternion_mul_vector3(q, Vec3{0, 0, 1})
rl.DrawLine3D(pos, pos + x, rl.RED)
rl.DrawLine3D(pos, pos + y, rl.GREEN)
@ -130,13 +130,13 @@ draw_debug_scene :: proc(scene: ^Scene) {
}
}
debug_transform_points_local_to_world :: proc(body: Body_Ptr, points: []rl.Vector3) {
debug_transform_points_local_to_world :: proc(body: Body_Ptr, points: []Vec3) {
for i in 0 ..< len(points) {
points[i] = body_local_to_world(body, points[i])
}
}
debug_draw_manifold_points :: proc(normal: rl.Vector3, points: []rl.Vector3, color: rl.Color) {
debug_draw_manifold_points :: proc(normal: Vec3, points: []Vec3, color: rl.Color) {
if len(points) >= 3 {
// Triangle or quad
v1 := points[0]

View File

@ -3,7 +3,6 @@ package physics
import "collision"
import lg "core:math/linalg"
import "game:halfedge"
import rl "vendor:raylib"
inertia_tensor_sphere :: proc(radius: f32) -> (tensor: Matrix3) {
tensor = radius * radius * (2.0 / 3.0)
@ -11,7 +10,7 @@ inertia_tensor_sphere :: proc(radius: f32) -> (tensor: Matrix3) {
return
}
inertia_tensor_box :: proc(size: rl.Vector3) -> (tensor: Matrix3) {
inertia_tensor_box :: proc(size: Vec3) -> (tensor: Matrix3) {
CONSTANT :: f32(1.0 / 12.0)
tensor[0][0] = size.z * size.z + size.y * size.y
@ -35,32 +34,32 @@ inertia_tensor_collision_shape :: proc(shape: Input_Shape) -> (tensor: Matrix3)
return
}
body_local_to_world :: #force_inline proc(body: Body_Ptr, pos: rl.Vector3) -> rl.Vector3 {
body_local_to_world :: #force_inline proc(body: Body_Ptr, pos: Vec3) -> Vec3 {
return body.x + lg.quaternion_mul_vector3(body.q, pos)
}
body_local_to_world_vec :: #force_inline proc(body: Body_Ptr, vec: rl.Vector3) -> rl.Vector3 {
body_local_to_world_vec :: #force_inline proc(body: Body_Ptr, vec: Vec3) -> Vec3 {
return lg.normalize0(lg.quaternion_mul_vector3(body.q, vec))
}
body_world_to_local :: #force_inline proc(body: Body_Ptr, pos: rl.Vector3) -> rl.Vector3 {
body_world_to_local :: #force_inline proc(body: Body_Ptr, pos: Vec3) -> Vec3 {
inv_q := lg.quaternion_normalize0(lg.quaternion_inverse(body.q))
return lg.quaternion_mul_vector3(inv_q, pos - body.x)
}
body_world_to_local_vec :: #force_inline proc(body: Body_Ptr, vec: rl.Vector3) -> rl.Vector3 {
body_world_to_local_vec :: #force_inline proc(body: Body_Ptr, vec: Vec3) -> Vec3 {
inv_q := lg.quaternion_inverse(body.q)
return lg.normalize0(lg.quaternion_mul_vector3(inv_q, vec))
}
body_velocity_at_point :: #force_inline proc(body: Body_Ptr, pos: rl.Vector3) -> rl.Vector3 {
body_velocity_at_point :: #force_inline proc(body: Body_Ptr, pos: Vec3) -> Vec3 {
return body.v + lg.cross(body.w, pos - body.x)
}
wheel_get_rel_wheel_pos :: #force_inline proc(
body: Body_Ptr,
wheel: Suspension_Constraint_Ptr,
) -> rl.Vector3 {
) -> Vec3 {
t := wheel.hit_t > 0 ? wheel.hit_t : wheel.rest
return wheel.rel_pos + wheel.rel_dir * (t - wheel.radius)
}
@ -68,15 +67,15 @@ wheel_get_rel_wheel_pos :: #force_inline proc(
wheel_get_right_vec :: #force_inline proc(
body: Body_Ptr,
wheel: Suspension_Constraint_Ptr,
) -> rl.Vector3 {
) -> Vec3 {
local_right := lg.quaternion_mul_vector3(
lg.quaternion_angle_axis(wheel.turn_angle, rl.Vector3{0, 1, 0}),
rl.Vector3{1, 0, 0},
lg.quaternion_angle_axis(wheel.turn_angle, Vec3{0, 1, 0}),
Vec3{1, 0, 0},
)
return body_local_to_world_vec(body, local_right)
}
body_get_shape_offset_local :: proc(body: Body_Ptr) -> (offset: rl.Vector3) {
body_get_shape_offset_local :: proc(body: Body_Ptr) -> (offset: Vec3) {
#partial switch s in body.shape {
case Internal_Shape_Convex:
offset = -s.center_of_mass
@ -86,7 +85,7 @@ body_get_shape_offset_local :: proc(body: Body_Ptr) -> (offset: rl.Vector3) {
// Returns the shape's world position
// Shape can be offset from COM
body_get_shape_pos :: proc(body: Body_Ptr) -> rl.Vector3 {
body_get_shape_pos :: proc(body: Body_Ptr) -> Vec3 {
offset := body_get_shape_offset_local(body)
return body_local_to_world(body, offset)
}

View File

@ -2,10 +2,11 @@ package physics
import "collision"
import lg "core:math/linalg"
import rl "vendor:raylib"
MAX_CONTACTS :: 1024
Vec3 :: [3]f32
Quat :: quaternion128
Matrix3 :: # row_major matrix[3, 3]f32
Sim_State :: struct {
@ -37,13 +38,13 @@ Body :: struct {
// Is this body alive (if not it doesn't exist)
alive: bool,
// Pos
x: rl.Vector3,
x: Vec3,
// Linear vel
v: rl.Vector3,
v: Vec3,
// Orientation
q: rl.Quaternion,
q: Quat,
// Angular vel (omega)
w: rl.Vector3,
w: Vec3,
// Mass
inv_mass: f32,
// Moment of inertia
@ -58,18 +59,18 @@ Shape_Sphere :: struct {
}
Shape_Box :: struct {
size: rl.Vector3,
size: Vec3,
}
Internal_Shape_Convex :: struct {
mesh: Convex_Handle,
center_of_mass: rl.Vector3,
center_of_mass: Vec3,
inertia_tensor: Matrix3,
}
Shape_Convex :: struct {
mesh: collision.Convex,
center_of_mass: rl.Vector3,
center_of_mass: Vec3,
inertia_tensor: Matrix3,
}
@ -81,9 +82,9 @@ Collision_Shape :: union {
Suspension_Constraint :: struct {
alive: bool,
// Pos relative to the body
rel_pos: rl.Vector3,
rel_pos: Vec3,
// Dir relative to the body
rel_dir: rl.Vector3,
rel_dir: Vec3,
// Handle of the rigid body
body: Body_Handle,
// Wheel radius
@ -97,13 +98,13 @@ Suspension_Constraint :: struct {
// Runtime state
hit: bool,
hit_point: rl.Vector3,
hit_point: Vec3,
// rel_hit_point = rel_pos + rel_dir * hit_t
hit_t: f32,
turn_angle: f32,
drive_impulse: f32,
brake_impulse: f32,
applied_impulse: rl.Vector3,
applied_impulse: Vec3,
// Free list
next_plus_one: i32,
@ -149,11 +150,14 @@ get_prev_sim_state :: proc(scene: ^Scene) -> ^Sim_State {
}
get_next_sim_state :: proc(scene: ^Scene) -> ^Sim_State {
return &scene.simulation_states[(scene.simulation_state_index + 1) %% i32(len(scene.simulation_states))]
return(
&scene.simulation_states[(scene.simulation_state_index + 1) %% i32(len(scene.simulation_states))] \
)
}
flip_sim_state :: proc(scene: ^Scene) {
scene.simulation_state_index = (scene.simulation_state_index + 1) %% i32(len(scene.simulation_states))
scene.simulation_state_index =
(scene.simulation_state_index + 1) %% i32(len(scene.simulation_states))
}
/// Returns pointer to soa slice. NEVER STORE IT
@ -180,10 +184,10 @@ Input_Shape :: union {
}
Body_Config :: struct {
initial_pos: rl.Vector3,
initial_rot: rl.Quaternion,
initial_vel: rl.Vector3,
initial_ang_vel: rl.Vector3,
initial_pos: Vec3,
initial_rot: Quat,
initial_vel: Vec3,
initial_ang_vel: Vec3,
shape: Input_Shape,
mass: f32,
inertia_mode: Body_Config_Inertia_Mode,
@ -193,8 +197,8 @@ Body_Config :: struct {
// TODO: rename to wheel
Suspension_Constraint_Config :: struct {
rel_pos: rl.Vector3,
rel_dir: rl.Vector3,
rel_pos: Vec3,
rel_dir: Vec3,
body: Body_Handle,
rest: f32,
compliance: f32,

View File

@ -1,21 +1,26 @@
package physics
import he "game:halfedge"
import "game:container/spanpool"
import he "game:halfedge"
Convex_Container :: struct {
vertices: spanpool.Span_Pool(he.Vertex),
faces: spanpool.Span_Pool(he.Face),
edges: spanpool.Span_Pool(he.Half_Edge),
faces: spanpool.Span_Pool(he.Face),
edges: spanpool.Span_Pool(he.Half_Edge),
}
Convex_Handle :: struct {
vertices: spanpool.Handle,
faces: spanpool.Handle,
edges: spanpool.Handle,
faces: spanpool.Handle,
edges: spanpool.Handle,
}
convex_container_add :: proc(container: ^Convex_Container, mesh: he.Half_Edge_Mesh) -> (handle: Convex_Handle) {
convex_container_add :: proc(
container: ^Convex_Container,
mesh: he.Half_Edge_Mesh,
) -> (
handle: Convex_Handle,
) {
handle.vertices = spanpool.allocate_elems(&container.vertices, ..mesh.vertices)
handle.faces = spanpool.allocate_elems(&container.faces, ..mesh.faces)
handle.edges = spanpool.allocate_elems(&container.edges, ..mesh.edges)
@ -23,7 +28,12 @@ convex_container_add :: proc(container: ^Convex_Container, mesh: he.Half_Edge_Me
return
}
convex_container_get_mesh :: proc(container: ^Convex_Container, handle: Convex_Handle) -> (mesh: he.Half_Edge_Mesh) {
convex_container_get_mesh :: proc(
container: ^Convex_Container,
handle: Convex_Handle,
) -> (
mesh: he.Half_Edge_Mesh,
) {
mesh.vertices = spanpool.resolve_slice(&container.vertices, handle.vertices)
mesh.faces = spanpool.resolve_slice(&container.faces, handle.faces)
mesh.edges = spanpool.resolve_slice(&container.edges, handle.edges)
@ -86,7 +96,7 @@ convex_container_destroy :: proc(container: ^Convex_Container) {
// }
//
// box_to_convex :: proc(box: Shape_Box, allocator := context.allocator) -> (convex: Shape_Convex) {
// vertices := make([]rl.Vector3, 8, context.temp_allocator)
// vertices := make([]Vec3, 8, context.temp_allocator)
//
// for corner, i in BOX_CORNERS_NORM {
// vertices[i] = corner * box.size
@ -98,7 +108,7 @@ convex_container_destroy :: proc(container: ^Convex_Container) {
// }
//
// Shape_Box :: struct {
// size: rl.Vector3,
// size: Vec3,
// }
//
// Shape_Union :: struct {
@ -112,8 +122,8 @@ convex_container_destroy :: proc(container: ^Convex_Container) {
// }
//
// Shape_Instance :: struct {
// pos: rl.Vector3,
// rot: rl.Quaternion,
// pos: Vec3,
// rot: Quat,
// shape: Shape_Variant,
// }
//
@ -128,8 +138,8 @@ convex_container_destroy :: proc(container: ^Convex_Container) {
// }
//
// Shape_Desc :: struct {
// pos: rl.Vector3,
// rot: rl.Quaternion,
// pos: Vec3,
// rot: Quat,
// shape: Shape_Desc_Variant,
// using link: list.Node,
// }

View File

@ -6,7 +6,6 @@ import "core:math"
import lg "core:math/linalg"
import "core:slice"
import "libs:tracy"
import rl "vendor:raylib"
_ :: math
_ :: fmt
@ -14,7 +13,7 @@ _ :: fmt
Solver_Config :: struct {
// Will automatically do fixed timestep
timestep: f32,
gravity: rl.Vector3,
gravity: Vec3,
substreps_minus_one: i32,
}
@ -117,21 +116,21 @@ simulate :: proc(
}
Body_Sim_State :: struct {
prev_x: rl.Vector3,
prev_v: rl.Vector3,
prev_w: rl.Vector3,
prev_q: rl.Quaternion,
prev_x: Vec3,
prev_v: Vec3,
prev_w: Vec3,
prev_q: Quat,
}
GLOBAL_PLANE :: collision.Plane {
normal = rl.Vector3{0, 1, 0},
normal = Vec3{0, 1, 0},
dist = 0,
}
Contact_Pair :: struct {
a, b: Body_Handle,
prev_x_a, prev_x_b: rl.Vector3,
prev_q_a, prev_q_b: rl.Quaternion,
prev_x_a, prev_x_b: Vec3,
prev_q_a, prev_q_b: Quat,
manifold: collision.Contact_Manifold,
applied_corrections: int,
lambda_normal: [4]f32,
@ -552,7 +551,7 @@ simulate_step :: proc(sim_state: ^Sim_State, config: Solver_Config) {
// Drive forces
if true {
total_impulse := v.drive_impulse - v.brake_impulse
forward := body_local_to_world_vec(body, rl.Vector3{0, 0, 1})
forward := body_local_to_world_vec(body, Vec3{0, 0, 1})
_ = apply_constraint_correction_unilateral(
dt,
@ -600,7 +599,7 @@ body_solve_velocity :: #force_inline proc(body: Body_Ptr, state: Body_Sim_State,
body.v = (body.x - state.prev_x) * inv_dt
delta_q := body.q * lg.quaternion_inverse(state.prev_q)
body.w = rl.Vector3{delta_q.x, delta_q.y, delta_q.z} * 2.0 * inv_dt
body.w = Vec3{delta_q.x, delta_q.y, delta_q.z} * 2.0 * inv_dt
if delta_q.w < 0 {
body.w = -body.w
@ -612,13 +611,13 @@ calculate_constraint_params1 :: proc(
body: Body_Ptr,
compliance: f32,
error: f32,
error_gradient: rl.Vector3,
pos: rl.Vector3,
error_gradient: Vec3,
pos: Vec3,
other_combined_inv_mass: f32,
) -> (
lambda: f32,
w: f32,
correction: rl.Vector3,
correction: Vec3,
ok: bool,
) {
if error == 0 {
@ -647,13 +646,13 @@ calculate_constraint_params2 :: proc(
body2: Body_Ptr,
compliance: f32,
error: f32,
error_gradient: rl.Vector3,
pos1: rl.Vector3,
pos2: rl.Vector3,
error_gradient: Vec3,
pos1: Vec3,
pos2: Vec3,
) -> (
lambda: f32,
correction1: rl.Vector3,
correction2: rl.Vector3,
correction1: Vec3,
correction2: Vec3,
ok: bool,
) {
if error == 0 {
@ -682,14 +681,14 @@ apply_constraint_correction_unilateral :: proc(
body: Body_Ptr,
compliance: f32,
error: f32,
error_gradient: rl.Vector3,
pos: rl.Vector3,
error_gradient: Vec3,
pos: Vec3,
other_combined_inv_mass: f32 = 0,
) -> (
lambda: f32,
) {
w: f32
correction: rl.Vector3
correction: Vec3
ok: bool
lambda, w, correction, ok = calculate_constraint_params1(
dt,
@ -708,7 +707,7 @@ apply_constraint_correction_unilateral :: proc(
return
}
multiply_inv_intertia :: proc(body: Body_Ptr, vec: rl.Vector3) -> (result: rl.Vector3) {
multiply_inv_intertia :: proc(body: Body_Ptr, vec: Vec3) -> (result: Vec3) {
q := body.q
inv_q := lg.quaternion_normalize0(lg.quaternion_inverse(q))
@ -719,7 +718,7 @@ multiply_inv_intertia :: proc(body: Body_Ptr, vec: rl.Vector3) -> (result: rl.Ve
return result
}
apply_correction :: proc(body: Body_Ptr, corr: rl.Vector3, pos: rl.Vector3) {
apply_correction :: proc(body: Body_Ptr, corr: Vec3, pos: Vec3) {
// rl.DrawSphereWires(pos, 0.5, 4, 4, rl.BLUE)
// rl.DrawLine3D(pos, pos + corr, rl.BLUE)
@ -744,7 +743,7 @@ apply_correction :: proc(body: Body_Ptr, corr: rl.Vector3, pos: rl.Vector3) {
body.q = q
}
get_body_inverse_mass :: proc(body: Body_Ptr, normal, pos: rl.Vector3) -> f32 {
get_body_inverse_mass :: proc(body: Body_Ptr, normal, pos: Vec3) -> f32 {
q := body.q
inv_q := lg.quaternion_normalize0(lg.quaternion_inverse(q))