Add underwater fog effect and update water material handling
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
|||||||
DirectionalLight,
|
DirectionalLight,
|
||||||
Euler,
|
Euler,
|
||||||
Group,
|
Group,
|
||||||
|
FogExp2,
|
||||||
LoopOnce,
|
LoopOnce,
|
||||||
LoopRepeat,
|
LoopRepeat,
|
||||||
Material,
|
Material,
|
||||||
@@ -38,7 +39,13 @@ import {
|
|||||||
resolveBoxVolumeRenderPaths,
|
resolveBoxVolumeRenderPaths,
|
||||||
type ResolvedBoxVolumeRenderPaths
|
type ResolvedBoxVolumeRenderPaths
|
||||||
} from "../rendering/advanced-rendering";
|
} from "../rendering/advanced-rendering";
|
||||||
import { collectWaterContactPatches, createWaterContactPatchAxisUniformValue, createWaterContactPatchUniformValue, createWaterMaterial } from "../rendering/water-material";
|
import {
|
||||||
|
collectWaterContactPatches,
|
||||||
|
createWaterContactPatchAxisUniformValue,
|
||||||
|
createWaterContactPatchShapeUniformValue,
|
||||||
|
createWaterContactPatchUniformValue,
|
||||||
|
createWaterMaterial
|
||||||
|
} from "../rendering/water-material";
|
||||||
import {
|
import {
|
||||||
areAdvancedRenderingSettingsEqual,
|
areAdvancedRenderingSettingsEqual,
|
||||||
cloneAdvancedRenderingSettings,
|
cloneAdvancedRenderingSettings,
|
||||||
@@ -51,6 +58,7 @@ import { RapierCollisionWorld } from "./rapier-collision-world";
|
|||||||
import { RuntimeInteractionSystem, type RuntimeInteractionDispatcher, type RuntimeInteractionPrompt } from "./runtime-interaction-system";
|
import { RuntimeInteractionSystem, type RuntimeInteractionDispatcher, type RuntimeInteractionPrompt } from "./runtime-interaction-system";
|
||||||
import { RuntimeAudioSystem } from "./runtime-audio-system";
|
import { RuntimeAudioSystem } from "./runtime-audio-system";
|
||||||
import { OrbitVisitorNavigationController } from "./orbit-visitor-navigation-controller";
|
import { OrbitVisitorNavigationController } from "./orbit-visitor-navigation-controller";
|
||||||
|
import { resolveUnderwaterFogState } from "./underwater-fog";
|
||||||
import type {
|
import type {
|
||||||
RuntimeBoxBrushInstance,
|
RuntimeBoxBrushInstance,
|
||||||
RuntimeLocalLightCollection,
|
RuntimeLocalLightCollection,
|
||||||
@@ -72,6 +80,7 @@ interface RuntimeWaterContactUniformBinding {
|
|||||||
brush: RuntimeBoxBrushInstance;
|
brush: RuntimeBoxBrushInstance;
|
||||||
uniform: { value: import("three").Vector4[] };
|
uniform: { value: import("three").Vector4[] };
|
||||||
axisUniform: { value: import("three").Vector2[] };
|
axisUniform: { value: import("three").Vector2[] };
|
||||||
|
shapeUniform: { value: number[] };
|
||||||
staticContactPatches: ReturnType<typeof collectWaterContactPatches>;
|
staticContactPatches: ReturnType<typeof collectWaterContactPatches>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +102,7 @@ export class RuntimeHost {
|
|||||||
private readonly orbitVisitorController = new OrbitVisitorNavigationController();
|
private readonly orbitVisitorController = new OrbitVisitorNavigationController();
|
||||||
private readonly interactionSystem = new RuntimeInteractionSystem();
|
private readonly interactionSystem = new RuntimeInteractionSystem();
|
||||||
private readonly audioSystem = new RuntimeAudioSystem(this.scene, this.camera, null);
|
private readonly audioSystem = new RuntimeAudioSystem(this.scene, this.camera, null);
|
||||||
|
private readonly underwaterSceneFog = new FogExp2("#2c6f8d", 0.03);
|
||||||
private readonly brushMeshes = new Map<string, Mesh<BufferGeometry, Material[]>>();
|
private readonly brushMeshes = new Map<string, Mesh<BufferGeometry, Material[]>>();
|
||||||
private volumeTime = 0;
|
private volumeTime = 0;
|
||||||
private readonly volumeAnimatedMaterials: ShaderMaterial[] = [];
|
private readonly volumeAnimatedMaterials: ShaderMaterial[] = [];
|
||||||
@@ -323,6 +333,7 @@ export class RuntimeHost {
|
|||||||
this.advancedRenderingComposer?.dispose();
|
this.advancedRenderingComposer?.dispose();
|
||||||
this.advancedRenderingComposer = null;
|
this.advancedRenderingComposer = null;
|
||||||
this.currentAdvancedRenderingSettings = null;
|
this.currentAdvancedRenderingSettings = null;
|
||||||
|
this.scene.fog = null;
|
||||||
if (this.renderer !== null) {
|
if (this.renderer !== null) {
|
||||||
this.renderer.autoClear = true;
|
this.renderer.autoClear = true;
|
||||||
}
|
}
|
||||||
@@ -637,6 +648,7 @@ export class RuntimeHost {
|
|||||||
brush,
|
brush,
|
||||||
uniform: waterMaterial.contactPatchesUniform,
|
uniform: waterMaterial.contactPatchesUniform,
|
||||||
axisUniform: waterMaterial.contactPatchAxesUniform,
|
axisUniform: waterMaterial.contactPatchAxesUniform,
|
||||||
|
shapeUniform: waterMaterial.contactPatchShapesUniform ?? { value: [] },
|
||||||
staticContactPatches
|
staticContactPatches
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -683,9 +695,12 @@ export class RuntimeHost {
|
|||||||
|
|
||||||
const vertexShader = /* glsl */ `
|
const vertexShader = /* glsl */ `
|
||||||
varying vec2 vUv;
|
varying vec2 vUv;
|
||||||
|
#include <fog_pars_vertex>
|
||||||
void main() {
|
void main() {
|
||||||
vUv = uv;
|
vUv = uv;
|
||||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
|
||||||
|
gl_Position = projectionMatrix * mvPosition;
|
||||||
|
#include <fog_vertex>
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -694,6 +709,7 @@ export class RuntimeHost {
|
|||||||
uniform float fogDensity;
|
uniform float fogDensity;
|
||||||
uniform float time;
|
uniform float time;
|
||||||
varying vec2 vUv;
|
varying vec2 vUv;
|
||||||
|
#include <fog_pars_fragment>
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// Soft fade: distance from the center of each face in UV space
|
// Soft fade: distance from the center of each face in UV space
|
||||||
@@ -710,6 +726,7 @@ export class RuntimeHost {
|
|||||||
// Edge scatter brightening
|
// Edge scatter brightening
|
||||||
vec3 color = mix(fogColor, vec3(1.0), (1.0 - edgeFade) * 0.09);
|
vec3 color = mix(fogColor, vec3(1.0), (1.0 - edgeFade) * 0.09);
|
||||||
gl_FragColor = vec4(color, alpha);
|
gl_FragColor = vec4(color, alpha);
|
||||||
|
#include <fog_fragment>
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -723,12 +740,34 @@ export class RuntimeHost {
|
|||||||
},
|
},
|
||||||
transparent: true,
|
transparent: true,
|
||||||
depthWrite: false,
|
depthWrite: false,
|
||||||
|
fog: true,
|
||||||
side: 2 // THREE.DoubleSide — fog is visible from inside too
|
side: 2 // THREE.DoubleSide — fog is visible from inside too
|
||||||
});
|
});
|
||||||
this.volumeAnimatedMaterials.push(mat);
|
this.volumeAnimatedMaterials.push(mat);
|
||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateUnderwaterSceneFog() {
|
||||||
|
const fogState =
|
||||||
|
this.activeController === this.firstPersonController
|
||||||
|
? resolveUnderwaterFogState(this.runtimeScene, this.currentFirstPersonTelemetry)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (fogState === null) {
|
||||||
|
if (this.scene.fog !== null) {
|
||||||
|
this.scene.fog = null;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.underwaterSceneFog.color.set(fogState.colorHex);
|
||||||
|
this.underwaterSceneFog.density = fogState.density;
|
||||||
|
|
||||||
|
if (this.scene.fog !== this.underwaterSceneFog) {
|
||||||
|
this.scene.fog = this.underwaterSceneFog;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private getOrCreateTexture(material: NonNullable<RuntimeBoxBrushInstance["faces"]["posX"]["material"]>) {
|
private getOrCreateTexture(material: NonNullable<RuntimeBoxBrushInstance["faces"]["posX"]["material"]>) {
|
||||||
const signature = createStarterMaterialSignature(material);
|
const signature = createStarterMaterialSignature(material);
|
||||||
const cachedTexture = this.materialTextureCache.get(material.id);
|
const cachedTexture = this.materialTextureCache.get(material.id);
|
||||||
@@ -898,6 +937,7 @@ export class RuntimeHost {
|
|||||||
const mergedPatches = this.mergeRuntimeWaterContactPatches(binding.staticContactPatches, this.collectRuntimePlayerWaterContactPatches(binding.brush));
|
const mergedPatches = this.mergeRuntimeWaterContactPatches(binding.staticContactPatches, this.collectRuntimePlayerWaterContactPatches(binding.brush));
|
||||||
binding.uniform.value = createWaterContactPatchUniformValue(mergedPatches);
|
binding.uniform.value = createWaterContactPatchUniformValue(mergedPatches);
|
||||||
binding.axisUniform.value = createWaterContactPatchAxisUniformValue(mergedPatches);
|
binding.axisUniform.value = createWaterContactPatchAxisUniformValue(mergedPatches);
|
||||||
|
binding.shapeUniform.value = createWaterContactPatchShapeUniformValue(mergedPatches);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -980,6 +1020,8 @@ export class RuntimeHost {
|
|||||||
this.updateRuntimeWaterContactUniforms();
|
this.updateRuntimeWaterContactUniforms();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.updateUnderwaterSceneFog();
|
||||||
|
|
||||||
if (this.advancedRenderingComposer !== null) {
|
if (this.advancedRenderingComposer !== null) {
|
||||||
this.advancedRenderingComposer.render(dt);
|
this.advancedRenderingComposer.render(dt);
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user