space-game/src/core/sceneSetup.ts
Michael Mainguy 453e26e57b Clarify WebGPU warning message to mention engine type
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 06:55:48 -06:00

101 lines
3.5 KiB
TypeScript

import {
AbstractEngine,
AudioEngineV2,
Color3,
CreateAudioEngineAsync,
Engine,
HavokPlugin,
Scene,
Vector3,
WebGPUEngine,
} from "@babylonjs/core";
import HavokPhysics from "@babylonjs/havok";
import { DefaultScene } from "./defaultScene";
import { ProgressReporter } from "./xrSetup";
import { useWebGPU } from "./queryParams";
import log from './logger';
export interface SceneSetupResult {
engine: AbstractEngine;
audioEngine: AudioEngineV2;
}
/**
* Setup the BabylonJS engine, scene, physics, and audio
*/
export async function setupScene(
canvas: HTMLCanvasElement,
reporter: ProgressReporter
): Promise<SceneSetupResult> {
reporter.reportProgress(5, 'Creating rendering engine...');
const engine = await createEngine(canvas);
reporter.reportProgress(10, 'Creating scene...');
createMainScene(engine);
reporter.reportProgress(15, 'Loading physics engine...');
await setupPhysics();
reporter.reportProgress(20, 'Physics engine ready');
reporter.reportProgress(22, 'Initializing spatial audio...');
const audioEngine = await createAudioEngine();
reporter.reportProgress(30, 'Audio engine ready');
// Stop any existing render loop before starting new one (prevents doubling on reload)
engine.stopRenderLoop();
engine.runRenderLoop(() => DefaultScene.MainScene.render());
return { engine, audioEngine };
}
async function createEngine(canvas: HTMLCanvasElement): Promise<AbstractEngine> {
let engine: AbstractEngine;
if (useWebGPU) {
log.info('[Engine] Creating WebGPU engine');
log.warn('[Engine] WebXR/VR is still experimental with WebGPU engine');
engine = await WebGPUEngine.CreateAsync(canvas, { antialias: true });
} else {
log.info('[Engine] Creating WebGL engine');
engine = new Engine(canvas, true);
}
engine.setHardwareScalingLevel(1 / window.devicePixelRatio);
window.onresize = () => engine.resize();
return engine;
}
function createMainScene(engine: AbstractEngine): void {
// Dispose old scene if it exists (prevents doubling on reload)
if (DefaultScene.MainScene && !DefaultScene.MainScene.isDisposed) {
DefaultScene.MainScene.dispose();
}
DefaultScene.MainScene = new Scene(engine);
DefaultScene.MainScene.ambientColor = new Color3(.2, .2, .2);
DefaultScene.MainScene.clearColor = new Color3(0, 0, 0).toColor4();
// Performance optimizations for Quest 2
//DefaultScene.MainScene.performancePriority = ScenePerformancePriority.Intermediate;
DefaultScene.MainScene.autoClear = false;
DefaultScene.MainScene.autoClearDepthAndStencil = false;
//const hdrTexture = new HDRCubeTexture("/assets/untitled.hdr", DefaultScene.MainScene, 2048);
//DefaultScene.MainScene.environmentTexture = hdrTexture;
//DefaultScene.MainScene.createDefaultSkybox(hdrTexture, true, 1000);
}
async function setupPhysics(): Promise<void> {
const havok = await HavokPhysics();
const havokPlugin = new HavokPlugin(true, havok);
DefaultScene.MainScene.enablePhysics(new Vector3(0, 0, 0), havokPlugin);
DefaultScene.MainScene.getPhysicsEngine()!.setTimeStep(1/60);
DefaultScene.MainScene.getPhysicsEngine()!.setSubTimeStep(2);
DefaultScene.MainScene.collisionsEnabled = true;
}
async function createAudioEngine(): Promise<AudioEngineV2> {
return await CreateAudioEngineAsync({
volume: 1.0,
listenerAutoUpdate: true,
listenerEnabled: true,
resumeOnInteraction: true
});
}