realizeStage function
Applies document's stage render settings to scene: environment,
environment intensity, exposure, tone mapping, skybox, and sky lighting.
When the stage binds sky lighting (skyEnvironment), the binding owns
Scene.environment and the stage's environment is not applied. A skybox
and a sky-lighting binding whose sources describe the same sky share one
live source, so mutating it (or hot reloading its .fmat) updates both.
GPU-bound and async (an asset environment decodes its image, an fmat sky
loads by source path from bundle, default the root bundle).
Implementation
Future<void> realizeStage(
SceneDocument document,
Scene scene, {
AssetBundle? bundle,
}) async {
final stage = document.stage;
scene.environmentIntensity = stage.environmentIntensity;
scene.exposure = stage.exposure;
scene.toneMapping = _toneMapping(stage.toneMapping);
scene.antiAliasingMode = _byName(
AntiAliasingMode.values,
stage.antiAliasingMode,
AntiAliasingMode.auto,
);
scene.renderScale = stage.renderScale;
scene.filterQuality = _byName(
ui.FilterQuality.values,
stage.filterQuality,
ui.FilterQuality.medium,
);
// Realize each distinct sky source once so a skybox and sky lighting
// describing the same sky share one live source.
final realized = <String, SkySource?>{};
Future<SkySource?> sourceFor(SkySourceSpec spec) async =>
realized[canonicalJson(encodeSkySource(spec))] ??=
await _realizeSkySource(spec, bundle);
final skyEnvironmentSpec = stage.skyEnvironment;
if (skyEnvironmentSpec == null) {
scene.skyEnvironment = null;
await _applyEnvironment(stage.environment, scene, bundle);
} else {
final source = await sourceFor(skyEnvironmentSpec.source);
if (source is ShaderSkySource) {
scene.skyEnvironment = SkyEnvironment(
source,
refresh: _refresh(skyEnvironmentSpec.refresh),
interval: Duration(
microseconds: (skyEnvironmentSpec.intervalSeconds * 1e6).round(),
),
faceResolution: skyEnvironmentSpec.faceResolution,
equirectWidth: skyEnvironmentSpec.equirectWidth,
);
} else {
if (source != null) {
debugPrint(
'fscene: skyEnvironment needs a shader sky (fmat, gradient, or '
'physical); skipping the binding',
);
}
scene.skyEnvironment = null;
await _applyEnvironment(stage.environment, scene, bundle);
}
}
final skyboxSpec = stage.skybox;
if (skyboxSpec == null) {
scene.skybox = null;
} else {
final source = await sourceFor(skyboxSpec.source);
scene.skybox = source == null
? null
: Skybox(source, intensity: skyboxSpec.intensity);
}
}