下雨效果
This commit is contained in:
51
index.html
51
index.html
@@ -157,6 +157,27 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.control-toggle {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: rgba(255,255,255,0.06);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-toggle label {
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-toggle input[type="checkbox"] {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
accent-color: #5da9ff;
|
||||||
|
}
|
||||||
|
|
||||||
.control-value {
|
.control-value {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
@@ -285,6 +306,36 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="control-section">
|
||||||
|
<div class="control-section-title">雨效</div>
|
||||||
|
<div class="control-toggle">
|
||||||
|
<label for="rain-enabled">启用镜头雨幕</label>
|
||||||
|
<input type="checkbox" id="rain-enabled">
|
||||||
|
</div>
|
||||||
|
<div class="control-grid">
|
||||||
|
<div class="control-group">
|
||||||
|
<label>屏幕雨滴</label>
|
||||||
|
<input type="range" id="rain-screen-intensity" min="0" max="1.5" value="0.41" step="0.01">
|
||||||
|
<div class="control-value" id="rain-screen-intensity-value">0.41</div>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label>雨线强度</label>
|
||||||
|
<input type="range" id="rain-veil-intensity" min="0" max="1.5" value="1.15" step="0.01">
|
||||||
|
<div class="control-value" id="rain-veil-intensity-value">1.15</div>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label>雨滴尺寸</label>
|
||||||
|
<input type="range" id="rain-drop-size" min="0.4" max="1.8" value="1.00" step="0.01">
|
||||||
|
<div class="control-value" id="rain-drop-size-value">1.00</div>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label>速度</label>
|
||||||
|
<input type="range" id="rain-speed" min="0.2" max="2.5" value="1.00" step="0.01">
|
||||||
|
<div class="control-value" id="rain-speed-value">1.00</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="stats">FPS: <span id="fps">60</span></div>
|
<div id="stats">FPS: <span id="fps">60</span></div>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
|||||||
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
|
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
|
||||||
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
|
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
|
||||||
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
|
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
|
||||||
|
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
|
||||||
import { TerrainGenerator } from './TerrainGenerator.js';
|
import { TerrainGenerator } from './TerrainGenerator.js';
|
||||||
import { VegetationSystem } from './VegetationSystem.js';
|
import { VegetationSystem } from './VegetationSystem.js';
|
||||||
|
|
||||||
@@ -27,6 +28,7 @@ export class OceanScene {
|
|||||||
this.vegetationFillLight = null;
|
this.vegetationFillLight = null;
|
||||||
this.composer = null;
|
this.composer = null;
|
||||||
this.bloomPass = null;
|
this.bloomPass = null;
|
||||||
|
this.rainPass = null;
|
||||||
this.cloudGroup = null;
|
this.cloudGroup = null;
|
||||||
this.cloudMaterials = [];
|
this.cloudMaterials = [];
|
||||||
this.cloudLayers = [];
|
this.cloudLayers = [];
|
||||||
@@ -50,6 +52,11 @@ export class OceanScene {
|
|||||||
fogDensity: 0.42,
|
fogDensity: 0.42,
|
||||||
fogHeight: 0.32,
|
fogHeight: 0.32,
|
||||||
fogRange: 0.55,
|
fogRange: 0.55,
|
||||||
|
rainEnabled: false,
|
||||||
|
rainScreenIntensity: 0.41,
|
||||||
|
rainVeilIntensity: 1.15,
|
||||||
|
rainDropSize: 1.0,
|
||||||
|
rainSpeed: 1.0,
|
||||||
mieCoefficient: 0.005,
|
mieCoefficient: 0.005,
|
||||||
mieDirectionalG: 0.8
|
mieDirectionalG: 0.8
|
||||||
};
|
};
|
||||||
@@ -148,6 +155,245 @@ export class OceanScene {
|
|||||||
this.params.bloomThreshold
|
this.params.bloomThreshold
|
||||||
);
|
);
|
||||||
this.composer.addPass(this.bloomPass);
|
this.composer.addPass(this.bloomPass);
|
||||||
|
|
||||||
|
this.rainPass = new ShaderPass(this.createRainShader());
|
||||||
|
this.rainPass.enabled = this.params.rainEnabled;
|
||||||
|
this.rainPass.material.uniforms.resolution.value.set(window.innerWidth, window.innerHeight);
|
||||||
|
this.rainPass.material.uniforms.screenIntensity.value = this.params.rainScreenIntensity;
|
||||||
|
this.rainPass.material.uniforms.veilIntensity.value = this.params.rainVeilIntensity;
|
||||||
|
this.rainPass.material.uniforms.dropSize.value = this.params.rainDropSize;
|
||||||
|
this.rainPass.material.uniforms.rainSpeed.value = this.params.rainSpeed;
|
||||||
|
this.composer.addPass(this.rainPass);
|
||||||
|
}
|
||||||
|
|
||||||
|
createRainShader() {
|
||||||
|
return {
|
||||||
|
uniforms: {
|
||||||
|
tDiffuse: { value: null },
|
||||||
|
time: { value: 0 },
|
||||||
|
screenIntensity: { value: this.params.rainScreenIntensity },
|
||||||
|
veilIntensity: { value: this.params.rainVeilIntensity },
|
||||||
|
dropSize: { value: this.params.rainDropSize },
|
||||||
|
rainSpeed: { value: this.params.rainSpeed },
|
||||||
|
resolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) }
|
||||||
|
},
|
||||||
|
vertexShader: `
|
||||||
|
varying vec2 vUv;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vUv = uv;
|
||||||
|
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
fragmentShader: `
|
||||||
|
uniform sampler2D tDiffuse;
|
||||||
|
uniform float time;
|
||||||
|
uniform float screenIntensity;
|
||||||
|
uniform float veilIntensity;
|
||||||
|
uniform float dropSize;
|
||||||
|
uniform float rainSpeed;
|
||||||
|
uniform vec2 resolution;
|
||||||
|
|
||||||
|
varying vec2 vUv;
|
||||||
|
|
||||||
|
float hash11(float p) {
|
||||||
|
p = fract(p * 0.1031);
|
||||||
|
p *= p + 33.33;
|
||||||
|
p *= p + p;
|
||||||
|
return fract(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
float hash21(vec2 p) {
|
||||||
|
vec3 p3 = fract(vec3(p.xyx) * 0.1031);
|
||||||
|
p3 += dot(p3, p3.yzx + 33.33);
|
||||||
|
return fract((p3.x + p3.y) * p3.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 hash31(float p) {
|
||||||
|
vec3 p3 = fract(vec3(p) * vec3(0.1031, 0.11369, 0.13787));
|
||||||
|
p3 += dot(p3, p3.yzx + 19.19);
|
||||||
|
return fract(vec3(
|
||||||
|
(p3.x + p3.y) * p3.z,
|
||||||
|
(p3.x + p3.z) * p3.y,
|
||||||
|
(p3.y + p3.z) * p3.x
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeOutCubic(float x) {
|
||||||
|
float inv = 1.0 - clamp(x, 0.0, 1.0);
|
||||||
|
return 1.0 - inv * inv * inv;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 dropLayer(vec2 uv, float t, float sizeFactor) {
|
||||||
|
vec2 grid = vec2(9.0, 4.0) / mix(0.7, 1.45, sizeFactor);
|
||||||
|
vec2 p = uv * grid;
|
||||||
|
vec2 cell = floor(p);
|
||||||
|
vec2 local = fract(p) - 0.5;
|
||||||
|
vec3 n = hash31(cell.x * 53.17 + cell.y * 417.43);
|
||||||
|
|
||||||
|
float rate = (0.45 + n.z * 0.95) * mix(0.82, 1.45, sizeFactor);
|
||||||
|
float cycle = t * rate + n.z * 11.0;
|
||||||
|
float phase = fract(cycle);
|
||||||
|
|
||||||
|
vec2 spawn = (n.xy - 0.5) * vec2(0.72, 0.28);
|
||||||
|
float onset = smoothstep(0.0, 0.07, phase);
|
||||||
|
float lifeFade = 1.0 - smoothstep(0.52, 0.82, phase);
|
||||||
|
float fall = easeOutCubic(smoothstep(0.02, 0.58, phase));
|
||||||
|
float fallDistance = mix(0.9, 2.15, n.y) * mix(0.85, 1.4, sizeFactor) * fall;
|
||||||
|
vec2 center = vec2(spawn.x, 0.62 + spawn.y - fallDistance);
|
||||||
|
|
||||||
|
vec2 delta = local - center;
|
||||||
|
float aspect = mix(0.8, 1.45, n.x);
|
||||||
|
float bodyRadius = mix(0.18, 0.3, sizeFactor);
|
||||||
|
float body = smoothstep(bodyRadius, 0.03, length(delta * vec2(aspect, 1.0)));
|
||||||
|
|
||||||
|
float tail = smoothstep(mix(0.06, 0.095, sizeFactor), 0.0, abs(delta.x)) *
|
||||||
|
smoothstep(0.04, -0.12, delta.y) *
|
||||||
|
smoothstep(-0.72, -0.04, delta.y) *
|
||||||
|
smoothstep(0.04, 0.18, phase);
|
||||||
|
|
||||||
|
float spitSeed = hash21(cell + floor(cycle) + 3.7);
|
||||||
|
float spitY = center.y + 0.18 + fract(local.y * 3.7 + spitSeed) * 0.42;
|
||||||
|
float spit = smoothstep(mix(0.06, 0.11, sizeFactor), 0.0, length(local - vec2(center.x + (spitSeed - 0.5) * 0.14, spitY)));
|
||||||
|
spit *= smoothstep(0.02, 0.14, phase) * (1.0 - smoothstep(0.18, 0.34, phase));
|
||||||
|
|
||||||
|
float impactFlash = smoothstep(0.14, 0.0, phase) * smoothstep(0.24, 0.02, length(local - vec2(spawn.x, 0.58 + spawn.y)));
|
||||||
|
float mask = (max(body, tail * 0.9) * onset + spit * 0.55 + impactFlash * 0.7) * lifeFade;
|
||||||
|
float trail = tail * onset * lifeFade;
|
||||||
|
return vec2(mask, trail);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 drops(vec2 uv, float t, float l0, float l1, float l2, float sizeFactor) {
|
||||||
|
vec2 m1 = dropLayer(uv, t, sizeFactor) * l1;
|
||||||
|
vec2 m2 = dropLayer(uv * 1.85, t, sizeFactor * 0.82) * l2;
|
||||||
|
|
||||||
|
float c = m1.x + m2.x;
|
||||||
|
c = smoothstep(0.3, 1.0, c);
|
||||||
|
|
||||||
|
float trail = max(m1.y * l1, m2.y * l2);
|
||||||
|
return vec2(c, trail);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 impactLayer(vec2 uv, float t, float rainAmount, float sizeFactor) {
|
||||||
|
vec2 grid = vec2(11.0, 6.0) / mix(0.75, 1.35, sizeFactor);
|
||||||
|
vec2 p = uv * grid;
|
||||||
|
vec2 cell = floor(p);
|
||||||
|
vec2 local = fract(p) - 0.5;
|
||||||
|
vec3 n = hash31(cell.x * 97.13 + cell.y * 413.71);
|
||||||
|
|
||||||
|
float rate = (1.3 + n.z * 2.4) * mix(0.95, 1.55, sizeFactor);
|
||||||
|
float cycle = t * rate + n.x * 7.13 + n.y * 3.17;
|
||||||
|
float phase = fract(cycle);
|
||||||
|
vec2 center = (n.xy - 0.5) * vec2(0.72, 0.36);
|
||||||
|
float lifeFade = 1.0 - smoothstep(0.28, 0.56, phase);
|
||||||
|
center.y += easeOutCubic(smoothstep(0.01, 0.36, phase)) * mix(0.9, 1.45, sizeFactor);
|
||||||
|
vec2 d = local - center;
|
||||||
|
float radius = mix(0.012, mix(0.18, 0.32, sizeFactor), smoothstep(0.0, 0.22, phase));
|
||||||
|
|
||||||
|
float flash = smoothstep(0.09, 0.0, phase) * smoothstep(0.18, 0.015, length(d));
|
||||||
|
float ring = smoothstep(0.025, 0.0, abs(length(d) - radius)) * (1.0 - smoothstep(0.05, 0.24, phase));
|
||||||
|
float tail = smoothstep(0.055, 0.0, abs(d.x)) *
|
||||||
|
smoothstep(0.02, -0.12, d.y) *
|
||||||
|
smoothstep(-0.6, -0.04, d.y) *
|
||||||
|
smoothstep(0.02, 0.18, phase);
|
||||||
|
float sideSplash = smoothstep(0.055, 0.0, abs(d.y + 0.02)) *
|
||||||
|
smoothstep(0.16, 0.02, abs(abs(d.x) - mix(0.06, 0.22, phase))) *
|
||||||
|
(1.0 - smoothstep(0.06, 0.2, phase));
|
||||||
|
|
||||||
|
float mask = (flash + ring * 0.55 + tail * 0.65 + sideSplash * 0.4) * step(0.64, n.z) * rainAmount * lifeFade;
|
||||||
|
vec2 dir = normalize(d + vec2(0.0001));
|
||||||
|
return vec3(mask, dir * mask * (0.018 + flash * 0.028));
|
||||||
|
}
|
||||||
|
|
||||||
|
float rainVeil(vec2 uv, float t, float rainAmount) {
|
||||||
|
float accum = 0.0;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
float fi = float(i);
|
||||||
|
float scale = 18.0 + fi * 11.0;
|
||||||
|
float speed = 2.0 + fi * 0.9;
|
||||||
|
float slant = 0.16 + fi * 0.07;
|
||||||
|
vec2 p = uv;
|
||||||
|
p.x += p.y * slant;
|
||||||
|
p.y += t * speed;
|
||||||
|
p.x += sin(p.y * (7.0 + fi * 2.3) + fi * 11.7) * (0.015 + fi * 0.004);
|
||||||
|
|
||||||
|
vec2 layerUv = p * scale;
|
||||||
|
vec2 cell = floor(layerUv);
|
||||||
|
vec2 local = fract(layerUv) - 0.5;
|
||||||
|
vec3 n = hash31(cell.x * (41.0 + fi * 13.0) + cell.y * (289.0 + fi * 71.0) + fi * 19.0);
|
||||||
|
|
||||||
|
float lane = (n.x - 0.5) * 0.62;
|
||||||
|
float width = mix(0.01, 0.045, n.y * n.y);
|
||||||
|
float length = mix(0.24, 0.95, n.x);
|
||||||
|
float bend = sin((cell.y + t * speed * 8.0) * (0.9 + n.z * 1.6) + n.x * 6.2831) * 0.18;
|
||||||
|
float dx = local.x - lane - bend * (0.15 + fi * 0.05);
|
||||||
|
float dy = local.y + (n.z - 0.5) * 0.3;
|
||||||
|
|
||||||
|
float streak = smoothstep(width, width * 0.15, abs(dx));
|
||||||
|
streak *= smoothstep(length, length * 0.12, abs(dy) * 2.0);
|
||||||
|
|
||||||
|
float breakup = smoothstep(0.2, 0.85, sin((dy + n.y * 2.0) * 18.0 + n.z * 12.0) * 0.5 + 0.5);
|
||||||
|
float flicker = 0.35 + 0.65 * fract(n.z * 31.7 + t * (4.0 + n.x * 3.0) + fi * 2.1);
|
||||||
|
float density = step(0.34 - fi * 0.05, n.y);
|
||||||
|
streak *= mix(1.0, breakup, 0.55) * flicker * density;
|
||||||
|
|
||||||
|
accum += streak * (0.52 - fi * 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
return accum * smoothstep(0.08, 0.95, rainAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 uv = vUv;
|
||||||
|
vec2 centeredUv = (uv - 0.5) * vec2(resolution.x / max(resolution.y, 1.0), 1.0);
|
||||||
|
float screenAmount = clamp(screenIntensity / 1.5, 0.0, 1.0);
|
||||||
|
float veilAmount = clamp(veilIntensity / 1.5, 0.0, 1.0);
|
||||||
|
float sizeFactor = clamp((dropSize - 0.4) / 1.4, 0.0, 1.0);
|
||||||
|
float rainAmount = max(screenAmount, veilAmount);
|
||||||
|
float t = time * rainSpeed * 0.18;
|
||||||
|
|
||||||
|
float staticLayer = 0.0;
|
||||||
|
float densityScale = mix(1.2, 0.55, sizeFactor);
|
||||||
|
float layer1 = smoothstep(0.08, 0.55, screenAmount) * densityScale;
|
||||||
|
float layer2 = smoothstep(0.25, 0.95, screenAmount) * densityScale;
|
||||||
|
|
||||||
|
vec2 c = drops(centeredUv * 0.9, t, staticLayer, layer1, layer2, sizeFactor);
|
||||||
|
vec3 impact = impactLayer(centeredUv * vec2(1.0, 1.2), t * 2.2, screenAmount, sizeFactor);
|
||||||
|
float veil = rainVeil(centeredUv * vec2(1.0, 1.4), time * rainSpeed * 0.55, veilAmount);
|
||||||
|
vec2 e = vec2(0.0015, 0.0);
|
||||||
|
float cx = drops(centeredUv + e, t, staticLayer, layer1, layer2, sizeFactor).x;
|
||||||
|
float cy = drops(centeredUv + e.yx, t, staticLayer, layer1, layer2, sizeFactor).x;
|
||||||
|
vec2 normal = vec2(cx - c.x, cy - c.x) + impact.yz;
|
||||||
|
|
||||||
|
float maxBlur = mix(0.002, 0.009, rainAmount);
|
||||||
|
float minBlur = 0.001;
|
||||||
|
float focus = mix(maxBlur - c.y * 0.5, minBlur, smoothstep(0.05, 0.2, c.x + impact.x * 0.5));
|
||||||
|
|
||||||
|
vec2 texel = 1.0 / max(resolution, vec2(1.0));
|
||||||
|
vec2 distortion = normal * (0.35 + focus * 48.0 + impact.x * 1.6);
|
||||||
|
|
||||||
|
vec3 base =
|
||||||
|
texture2D(tDiffuse, uv + distortion).rgb * 0.4 +
|
||||||
|
texture2D(tDiffuse, uv + distortion + vec2(texel.x * focus * 24.0, 0.0)).rgb * 0.15 +
|
||||||
|
texture2D(tDiffuse, uv + distortion - vec2(texel.x * focus * 24.0, 0.0)).rgb * 0.15 +
|
||||||
|
texture2D(tDiffuse, uv + distortion + vec2(0.0, texel.y * focus * 24.0)).rgb * 0.15 +
|
||||||
|
texture2D(tDiffuse, uv + distortion - vec2(0.0, texel.y * focus * 24.0)).rgb * 0.15;
|
||||||
|
|
||||||
|
vec3 sharp = texture2D(tDiffuse, uv + distortion * 0.6).rgb;
|
||||||
|
vec3 col = mix(base, sharp, smoothstep(0.04, 0.22, c.x));
|
||||||
|
|
||||||
|
vec3 rainTint = vec3(0.86, 0.91, 0.95);
|
||||||
|
col = mix(col, col * 0.88 + rainTint * 0.12, clamp(c.x * 0.65 + c.y * 0.3 + impact.x * 0.4, 0.0, 1.0));
|
||||||
|
col += c.y * rainTint * 0.08 * screenAmount;
|
||||||
|
col += impact.x * rainTint * 0.18 * screenAmount;
|
||||||
|
col += veil * rainTint * (0.12 + veilAmount * 0.18);
|
||||||
|
col = mix(col, col * 0.94 + rainTint * 0.06, veil * 0.18);
|
||||||
|
col = mix(texture2D(tDiffuse, uv).rgb, col, clamp(rainAmount * 1.1, 0.0, 1.0));
|
||||||
|
|
||||||
|
gl_FragColor = vec4(col, 1.0);
|
||||||
|
}
|
||||||
|
`
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async initSky() {
|
async initSky() {
|
||||||
@@ -636,6 +882,9 @@ export class OceanScene {
|
|||||||
if (this.composer) {
|
if (this.composer) {
|
||||||
this.composer.setSize(window.innerWidth, window.innerHeight);
|
this.composer.setSize(window.innerWidth, window.innerHeight);
|
||||||
}
|
}
|
||||||
|
if (this.rainPass) {
|
||||||
|
this.rainPass.material.uniforms.resolution.value.set(window.innerWidth, window.innerHeight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setSunElevation(value) {
|
setSunElevation(value) {
|
||||||
@@ -718,6 +967,41 @@ export class OceanScene {
|
|||||||
this.updateFog();
|
this.updateFog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setRainEnabled(value) {
|
||||||
|
this.params.rainEnabled = value;
|
||||||
|
if (this.rainPass) {
|
||||||
|
this.rainPass.enabled = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setRainScreenIntensity(value) {
|
||||||
|
this.params.rainScreenIntensity = value;
|
||||||
|
if (this.rainPass) {
|
||||||
|
this.rainPass.material.uniforms.screenIntensity.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setRainVeilIntensity(value) {
|
||||||
|
this.params.rainVeilIntensity = value;
|
||||||
|
if (this.rainPass) {
|
||||||
|
this.rainPass.material.uniforms.veilIntensity.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setRainDropSize(value) {
|
||||||
|
this.params.rainDropSize = value;
|
||||||
|
if (this.rainPass) {
|
||||||
|
this.rainPass.material.uniforms.dropSize.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setRainSpeed(value) {
|
||||||
|
this.params.rainSpeed = value;
|
||||||
|
if (this.rainPass) {
|
||||||
|
this.rainPass.material.uniforms.rainSpeed.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateClouds() {
|
updateClouds() {
|
||||||
if (!this.cloudGroup) return;
|
if (!this.cloudGroup) return;
|
||||||
|
|
||||||
@@ -824,6 +1108,10 @@ export class OceanScene {
|
|||||||
this.vegetationSystem.update(time);
|
this.vegetationSystem.update(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.rainPass) {
|
||||||
|
this.rainPass.material.uniforms.time.value = time;
|
||||||
|
}
|
||||||
|
|
||||||
this.controls.update();
|
this.controls.update();
|
||||||
if (this.composer) {
|
if (this.composer) {
|
||||||
this.composer.render();
|
this.composer.render();
|
||||||
|
|||||||
14
src/main.js
14
src/main.js
@@ -42,6 +42,15 @@ function setupControls(oceanScene) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const bindCheckbox = (id, setter) => {
|
||||||
|
const checkbox = document.getElementById(id);
|
||||||
|
if (!checkbox) return;
|
||||||
|
|
||||||
|
checkbox.addEventListener('change', (e) => {
|
||||||
|
setter(e.target.checked);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
bindSlider('sun-elevation', (value) => `${value.toFixed(1)}°`, (value) => oceanScene.setSunElevation(value));
|
bindSlider('sun-elevation', (value) => `${value.toFixed(1)}°`, (value) => oceanScene.setSunElevation(value));
|
||||||
bindSlider('sun-azimuth', (value) => `${value.toFixed(1)}°`, (value) => oceanScene.setSunAzimuth(value));
|
bindSlider('sun-azimuth', (value) => `${value.toFixed(1)}°`, (value) => oceanScene.setSunAzimuth(value));
|
||||||
bindSlider('exposure', (value) => value.toFixed(2), (value) => oceanScene.setExposure(value));
|
bindSlider('exposure', (value) => value.toFixed(2), (value) => oceanScene.setExposure(value));
|
||||||
@@ -55,6 +64,11 @@ function setupControls(oceanScene) {
|
|||||||
bindSlider('fog-density', (value) => value.toFixed(2), (value) => oceanScene.setFogDensity(value));
|
bindSlider('fog-density', (value) => value.toFixed(2), (value) => oceanScene.setFogDensity(value));
|
||||||
bindSlider('fog-height', (value) => value.toFixed(2), (value) => oceanScene.setFogHeight(value));
|
bindSlider('fog-height', (value) => value.toFixed(2), (value) => oceanScene.setFogHeight(value));
|
||||||
bindSlider('fog-range', (value) => value.toFixed(2), (value) => oceanScene.setFogRange(value));
|
bindSlider('fog-range', (value) => value.toFixed(2), (value) => oceanScene.setFogRange(value));
|
||||||
|
bindSlider('rain-screen-intensity', (value) => value.toFixed(2), (value) => oceanScene.setRainScreenIntensity(value));
|
||||||
|
bindSlider('rain-veil-intensity', (value) => value.toFixed(2), (value) => oceanScene.setRainVeilIntensity(value));
|
||||||
|
bindSlider('rain-drop-size', (value) => value.toFixed(2), (value) => oceanScene.setRainDropSize(value));
|
||||||
|
bindSlider('rain-speed', (value) => value.toFixed(2), (value) => oceanScene.setRainSpeed(value));
|
||||||
|
bindCheckbox('rain-enabled', (value) => oceanScene.setRainEnabled(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch(console.error);
|
main().catch(console.error);
|
||||||
|
|||||||
Reference in New Issue
Block a user