/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_SPRING_GC 100.0f
#define VEHICLE_FRICTION_S 1000.0f #define VEHICLE_FRICTION_S 1000.0f
#define VEHICLE_FRICTION_K 100.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 */ /* TODO: shock springs, that are more loose, which are used to simulate the wheels */
/* initial, ideal corner positions */ /* initial, ideal corner positions */
@ -97,7 +98,10 @@ static uint8_t vbs[28][2] = {
{0, 6}, {1, 7}, {2, 4}, {3, 5}, {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 float height_at(SceneIngame *scn, Vec2 position);
static Vec3 normal_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 */ /* apply gravity */
Vec3 Facc[8] = {0}; 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 }; Vec3 const Fg = { .y = -VEHICLE_MASS * G_CONST };
for (size_t i = 0; i < 8; ++i) for (size_t i = 0; i < 8; ++i)
Facc[i] = vec3_add(Facc[i], Fg); Facc[i] = vec3_add(Facc[i], Fg);
@ -144,12 +157,15 @@ static void process_vehicle(SceneIngame *scn) {
Vec3 const v = vbv[i]; Vec3 const v = vbv[i];
float const h = height_at(scn, (Vec2){ p.x, p.z }); float const h = height_at(scn, (Vec2){ p.x, p.z });
if (h >= p.y) { if (h >= p.y) {
/* wheel processing */ /* back wheel processing: acceleration */
if (i == 0 || i == 3 || i == 4 || i == 7) { if (i == 0 || i == 3 || i == 4 || i == 7) {
if (scn->camera_mode == 2 && input_action_pressed("player_forward")) { float scale = 0;
Vec3 dir = i == 0 ? vec3_sub(vbp[1], vbp[0]) : vec3_sub(vbp[2], vbp[3]); if (scn->camera_mode == 2 && input_action_pressed("player_forward"))
Facc[i] = vec3_add(Facc[i], vec3_scale(vec3_norm(dir), 6500)); 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 */ /* normal force, for displacement */
@ -162,41 +178,64 @@ static void process_vehicle(SceneIngame *scn) {
/* friction force, perpendicular to normal force */ /* friction force, perpendicular to normal force */
/* TODO: is it right? aren't vn+vol should be = |v| */ /* TODO: is it right? aren't vn+vol should be = |v| */
Vec3 const von = vec3_norm(vec3_cross(n, vec3_cross(v, n))); 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); Vec3 const vo = vec3_scale(vec3_scale(von, vec3_length(v) - vn), -1);
float const vol = vec3_length(vo); float const vol = vec3_length(vo);
Vec3 const Fon = vec3_norm(vec3_cross(n, vec3_cross(Facc[i], n))); 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); 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 */ /* portion of total force along the surface */
float const Fol = vec3_length(Fo); float const Fol = vec3_length(Fo);
float const fkxn = VEHICLE_FRICTION_K * xn; float const fkxn = VEHICLE_FRICTION_K * xn;
/* at rest, might want to start moving */ /* at rest, might want to start moving */
if (fabsf(0.0f - vol) <= 0.0001f) { if (fabsf(0.0f - vol) <= 0.0001f) {
/* cannot overcome static friction, force along the surface is zeroed */ /* 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 */ /* 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 */ /* not at rest, stop accelerating along the surface */
} else if (vol + (Fol / VEHICLE_MASS) * ctx.frame_duration <= fkxn * ctx.frame_duration * 2) { } else if (vol + (Fol / VEHICLE_MASS) * ctx.frame_duration <= fkxn * ctx.frame_duration * 2) {
/* ugh ... */ /* ugh ... */
vbv[i] = vec3_add(vbv[i], vo); vbv[i] = vec3_add(vbv[i], vo);
log_info("test 2");
/* just apply friction */ /* just apply friction */
} else { } else {
Fo = vec3_scale(von, -fkxn * 400); Fo = vec3_scale(von, -fkxn * 400);
} }
Facc[i] = vec3_add(Facc[i], Fo); Facc[i] = vec3_add(Facc[i], Fo);
// Facc[i] = vec3_sub(Fo, Fn);
// Facc[i] = vec3_sub(Fo, Fn); /* front wheel processing */
Vec3 vd = vec3_scale(vec3_scale(Facc[i], (1.0f / VEHICLE_MASS)), ctx.frame_duration); if (i == 1 || i == 5 || i == 2 || i == 6) {
vbv[i] = vec3_add(vbv[i], vd); /* steering influences "center of turning", which is a point */
vbp[i] = vec3_add(vbp[i], vec3_scale(vbv[i], ctx.frame_duration)); /* laying on line defined by rear axle */
} else { /* front arms are rotated to be perpendicular to center of turning, */
Vec3 vd = vec3_scale(vec3_scale(Facc[i], (1.0f / VEHICLE_MASS)), ctx.frame_duration); /* which then are used to dissipate forces, thus providing control */
vbv[i] = vec3_add(vbv[i], vd); Vec3 const rear_bar = vec3_sub(vbp[0], vbp[3]);
vbp[i] = vec3_add(vbp[i], vec3_scale(vbv[i], ctx.frame_duration)); 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));
} }
} }

View File

@ -86,6 +86,10 @@ static inline Vec3 vec3_norm(Vec3 a) {
return vec3_scale(a, 1.0f / n); 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) { static inline Vec3 vec3_rotate(Vec3 v, float angle, Vec3 axis) {
/* from cglm */ /* from cglm */
Vec3 v1, v2, k; Vec3 v1, v2, k;