Add fog material creation and disposal methods in RuntimeHost
This commit is contained in:
@@ -14,6 +14,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 BOX_FACE_MATERIAL_COUNT = 6;
|
||||
const WATER_REFLECTION_UPDATE_INTERVAL_MS = 96;
|
||||
export class RuntimeHost {
|
||||
scene = new Scene();
|
||||
@@ -379,14 +380,15 @@ export class RuntimeHost {
|
||||
const contactPatches = brush.volume.mode === "water"
|
||||
? this.mergeRuntimeWaterContactPatches(staticContactPatches, this.collectRuntimePlayerWaterContactPatches(brush))
|
||||
: [];
|
||||
const materials = [
|
||||
this.createFaceMaterial(brush, "posX", brush.faces.posX.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "negX", brush.faces.negX.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "posY", brush.faces.posY.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "negY", brush.faces.negY.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "posZ", brush.faces.posZ.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "negZ", brush.faces.negZ.material, volumeRenderPaths, contactPatches, staticContactPatches)
|
||||
];
|
||||
const materials = this.createFogMaterialSet(brush, volumeRenderPaths) ??
|
||||
[
|
||||
this.createFaceMaterial(brush, "posX", brush.faces.posX.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "negX", brush.faces.negX.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "posY", brush.faces.posY.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "negY", brush.faces.negY.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "posZ", brush.faces.posZ.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "negZ", brush.faces.negZ.material, volumeRenderPaths, contactPatches, staticContactPatches)
|
||||
];
|
||||
const mesh = new Mesh(geometry, materials);
|
||||
mesh.position.set(brush.center.x, brush.center.y, brush.center.z);
|
||||
mesh.rotation.set((brush.rotationDegrees.x * Math.PI) / 180, (brush.rotationDegrees.y * Math.PI) / 180, (brush.rotationDegrees.z * Math.PI) / 180);
|
||||
@@ -396,6 +398,34 @@ export class RuntimeHost {
|
||||
}
|
||||
this.applyShadowState();
|
||||
}
|
||||
createFogMaterialSet(brush, volumeRenderPaths) {
|
||||
if (brush.volume.mode !== "fog") {
|
||||
return null;
|
||||
}
|
||||
if (volumeRenderPaths.fog === "quality") {
|
||||
const fogMaterial = createFogQualityMaterial({
|
||||
colorHex: brush.volume.fog.colorHex,
|
||||
density: brush.volume.fog.density,
|
||||
padding: brush.volume.fog.padding,
|
||||
time: this.volumeTime,
|
||||
halfSize: {
|
||||
x: brush.size.x * 0.5,
|
||||
y: brush.size.y * 0.5,
|
||||
z: brush.size.z * 0.5
|
||||
}
|
||||
});
|
||||
this.volumeAnimatedUniforms.push(fogMaterial.animationUniform);
|
||||
return Array.from({ length: BOX_FACE_MATERIAL_COUNT }, () => fogMaterial.material);
|
||||
}
|
||||
const densityOpacity = Math.max(0.06, Math.min(0.72, brush.volume.fog.density * 0.8 + 0.08));
|
||||
const fogMaterial = new MeshBasicMaterial({
|
||||
color: brush.volume.fog.colorHex,
|
||||
transparent: true,
|
||||
opacity: densityOpacity,
|
||||
depthWrite: false
|
||||
});
|
||||
return Array.from({ length: BOX_FACE_MATERIAL_COUNT }, () => fogMaterial);
|
||||
}
|
||||
configureFogVolumeMesh(mesh, materials) {
|
||||
const fogMaterials = materials.filter((material) => material instanceof ShaderMaterial && material.uniforms["localCameraPosition"] !== undefined);
|
||||
if (fogMaterials.length === 0) {
|
||||
@@ -666,9 +696,7 @@ export class RuntimeHost {
|
||||
for (const mesh of this.brushMeshes.values()) {
|
||||
this.brushGroup.remove(mesh);
|
||||
mesh.geometry.dispose();
|
||||
for (const material of mesh.material) {
|
||||
material.dispose();
|
||||
}
|
||||
this.disposeUniqueMaterials(mesh.material);
|
||||
}
|
||||
this.brushMeshes.clear();
|
||||
this.volumeAnimatedUniforms.length = 0;
|
||||
@@ -677,6 +705,11 @@ export class RuntimeHost {
|
||||
}
|
||||
this.runtimeWaterContactUniforms.length = 0;
|
||||
}
|
||||
disposeUniqueMaterials(materials) {
|
||||
for (const material of new Set(materials)) {
|
||||
material.dispose();
|
||||
}
|
||||
}
|
||||
createPlayerWaterContactBounds() {
|
||||
if (this.runtimeScene === null || this.currentFirstPersonTelemetry === null) {
|
||||
return null;
|
||||
|
||||
@@ -94,6 +94,7 @@ interface RuntimeWaterContactUniformBinding {
|
||||
}
|
||||
|
||||
const FALLBACK_FACE_COLOR = 0x747d89;
|
||||
const BOX_FACE_MATERIAL_COUNT = 6;
|
||||
const WATER_REFLECTION_UPDATE_INTERVAL_MS = 96;
|
||||
|
||||
export class RuntimeHost {
|
||||
@@ -562,14 +563,16 @@ export class RuntimeHost {
|
||||
? this.mergeRuntimeWaterContactPatches(brush, staticContactPatches, this.collectRuntimePlayerWaterContactPatches(brush))
|
||||
: [];
|
||||
|
||||
const materials = [
|
||||
this.createFaceMaterial(brush, "posX", brush.faces.posX.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "negX", brush.faces.negX.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "posY", brush.faces.posY.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "negY", brush.faces.negY.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "posZ", brush.faces.posZ.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "negZ", brush.faces.negZ.material, volumeRenderPaths, contactPatches, staticContactPatches)
|
||||
];
|
||||
const materials =
|
||||
this.createFogMaterialSet(brush, volumeRenderPaths) ??
|
||||
[
|
||||
this.createFaceMaterial(brush, "posX", brush.faces.posX.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "negX", brush.faces.negX.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "posY", brush.faces.posY.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "negY", brush.faces.negY.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "posZ", brush.faces.posZ.material, volumeRenderPaths, contactPatches, staticContactPatches),
|
||||
this.createFaceMaterial(brush, "negZ", brush.faces.negZ.material, volumeRenderPaths, contactPatches, staticContactPatches)
|
||||
];
|
||||
|
||||
const mesh = new Mesh(geometry, materials);
|
||||
mesh.position.set(brush.center.x, brush.center.y, brush.center.z);
|
||||
@@ -586,6 +589,42 @@ export class RuntimeHost {
|
||||
this.applyShadowState();
|
||||
}
|
||||
|
||||
private createFogMaterialSet(
|
||||
brush: RuntimeBoxBrushInstance,
|
||||
volumeRenderPaths: { fog: "performance" | "quality"; water: "performance" | "quality" }
|
||||
): Material[] | null {
|
||||
if (brush.volume.mode !== "fog") {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (volumeRenderPaths.fog === "quality") {
|
||||
const fogMaterial = createFogQualityMaterial({
|
||||
colorHex: brush.volume.fog.colorHex,
|
||||
density: brush.volume.fog.density,
|
||||
padding: brush.volume.fog.padding,
|
||||
time: this.volumeTime,
|
||||
halfSize: {
|
||||
x: brush.size.x * 0.5,
|
||||
y: brush.size.y * 0.5,
|
||||
z: brush.size.z * 0.5
|
||||
}
|
||||
});
|
||||
|
||||
this.volumeAnimatedUniforms.push(fogMaterial.animationUniform);
|
||||
return Array.from({ length: BOX_FACE_MATERIAL_COUNT }, () => fogMaterial.material);
|
||||
}
|
||||
|
||||
const densityOpacity = Math.max(0.06, Math.min(0.72, brush.volume.fog.density * 0.8 + 0.08));
|
||||
const fogMaterial = new MeshBasicMaterial({
|
||||
color: brush.volume.fog.colorHex,
|
||||
transparent: true,
|
||||
opacity: densityOpacity,
|
||||
depthWrite: false
|
||||
});
|
||||
|
||||
return Array.from({ length: BOX_FACE_MATERIAL_COUNT }, () => fogMaterial);
|
||||
}
|
||||
|
||||
private configureFogVolumeMesh(mesh: Mesh<BufferGeometry, Material[]>, materials: Material[]) {
|
||||
const fogMaterials = materials.filter(
|
||||
(material): material is ShaderMaterial => material instanceof ShaderMaterial && material.uniforms["localCameraPosition"] !== undefined
|
||||
@@ -926,10 +965,7 @@ export class RuntimeHost {
|
||||
for (const mesh of this.brushMeshes.values()) {
|
||||
this.brushGroup.remove(mesh);
|
||||
mesh.geometry.dispose();
|
||||
|
||||
for (const material of mesh.material) {
|
||||
material.dispose();
|
||||
}
|
||||
this.disposeUniqueMaterials(mesh.material);
|
||||
}
|
||||
|
||||
this.brushMeshes.clear();
|
||||
@@ -940,6 +976,12 @@ export class RuntimeHost {
|
||||
this.runtimeWaterContactUniforms.length = 0;
|
||||
}
|
||||
|
||||
private disposeUniqueMaterials(materials: Material[]) {
|
||||
for (const material of new Set(materials)) {
|
||||
material.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private createPlayerWaterContactBounds() {
|
||||
if (this.runtimeScene === null || this.currentFirstPersonTelemetry === null) {
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user