Add water reflection update interval and fix fog handling in RuntimeHost

This commit is contained in:
2026-04-07 07:19:35 +02:00
parent 6881b3ae2f
commit cb2b511cfc

View File

@@ -13,6 +13,7 @@ import { RuntimeAudioSystem } from "./runtime-audio-system";
import { OrbitVisitorNavigationController } from "./orbit-visitor-navigation-controller";
import { resolveUnderwaterFogState } from "./underwater-fog";
const FALLBACK_FACE_COLOR = 0x747d89;
const WATER_REFLECTION_UPDATE_INTERVAL_MS = 96;
export class RuntimeHost {
scene = new Scene();
camera = new PerspectiveCamera(70, 1, 0.05, 1000);
@@ -70,6 +71,8 @@ export class RuntimeHost {
this.scene.add(this.localLightGroup);
this.scene.add(this.brushGroup);
this.scene.add(this.modelGroup);
this.underwaterSceneFog.density = 0;
this.scene.fog = this.underwaterSceneFog;
this.renderer = enableRendering ? new WebGLRenderer({ antialias: false, alpha: true }) : null;
this.domElement = this.renderer?.domElement ?? document.createElement("canvas");
if (this.renderer !== null) {
@@ -432,6 +435,7 @@ export class RuntimeHost {
colorHex: brush.volume.water.colorHex,
surfaceOpacity: brush.volume.water.surfaceOpacity,
waveStrength: brush.volume.water.waveStrength,
surfaceDisplacementEnabled: brush.volume.water.surfaceDisplacementEnabled,
opacity: faceId === "posY" ? Math.min(1, baseOpacity + 0.18) : baseOpacity * 0.5,
quality: volumeRenderPaths.water === "quality",
wireframe: false,
@@ -460,7 +464,8 @@ export class RuntimeHost {
reflectionTextureUniform: waterMaterial.reflectionTextureUniform,
reflectionMatrixUniform: waterMaterial.reflectionMatrixUniform,
reflectionEnabledUniform: waterMaterial.reflectionEnabledUniform,
reflectionRenderTarget: this.getWaterReflectionMode() !== "none" ? this.createWaterReflectionRenderTarget() : null
reflectionRenderTarget: this.getWaterReflectionMode() !== "none" ? this.createWaterReflectionRenderTarget() : null,
lastReflectionUpdateTime: Number.NEGATIVE_INFINITY
});
}
return waterMaterial.material;
@@ -549,16 +554,11 @@ export class RuntimeHost {
? resolveUnderwaterFogState(this.runtimeScene, this.currentFirstPersonTelemetry)
: null;
if (fogState === null) {
if (this.scene.fog !== null) {
this.scene.fog = null;
}
this.underwaterSceneFog.density = 0;
return;
}
this.underwaterSceneFog.color.set(fogState.colorHex);
this.underwaterSceneFog.density = fogState.density;
if (this.scene.fog !== this.underwaterSceneFog) {
this.scene.fog = this.underwaterSceneFog;
}
}
getWaterReflectionMode() {
if (this.currentWorld === null || !this.currentWorld.advancedRendering.enabled || this.currentWorld.advancedRendering.waterPath !== "quality") {
@@ -580,6 +580,7 @@ export class RuntimeHost {
const height = Math.max(128, Math.round(Math.max(canvasHeight, 512) * 0.5));
for (const binding of this.runtimeWaterContactUniforms) {
binding.reflectionRenderTarget?.setSize(width, height);
binding.lastReflectionUpdateTime = Number.NEGATIVE_INFINITY;
}
}
updateRuntimeWaterReflections() {
@@ -587,6 +588,7 @@ export class RuntimeHost {
return;
}
const reflectionMode = this.getWaterReflectionMode();
const now = performance.now();
for (const binding of this.runtimeWaterContactUniforms) {
if (reflectionMode === "none" ||
binding.reflectionRenderTarget === null ||
@@ -603,6 +605,10 @@ export class RuntimeHost {
binding.reflectionEnabledUniform.value = 0;
continue;
}
if (binding.reflectionTextureUniform.value !== null && now - binding.lastReflectionUpdateTime < WATER_REFLECTION_UPDATE_INTERVAL_MS) {
binding.reflectionEnabledUniform.value = 0.36;
continue;
}
const hiddenWaterMeshes = [];
for (const runtimeBrush of this.runtimeScene.brushes) {
if (runtimeBrush.volume.mode !== "water") {
@@ -621,18 +627,26 @@ export class RuntimeHost {
}
const previousAutoClear = this.renderer.autoClear;
const previousRenderTarget = this.renderer.getRenderTarget();
this.renderer.autoClear = true;
this.renderer.setRenderTarget(binding.reflectionRenderTarget);
this.renderer.clear();
this.renderer.render(this.scene, this.waterReflectionCamera);
this.renderer.setRenderTarget(previousRenderTarget);
this.renderer.autoClear = previousAutoClear;
this.modelGroup.visible = previousModelGroupVisibility;
for (const hiddenWaterMesh of hiddenWaterMeshes) {
hiddenWaterMesh.mesh.visible = hiddenWaterMesh.visible;
const previousFogDensity = this.underwaterSceneFog.density;
try {
this.underwaterSceneFog.density = 0;
this.renderer.autoClear = true;
this.renderer.setRenderTarget(binding.reflectionRenderTarget);
this.renderer.clear();
this.renderer.render(this.scene, this.waterReflectionCamera);
}
finally {
this.renderer.setRenderTarget(previousRenderTarget);
this.renderer.autoClear = previousAutoClear;
this.modelGroup.visible = previousModelGroupVisibility;
this.underwaterSceneFog.density = previousFogDensity;
for (const hiddenWaterMesh of hiddenWaterMeshes) {
hiddenWaterMesh.mesh.visible = hiddenWaterMesh.visible;
}
}
binding.reflectionTextureUniform.value = binding.reflectionRenderTarget.texture;
binding.reflectionEnabledUniform.value = 0.36;
binding.lastReflectionUpdateTime = now;
}
}
getOrCreateTexture(material) {