Output: default to PNG with PPM fallback
This commit is contained in:
1 parent
83dc05fd52
commit
b0fdf1faca
7 files changed
+47
-26
No files matched your search
@@ -2,12 +2,15 @@ CC ?= cc
|
|||||||
CFLAGS ?= -std=c11 -O2 -Wall -Wextra -Wpedantic
|
CFLAGS ?= -std=c11 -O2 -Wall -Wextra -Wpedantic
|
||||||
OPENMP_FLAGS ?= -fopenmp
|
OPENMP_FLAGS ?= -fopenmp
|
||||||
LDLIBS ?= -lm
|
LDLIBS ?= -lm
|
||||||
ENABLE_PNG ?= 0
|
ENABLE_PNG ?= 1
|
||||||
SPACETIME ?= minkowski
|
SPACETIME ?= minkowski
|
||||||
|
|
||||||
ifeq ($(ENABLE_PNG),1)
|
ifeq ($(ENABLE_PNG),1)
|
||||||
CPPFLAGS += -DENABLE_PNG
|
CPPFLAGS += -DENABLE_PNG
|
||||||
LDLIBS += -lpng
|
LDLIBS += -lpng
|
||||||
|
IMAGE_EXT := png
|
||||||
|
else
|
||||||
|
IMAGE_EXT := ppm
|
||||||
endif
|
endif
|
||||||
|
|
||||||
COMMON_SOURCES := $(filter-out src/main.c src/spacetime_minkowski.c src/spacetime_schwarzschild.c,$(wildcard src/*.c))
|
COMMON_SOURCES := $(filter-out src/main.c src/spacetime_minkowski.c src/spacetime_schwarzschild.c,$(wildcard src/*.c))
|
||||||
@@ -40,7 +43,7 @@ build:
|
|||||||
|
|
||||||
run: $(TARGET)
|
run: $(TARGET)
|
||||||
mkdir -p output/imgs
|
mkdir -p output/imgs
|
||||||
./$(TARGET) --catalog assets/sky_grid_5deg.csv --output output/imgs/$(SPACETIME)_sky.ppm
|
./$(TARGET) --catalog assets/sky_grid_5deg.csv --output output/imgs/$(SPACETIME)_sky.$(IMAGE_EXT)
|
||||||
|
|
||||||
minkowski:
|
minkowski:
|
||||||
$(MAKE) SPACETIME=minkowski all
|
$(MAKE) SPACETIME=minkowski all
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ which equalizes their CIE/linear-sRGB luminance under the renderer's blackbody
|
|||||||
integration. Longitude boundaries belong to the sector to their east and the
|
integration. Longitude boundaries belong to the sector to their east and the
|
||||||
equator to the northern hemisphere, so boundary stars have a deterministic
|
equator to the northern hemisphere, so boundary stars have a deterministic
|
||||||
color.
|
color.
|
||||||
The output is a binary PPM at `output/imgs/minkowski_sky.ppm`; it can be inspected by
|
The default output is PNG at `output/imgs/minkowski_sky.png`.
|
||||||
most image viewers or converted to PNG with ImageMagick.
|
|
||||||
|
|
||||||
## Movie PNG sequence (Phase A)
|
## Movie PNG sequence (Phase A)
|
||||||
|
|
||||||
@@ -33,7 +32,7 @@ Minkowski benchmark—two coordinate seconds at 30 fps, accelerating from rest
|
|||||||
to about `0.95c`—then render its numbered PNG frames:
|
to about `0.95c`—then render its numbered PNG frames:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
make clean && make ENABLE_PNG=1
|
make clean && make
|
||||||
mkdir -p output/imgs
|
mkdir -p output/imgs
|
||||||
./build/minkowski_sky --write-minkowski-accel-track output/minkowski_accel_2s.csv \
|
./build/minkowski_sky --write-minkowski-accel-track output/minkowski_accel_2s.csv \
|
||||||
--duration 2 --fps 30 --proper-acceleration 1.52
|
--duration 2 --fps 30 --proper-acceleration 1.52
|
||||||
@@ -55,15 +54,18 @@ synthetic test catalog uses global default exposure `1e-3`; the accelerated
|
|||||||
benchmark explicitly uses `1e-5` because its physical Doppler blue shift
|
benchmark explicitly uses `1e-5` because its physical Doppler blue shift
|
||||||
otherwise clips the later frames.
|
otherwise clips the later frames.
|
||||||
|
|
||||||
PNG output is optional so the default build has no `libpng` dependency. Build
|
PNG is the default output and the default build links `libpng`:
|
||||||
with `make ENABLE_PNG=1`, then select it with a `.png` output path:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
make clean && make ENABLE_PNG=1
|
make clean && make
|
||||||
mkdir -p output/imgs
|
mkdir -p output/imgs
|
||||||
./build/minkowski_sky --output output/imgs/minkowski_sky.png
|
./build/minkowski_sky --output output/imgs/minkowski_sky.png
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If `libpng` is unavailable, rebuild with `make clean && make ENABLE_PNG=0`.
|
||||||
|
That intentionally selects the binary-PPM fallback, whose default path is
|
||||||
|
`output/imgs/minkowski_sky.ppm`; pass a `.ppm` path for explicit output.
|
||||||
|
|
||||||
Run the flat-spacetime geodesic regression with:
|
Run the flat-spacetime geodesic regression with:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@@ -79,7 +81,7 @@ Kerr--Schild coordinates (regular at the horizon), then render the test catalog
|
|||||||
to PNG:
|
to PNG:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
make clean && make SPACETIME=schwarzschild ENABLE_PNG=1
|
make clean && make SPACETIME=schwarzschild
|
||||||
mkdir -p output/imgs
|
mkdir -p output/imgs
|
||||||
./build/schwarzschild_sky --catalog assets/sky_grid_5deg.csv \
|
./build/schwarzschild_sky --catalog assets/sky_grid_5deg.csv \
|
||||||
--width 640 --height 360 --coarse-cell-pixels 8 --fov-deg 60 \
|
--width 640 --height 360 --coarse-cell-pixels 8 --fov-deg 60 \
|
||||||
@@ -113,13 +115,13 @@ Useful options:
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
./build/minkowski_sky --width 1920 --height 1080 --fov-deg 30 \
|
./build/minkowski_sky --width 1920 --height 1080 --fov-deg 30 \
|
||||||
--catalog assets/sky_grid_5deg.csv --output output/imgs/frame.ppm
|
--catalog assets/sky_grid_5deg.csv --output output/imgs/frame.png
|
||||||
./build/minkowski_sky --catalog assets/2mass/processed/2mass_psc_m31_0p5deg_stars.csv \
|
./build/minkowski_sky --catalog assets/2mass/processed/2mass_psc_m31_0p5deg_stars.csv \
|
||||||
--look-ra-deg 10.6847083 --look-dec-deg 41.26875 --fov-deg 1.8 \
|
--look-ra-deg 10.6847083 --look-dec-deg 41.26875 --fov-deg 1.8 \
|
||||||
--exposure 1e15 --output output/imgs/2mass_m31.ppm
|
--exposure 1e15 --output output/imgs/2mass_m31.png
|
||||||
./build/minkowski_sky --catalog assets/2mass/processed/2mass_psc_m44_1p0deg_stars.csv \
|
./build/minkowski_sky --catalog assets/2mass/processed/2mass_psc_m44_1p0deg_stars.csv \
|
||||||
--look-ra-deg 129.99165 --look-dec-deg 19.54139 --fov-deg 2.0 \
|
--look-ra-deg 129.99165 --look-dec-deg 19.54139 --fov-deg 2.0 \
|
||||||
--exposure 1e15 --width 1920 --height 1920 --output output/imgs/2mass_m44.ppm
|
--exposure 1e15 --width 1920 --height 1920 --output output/imgs/2mass_m44.png
|
||||||
./build/minkowski_sky --write-catalog assets/sky_grid_5deg.csv
|
./build/minkowski_sky --write-catalog assets/sky_grid_5deg.csv
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ tile tables after successful cleaning unless `--keep-raw` is passed.
|
|||||||
Use the directory mode rather than `--catalog` for this partitioned dataset:
|
Use the directory mode rather than `--catalog` for this partitioned dataset:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
make ENABLE_PNG=1 SPACETIME=minkowski all
|
make SPACETIME=minkowski all
|
||||||
./build/minkowski_sky --all-sky-catalog assets/2mass/processed/all_sky \
|
./build/minkowski_sky --all-sky-catalog assets/2mass/processed/all_sky \
|
||||||
--fov-deg 2 --look-ra-deg 180 --look-dec-deg -75 \
|
--fov-deg 2 --look-ra-deg 180 --look-dec-deg -75 \
|
||||||
--exposure 1e15 \
|
--exposure 1e15 \
|
||||||
@@ -87,8 +87,9 @@ with the rotating observer fixture:
|
|||||||
Missing tiles are skipped until the downloader has produced them. Fully
|
Missing tiles are skipped until the downloader has produced them. Fully
|
||||||
contained tiles skip per-star source-triangle containment; partial tiles retain
|
contained tiles skip per-star source-triangle containment; partial tiles retain
|
||||||
that exact check. For 2MASS apparent-solid-angle amplitudes, start with
|
that exact check. For 2MASS apparent-solid-angle amplitudes, start with
|
||||||
`--exposure 1e15`; use PNG (`make ENABLE_PNG=1`) for substantially smaller
|
`--exposure 1e15`; PNG is the default output format. If libpng is unavailable,
|
||||||
single-frame output than binary PPM.
|
use the PPM fallback with `make clean && make ENABLE_PNG=0` and a `.ppm`
|
||||||
|
output path.
|
||||||
|
|
||||||
The two existing fields imply roughly 15--17 GiB of cleaned CSV for the full
|
The two existing fields imply roughly 15--17 GiB of cleaned CSV for the full
|
||||||
PSC. Their raw response rows imply 70--75 GiB if every source appeared once.
|
PSC. Their raw response rows imply 70--75 GiB if every source appeared once.
|
||||||
|
|||||||
+13
-3
@@ -96,6 +96,11 @@ static int parse_moffat_beta(const char *text, double *value) {
|
|||||||
|
|
||||||
static int parse_args(int argc, char **argv, Settings *s,
|
static int parse_args(int argc, char **argv, Settings *s,
|
||||||
const char **write_path) {
|
const char **write_path) {
|
||||||
|
#ifdef ENABLE_PNG
|
||||||
|
const char *default_output_path = "output/imgs/minkowski_sky.png";
|
||||||
|
#else
|
||||||
|
const char *default_output_path = "output/imgs/minkowski_sky.ppm";
|
||||||
|
#endif
|
||||||
*s = (Settings){.width = 1280,
|
*s = (Settings){.width = 1280,
|
||||||
.height = 720,
|
.height = 720,
|
||||||
.coarse_cell_pixels = 16,
|
.coarse_cell_pixels = 16,
|
||||||
@@ -106,7 +111,7 @@ static int parse_args(int argc, char **argv, Settings *s,
|
|||||||
.observer_radius = 30.0,
|
.observer_radius = 30.0,
|
||||||
.psf = {2.7, 4.5},
|
.psf = {2.7, 4.5},
|
||||||
.catalog_path = "assets/sky_grid_5deg.csv",
|
.catalog_path = "assets/sky_grid_5deg.csv",
|
||||||
.output_path = "output/imgs/minkowski_sky.ppm",
|
.output_path = default_output_path,
|
||||||
.frames_prefix = "frame",
|
.frames_prefix = "frame",
|
||||||
.movie_duration = 2.0,
|
.movie_duration = 2.0,
|
||||||
.movie_fps = 30.0,
|
.movie_fps = 30.0,
|
||||||
@@ -246,13 +251,18 @@ static int render_frame(const Settings *s, StarCatalog *catalog,
|
|||||||
|
|
||||||
static int frame_output_path(char path[PATH_MAX], const Settings *s,
|
static int frame_output_path(char path[PATH_MAX], const Settings *s,
|
||||||
size_t frame_id) {
|
size_t frame_id) {
|
||||||
|
#ifdef ENABLE_PNG
|
||||||
|
const char *extension = "png";
|
||||||
|
#else
|
||||||
|
const char *extension = "ppm";
|
||||||
|
#endif
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (s->frames_dir == NULL || s->frames_prefix == NULL ||
|
if (s->frames_dir == NULL || s->frames_prefix == NULL ||
|
||||||
strchr(s->frames_prefix, '/') != NULL || stat(s->frames_dir, &st) ||
|
strchr(s->frames_prefix, '/') != NULL || stat(s->frames_dir, &st) ||
|
||||||
!S_ISDIR(st.st_mode))
|
!S_ISDIR(st.st_mode))
|
||||||
return -1;
|
return -1;
|
||||||
const int written = snprintf(path, PATH_MAX, "%s/%s_%06zu.png", s->frames_dir,
|
const int written = snprintf(path, PATH_MAX, "%s/%s_%06zu.%s", s->frames_dir,
|
||||||
s->frames_prefix, frame_id);
|
s->frames_prefix, frame_id, extension);
|
||||||
return written < 0 || written >= PATH_MAX ? -1 : 0;
|
return written < 0 || written >= PATH_MAX ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-5
@@ -120,6 +120,7 @@ static unsigned char tonemap_channel(double hdr_value)
|
|||||||
return (unsigned char)lround(255.0 * clamp(display, 0.0, 1.0));
|
return (unsigned char)lround(255.0 * clamp(display, 0.0, 1.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef ENABLE_PNG
|
||||||
static int write_tonemapped_ppm(const char *path, const double *hdr, int width,
|
static int write_tonemapped_ppm(const char *path, const double *hdr, int width,
|
||||||
int height)
|
int height)
|
||||||
{
|
{
|
||||||
@@ -132,6 +133,7 @@ static int write_tonemapped_ppm(const char *path, const double *hdr, int width,
|
|||||||
}
|
}
|
||||||
return fclose(file) == 0 ? 0 : -1;
|
return fclose(file) == 0 ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_PNG
|
#ifdef ENABLE_PNG
|
||||||
static int write_tonemapped_png(const char *path, const double *hdr, int width,
|
static int write_tonemapped_png(const char *path, const double *hdr, int width,
|
||||||
@@ -171,13 +173,16 @@ done:
|
|||||||
int write_tonemapped_image(const char *path, const double *hdr, int width, int height)
|
int write_tonemapped_image(const char *path, const double *hdr, int width, int height)
|
||||||
{
|
{
|
||||||
const size_t path_length = strlen(path);
|
const size_t path_length = strlen(path);
|
||||||
if (path_length >= 4 && strcmp(path + path_length - 4, ".png") == 0) {
|
|
||||||
#ifdef ENABLE_PNG
|
#ifdef ENABLE_PNG
|
||||||
|
if (path_length >= 4 && strcmp(path + path_length - 4, ".png") == 0)
|
||||||
return write_tonemapped_png(path, hdr, width, height);
|
return write_tonemapped_png(path, hdr, width, height);
|
||||||
|
fputs("PNG output is enabled; use a .png output path.\n", stderr);
|
||||||
|
return -1;
|
||||||
#else
|
#else
|
||||||
fputs("PNG output is disabled; rebuild with make ENABLE_PNG=1.\n", stderr);
|
if (path_length >= 4 && strcmp(path + path_length - 4, ".ppm") == 0)
|
||||||
return -1;
|
return write_tonemapped_ppm(path, hdr, width, height);
|
||||||
|
fputs("PNG output is unavailable; use a .ppm output path or rebuild with libpng.\n",
|
||||||
|
stderr);
|
||||||
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
return write_tonemapped_ppm(path, hdr, width, height);
|
|
||||||
}
|
}
|
||||||
+1
-1
@@ -13,7 +13,7 @@ LinearRgb blackbody_to_linear_rgb(double temperature_K);
|
|||||||
void splat_moffat(double *hdr, int width, int height, double x, double y,
|
void splat_moffat(double *hdr, int width, int height, double x, double y,
|
||||||
LinearRgb color, double flux,
|
LinearRgb color, double flux,
|
||||||
const PointSpreadFunction *psf);
|
const PointSpreadFunction *psf);
|
||||||
/* Writes PPM by default; a .png path requires a build with ENABLE_PNG=1. */
|
/* Writes PNG when built with libpng; non-libpng builds use PPM fallback. */
|
||||||
int write_tonemapped_image(const char *path, const double *hdr, int width,
|
int write_tonemapped_image(const char *path, const double *hdr, int width,
|
||||||
int height);
|
int height);
|
||||||
|
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ SampleRequest -> RayPool (SoA, inactive / active / terminated)
|
|||||||
1. 新增 `observer_track.h/.c`,将目前的 `ObserverState` 提升为可插值的 `ObserverTrack`:每个 sample 保存 `t_coordinate`、`tau`、`x[3]` 和完整 tetrad。提供加载、严格单调时间校验、区间查找、插值和销毁函数。原有固定 observer 构造函数保留,作为只含一个 sample 的兼容快捷方式。
|
1. 新增 `observer_track.h/.c`,将目前的 `ObserverState` 提升为可插值的 `ObserverTrack`:每个 sample 保存 `t_coordinate`、`tau`、`x[3]` 和完整 tetrad。提供加载、严格单调时间校验、区间查找、插值和销毁函数。原有固定 observer 构造函数保留,作为只含一个 sample 的兼容快捷方式。
|
||||||
2. 第一版轨迹输入采用人可审阅的 21 列 CSV,字段固定为 `t,tau,x,y,z,e0t,e0x,...,e3z`;不在 renderer 内从“速度曲线”临时猜 tetrad。loader 做完整性、有限数与严格单调时间检查;tetrad 的 metric 正交归一由轨迹生成器和 backend-aware regression 验证。另提供生成器工具/模式为测试写出 CSV。这样 NR 生产轨迹、解析测试轨迹和以后离线 trajectory generator 使用完全相同的 renderer 输入。
|
2. 第一版轨迹输入采用人可审阅的 21 列 CSV,字段固定为 `t,tau,x,y,z,e0t,e0x,...,e3z`;不在 renderer 内从“速度曲线”临时猜 tetrad。loader 做完整性、有限数与严格单调时间检查;tetrad 的 metric 正交归一由轨迹生成器和 backend-aware regression 验证。另提供生成器工具/模式为测试写出 CSV。这样 NR 生产轨迹、解析测试轨迹和以后离线 trajectory generator 使用完全相同的 renderer 输入。
|
||||||
3. 加入 `movie.h/.c`,定义 `MovieSettings`、`MovieFrame`(`frame_id`、`t_camera`、插值得到的 observer state、mesh、HDR image)与 `Movie`。用 `start-time`、`duration`、`fps` 生成 frame 时间表;先拒绝轨迹覆盖范围外的时间。
|
3. 加入 `movie.h/.c`,定义 `MovieSettings`、`MovieFrame`(`frame_id`、`t_camera`、插值得到的 observer state、mesh、HDR image)与 `Movie`。用 `start-time`、`duration`、`fps` 生成 frame 时间表;先拒绝轨迹覆盖范围外的时间。
|
||||||
4. 将 `render_frame()` 中与单帧无关的工作拆成“初始化 mesh / 安装 endpoint / splat HDR / 写出”四个明确步骤。保持现有单帧命令和 PPM/PNG 行为可用;movie 模式只是调用同一套 frame rendering 与 optics。
|
4. 将 `render_frame()` 中与单帧无关的工作拆成“初始化 mesh / 安装 endpoint / splat HDR / 写出”四个明确步骤。默认构建写 PNG;未启用 libpng 时单帧和 movie 序列统一退回 PPM。movie 模式只是调用同一套 frame rendering 与 optics。
|
||||||
5. 新增 `output.h/.c`,从 `optics` 移出文件命名和写图逻辑。PNG 仍复用当前 libpng 路径,movie PNG 命名固定为 `<output-dir>/<prefix>_%06u.png`,例如 `output/imgs/minkowski_accel_000042.png`。在创建前验证目录、prefix 与帧号范围,写入失败应指出 frame id 和路径。
|
5. 新增 `output.h/.c`,从 `optics` 移出文件命名和写图逻辑。默认 movie PNG 仍复用当前 libpng 路径,命名固定为 `<output-dir>/<prefix>_%06u.png`,例如 `output/imgs/minkowski_accel_000042.png`;无 libpng 的 PPM fallback 只替换扩展名。创建前验证目录、prefix 与帧号范围,写入失败应指出 frame id 和路径。
|
||||||
|
|
||||||
验收:原有 `make test` 和两种单帧 backend 的输出保持不变;新测试验证 CSV 拒绝缺列、非有限数与非单调时间,frame 时间表精确包含首帧且不越界,PNG 序号无冲突。此阶段不要求 FFmpeg,也不改变 ray tracing 的调度方式。
|
验收:原有 `make test` 和两种单帧 backend 的输出保持不变;新测试验证 CSV 拒绝缺列、非有限数与非单调时间,frame 时间表精确包含首帧且不越界,PNG 序号无冲突。此阶段不要求 FFmpeg,也不改变 ray tracing 的调度方式。
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user