1use super::{
9 prepare_distance_joint, prepare_motor_joint, prepare_parallel_joint, prepare_prismatic_joint,
10 prepare_revolute_joint, prepare_spherical_joint, prepare_weld_joint, prepare_wheel_joint,
11 solve_distance_joint, solve_motor_joint, solve_parallel_joint, solve_prismatic_joint,
12 solve_revolute_joint, solve_spherical_joint, solve_weld_joint, solve_wheel_joint,
13 warm_start_distance_joint, warm_start_motor_joint, warm_start_parallel_joint,
14 warm_start_prismatic_joint, warm_start_revolute_joint, warm_start_spherical_joint,
15 warm_start_weld_joint, warm_start_wheel_joint, JointSim, JointType,
16};
17use crate::body::{get_body_transform, BodyState};
18use crate::math_functions::{
19 abs_float, add, cross, length, min_float, mul_add, mul_quat, normalize, rotate_vector, Vec3,
20 VEC3_AXIS_Z,
21};
22use crate::solver::{make_soft, StepContext};
23use crate::world::World;
24
25pub fn prepare_joint(world: &World, base: &mut JointSim, context: &StepContext) {
27 let hertz = min_float(base.constraint_hertz, 0.25 * context.inv_h);
29 base.constraint_softness = make_soft(hertz, base.constraint_damping_ratio, context.h);
30
31 match base.type_ {
32 JointType::Parallel => prepare_parallel_joint(world, base, context),
33 JointType::Distance => prepare_distance_joint(world, base, context),
34 JointType::Filter => {}
35 JointType::Motor => prepare_motor_joint(world, base, context),
36 JointType::Prismatic => prepare_prismatic_joint(world, base, context),
37 JointType::Revolute => prepare_revolute_joint(world, base, context),
38 JointType::Spherical => prepare_spherical_joint(world, base, context),
39 JointType::Weld => prepare_weld_joint(world, base, context),
40 JointType::Wheel => prepare_wheel_joint(world, base, context),
41 }
42}
43
44pub fn warm_start_joint(base: &mut JointSim, states: &mut [BodyState]) {
46 match base.type_ {
47 JointType::Parallel => warm_start_parallel_joint(base, states),
48 JointType::Distance => warm_start_distance_joint(base, states),
49 JointType::Filter => {}
50 JointType::Motor => warm_start_motor_joint(base, states),
51 JointType::Prismatic => warm_start_prismatic_joint(base, states),
52 JointType::Revolute => warm_start_revolute_joint(base, states),
53 JointType::Spherical => warm_start_spherical_joint(base, states),
54 JointType::Weld => warm_start_weld_joint(base, states),
55 JointType::Wheel => warm_start_wheel_joint(base, states),
56 }
57}
58
59pub fn solve_joint(
64 base: &mut JointSim,
65 context: &StepContext,
66 states: &mut [BodyState],
67 use_bias: bool,
68) {
69 let _ = use_bias;
70
71 match base.type_ {
72 JointType::Parallel => solve_parallel_joint(base, context, states),
73 JointType::Distance => solve_distance_joint(base, context, states, use_bias),
74 JointType::Filter => {}
75 JointType::Motor => solve_motor_joint(base, context, states),
76 JointType::Prismatic => solve_prismatic_joint(base, context, states, use_bias),
77 JointType::Revolute => solve_revolute_joint(base, context, states, use_bias),
78 JointType::Spherical => solve_spherical_joint(base, context, states, use_bias),
79 JointType::Weld => solve_weld_joint(base, context, states, use_bias),
80 JointType::Wheel => solve_wheel_joint(base, context, states, use_bias),
81 }
82}
83
84pub fn get_joint_reaction(world: &World, sim: &JointSim, inv_time_step: f32) -> (f32, f32) {
86 let mut linear_impulse = 0.0f32;
87 let mut angular_impulse = 0.0f32;
88
89 match sim.type_ {
90 JointType::Parallel => {
91 let joint = sim.parallel();
92 let impulse = Vec3 {
93 x: joint.perp_impulse.x,
94 y: joint.perp_impulse.y,
95 z: 0.0,
96 };
97 angular_impulse = length(impulse);
98 }
99 JointType::Distance => {
100 let joint = sim.distance();
101 linear_impulse = abs_float(
102 joint.impulse + joint.lower_impulse - joint.upper_impulse + joint.motor_impulse,
103 );
104 }
105 JointType::Motor => {
106 let joint = sim.motor();
107 linear_impulse = length(add(
108 joint.linear_velocity_impulse,
109 joint.linear_spring_impulse,
110 ));
111 angular_impulse = length(add(
112 joint.angular_velocity_impulse,
113 joint.angular_spring_impulse,
114 ));
115 }
116 JointType::Prismatic => {
117 let joint = sim.prismatic();
118 let impulse = Vec3 {
119 x: joint.motor_impulse + joint.lower_impulse - joint.upper_impulse,
120 y: joint.perp_impulse.x,
121 z: joint.perp_impulse.y,
122 };
123 linear_impulse = length(impulse);
124 angular_impulse = length(joint.angular_impulse);
125 }
126 JointType::Revolute => {
127 let joint = sim.revolute();
128 linear_impulse = length(joint.linear_impulse);
129 let impulse = Vec3 {
130 x: joint.perp_impulse.x,
131 y: joint.perp_impulse.y,
132 z: joint.motor_impulse + joint.lower_impulse - joint.upper_impulse,
133 };
134 angular_impulse = length(impulse);
135 }
136 JointType::Spherical => {
137 let joint = sim.spherical();
138 linear_impulse = length(joint.linear_impulse);
139
140 let xf_a = get_body_transform(world, sim.body_id_a);
141 let xf_b = get_body_transform(world, sim.body_id_b);
142 let q_a = mul_quat(xf_a.q, sim.local_frame_a.q);
143 let q_b = mul_quat(xf_b.q, sim.local_frame_b.q);
144
145 let cone_axis = rotate_vector(q_a, VEC3_AXIS_Z);
147 let twist_axis = rotate_vector(q_b, VEC3_AXIS_Z);
148 let swing_axis = normalize(cross(cone_axis, twist_axis));
149
150 let mut impulse = add(joint.spring_impulse, joint.motor_impulse);
151 impulse = mul_add(
152 impulse,
153 joint.lower_twist_impulse - joint.upper_twist_impulse,
154 twist_axis,
155 );
156 impulse = mul_add(impulse, joint.swing_impulse, swing_axis);
157
158 angular_impulse = length(impulse);
159 }
160 JointType::Weld => {
161 let joint = sim.weld();
162 linear_impulse = length(joint.linear_impulse);
163 angular_impulse = length(joint.angular_impulse);
164 }
165 JointType::Wheel => {
166 let joint = sim.wheel();
168 let perp_impulse = joint.linear_impulse;
169 let axial_impulse = joint.suspension_spring_impulse + joint.lower_suspension_impulse
170 - joint.upper_suspension_impulse;
171 linear_impulse = (perp_impulse.x * perp_impulse.x
172 + perp_impulse.y * perp_impulse.y
173 + axial_impulse * axial_impulse)
174 .sqrt();
175 angular_impulse = abs_float(joint.spin_impulse);
176 }
177 JointType::Filter => {}
178 }
179
180 (
181 linear_impulse * inv_time_step,
182 angular_impulse * inv_time_step,
183 )
184}