Add optional WebGPU engine support via ?webGPU=true query parameter
Allows launching the game with WebGPU rendering by passing ?webGPU=true in the URL. Defaults to WebGL engine when the parameter is absent. Logs a warning that WebXR/VR is not yet supported with WebGPU. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
208d735ef4
commit
53388c8193
@ -1,11 +1,11 @@
|
|||||||
import { Engine } from "@babylonjs/core";
|
import { AbstractEngine } from "@babylonjs/core";
|
||||||
import { DefaultScene } from "./defaultScene";
|
import { DefaultScene } from "./defaultScene";
|
||||||
import { RockFactory } from "../environment/asteroids/rockFactory";
|
import { RockFactory } from "../environment/asteroids/rockFactory";
|
||||||
import log from './logger';
|
import log from './logger';
|
||||||
import Level from "../levels/level";
|
import Level from "../levels/level";
|
||||||
|
|
||||||
export interface CleanupContext {
|
export interface CleanupContext {
|
||||||
getEngine(): Engine;
|
getEngine(): AbstractEngine;
|
||||||
getCurrentLevel(): Level | null;
|
getCurrentLevel(): Level | null;
|
||||||
setCurrentLevel(level: Level | null): void;
|
setCurrentLevel(level: Level | null): void;
|
||||||
resetState(): void;
|
resetState(): void;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { AudioEngineV2, Engine, ParticleHelper } from "@babylonjs/core";
|
import { AbstractEngine, AudioEngineV2, ParticleHelper } from "@babylonjs/core";
|
||||||
import { DefaultScene } from "../defaultScene";
|
import { DefaultScene } from "../defaultScene";
|
||||||
import { Level1 } from "../../levels/level1";
|
import { Level1 } from "../../levels/level1";
|
||||||
import Level from "../../levels/level";
|
import Level from "../../levels/level";
|
||||||
@ -20,7 +20,7 @@ export interface LevelSelectedContext {
|
|||||||
initializeEngine(): Promise<void>;
|
initializeEngine(): Promise<void>;
|
||||||
initializeXR(): Promise<void>;
|
initializeXR(): Promise<void>;
|
||||||
getAudioEngine(): AudioEngineV2;
|
getAudioEngine(): AudioEngineV2;
|
||||||
getEngine(): Engine;
|
getEngine(): AbstractEngine;
|
||||||
setCurrentLevel(level: Level): void;
|
setCurrentLevel(level: Level): void;
|
||||||
setProgressCallback(callback: (percent: number, message: string) => void): void;
|
setProgressCallback(callback: (percent: number, message: string) => void): void;
|
||||||
play(): Promise<void>;
|
play(): Promise<void>;
|
||||||
@ -169,7 +169,7 @@ function attachAudioListener(audioEngine: AudioEngineV2): void {
|
|||||||
|
|
||||||
async function finalizeLevelStart(
|
async function finalizeLevelStart(
|
||||||
level: Level1,
|
level: Level1,
|
||||||
engine: Engine,
|
engine: AbstractEngine,
|
||||||
preloader: Preloader,
|
preloader: Preloader,
|
||||||
context: LevelSelectedContext
|
context: LevelSelectedContext
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
@ -188,7 +188,7 @@ async function finalizeLevelStart(
|
|||||||
await context.play();
|
await context.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
function showCanvasForFlatMode(engine: Engine): void {
|
function showCanvasForFlatMode(engine: AbstractEngine): void {
|
||||||
const canvas = document.getElementById('gameCanvas');
|
const canvas = document.getElementById('gameCanvas');
|
||||||
if (canvas) canvas.style.display = 'block';
|
if (canvas) canvas.style.display = 'block';
|
||||||
engine.stopRenderLoop();
|
engine.stopRenderLoop();
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Engine, FreeCamera, Vector3 } from "@babylonjs/core";
|
import { AbstractEngine, FreeCamera, Vector3 } from "@babylonjs/core";
|
||||||
import { DefaultScene } from "../defaultScene";
|
import { DefaultScene } from "../defaultScene";
|
||||||
import { LevelConfig } from "../../levels/config/levelConfig";
|
import { LevelConfig } from "../../levels/config/levelConfig";
|
||||||
import log from '../logger';
|
import log from '../logger';
|
||||||
@ -9,7 +9,7 @@ import log from '../logger';
|
|||||||
*/
|
*/
|
||||||
export async function enterXRMode(
|
export async function enterXRMode(
|
||||||
config: LevelConfig,
|
config: LevelConfig,
|
||||||
engine: Engine
|
engine: AbstractEngine
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
if (!DefaultScene.XR) {
|
if (!DefaultScene.XR) {
|
||||||
return startFlatMode(engine);
|
return startFlatMode(engine);
|
||||||
@ -39,7 +39,7 @@ function prePositionCamera(config: LevelConfig): void {
|
|||||||
log.debug('[XR] Camera pre-positioned at cockpit:', cockpitPosition.toString());
|
log.debug('[XR] Camera pre-positioned at cockpit:', cockpitPosition.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
function startFlatMode(engine: Engine): null {
|
function startFlatMode(engine: AbstractEngine): null {
|
||||||
const canvas = document.getElementById('gameCanvas');
|
const canvas = document.getElementById('gameCanvas');
|
||||||
if (canvas) canvas.style.display = 'block';
|
if (canvas) canvas.style.display = 'block';
|
||||||
engine.stopRenderLoop();
|
engine.stopRenderLoop();
|
||||||
|
|||||||
3
src/core/queryParams.ts
Normal file
3
src/core/queryParams.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
|
export const useWebGPU = urlParams.get('webGPU') === 'true';
|
||||||
@ -1,18 +1,22 @@
|
|||||||
import {
|
import {
|
||||||
|
AbstractEngine,
|
||||||
AudioEngineV2,
|
AudioEngineV2,
|
||||||
Color3,
|
Color3,
|
||||||
CreateAudioEngineAsync,
|
CreateAudioEngineAsync,
|
||||||
Engine,
|
Engine,
|
||||||
HavokPlugin,
|
HavokPlugin,
|
||||||
Scene,
|
Scene,
|
||||||
Vector3
|
Vector3,
|
||||||
|
WebGPUEngine,
|
||||||
} from "@babylonjs/core";
|
} from "@babylonjs/core";
|
||||||
import HavokPhysics from "@babylonjs/havok";
|
import HavokPhysics from "@babylonjs/havok";
|
||||||
import { DefaultScene } from "./defaultScene";
|
import { DefaultScene } from "./defaultScene";
|
||||||
import { ProgressReporter } from "./xrSetup";
|
import { ProgressReporter } from "./xrSetup";
|
||||||
|
import { useWebGPU } from "./queryParams";
|
||||||
|
import log from './logger';
|
||||||
|
|
||||||
export interface SceneSetupResult {
|
export interface SceneSetupResult {
|
||||||
engine: Engine;
|
engine: AbstractEngine;
|
||||||
audioEngine: AudioEngineV2;
|
audioEngine: AudioEngineV2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,7 +28,7 @@ export async function setupScene(
|
|||||||
reporter: ProgressReporter
|
reporter: ProgressReporter
|
||||||
): Promise<SceneSetupResult> {
|
): Promise<SceneSetupResult> {
|
||||||
reporter.reportProgress(5, 'Creating rendering engine...');
|
reporter.reportProgress(5, 'Creating rendering engine...');
|
||||||
const engine = createEngine(canvas);
|
const engine = await createEngine(canvas);
|
||||||
|
|
||||||
reporter.reportProgress(10, 'Creating scene...');
|
reporter.reportProgress(10, 'Creating scene...');
|
||||||
createMainScene(engine);
|
createMainScene(engine);
|
||||||
@ -44,14 +48,22 @@ export async function setupScene(
|
|||||||
return { engine, audioEngine };
|
return { engine, audioEngine };
|
||||||
}
|
}
|
||||||
|
|
||||||
function createEngine(canvas: HTMLCanvasElement): Engine {
|
async function createEngine(canvas: HTMLCanvasElement): Promise<AbstractEngine> {
|
||||||
const engine = new Engine(canvas, true);
|
let engine: AbstractEngine;
|
||||||
|
if (useWebGPU) {
|
||||||
|
log.info('[Engine] Creating WebGPU engine');
|
||||||
|
log.warn('[Engine] WebXR/VR is still experimental');
|
||||||
|
engine = await WebGPUEngine.CreateAsync(canvas, { antialias: true });
|
||||||
|
} else {
|
||||||
|
log.info('[Engine] Creating WebGL engine');
|
||||||
|
engine = new Engine(canvas, true);
|
||||||
|
}
|
||||||
engine.setHardwareScalingLevel(1 / window.devicePixelRatio);
|
engine.setHardwareScalingLevel(1 / window.devicePixelRatio);
|
||||||
window.onresize = () => engine.resize();
|
window.onresize = () => engine.resize();
|
||||||
return engine;
|
return engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMainScene(engine: Engine): void {
|
function createMainScene(engine: AbstractEngine): void {
|
||||||
// Dispose old scene if it exists (prevents doubling on reload)
|
// Dispose old scene if it exists (prevents doubling on reload)
|
||||||
if (DefaultScene.MainScene && !DefaultScene.MainScene.isDisposed) {
|
if (DefaultScene.MainScene && !DefaultScene.MainScene.isDisposed) {
|
||||||
DefaultScene.MainScene.dispose();
|
DefaultScene.MainScene.dispose();
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { AudioEngineV2, Engine } from "@babylonjs/core";
|
import { AbstractEngine, AudioEngineV2 } from "@babylonjs/core";
|
||||||
import '@babylonjs/loaders';
|
import '@babylonjs/loaders';
|
||||||
|
|
||||||
import { DefaultScene } from "./core/defaultScene";
|
import { DefaultScene } from "./core/defaultScene";
|
||||||
@ -20,7 +20,7 @@ const canvas = document.querySelector('#gameCanvas') as HTMLCanvasElement;
|
|||||||
|
|
||||||
export class Main implements LevelSelectedContext, CleanupContext {
|
export class Main implements LevelSelectedContext, CleanupContext {
|
||||||
private _currentLevel: Level | null = null;
|
private _currentLevel: Level | null = null;
|
||||||
private _engine: Engine;
|
private _engine: AbstractEngine;
|
||||||
private _audioEngine: AudioEngineV2;
|
private _audioEngine: AudioEngineV2;
|
||||||
private _initialized: boolean = false;
|
private _initialized: boolean = false;
|
||||||
private _assetsLoaded: boolean = false;
|
private _assetsLoaded: boolean = false;
|
||||||
@ -43,7 +43,7 @@ export class Main implements LevelSelectedContext, CleanupContext {
|
|||||||
areAssetsLoaded(): boolean { return this._assetsLoaded; }
|
areAssetsLoaded(): boolean { return this._assetsLoaded; }
|
||||||
setAssetsLoaded(value: boolean): void { this._assetsLoaded = value; }
|
setAssetsLoaded(value: boolean): void { this._assetsLoaded = value; }
|
||||||
getAudioEngine(): AudioEngineV2 { return this._audioEngine; }
|
getAudioEngine(): AudioEngineV2 { return this._audioEngine; }
|
||||||
getEngine(): Engine { return this._engine; }
|
getEngine(): AbstractEngine { return this._engine; }
|
||||||
setCurrentLevel(level: Level): void { this._currentLevel = level; }
|
setCurrentLevel(level: Level): void { this._currentLevel = level; }
|
||||||
setProgressCallback(cb: (percent: number, message: string) => void): void {
|
setProgressCallback(cb: (percent: number, message: string) => void): void {
|
||||||
this._progressCallback = cb;
|
this._progressCallback = cb;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user