Add fog quality material and update runtime/viewport hosts
This commit is contained in:
@@ -18,11 +18,8 @@ import {
|
||||
PointLight,
|
||||
Quaternion,
|
||||
Scene,
|
||||
ShaderMaterial,
|
||||
Vector3,
|
||||
SpotLight,
|
||||
UniformsLib,
|
||||
UniformsUtils,
|
||||
WebGLRenderTarget,
|
||||
WebGLRenderer
|
||||
} from "three";
|
||||
@@ -50,6 +47,7 @@ import {
|
||||
createWaterContactPatchUniformValue,
|
||||
createWaterMaterial
|
||||
} from "../rendering/water-material";
|
||||
import { createFogQualityMaterial } from "../rendering/fog-material";
|
||||
import { updatePlanarReflectionCamera } from "../rendering/planar-reflection";
|
||||
import {
|
||||
areAdvancedRenderingSettingsEqual,
|
||||
@@ -117,7 +115,6 @@ export class RuntimeHost {
|
||||
private readonly waterReflectionCamera = new PerspectiveCamera();
|
||||
private readonly brushMeshes = new Map<string, Mesh<BufferGeometry, Material[]>>();
|
||||
private volumeTime = 0;
|
||||
private readonly volumeAnimatedMaterials: ShaderMaterial[] = [];
|
||||
private readonly volumeAnimatedUniforms: Array<{ value: number }> = [];
|
||||
private readonly runtimeWaterContactUniforms: RuntimeWaterContactUniformBinding[] = [];
|
||||
private readonly localLightObjects = new Map<string, Group>();
|
||||
@@ -685,7 +682,20 @@ export class RuntimeHost {
|
||||
|
||||
if (brush.volume.mode === "fog") {
|
||||
if (volumeRenderPaths.fog === "quality") {
|
||||
return this.createFogQualityMaterial(brush.volume.fog);
|
||||
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 fogMaterial.material;
|
||||
}
|
||||
// Performance fallback: simple transparent material
|
||||
const densityOpacity = Math.max(0.06, Math.min(0.72, brush.volume.fog.density * 0.8 + 0.08));
|
||||
@@ -713,72 +723,6 @@ export class RuntimeHost {
|
||||
});
|
||||
}
|
||||
|
||||
// Soft edge-faded fog shader with slow drift animation — quality mode only.
|
||||
private createFogQualityMaterial(fog: { colorHex: string; density: number }): ShaderMaterial {
|
||||
const hex = fog.colorHex.replace("#", "");
|
||||
const cr = parseInt(hex.substring(0, 2), 16) / 255;
|
||||
const cg = parseInt(hex.substring(2, 4), 16) / 255;
|
||||
const cb = parseInt(hex.substring(4, 6), 16) / 255;
|
||||
|
||||
const vertexShader = /* glsl */ `
|
||||
varying vec2 vUv;
|
||||
#include <fog_pars_vertex>
|
||||
void main() {
|
||||
vUv = uv;
|
||||
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
|
||||
gl_Position = projectionMatrix * mvPosition;
|
||||
#include <fog_vertex>
|
||||
}
|
||||
`;
|
||||
|
||||
const fragmentShader = /* glsl */ `
|
||||
uniform vec3 volumeFogColor;
|
||||
uniform float volumeFogDensity;
|
||||
uniform float time;
|
||||
varying vec2 vUv;
|
||||
#include <fog_pars_fragment>
|
||||
|
||||
void main() {
|
||||
// Soft fade: distance from the center of each face in UV space
|
||||
vec2 dist = abs(vUv - 0.5) * 2.0; // 0 at center, 1 at edge
|
||||
float edgeFade = 1.0 - smoothstep(0.4, 1.0, max(dist.x, dist.y));
|
||||
|
||||
// Slow drifting noise to break up the flat look
|
||||
float drift = sin(vUv.x * 4.5 + time * 0.28) * sin(vUv.y * 3.2 + time * 0.22);
|
||||
float variation = 0.82 + drift * 0.18;
|
||||
|
||||
float alpha = volumeFogDensity * edgeFade * variation;
|
||||
alpha = clamp(alpha, 0.0, 0.88);
|
||||
|
||||
// Edge scatter brightening
|
||||
vec3 color = mix(volumeFogColor, vec3(1.0), (1.0 - edgeFade) * 0.09);
|
||||
gl_FragColor = vec4(color, alpha);
|
||||
#include <fog_fragment>
|
||||
}
|
||||
`;
|
||||
|
||||
const uniforms = UniformsUtils.merge([
|
||||
UniformsLib.fog,
|
||||
{
|
||||
volumeFogColor: { value: [cr, cg, cb] },
|
||||
volumeFogDensity: { value: Math.min(0.9, fog.density + 0.12) },
|
||||
time: { value: this.volumeTime }
|
||||
}
|
||||
]);
|
||||
|
||||
const mat = new ShaderMaterial({
|
||||
vertexShader,
|
||||
fragmentShader,
|
||||
uniforms,
|
||||
transparent: true,
|
||||
depthWrite: false,
|
||||
fog: true,
|
||||
side: 2 // THREE.DoubleSide — fog is visible from inside too
|
||||
});
|
||||
this.volumeAnimatedMaterials.push(mat);
|
||||
return mat;
|
||||
}
|
||||
|
||||
private updateUnderwaterSceneFog() {
|
||||
const fogState =
|
||||
this.activeController === this.firstPersonController
|
||||
@@ -968,7 +912,6 @@ export class RuntimeHost {
|
||||
}
|
||||
|
||||
this.brushMeshes.clear();
|
||||
this.volumeAnimatedMaterials.length = 0;
|
||||
this.volumeAnimatedUniforms.length = 0;
|
||||
for (const binding of this.runtimeWaterContactUniforms) {
|
||||
binding.reflectionRenderTarget?.dispose();
|
||||
@@ -1164,9 +1107,6 @@ export class RuntimeHost {
|
||||
this.audioSystem.updateListenerTransform();
|
||||
|
||||
this.volumeTime += dt;
|
||||
for (const mat of this.volumeAnimatedMaterials) {
|
||||
(mat.uniforms["time"] as { value: number }).value = this.volumeTime;
|
||||
}
|
||||
for (const uniform of this.volumeAnimatedUniforms) {
|
||||
uniform.value = this.volumeTime;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user