Skip to content

Commit 1a09526

Browse files
authored
Merge pull request #46 from mavlink/feat/adaptive-trail-sampling
feat: adaptive trail sampling for smoother ribbons with less geometry
2 parents d1bc7e4 + de75186 commit 1a09526

File tree

2 files changed

+47
-4
lines changed

2 files changed

+47
-4
lines changed

src/vehicle.c

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include <stdlib.h>
1212

1313
#define EARTH_RADIUS 6371000.0
14-
#define TRAIL_MAX 3600
14+
#define TRAIL_MAX 1800
1515
#define TRAIL_INTERVAL 0.016f
1616
#define TRAIL_DIST_INTERVAL 0.01f // meters between ribbon samples
1717

@@ -208,6 +208,27 @@ static Color heat_to_color(float heat, unsigned char alpha, view_mode_t mode) {
208208
float s = (heat - 0.83f) / 0.17f;
209209
cr = 255; cg = 250 + 5 * s; cb = 60 + 195 * s;
210210
}
211+
} else if (mode == VIEW_SNOW) {
212+
// Snow: deep navy → royal blue → teal → green → yellow → red
213+
if (heat < 0.16f) {
214+
float s = heat / 0.16f;
215+
cr = 10 + 10 * s; cg = 20 + 20 * s; cb = 100 + 40 * s;
216+
} else if (heat < 0.33f) {
217+
float s = (heat - 0.16f) / 0.17f;
218+
cr = 20 - 10 * s; cg = 40 + 80 * s; cb = 140 + 40 * s;
219+
} else if (heat < 0.5f) {
220+
float s = (heat - 0.33f) / 0.17f;
221+
cr = 10 - 10 * s; cg = 120 + 40 * s; cb = 180 - 100 * s;
222+
} else if (heat < 0.66f) {
223+
float s = (heat - 0.5f) / 0.16f;
224+
cr = 0 + 60 * s; cg = 160 + 40 * s; cb = 80 - 80 * s;
225+
} else if (heat < 0.83f) {
226+
float s = (heat - 0.66f) / 0.17f;
227+
cr = 60 + 180 * s; cg = 200 + 20 * s; cb = 0;
228+
} else {
229+
float s = (heat - 0.83f) / 0.17f;
230+
cr = 240; cg = 220 - 180 * s; cb = 0;
231+
}
211232
} else {
212233
// Grid (default): purple → magenta → red → orange → yellow → white
213234
if (heat < 0.16f) {
@@ -351,18 +372,39 @@ void vehicle_update(vehicle_t *v, const hil_state_t *state, const home_position_
351372
v->airspeed = state->ind_airspeed * 0.01f;
352373
v->altitude_rel = (float)(alt - v->alt0);
353374

354-
// Sample trail by time OR distance (whichever triggers first)
375+
// Adaptive trail sampling: record a point when direction changes (tight turns
376+
// get dense coverage) or after a max distance on straight runs (so they don't
377+
// go bare). Minimum distance gate prevents duplicate points when hovering.
355378
float dist_since = 0.0f;
379+
Vector3 cur_dir = {0};
356380
if (v->trail_count > 0) {
357381
int last = (v->trail_head - 1 + v->trail_capacity) % v->trail_capacity;
358382
float ddx = v->position.x - v->trail[last].x;
359383
float ddy = v->position.y - v->trail[last].y;
360384
float ddz = v->position.z - v->trail[last].z;
361385
dist_since = sqrtf(ddx*ddx + ddy*ddy + ddz*ddz);
386+
if (dist_since > 0.001f) {
387+
cur_dir = (Vector3){ ddx/dist_since, ddy/dist_since, ddz/dist_since };
388+
}
362389
}
390+
391+
// Direction change: dot product < threshold means significant turn
392+
float dir_dot = 1.0f;
393+
if (v->trail_count > 1 && dist_since > 0.001f) {
394+
dir_dot = cur_dir.x * v->trail_last_dir.x +
395+
cur_dir.y * v->trail_last_dir.y +
396+
cur_dir.z * v->trail_last_dir.z;
397+
}
398+
399+
// Sample triggers: dense on turns, sparse on straights
363400
v->trail_timer += GetFrameTime();
364-
if (v->trail_timer >= TRAIL_INTERVAL || dist_since >= TRAIL_DIST_INTERVAL) {
401+
bool dir_trigger = (dir_dot < 0.995f) && (dist_since >= TRAIL_DIST_INTERVAL);
402+
bool dist_trigger = (dist_since >= 0.5f);
403+
bool time_trigger = (v->trail_timer >= TRAIL_INTERVAL * 4.0f);
404+
405+
if (dir_trigger || dist_trigger || time_trigger) {
365406
v->trail_timer = 0.0f;
407+
if (dist_since > 0.001f) v->trail_last_dir = cur_dir;
366408
v->trail[v->trail_head] = v->position;
367409
v->trail_roll[v->trail_head] = v->roll_deg;
368410
v->trail_pitch[v->trail_head] = v->pitch_deg;
@@ -616,7 +658,7 @@ void vehicle_draw(vehicle_t *v, view_mode_t view_mode, bool selected,
616658
rlEnd();
617659
} else {
618660
// ── Speed ribbon trail (mode 2) ──
619-
// Batched triangle ribbon: single rlBegin/rlEnd instead of per-quad DrawTriangle3D.
661+
// Batched triangle ribbon with adaptive sampling (dense on turns, sparse on straights).
620662
// Perpendicular blending (70% previous + 30% current) prevents twisting on tight turns.
621663
float max_speed = v->trail_speed_max > 1.0f ? v->trail_speed_max : 1.0f;
622664
float max_half_w = v->model_scale * 0.25f;

src/vehicle.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ typedef struct {
7777
int trail_head;
7878
int trail_capacity;
7979
float trail_timer;
80+
Vector3 trail_last_dir; // direction of last recorded segment (for adaptive sampling)
8081
Shader lighting_shader; // shared lighting shader (id=0 if none)
8182
int loc_matNormal; // shader uniform for normal matrix
8283
} vehicle_t;

0 commit comments

Comments
 (0)