| … | … | @@ -367,6 +367,31 @@ def bake_document(doc, out_path, size=256, dispatches=200, bounds=None, |
| 367 | 367 | invocation_iters) |
| 368 | 368 | path, peak = write_vdb(grid, bounds, out_path, gamma=gamma) |
| 369 | 369 | occupied = int((grid[:, :, :, 3] > 0).sum()) |
| 370 | |
| 371 | # How bright to drive emission, DERIVED rather than guessed. A fixed number cannot |
| 372 | # work: measured across two shipped templates the required scale differs by ~200x |
| 373 | # (nebula wants ~1100, the gasket ~5), because peak-normalised density depends |
| 374 | # entirely on how long-tailed that particular fractal's histogram is. A constant |
| 375 | # tuned on one document blows the other to white, which is exactly what happened. |
| 376 | # |
| 377 | # The statistic is what the renderer actually integrates: density summed ALONG A |
| 378 | # RAY. Sum each column, average over the columns that contain anything, and scale |
| 379 | # so a typical ray through the fractal integrates to ~1. Not a heuristic - it is |
| 380 | # the quantity the volume integrator accumulates. |
| 381 | # Averaged over ALL THREE axes, not one. Summing a single axis measures the path |
| 382 | # a ray takes along that axis only, and for a PLANAR fractal - the gasket is two |
| 383 | # probe voxels thick - the fixed axis is the thin direction, so the statistic |
| 384 | # reports the shortest possible path and derives an exposure far too dark. The |
| 385 | # camera can look from anywhere, so the metric has to be view-independent. |
| 386 | normalised = grid[:, :, :, 3] / peak if peak > 0 else grid[:, :, :, 3] |
| 387 | per_axis = [] |
| 388 | for axis in range(3): |
| 389 | columns = normalised.sum(axis=axis) |
| 390 | lit_columns = columns[columns > 0] |
| 391 | if lit_columns.size: |
| 392 | per_axis.append(float(lit_columns.mean())) |
| 393 | mean_column = float(np.mean(per_axis)) if per_axis else 0.0 |
| 394 | emission_scale = (1.0 / mean_column) if mean_column > 0 else 1.0 |
| 370 | 395 | return path, { |
| 371 | 396 | **fit, |
| 372 | 397 | "bounds": bounds, |
| … | … | @@ -374,6 +399,8 @@ def bake_document(doc, out_path, size=256, dispatches=200, bounds=None, |
| 374 | 399 | "occupied_voxels": occupied, |
| 375 | 400 | "total_voxels": size ** 3, |
| 376 | 401 | "peak_density": peak, |
| 402 | "emission_scale": emission_scale, |
| 403 | "mean_column_density": mean_column, |
| 377 | 404 | } |
| 378 | 405 | |
| 379 | 406 | |