Feat: generate freely falling Schwarzschild camera tracks
Integrate timelike geodesics and Fermi-Walker tetrads in ingoing Kerr-Schild coordinates, sampled at a configurable proper-time cadence. Add movie-track-samples to preserve CSV events as frames. Document usage and singularity guards, and cover analytic orbits, transport convergence, sampling, and CSV rendering.
This commit is contained in:
1 parent
8d011b7ec5
commit
b69c9cfd45
9 files changed
+446
-3
No files matched your search
+13
-3
@@ -44,6 +44,7 @@ typedef struct {
|
||||
char hdr_output_path[PATH_MAX];
|
||||
#endif
|
||||
const char *observer_track_path;
|
||||
int movie_track_samples;
|
||||
const char *frames_dir;
|
||||
const char *frames_prefix;
|
||||
const char *write_minkowski_accel_track_path;
|
||||
@@ -299,6 +300,8 @@ static int parse_args(int argc, char **argv, Settings *s,
|
||||
*write_path = argv[++i];
|
||||
else if (!strcmp(argv[i], "--observer-track") && i + 1 < argc)
|
||||
s->observer_track_path = argv[++i];
|
||||
else if (!strcmp(argv[i], "--movie-track-samples"))
|
||||
s->movie_track_samples = 1;
|
||||
else if (!strcmp(argv[i], "--frames-dir") && i + 1 < argc)
|
||||
s->frames_dir = argv[++i];
|
||||
else if (!strcmp(argv[i], "--frames-prefix") && i + 1 < argc)
|
||||
@@ -385,6 +388,7 @@ static void print_help(const char *program) {
|
||||
" --draw-mesh Draw the final lens mesh overlay (default: disabled)\n"
|
||||
"\nMovie and observer track:\n"
|
||||
" --observer-track PATH Observer worldline/tetrad CSV for movie rendering (default: disabled)\n"
|
||||
" --movie-track-samples One frame per CSV row; ignores start-time/duration/fps (default: disabled)\n"
|
||||
" --frames-dir DIR Write a movie image sequence to this directory (default: disabled)\n"
|
||||
" --frames-prefix NAME Movie frame filename prefix (default: frame)\n"
|
||||
" --start-time T Movie start coordinate time (default: 0)\n"
|
||||
@@ -508,6 +512,11 @@ static GeodesicTraceConfig trace_config(void) {
|
||||
}
|
||||
|
||||
static int resolve_camera(Settings *s) {
|
||||
if (s->movie_track_samples && (!s->observer_track_path || !s->frames_dir ||
|
||||
s->lens_map_input_path)) {
|
||||
fputs("--movie-track-samples requires --observer-track and --frames-dir, without --lens-map-input.\n", stderr);
|
||||
return -1;
|
||||
}
|
||||
const int camera_specified = s->position_specified || s->look_specified ||
|
||||
s->radius_specified || s->velocity_specified || s->roll_specified;
|
||||
if (s->position_specified && s->radius_specified) {
|
||||
@@ -798,8 +807,9 @@ static int render_movie(const Settings *s, StarCatalog *catalog,
|
||||
int result = -1;
|
||||
if (s->observer_track_path == NULL ||
|
||||
observer_track_load_csv(&track, s->observer_track_path) ||
|
||||
movie_init(&movie, &track, s->movie_start_time, s->movie_duration,
|
||||
s->movie_fps) ||
|
||||
(s->movie_track_samples ? movie_init_track_samples(&movie, &track) :
|
||||
movie_init(&movie, &track, s->movie_start_time, s->movie_duration,
|
||||
s->movie_fps)) ||
|
||||
movie_build_coarse_meshes(&movie, s->width, s->height,
|
||||
s->coarse_cell_pixels, s->horizontal_fov_deg))
|
||||
goto done;
|
||||
@@ -990,7 +1000,7 @@ int main(int argc, char **argv) {
|
||||
"[--draw-mesh] [--write-catalog PATH] "
|
||||
"[--catalog-load-workers N] "
|
||||
"[--observer-track PATH --frames-dir DIR --frames-prefix NAME "
|
||||
"--start-time T --duration T --fps N] "
|
||||
"--start-time T --duration T --fps N | --movie-track-samples] "
|
||||
"[--proper-acceleration A --write-minkowski-accel-track PATH]\n",
|
||||
argv[0]);
|
||||
return 2;
|
||||
|
||||
+22
@@ -3,6 +3,28 @@
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int movie_init_track_samples(Movie *movie, const ObserverTrack *track) {
|
||||
if (!movie || !track || !track->samples || !track->count ||
|
||||
track->count > SIZE_MAX / sizeof *movie->frames)
|
||||
return -1;
|
||||
*movie = (Movie){0};
|
||||
movie->frames = calloc(track->count, sizeof *movie->frames);
|
||||
if (!movie->frames) return -1;
|
||||
movie->frame_count = track->count;
|
||||
for (size_t i = 0; i < track->count; ++i) {
|
||||
const ObserverSample *s = &track->samples[i];
|
||||
MovieFrame *f = &movie->frames[i];
|
||||
f->frame_id = i;
|
||||
f->coordinate_time = f->observer.coordinate_time = s->coordinate_time;
|
||||
f->proper_time = s->proper_time;
|
||||
memcpy(f->observer.coordinate_position, s->coordinate_position,
|
||||
sizeof s->coordinate_position);
|
||||
memcpy(f->observer.tetrad, s->tetrad, sizeof s->tetrad);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int movie_init(Movie *movie, const ObserverTrack *track, double start_time,
|
||||
double duration, double frames_per_second) {
|
||||
|
||||
@@ -21,6 +21,8 @@ typedef struct {
|
||||
|
||||
int movie_init(Movie *movie, const ObserverTrack *track, double start_time,
|
||||
double duration, double frames_per_second);
|
||||
/* Preserve the supplied event and tetrad exactly: one CSV sample per frame. */
|
||||
int movie_init_track_samples(Movie *movie, const ObserverTrack *track);
|
||||
int movie_build_coarse_meshes(Movie *movie, int width, int height,
|
||||
int cell_pixels, double horizontal_fov_deg);
|
||||
void movie_destroy(Movie *movie);
|
||||
|
||||
Reference in new issue
Block a user