/apps/demos/scenery: some friction
This commit is contained in:
		| @@ -53,14 +53,16 @@ static float heightmap[TERRAIN_DISTANCE][TERRAIN_DISTANCE]; | ||||
| /* else if length(v(o) + (F(o)/m)*t) <= (f(k)*x(n)*t), v(o) = 0 */ | ||||
| /*     else, F = -unit(v(o)*f(k)*x(n)) */ | ||||
|  | ||||
| #define VEHICLE_MASS 10.0f | ||||
| #define VEHICLE_MASS 200.0f | ||||
| #define VEHICLE_LENGTH 3.0f | ||||
| #define VEHICLE_WIDTH 1.7f | ||||
| #define VEHICLE_HEIGHT 1.3f | ||||
| /* spring constant */ | ||||
| #define VEHICLE_SPRING_K 20.0f | ||||
| #define VEHICLE_SPRING_K 400.0f | ||||
| /* damping constant */ | ||||
| #define VEHICLE_SPRING_C 50.0f | ||||
| #define VEHICLE_SPRING_C 20.0f | ||||
| #define VEHICLE_FRICTION_S 1000000.0f | ||||
| #define VEHICLE_FRICTION_K 1000000.0f | ||||
|  | ||||
| /* initial, ideal corner positions */ | ||||
| static const Vec3 vbpi[8] = { | ||||
| @@ -110,11 +112,11 @@ static void draw_vehicle(SceneIngame *scn) { | ||||
|  | ||||
| static void process_vehicle(SceneIngame *scn) { | ||||
|     /* apply gravity */ | ||||
|     Vec3 Facc[8] = {0}; | ||||
|  | ||||
|     Vec3 const Fg = { .y = -VEHICLE_MASS * G_CONST }; | ||||
|     for (size_t i = 0; i < 8; ++i) { | ||||
|         Vec3 const vd = vec3_scale(Fg, (1.0f / VEHICLE_MASS) * ctx.frame_duration); | ||||
|         vbv[i] = vec3_add(vbv[i], vd); | ||||
|     } | ||||
|     for (size_t i = 0; i < 8; ++i) | ||||
|         Facc[i] = vec3_add(Facc[i], Fg); | ||||
|  | ||||
|     /* apply springs */ | ||||
|     for (size_t i = 0; i < 24; ++i) { | ||||
| @@ -129,30 +131,54 @@ static void process_vehicle(SceneIngame *scn) { | ||||
|         float const x = vec3_length(pd) - lar; | ||||
|         float const v = vec3_dot(vec3_sub(v1, v0), pn); | ||||
|         Vec3 const Fs = vec3_scale(pn, -VEHICLE_SPRING_K * x - VEHICLE_SPRING_C * v); | ||||
|         Vec3 const vd = vec3_scale(Fs, (1.0f / VEHICLE_MASS) * ctx.frame_duration); | ||||
|  | ||||
|         vbv[vbs[i][0]] = vec3_sub(vbv[vbs[i][0]], vd); | ||||
|         vbv[vbs[i][1]] = vec3_add(vbv[vbs[i][1]], vd); | ||||
|         Facc[vbs[i][0]] = vec3_sub(Facc[vbs[i][0]], Fs); | ||||
|         Facc[vbs[i][1]] = vec3_add(Facc[vbs[i][1]], Fs); | ||||
|     } | ||||
|  | ||||
|     /* spring out points that are underground */ | ||||
|     /* spring and friction against the ground */ | ||||
|     for (size_t i = 0; i < 8; ++i) { | ||||
|         Vec3 const p = vbp[i]; | ||||
|         Vec3 const v = vbv[i]; | ||||
|         float const h = height_at(scn, (Vec2){ p.x, p.z }); | ||||
|         if (h > p.y) { | ||||
|             /* displacement force */ | ||||
|             Vec3 const n = normal_at(scn, (Vec2){ p.x, p.z }); | ||||
|             float const xn = (h - p.y) * n.y; | ||||
|             float const vn = vec3_dot(v, n); | ||||
|             Vec3 const Fd = vec3_scale(n, -VEHICLE_SPRING_K * xn - VEHICLE_SPRING_C * vn); | ||||
|             vbv[i] = vec3_add(vbv[i], vec3_scale(Fd, -(1.0f / VEHICLE_MASS) * ctx.frame_duration)); | ||||
|             Facc[i] = vec3_sub(Facc[i], Fd); | ||||
|  | ||||
|             /* friction force, perpendicular to displacement */ | ||||
|             /* portions aligned to surface normal */ | ||||
|             Vec3 const vov = vec3_sub(v, vec3_scale(n, vn)); | ||||
|             float const vo = vec3_length(vov); | ||||
|             Vec3 const Fov = vec3_sub(Facc[i], vec3_scale(n, vec3_dot(Facc[i], n))); | ||||
|             float const Fo = vec3_length(Fov); | ||||
|             float const fkxn = VEHICLE_FRICTION_K * xn; | ||||
|             if (fabsf(0.0f - vo) <= 0.0001f) { | ||||
|                 /* cannot overcome static friction, zero force along the surface */ | ||||
|                 if (Fo <= VEHICLE_FRICTION_S * xn) { | ||||
|                     Facc[i] = vec3_sub(Facc[i], Fov); | ||||
|                 } | ||||
|                 /* apply kinematic friction */ | ||||
|                 else { | ||||
|                     Facc[i] = vec3_sub(Facc[i], vec3_scale(vec3_norm(Fov), fkxn)); | ||||
|                 } | ||||
|             /* velocity with gain along the surface will not overcome */ | ||||
|             } else if (vo + (Fo / VEHICLE_MASS) * ctx.frame_duration <= fkxn * ctx.frame_duration) { | ||||
|                 vbv[i] = vec3_sub(vbv[i], vov); | ||||
|             } else { | ||||
|                 Facc[i] = vec3_sub(Facc[i], vec3_scale(vec3_norm(vov), fkxn)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* apply velocity */ | ||||
|     /* integrate forces and velocity */ | ||||
|     for (size_t i = 0; i < 8; ++i) { | ||||
|         Vec3 const vd = vec3_scale(Facc[i], (1.0f / VEHICLE_MASS) * ctx.frame_duration); | ||||
|         vbv[i] = vec3_add(vbv[i], vd); | ||||
|         vbp[i] = vec3_add(vbp[i], vbv[i]); | ||||
|         vbv[i] = vec3_scale(vbv[i], 0.99f); /* friction... */ | ||||
|         vbv[i] = vec3_scale(vbv[i], 0.99f); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -188,8 +214,8 @@ static void process_fly_mode(State *state) { | ||||
|  | ||||
| /* TODO: could be baked in map format */ | ||||
| static Vec3 normal_at(SceneIngame *scn, Vec2 position) { | ||||
|     int const x = (int)(HALF_TERRAIN_DISTANCE + (position.x - scn->pos.x)); | ||||
|     int const y = (int)(HALF_TERRAIN_DISTANCE + (position.y - scn->pos.z)); | ||||
|     int const x = (int)(roundf(HALF_TERRAIN_DISTANCE + (position.x - scn->pos.x))); | ||||
|     int const y = (int)(roundf(HALF_TERRAIN_DISTANCE + (position.y - scn->pos.z))); | ||||
|  | ||||
|     float const height0 = heightmap[x][y]; | ||||
|     float const height1 = heightmap[x + 1][y]; | ||||
| @@ -203,31 +229,22 @@ static Vec3 normal_at(SceneIngame *scn, Vec2 position) { | ||||
|  | ||||
| /* TODO: don't operate on triangles, instead interpolate on quads */ | ||||
| static float height_at(SceneIngame *scn, Vec2 position) { | ||||
|     float height0, height1, height2, weight0, weight1, weight2; | ||||
|     int const x = (int)(roundf(HALF_TERRAIN_DISTANCE + (position.x - scn->pos.x))); | ||||
|     int const y = (int)(roundf(HALF_TERRAIN_DISTANCE + (position.y - scn->pos.z))); | ||||
|  | ||||
|     int const x = (int)(HALF_TERRAIN_DISTANCE + (position.x - scn->pos.x)); | ||||
|     int const y = (int)(HALF_TERRAIN_DISTANCE + (position.y - scn->pos.z)); | ||||
|  | ||||
|     height0 = heightmap[x][y]; | ||||
|     height1 = heightmap[x + 1][y + 1]; | ||||
|     float const height0 = heightmap[x][y]; | ||||
|     float const height1 = heightmap[x + 1][y]; | ||||
|     float const height2 = heightmap[x][y + 1]; | ||||
|     float const height3 = heightmap[x + 1][y + 1]; | ||||
|  | ||||
|     Vec2 incell = { position.x - floorf(position.x), position.y - floorf(position.y) }; | ||||
|  | ||||
|     /* who needs barycentric coordinates, am i right? */ | ||||
|     weight0 = 1 / sqrtf(powf(incell.x, 2) + powf(incell.y, 2)); | ||||
|     weight1 = 1 / sqrtf(powf(1 - incell.x, 2) + powf(1 - incell.y, 2)); | ||||
|     float const weight0 = (1 - incell.x) * (1 - incell.y); | ||||
|     float const weight1 = ( incell.x) * (1 - incell.y); | ||||
|     float const weight2 = (1 - incell.x) * ( incell.y); | ||||
|     float const weight3 = ( incell.x) * ( incell.y); | ||||
|  | ||||
|     /* find which triangle we're directly under */ | ||||
|     /* for this manhattan distance is sufficient */ | ||||
|     if (incell.x + (1 - incell.y) < (1 - incell.x) + incell.y) { | ||||
|         height2 = heightmap[x][y + 1]; | ||||
|         weight2 = 1 / sqrtf(powf(incell.x, 2) + powf(1 - incell.y, 2)); | ||||
|     } else { | ||||
|         height2 = heightmap[x + 1][y]; | ||||
|         weight2 = 1 / sqrtf(powf(1 - incell.x, 2) + powf(incell.y, 2)); | ||||
|     } | ||||
|  | ||||
|     return (height0 * weight0 + height1 * weight1 + height2 * weight2) / (weight0 + weight1 + weight2); | ||||
|     return (height0 * weight0 + height1 * weight1 + height2 * weight2 + height3 * weight3) / (weight0 + weight1 + weight2 + weight3); | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user