mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
fix(sky): keep the Milky Way out of model lighting, test the sky wiring
Scene reads skyBox._cubeMap as the environment map that lights models, in the TEME, flipY layout of Cesium's own sky box; the ICRF Milky Way would light them rotated. Rename the field so models keep Cesium's default. Test the anime fade on a real StarrySky and that the viewer gets the sky as an option (skyBox: false would drop the Sun and Moon). Correct three comments on the star limit and the Milky Way levels. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
86ae5e9cf4
commit
d94cc35c81
7 files changed
+54
-17
No files matched your search
@@ -31,7 +31,9 @@
|
|||||||
* celestial pole — rotating each direction into galactic coordinates
|
* celestial pole — rotating each direction into galactic coordinates
|
||||||
* with the IAU J2000 matrix.
|
* with the IAU J2000 matrix.
|
||||||
* 6. Map the median sky to black, easing in with a soft knee, and the
|
* 6. Map the median sky to black, easing in with a soft knee, and the
|
||||||
* brightest 0.01 % to white (on luminance, keeping each pixel's hue),
|
* brightest 0.01 % to about 97 % white, the knee's offset there (both
|
||||||
|
* levels taken before the faint-glow blend; on luminance, keeping each
|
||||||
|
* pixel's hue),
|
||||||
* encode with gamma 1/2.2 and ±0.5 LSB dither against banding; WebP.
|
* encode with gamma 1/2.2 and ±0.5 LSB dither against banding; WebP.
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
@@ -373,6 +375,8 @@ async function main() {
|
|||||||
for (const plane of planes) blurPlane(plane, width, height, sigmaPx);
|
for (const plane of planes) blurPlane(plane, width, height, sigmaPx);
|
||||||
for (const plane of wide)
|
for (const plane of wide)
|
||||||
blurPlane(plane, width, height, (FAINT_BLUR_DEG / 180) * height);
|
blurPlane(plane, width, height, (FAINT_BLUR_DEG / 180) * height);
|
||||||
|
// Levels from the fine blur, so the blend weight and the output share
|
||||||
|
// them; the blend moves the median only in the faint sky it smooths.
|
||||||
const black = luminancePercentile(planes, BLACK_PERCENTILE);
|
const black = luminancePercentile(planes, BLACK_PERCENTILE);
|
||||||
const white = luminancePercentile(planes, WHITE_PERCENTILE);
|
const white = luminancePercentile(planes, WHITE_PERCENTILE);
|
||||||
blendByBrightness(planes, wide, (luminance) =>
|
blendByBrightness(planes, wide, (luminance) =>
|
||||||
|
|||||||
@@ -219,6 +219,17 @@ test('the separate viewer export imports without constructing a browser viewer',
|
|||||||
assert.throws(() => createApplicationViewer({}), /containers are required/);
|
assert.throws(() => createApplicationViewer({}), /containers are required/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('the viewer gets the starry sky as an option, which keeps the Sun and Moon', async () => {
|
||||||
|
const { applicationViewerOptions } = await import('./viewer.js');
|
||||||
|
const { StarrySky } = await import('../sky/starrySky.js');
|
||||||
|
const creditContainer = {};
|
||||||
|
const options = applicationViewerOptions(creditContainer);
|
||||||
|
// CesiumWidget skips scene.sun and scene.moon when skyBox is false.
|
||||||
|
assert.ok(options.skyBox instanceof StarrySky);
|
||||||
|
assert.equal(options.creditContainer, creditContainer);
|
||||||
|
options.skyBox.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
function pinchFixture({ zoomEventTypes } = {}) {
|
function pinchFixture({ zoomEventTypes } = {}) {
|
||||||
const handlers = new Set();
|
const handlers = new Set();
|
||||||
const relayed = [];
|
const relayed = [];
|
||||||
|
|||||||
+14
-6
@@ -103,11 +103,9 @@ export function installTrackpadPinchZoom(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Create the standard globe viewer in caller-owned, visible containers. */
|
/** Cesium.Viewer options of the standard globe viewer. */
|
||||||
export function createApplicationViewer({ container, creditContainer }) {
|
export function applicationViewerOptions(creditContainer) {
|
||||||
if (!container || !creditContainer)
|
return {
|
||||||
throw new TypeError('Viewer and credit containers are required');
|
|
||||||
const viewer = new Cesium.Viewer(container, {
|
|
||||||
timeline: false,
|
timeline: false,
|
||||||
animation: false,
|
animation: false,
|
||||||
baseLayerPicker: false,
|
baseLayerPicker: false,
|
||||||
@@ -127,7 +125,17 @@ export function createApplicationViewer({ container, creditContainer }) {
|
|||||||
creditContainer,
|
creditContainer,
|
||||||
msaaSamples: 4,
|
msaaSamples: 4,
|
||||||
contextOptions: { webgl: { preserveDrawingBuffer: true } },
|
contextOptions: { webgl: { preserveDrawingBuffer: true } },
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create the standard globe viewer in caller-owned, visible containers. */
|
||||||
|
export function createApplicationViewer({ container, creditContainer }) {
|
||||||
|
if (!container || !creditContainer)
|
||||||
|
throw new TypeError('Viewer and credit containers are required');
|
||||||
|
const viewer = new Cesium.Viewer(
|
||||||
|
container,
|
||||||
|
applicationViewerOptions(creditContainer),
|
||||||
|
);
|
||||||
try {
|
try {
|
||||||
viewer.targetFrameRate = 60;
|
viewer.targetFrameRate = 60;
|
||||||
// Before any tile builds a draw command: Cesium's per-vertex model
|
// Before any tile builds a draw command: Cesium's per-vertex model
|
||||||
|
|||||||
@@ -180,7 +180,10 @@ export class StarrySky {
|
|||||||
this._loading = false;
|
this._loading = false;
|
||||||
this._starData = undefined;
|
this._starData = undefined;
|
||||||
this._faceImages = undefined;
|
this._faceImages = undefined;
|
||||||
this._cubeMap = undefined;
|
// Not `_cubeMap`: Scene reads `skyBox._cubeMap` as the environment map
|
||||||
|
// that lights models, in the TEME, flipY layout of its own sky box. This
|
||||||
|
// ICRF map would light them rotated, so models keep Cesium's default.
|
||||||
|
this._milkyWayCubeMap = undefined;
|
||||||
this._milkyWayCommand = undefined;
|
this._milkyWayCommand = undefined;
|
||||||
this._milkyWayAttributes = undefined;
|
this._milkyWayAttributes = undefined;
|
||||||
this._starCommand = undefined;
|
this._starCommand = undefined;
|
||||||
@@ -191,7 +194,7 @@ export class StarrySky {
|
|||||||
};
|
};
|
||||||
this._milkyWayUniforms = {
|
this._milkyWayUniforms = {
|
||||||
...uniforms,
|
...uniforms,
|
||||||
u_milkyWay: () => this._cubeMap,
|
u_milkyWay: () => this._milkyWayCubeMap,
|
||||||
u_intensity: () => this.milkyWayIntensity * this.milkyWayVisibility,
|
u_intensity: () => this.milkyWayIntensity * this.milkyWayVisibility,
|
||||||
};
|
};
|
||||||
this._starUniforms = {
|
this._starUniforms = {
|
||||||
@@ -301,7 +304,7 @@ export class StarrySky {
|
|||||||
cubeMap.sampler = new Cesium.Sampler({
|
cubeMap.sampler = new Cesium.Sampler({
|
||||||
minificationFilter: Cesium.TextureMinificationFilter.LINEAR_MIPMAP_LINEAR,
|
minificationFilter: Cesium.TextureMinificationFilter.LINEAR_MIPMAP_LINEAR,
|
||||||
});
|
});
|
||||||
this._cubeMap = cubeMap;
|
this._milkyWayCubeMap = cubeMap;
|
||||||
this._faceImages = undefined;
|
this._faceImages = undefined;
|
||||||
const geometry = Cesium.BoxGeometry.createGeometry(
|
const geometry = Cesium.BoxGeometry.createGeometry(
|
||||||
Cesium.BoxGeometry.fromDimensions({
|
Cesium.BoxGeometry.fromDimensions({
|
||||||
@@ -440,7 +443,7 @@ export class StarrySky {
|
|||||||
command.vertexArray?.destroy();
|
command.vertexArray?.destroy();
|
||||||
command.shaderProgram?.destroy();
|
command.shaderProgram?.destroy();
|
||||||
}
|
}
|
||||||
this._cubeMap = this._cubeMap?.destroy();
|
this._milkyWayCubeMap = this._milkyWayCubeMap?.destroy();
|
||||||
this._milkyWayCommand = undefined;
|
this._milkyWayCommand = undefined;
|
||||||
this._starCommand = undefined;
|
this._starCommand = undefined;
|
||||||
this._commands.length = 0;
|
this._commands.length = 0;
|
||||||
|
|||||||
@@ -127,3 +127,11 @@ test('the Milky Way glow scales with its visibility, for styles that hide it', (
|
|||||||
assert.equal(sky._milkyWayUniforms.u_intensity(), 0);
|
assert.equal(sky._milkyWayUniforms.u_intensity(), 0);
|
||||||
sky.destroy();
|
sky.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('the Milky Way stays out of the environment map that lights models', () => {
|
||||||
|
// Scene#render hands `skyBox._cubeMap` to image-based lighting, which
|
||||||
|
// expects Cesium's own TEME, flipY layout; this ICRF map would be rotated.
|
||||||
|
const sky = new StarrySky({ requestRender: () => {} });
|
||||||
|
assert.equal('_cubeMap' in sky, false);
|
||||||
|
sky.destroy();
|
||||||
|
});
|
||||||
+1
-1
@@ -13,7 +13,7 @@
|
|||||||
* @module sky/stars
|
* @module sky/stars
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Faintest catalogue magnitude; also the reference for brightness. */
|
/** Faintest magnitude drawn distinctly (fainter catalogue stars look like it); the brightness reference. */
|
||||||
export const STAR_LIMIT_MAGNITUDE = 6.5;
|
export const STAR_LIMIT_MAGNITUDE = 6.5;
|
||||||
/** Gaussian σ of the faintest star, CSS pixels. */
|
/** Gaussian σ of the faintest star, CSS pixels. */
|
||||||
export const STAR_MIN_SIGMA_PX = 0.55;
|
export const STAR_MIN_SIGMA_PX = 0.55;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
import test from 'node:test';
|
import test from 'node:test';
|
||||||
import { VisualEffects } from './visualEffects.js';
|
import { VisualEffects } from './visualEffects.js';
|
||||||
|
import { MILKY_WAY_INTENSITY, StarrySky } from '../sky/starrySky.js';
|
||||||
import {
|
import {
|
||||||
GLOBAL_POST_DEFAULTS,
|
GLOBAL_POST_DEFAULTS,
|
||||||
STYLE_PRESET_DEFAULTS,
|
STYLE_PRESET_DEFAULTS,
|
||||||
@@ -160,17 +161,19 @@ test('direct Cockpit intensity writes are reconciled before rendering', () => {
|
|||||||
|
|
||||||
test('the anime stage fades the Milky Way out with its own intensity', () => {
|
test('the anime stage fades the Milky Way out with its own intensity', () => {
|
||||||
const f = fixture();
|
const f = fixture();
|
||||||
const sky = { milkyWayVisibility: 1 };
|
const sky = new StarrySky({ requestRender: () => {} });
|
||||||
|
const glow = () => sky._milkyWayUniforms.u_intensity();
|
||||||
f.effects.viewer.scene.skyBox = sky;
|
f.effects.viewer.scene.skyBox = sky;
|
||||||
f.effects.initStyles();
|
f.effects.initStyles();
|
||||||
f.effects.setStageIntensity(f.effects.stages.thermal, 1);
|
f.effects.setStageIntensity(f.effects.stages.thermal, 1);
|
||||||
assert.equal(sky.milkyWayVisibility, 1, 'other styles keep the glow');
|
assert.equal(glow(), MILKY_WAY_INTENSITY, 'other styles keep the glow');
|
||||||
f.effects.setStageIntensity(f.effects.stages.anime, 0.25);
|
f.effects.setStageIntensity(f.effects.stages.anime, 0.25);
|
||||||
assert.equal(sky.milkyWayVisibility, 0.75);
|
assert.equal(glow(), MILKY_WAY_INTENSITY * 0.75);
|
||||||
f.effects.setStageIntensity(f.effects.stages.anime, 1);
|
f.effects.setStageIntensity(f.effects.stages.anime, 1);
|
||||||
assert.equal(sky.milkyWayVisibility, 0);
|
assert.equal(glow(), 0);
|
||||||
f.effects.setStageIntensity(f.effects.stages.anime, 0);
|
f.effects.setStageIntensity(f.effects.stages.anime, 0);
|
||||||
assert.equal(sky.milkyWayVisibility, 1);
|
assert.equal(glow(), MILKY_WAY_INTENSITY);
|
||||||
|
sky.destroy();
|
||||||
// A sky box without the knob (Cesium's own) is left alone.
|
// A sky box without the knob (Cesium's own) is left alone.
|
||||||
const plain = {};
|
const plain = {};
|
||||||
f.effects.viewer.scene.skyBox = plain;
|
f.effects.viewer.scene.skyBox = plain;
|
||||||
|
|||||||
Reference in new issue
Block a user