Add underwater fog effect and update shader material for water patches
This commit is contained in:
@@ -1,15 +1,16 @@
|
|||||||
import { AmbientLight, AnimationClip, AnimationMixer, DirectionalLight, Euler, Group, LoopOnce, LoopRepeat, Mesh, MeshBasicMaterial, MeshStandardMaterial, PerspectiveCamera, PointLight, Quaternion, Scene, ShaderMaterial, Vector3, SpotLight, WebGLRenderer } from "three";
|
import { AmbientLight, AnimationClip, AnimationMixer, DirectionalLight, Euler, FogExp2, Group, LoopOnce, LoopRepeat, Mesh, MeshBasicMaterial, MeshStandardMaterial, PerspectiveCamera, PointLight, Quaternion, Scene, ShaderMaterial, Vector3, SpotLight, WebGLRenderer } from "three";
|
||||||
import { createModelInstanceRenderGroup, disposeModelInstance } from "../assets/model-instance-rendering";
|
import { createModelInstanceRenderGroup, disposeModelInstance } from "../assets/model-instance-rendering";
|
||||||
import { buildBoxBrushDerivedMeshData } from "../geometry/box-brush-mesh";
|
import { buildBoxBrushDerivedMeshData } from "../geometry/box-brush-mesh";
|
||||||
import { createStarterMaterialSignature, createStarterMaterialTexture } from "../materials/starter-material-textures";
|
import { createStarterMaterialSignature, createStarterMaterialTexture } from "../materials/starter-material-textures";
|
||||||
import { applyAdvancedRenderingLightShadowFlags, applyAdvancedRenderingRenderableShadowFlags, configureAdvancedRenderingRenderer, createAdvancedRenderingComposer, resolveBoxVolumeRenderPaths } from "../rendering/advanced-rendering";
|
import { applyAdvancedRenderingLightShadowFlags, applyAdvancedRenderingRenderableShadowFlags, configureAdvancedRenderingRenderer, createAdvancedRenderingComposer, resolveBoxVolumeRenderPaths } from "../rendering/advanced-rendering";
|
||||||
import { collectWaterContactPatches, createWaterContactPatchAxisUniformValue, createWaterContactPatchUniformValue, createWaterMaterial } from "../rendering/water-material";
|
import { collectWaterContactPatches, createWaterContactPatchAxisUniformValue, createWaterContactPatchShapeUniformValue, createWaterContactPatchUniformValue, createWaterMaterial } from "../rendering/water-material";
|
||||||
import { areAdvancedRenderingSettingsEqual, cloneAdvancedRenderingSettings } from "../document/world-settings";
|
import { areAdvancedRenderingSettingsEqual, cloneAdvancedRenderingSettings } from "../document/world-settings";
|
||||||
import { FirstPersonNavigationController } from "./first-person-navigation-controller";
|
import { FirstPersonNavigationController } from "./first-person-navigation-controller";
|
||||||
import { RapierCollisionWorld } from "./rapier-collision-world";
|
import { RapierCollisionWorld } from "./rapier-collision-world";
|
||||||
import { RuntimeInteractionSystem } from "./runtime-interaction-system";
|
import { RuntimeInteractionSystem } 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";
|
||||||
const FALLBACK_FACE_COLOR = 0x747d89;
|
const FALLBACK_FACE_COLOR = 0x747d89;
|
||||||
export class RuntimeHost {
|
export class RuntimeHost {
|
||||||
scene = new Scene();
|
scene = new Scene();
|
||||||
@@ -27,6 +28,7 @@ export class RuntimeHost {
|
|||||||
orbitVisitorController = new OrbitVisitorNavigationController();
|
orbitVisitorController = new OrbitVisitorNavigationController();
|
||||||
interactionSystem = new RuntimeInteractionSystem();
|
interactionSystem = new RuntimeInteractionSystem();
|
||||||
audioSystem = new RuntimeAudioSystem(this.scene, this.camera, null);
|
audioSystem = new RuntimeAudioSystem(this.scene, this.camera, null);
|
||||||
|
underwaterSceneFog = new FogExp2("#2c6f8d", 0.03);
|
||||||
brushMeshes = new Map();
|
brushMeshes = new Map();
|
||||||
volumeTime = 0;
|
volumeTime = 0;
|
||||||
volumeAnimatedMaterials = [];
|
volumeAnimatedMaterials = [];
|
||||||
@@ -209,6 +211,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;
|
||||||
}
|
}
|
||||||
@@ -446,6 +449,7 @@ export class RuntimeHost {
|
|||||||
brush,
|
brush,
|
||||||
uniform: waterMaterial.contactPatchesUniform,
|
uniform: waterMaterial.contactPatchesUniform,
|
||||||
axisUniform: waterMaterial.contactPatchAxesUniform,
|
axisUniform: waterMaterial.contactPatchAxesUniform,
|
||||||
|
shapeUniform: waterMaterial.contactPatchShapesUniform ?? { value: [] },
|
||||||
staticContactPatches
|
staticContactPatches
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -484,9 +488,12 @@ export class RuntimeHost {
|
|||||||
const cb = parseInt(hex.substring(4, 6), 16) / 255;
|
const cb = parseInt(hex.substring(4, 6), 16) / 255;
|
||||||
const vertexShader = `
|
const vertexShader = `
|
||||||
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>
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
const fragmentShader = `
|
const fragmentShader = `
|
||||||
@@ -494,6 +501,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() {
|
||||||
vec2 dist = abs(vUv - 0.5) * 2.0;
|
vec2 dist = abs(vUv - 0.5) * 2.0;
|
||||||
float edgeFade = 1.0 - smoothstep(0.4, 1.0, max(dist.x, dist.y));
|
float edgeFade = 1.0 - smoothstep(0.4, 1.0, max(dist.x, dist.y));
|
||||||
@@ -503,6 +511,7 @@ export class RuntimeHost {
|
|||||||
alpha = clamp(alpha, 0.0, 0.88);
|
alpha = clamp(alpha, 0.0, 0.88);
|
||||||
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>
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
const mat = new ShaderMaterial({
|
const mat = new ShaderMaterial({
|
||||||
@@ -515,11 +524,28 @@ export class RuntimeHost {
|
|||||||
},
|
},
|
||||||
transparent: true,
|
transparent: true,
|
||||||
depthWrite: false,
|
depthWrite: false,
|
||||||
|
fog: true,
|
||||||
side: 2
|
side: 2
|
||||||
});
|
});
|
||||||
this.volumeAnimatedMaterials.push(mat);
|
this.volumeAnimatedMaterials.push(mat);
|
||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
getOrCreateTexture(material) {
|
getOrCreateTexture(material) {
|
||||||
const signature = createStarterMaterialSignature(material);
|
const signature = createStarterMaterialSignature(material);
|
||||||
const cachedTexture = this.materialTextureCache.get(material.id);
|
const cachedTexture = this.materialTextureCache.get(material.id);
|
||||||
@@ -655,6 +681,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clearModelInstances() {
|
clearModelInstances() {
|
||||||
@@ -717,6 +744,7 @@ export class RuntimeHost {
|
|||||||
if (this.runtimeWaterContactUniforms.length > 0) {
|
if (this.runtimeWaterContactUniforms.length > 0) {
|
||||||
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