/apps/demos/scenery: drift ! steer !

This commit is contained in:
veclavtalica 2025-03-05 05:26:05 +03:00
parent f90b973d86
commit 787977b747
2 changed files with 63 additions and 20 deletions

View File

@ -65,6 +65,7 @@ static float heightmap[TERRAIN_DISTANCE][TERRAIN_DISTANCE];
#define VEHICLE_SPRING_GC 100.0f
#define VEHICLE_FRICTION_S 1000.0f
#define VEHICLE_FRICTION_K 100.0f
#define VEHICLE_FRICTION_V 4000.0f
/* TODO: shock springs, that are more loose, which are used to simulate the wheels */
/* initial, ideal corner positions */
@ -97,7 +98,10 @@ static uint8_t vbs[28][2] = {
{0, 6}, {1, 7}, {2, 4}, {3, 5},
};
/* ackermann steering geometry */
static float vehicle_turning_extend;
static float vehicle_turning_speed = 0.12f;
static float vehicle_turning_extend_limit = VEHICLE_WIDTH * 1.75f;
static float height_at(SceneIngame *scn, Vec2 position);
static Vec3 normal_at(SceneIngame *scn, Vec2 position);
@ -117,6 +121,15 @@ static void process_vehicle(SceneIngame *scn) {
/* apply gravity */
Vec3 Facc[8] = {0};
/* steering */
if (input_action_pressed("player_left"))
vehicle_turning_extend -= vehicle_turning_speed;
if (input_action_pressed("player_right"))
vehicle_turning_extend += vehicle_turning_speed;
vehicle_turning_extend = clampf(vehicle_turning_extend, -vehicle_turning_extend_limit, vehicle_turning_extend_limit);
Vec3 const Fg = { .y = -VEHICLE_MASS * G_CONST };
for (size_t i = 0; i < 8; ++i)
Facc[i] = vec3_add(Facc[i], Fg);
@ -144,12 +157,15 @@ static void process_vehicle(SceneIngame *scn) {
Vec3 const v = vbv[i];
float const h = height_at(scn, (Vec2){ p.x, p.z });
if (h >= p.y) {
/* wheel processing */
/* back wheel processing: acceleration */
if (i == 0 || i == 3 || i == 4 || i == 7) {
if (scn->camera_mode == 2 && input_action_pressed("player_forward")) {
Vec3 dir = i == 0 ? vec3_sub(vbp[1], vbp[0]) : vec3_sub(vbp[2], vbp[3]);
Facc[i] = vec3_add(Facc[i], vec3_scale(vec3_norm(dir), 6500));
}
float scale = 0;
if (scn->camera_mode == 2 && input_action_pressed("player_forward"))
scale += 1;
if (scn->camera_mode == 2 && input_action_pressed("player_backward"))
scale -= 1;
Vec3 const dir = vec3_sub(vbp[1], vbp[0]);
Facc[i] = vec3_add(Facc[i], vec3_scale(vec3_norm(dir), 6500 * scale));
}
/* normal force, for displacement */
@ -162,43 +178,66 @@ static void process_vehicle(SceneIngame *scn) {
/* friction force, perpendicular to normal force */
/* TODO: is it right? aren't vn+vol should be = |v| */
Vec3 const von = vec3_norm(vec3_cross(n, vec3_cross(v, n)));
draw_line_3d(vbp[i], vec3_add(vbp[i], von), 1, (Color){255,255,0,255});
Vec3 const vo = vec3_scale(vec3_scale(von, vec3_length(v) - vn), -1);
float const vol = vec3_length(vo);
Vec3 const Fon = vec3_norm(vec3_cross(n, vec3_cross(Facc[i], n)));
Vec3 Fo = vec3_scale(vec3_scale(Fon, vec3_length(Facc[i]) - vec3_dot(Facc[i], n)), -1);
draw_line_3d(vbp[i], vec3_add(vbp[i], Fon), 1, (Color){255,255,0,255});
/* portion of total force along the surface */
float const Fol = vec3_length(Fo);
float const fkxn = VEHICLE_FRICTION_K * xn;
/* at rest, might want to start moving */
if (fabsf(0.0f - vol) <= 0.0001f) {
/* cannot overcome static friction, force along the surface is zeroed */
if (Fol <= VEHICLE_FRICTION_S * xn) {log_info("test 0"); Fo = vec3_scale(Fo, -1);}
if (Fol <= VEHICLE_FRICTION_S * xn) { Fo = vec3_scale(Fo, -1);}
/* resist the force by friction, while starting to move */
else {log_info("test 1"); Fo = vec3_sub(Fo, vec3_scale(von, fkxn));}
else { Fo = vec3_sub(Fo, vec3_scale(von, fkxn));}
/* not at rest, stop accelerating along the surface */
} else if (vol + (Fol / VEHICLE_MASS) * ctx.frame_duration <= fkxn * ctx.frame_duration * 2) {
/* ugh ... */
vbv[i] = vec3_add(vbv[i], vo);
log_info("test 2");
/* just apply friction */
} else {
Fo = vec3_scale(von, -fkxn * 400);
}
Facc[i] = vec3_add(Facc[i], Fo);
// Facc[i] = vec3_sub(Fo, Fn);
// Facc[i] = vec3_sub(Fo, Fn);
Vec3 vd = vec3_scale(vec3_scale(Facc[i], (1.0f / VEHICLE_MASS)), ctx.frame_duration);
vbv[i] = vec3_add(vbv[i], vd);
vbp[i] = vec3_add(vbp[i], vec3_scale(vbv[i], ctx.frame_duration));
/* front wheel processing */
if (i == 1 || i == 5 || i == 2 || i == 6) {
/* steering influences "center of turning", which is a point */
/* laying on line defined by rear axle */
/* front arms are rotated to be perpendicular to center of turning, */
/* which then are used to dissipate forces, thus providing control */
Vec3 const rear_bar = vec3_sub(vbp[0], vbp[3]);
Vec3 const rear_center = vec3_add(vbp[3], vec3_scale(rear_bar, 0.5));
Vec3 a, b, r;
if (i == 1) {
a = vec3_sub(vbp[3], vbp[2]);
b = vec3_sub(rear_center, vbp[2]);
r = vbp[2];
} else {
a = vec3_sub(vbp[0], vbp[1]);
b = vec3_sub(rear_center, vbp[1]);
r = vbp[1];
}
float const arm_angle = vec3_angle(a, b);
Vec3 const turn_center = vec3_add(rear_center, vec3_scale(vec3_norm(rear_bar), vehicle_turning_extend));
Vec3 const arm = vec3_sub(r, turn_center);
Vec3 const n = vec3_norm(vec3_cross(a, b));
Vec3 const wheel = vec3_norm(vec3_rotate(arm, -arm_angle, n));
Vec3 const p = vec3_norm(vec3_cross(wheel, n));
draw_line_3d(r, vec3_add(r, wheel), 1, (Color){0,255,255,255});
Vec3 const Fp = vec3_scale(p, vec3_dot(vbv[i], p) * -VEHICLE_FRICTION_V);
Facc[i] = vec3_add(Facc[i], Fp);
}
}
Vec3 vd = vec3_scale(vec3_scale(Facc[i], (1.0f / VEHICLE_MASS)), ctx.frame_duration);
vbv[i] = vec3_add(vbv[i], vd);
vbp[i] = vec3_add(vbp[i], vec3_scale(vbv[i], ctx.frame_duration));
}
}
}
static void process_vehicle_mode(State *state) {

View File

@ -86,6 +86,10 @@ static inline Vec3 vec3_norm(Vec3 a) {
return vec3_scale(a, 1.0f / n);
}
static inline float vec3_angle(Vec3 a, Vec3 b) {
return acosf(vec3_dot(vec3_norm(a), vec3_norm(b)));
}
static inline Vec3 vec3_rotate(Vec3 v, float angle, Vec3 axis) {
/* from cglm */
Vec3 v1, v2, k;