From 63c6e78b188fecdc34ad492ad44a81e6ebb96da0 Mon Sep 17 00:00:00 2001 From: Anuj K Date: Sat, 6 Sep 2025 03:30:32 +0530 Subject: [PATCH] overlay redone --- src/fluidDistortion.js | 342 +++++++++++++++++++++++------------------ src/main.js | 95 +++--------- 2 files changed, 213 insertions(+), 224 deletions(-) diff --git a/src/fluidDistortion.js b/src/fluidDistortion.js index 426522f..1b37217 100644 --- a/src/fluidDistortion.js +++ b/src/fluidDistortion.js @@ -1,19 +1,21 @@ import * as THREE from 'three'; -// Enhanced ripple simulation with multiple trailing ripples and lighting - -const FluidSimShader = { +const InkSimShader = { uniforms: { tPrev: { value: null }, iResolution: { value: new THREE.Vector2() }, iTime: { value: 0.0 }, mouse: { value: new THREE.Vector3(-1, -1, 0.0) }, - dissipation: { value: 0.95 }, // Slightly more persistent for trails - tension: { value: 2.2 }, // Higher tension for stronger ripples - radius: { value: 20.0 }, // Larger splat radius - trailLength: { value: 5 }, // Number of trailing ripples + dissipation: { value: 0.96 }, + turbulence: { value: 2.2 }, + scale: { value: 0.9 }, + speed: { value: 1.0 }, + octaves: { value: 4 }, + lacunarity: { value: 2.0 }, + gain: { value: 0.5 }, + mouseRadius: { value: 0.25 }, + globalChaos: { value: 0.15 } }, - vertexShader: ` varying vec2 vUv; void main() { @@ -21,7 +23,6 @@ const FluidSimShader = { gl_Position = vec4(position.xy, 0.0, 1.0); } `, - fragmentShader: ` precision highp float; varying vec2 vUv; @@ -30,86 +31,119 @@ const FluidSimShader = { uniform float iTime; uniform vec3 mouse; uniform float dissipation; - uniform float tension; - uniform float radius; - uniform float trailLength; + uniform float turbulence; + uniform float scale; + uniform float speed; + uniform float octaves; + uniform float lacunarity; + uniform float gain; + uniform float mouseRadius; + uniform float globalChaos; - vec2 readRG(vec2 uv) { - vec4 c = texture2D(tPrev, uv); - return c.rg; + vec2 hash22(vec2 p) { + p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3))); + return -1.0 + 2.0 * fract(sin(p) * 43758.5453123); + } + + float noise(vec2 p) { + vec2 i = floor(p); + vec2 f = fract(p); + vec2 u = f * f * (3.0 - 2.0 * f); + return mix( + mix(dot(hash22(i + vec2(0.0, 0.0)), f - vec2(0.0, 0.0)), + dot(hash22(i + vec2(1.0, 0.0)), f - vec2(1.0, 0.0)), u.x), + mix(dot(hash22(i + vec2(0.0, 1.0)), f - vec2(0.0, 1.0)), + dot(hash22(i + vec2(1.0, 1.0)), f - vec2(1.0, 1.0)), u.x), u.y); + } + + float fbm(vec2 p) { + float value = 0.0; + float amplitude = 0.5; + float frequency = scale; + for(float i = 0.0; i < 8.0; i++) { + if(i >= octaves) break; + value += amplitude * noise(p * frequency); + frequency *= lacunarity; + amplitude *= gain; + } + return value; } void main() { - vec2 texel = 1.0 / iResolution; - vec2 currPrev = readRG(vUv); - float curr = currPrev.r; - float prev = currPrev.g; + vec2 uv = vUv; + vec4 prev = texture2D(tPrev, uv); + float time = iTime * speed; + + float distortion = 0.0; + + // Global background chaos - always present but subtle + vec2 globalP = uv * 3.0 + time * 0.12; + vec2 q = vec2(fbm(globalP), fbm(globalP + vec2(5.2, 1.3))); + distortion = fbm(globalP + 2.0 * q) * globalChaos; - // Enhanced 8-neighbor laplacian for stronger ripples - float up = readRG(vUv + vec2(0.0, texel.y)).r; - float down = readRG(vUv + vec2(0.0, -texel.y)).r; - float right = readRG(vUv + vec2( texel.x, 0.0)).r; - float left = readRG(vUv + vec2(-texel.x, 0.0)).r; - - // Diagonal neighbors for smoother ripples - float upLeft = readRG(vUv + vec2(-texel.x, texel.y)).r; - float upRight = readRG(vUv + vec2( texel.x, texel.y)).r; - float downLeft = readRG(vUv + vec2(-texel.x, -texel.y)).r; - float downRight = readRG(vUv + vec2( texel.x, -texel.y)).r; - - // Enhanced laplacian with diagonal weights - float lap = (up + down + left + right) * 0.2 + - (upLeft + upRight + downLeft + downRight) * 0.05 - curr; - - // Wave equation with enhanced parameters - float next = curr + (curr - prev) * dissipation + lap * tension; - - // Multiple trailing ripples from mouse movement - if (mouse.z > 0.0001) { - vec2 uvPx = vUv * iResolution; - vec2 d = uvPx - mouse.xy; - float dist = length(d); - - // Create multiple concentric ripples - for (float i = 0.0; i < 4.0; i++) { - if (i >= trailLength) break; + // Mouse-driven intense ink distortion + if(mouse.z > 0.001) { + vec2 mouseUv = mouse.xy / iResolution; + vec2 diff = uv - mouseUv; + float dist = length(diff); + + // Larger, softer falloff around mouse cursor + float falloff = 1.0 - smoothstep(0.0, mouseRadius * 2.0, dist); + float coreFalloff = 1.0 - smoothstep(0.0, mouseRadius * 0.5, dist); + + if(falloff > 0.0) { + // Domain warping near cursor + vec2 p = uv * 6.0 + time * 0.3; + vec2 warpQ = vec2(fbm(p), fbm(p + vec2(5.2, 1.3))); + vec2 warpR = vec2(fbm(p + 3.0 * warpQ + vec2(1.7, 9.2) + time * 0.15), + fbm(p + 3.0 * warpQ + vec2(8.3, 2.8) + time * 0.12)); - float offset = i * radius * 0.4; // Spacing between ripples - float r = radius + offset; - float timeOffset = i * 0.3; // Temporal offset for trailing effect + // Chaotic ink splash effect + float inkDistortion = fbm(p + 4.0 * warpR + diff * 8.0) * turbulence; - // Gaussian with sine wave for ripple pattern - float g = exp(-pow(dist - offset, 2.0) / (r * r * 0.5)); - float ripple = sin(dist * 0.2 - iTime * 16.0 + timeOffset) * g; + // Add swirling motion around cursor + float angle = atan(diff.y, diff.x); + float spiral = sin(angle * 4.0 + time * 10.0 + dist * 15.0) * 0.6; + inkDistortion += spiral * coreFalloff; - // Diminishing strength for trailing ripples - float strength = mouse.z * (1.0 - i * 0.2) * 0.8; - next += ripple * strength; + // Add noise based on mouse movement speed + float mouseNoise = fbm(uv * 10.0 + time * 4.0 + mouseUv * 6.0); + inkDistortion += mouseNoise * mouse.z * 1.2; + + // Apply falloff and strength + distortion += inkDistortion * falloff * mouse.z * 0.8; + } + + // Add trailing effect that persists even outside main radius + float trailFalloff = 1.0 - smoothstep(0.0, mouseRadius * 4.0, dist); + if(trailFalloff > 0.0) { + float trail = fbm(uv * 8.0 + time * 2.0 + mouseUv * 4.0) * mouse.z * 0.3; + distortion += trail * trailFalloff; } } - gl_FragColor = vec4(next, curr, 0.0, 1.0); + // Apply dissipation and combine + float newValue = prev.r * dissipation + distortion * 0.12; + newValue = clamp(newValue, -2.0, 2.0); + + gl_FragColor = vec4(newValue, prev.r, 0.0, 1.0); } ` }; -// Enhanced distortion shader with dynamic lighting and ripple whiteness -export const FluidDistortionShader = { +export const InkDistortionShader = { uniforms: { tDiffuse: { value: null }, tSim: { value: null }, iResolution: { value: new THREE.Vector2() }, - amount: { value: 0.12 }, // Stronger base distortion - chromaticAmount: { value: 0.015 }, // Enhanced chromatic aberration - lightPosition: { value: new THREE.Vector3(0.5, 0.5, 1.0) }, // Light position - lightIntensity: { value: 1.5 }, // Light brightness - lightColor: { value: new THREE.Color(0.8, 0.9, 1.0) }, // Cool light color - normalStrength: { value: 2.0 }, // How pronounced the lighting effect is - ambientLight: { value: 0.15 }, // Base ambient lighting - rippleWhiteness: { value: 0.15 }, // Amount of white tint for ripples - rippleBrightness: { value: 1.8 }, // Brightness multiplier for ripple areas + amount: { value: 0.035 }, + chromaticAmount: { value: 0.015 }, + time: { value: 0.0 }, + noiseScale: { value: 2.0 }, + flowSpeed: { value: 1.0 }, + inkDensity: { value: 0.4 }, + chaosAmount: { value: 1.3 } }, - vertexShader: ` varying vec2 vUv; void main() { @@ -117,7 +151,6 @@ export const FluidDistortionShader = { gl_Position = vec4(position.xy, 0.0, 1.0); } `, - fragmentShader: ` precision highp float; varying vec2 vUv; @@ -126,121 +159,126 @@ export const FluidDistortionShader = { uniform vec2 iResolution; uniform float amount; uniform float chromaticAmount; - uniform vec3 lightPosition; - uniform float lightIntensity; - uniform vec3 lightColor; - uniform float normalStrength; - uniform float ambientLight; - uniform float rippleWhiteness; - uniform float rippleBrightness; + uniform float time; + uniform float noiseScale; + uniform float flowSpeed; + uniform float inkDensity; + uniform float chaosAmount; + + vec2 hash22(vec2 p) { + p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3))); + return -1.0 + 2.0 * fract(sin(p) * 43758.5453123); + } + + float noise(vec2 p) { + vec2 i = floor(p); + vec2 f = fract(p); + vec2 u = f * f * (3.0 - 2.0 * f); + return mix( + mix(dot(hash22(i + vec2(0.0, 0.0)), f - vec2(0.0, 0.0)), + dot(hash22(i + vec2(1.0, 0.0)), f - vec2(1.0, 0.0)), u.x), + mix(dot(hash22(i + vec2(0.0, 1.0)), f - vec2(0.0, 1.0)), + dot(hash22(i + vec2(1.0, 1.0)), f - vec2(1.0, 1.0)), u.x), u.y); + } + + float fbm(vec2 p) { + float value = 0.0; + float amplitude = 0.5; + float frequency = 1.0; + for(int i = 0; i < 4; i++) { + value += amplitude * noise(p * frequency); + frequency *= 2.0; + amplitude *= 0.5; + } + return value; + } void main() { - vec2 texel = 1.0 / iResolution; - - // Sample height field for normal calculation - float hC = texture2D(tSim, vUv).r; - float hL = texture2D(tSim, vUv - vec2(texel.x, 0.0)).r; - float hR = texture2D(tSim, vUv + vec2(texel.x, 0.0)).r; - float hD = texture2D(tSim, vUv - vec2(0.0, texel.y)).r; - float hU = texture2D(tSim, vUv + vec2(0.0, texel.y)).r; - - // Calculate gradient and normal - vec2 grad = vec2(hR - hL, hU - hD) * normalStrength; - vec3 normal = normalize(vec3(-grad.x, -grad.y, 1.0)); - - // Enhanced distortion with trailing effect - vec2 baseOffset = grad * amount; + float distortionField = texture2D(tSim, vUv).r; - // Add subtle trailing distortion based on height - vec2 trailOffset = grad * abs(hC) * amount * 0.3; - vec2 totalOffset = baseOffset + trailOffset; + // Apply base distortion everywhere there's simulation data + vec2 totalDistortion = vec2(distortionField) * amount; + + // Add procedural chaos based on distortion intensity + float distortionIntensity = abs(distortionField); + + if(distortionIntensity > 0.005) { + vec2 flowTime = vec2(time * flowSpeed * 0.3, time * flowSpeed * 0.2); + vec2 flowNoise = vec2( + fbm(vUv * noiseScale + flowTime), + fbm(vUv * noiseScale + flowTime + vec2(100.0, 50.0)) + ); + + totalDistortion += flowNoise * chaosAmount * 0.02 * distortionIntensity; + + // Swirls based on distortion field + float swirl = sin(time * 2.0 + vUv.x * 15.0) * cos(time * 1.7 + vUv.y * 12.0); + vec2 swirlOffset = vec2(-swirl, swirl) * 0.01 * chaosAmount * distortionIntensity; + totalDistortion += swirlOffset; + } - // Chromatic aberration with enhanced separation - vec2 chromaticOffset = grad * chromaticAmount; - vec2 uvR = vUv + totalOffset + chromaticOffset; - vec2 uvG = vUv + totalOffset; - vec2 uvB = vUv + totalOffset - chromaticOffset; + // Enhanced chromatic aberration + vec2 chromaticOffset = totalDistortion * chromaticAmount; + vec2 chaosChromatic = totalDistortion * 0.3; + + vec2 uvR = vUv + totalDistortion + chromaticOffset + chaosChromatic; + vec2 uvG = vUv + totalDistortion; + vec2 uvB = vUv + totalDistortion - chromaticOffset - chaosChromatic * 0.5; - // Clamp UVs uvR = clamp(uvR, vec2(0.0), vec2(1.0)); uvG = clamp(uvG, vec2(0.0), vec2(1.0)); uvB = clamp(uvB, vec2(0.0), vec2(1.0)); - // Sample distorted colors float r = texture2D(tDiffuse, uvR).r; float g = texture2D(tDiffuse, uvG).g; float b = texture2D(tDiffuse, uvB).b; - vec3 distortedColor = vec3(r, g, b); - // Dynamic lighting calculation - vec3 lightDir = normalize(vec3(lightPosition.xy - vUv, lightPosition.z)); - float NdotL = max(dot(normal, lightDir), 0.0); + vec3 color = vec3(r, g, b); - // Create rim lighting effect for ripples - float rimLight = pow(1.0 - abs(dot(normal, vec3(0.0, 0.0, 1.0))), 2.0); + // Apply ink effects based on distortion intensity + if(distortionIntensity > 0.005) { + float density = distortionIntensity * inkDensity; + float inkEffect = 1.0 + density * 0.5; + color *= inkEffect; + + float bleeding = smoothstep(0.02, 0.6, distortionIntensity); + color = mix(color, color * 0.92, bleeding * 0.3); + } - // Combine lighting effects - vec3 lighting = lightColor * (NdotL * lightIntensity + rimLight * 0.3) + ambientLight; - - // Calculate ripple intensity for both lighting and whiteness - float rippleIntensity = abs(hC) + length(grad) * 0.5; - rippleIntensity = clamp(rippleIntensity, 0.0, 1.0); - - // Apply lighting selectively - stronger where there are ripples - vec3 litColor = mix(distortedColor, distortedColor * lighting, rippleIntensity); - - // Add white tint to ripples for visibility over black areas - vec3 whiteColor = vec3(1.0, 1.0, 1.0); - - // Create a smooth falloff for the whiteness effect - float whiteIntensity = smoothstep(0.0, 0.3, rippleIntensity) * rippleWhiteness; - - // Blend in the white tint - vec3 rippleColor = mix(litColor, whiteColor, whiteIntensity); - - // Brighten areas with ripples - rippleColor = mix(rippleColor, rippleColor * rippleBrightness, rippleIntensity * 0.5); - - gl_FragColor = vec4(rippleColor, 1.0); + gl_FragColor = vec4(color, 1.0); } ` }; -// Enhanced fluid simulation factory -export function createFluidSimulation(renderer, dpr = 1) { +export function createInkSimulation(renderer, dpr = 1) { const simScene = new THREE.Scene(); const simCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1); - const quad = new THREE.Mesh( new THREE.PlaneGeometry(2, 2), new THREE.ShaderMaterial({ - uniforms: THREE.UniformsUtils.clone(FluidSimShader.uniforms), - vertexShader: FluidSimShader.vertexShader, - fragmentShader: FluidSimShader.fragmentShader, + uniforms: THREE.UniformsUtils.clone(InkSimShader.uniforms), + vertexShader: InkSimShader.vertexShader, + fragmentShader: InkSimShader.fragmentShader, depthTest: false, depthWrite: false }) ); - simScene.add(quad); - // Higher precision for better ripple quality const params = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat, - type: THREE.FloatType, // Use float for better precision + type: THREE.FloatType, depthBuffer: false, stencilBuffer: false }; - let width = Math.max(2, Math.floor(window.innerWidth * dpr)); - let height = Math.max(2, Math.floor(window.innerHeight * dpr)); - + let width = Math.max(2, Math.floor(window.innerWidth * dpr * 0.5)); + let height = Math.max(2, Math.floor(window.innerHeight * dpr * 0.5)); let rtA = new THREE.WebGLRenderTarget(width, height, params); let rtB = new THREE.WebGLRenderTarget(width, height, params); - // Initialize renderer.setRenderTarget(rtA); renderer.clear(); renderer.setRenderTarget(rtB); @@ -251,25 +289,23 @@ export function createFluidSimulation(renderer, dpr = 1) { quad.material.uniforms.tPrev.value = rtA.texture; function swap() { - const tmp = rtA; rtA = rtB; rtB = tmp; + const tmp = rtA; + rtA = rtB; + rtB = tmp; } function update(mouseX, mouseY, strength, timeSec) { quad.material.uniforms.iTime.value = timeSec; - if (mouseX < 0.0 || mouseY < 0.0) { quad.material.uniforms.mouse.value.set(-1, -1, 0.0); } else { - // Enhanced strength for better trailing effect - const enhancedStrength = Math.max(0.0, Math.min(1.0, strength * 1.5)); - quad.material.uniforms.mouse.value.set(mouseX, mouseY, enhancedStrength); + const enhancedStrength = Math.max(0.0, Math.min(1.0, strength * 2.5)); + quad.material.uniforms.mouse.value.set(mouseX * 0.5, mouseY * 0.5, enhancedStrength); } - quad.material.uniforms.tPrev.value = rtA.texture; renderer.setRenderTarget(rtB); renderer.render(simScene, simCamera); renderer.setRenderTarget(null); - swap(); } @@ -278,8 +314,8 @@ export function createFluidSimulation(renderer, dpr = 1) { } function resize(w, h, newDpr = dpr) { - width = Math.max(2, Math.floor(w * newDpr)); - height = Math.max(2, Math.floor(h * newDpr)); + width = Math.max(2, Math.floor(w * newDpr * 0.5)); + height = Math.max(2, Math.floor(h * newDpr * 0.5)); rtA.setSize(width, height); rtB.setSize(width, height); quad.material.uniforms.iResolution.value.set(width, height); diff --git a/src/main.js b/src/main.js index 4f6d1e3..be5581d 100644 --- a/src/main.js +++ b/src/main.js @@ -1,10 +1,8 @@ import './style.css'; import * as THREE from 'three'; - import { SceneLoader } from './sceneLoader.js'; import { createScene, setupLighting, setupControls } from './sceneSetup.js'; import { createModelFromPreloaded } from './modelManager.js'; - import { currentModel, nextModel, @@ -16,64 +14,47 @@ import { setCurrentModel, setMixer, setGLBRepulsionSystem, - calculateTransitionVectors // ⬅ added + calculateTransitionVectors } from './transitionManager.js'; - import { startBoldRoughnessAnimation, updateBoldRoughnessAnimation, updateInnovationGlassAnimation } from './animationManager.js'; - import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js'; -import { createFluidSimulation, FluidDistortionShader } from './fluidDistortion.js'; +import { createInkSimulation, InkDistortionShader } from './fluidDistortion.js'; import { createStarfield } from './starfield.js'; -/* ------------------------------------------------------------------ */ -/* loader */ const sceneLoader = new SceneLoader(); sceneLoader.setLoadingMessage('Preparing Your Experience...'); -/* ------------------------------------------------------------------ */ -/* scene */ const { scene, camera, renderer, composer } = createScene(); setupLighting(scene, camera); const controls = setupControls(camera, renderer); -/* realign transition vectors whenever user moves the camera */ controls.addEventListener('change', () => calculateTransitionVectors(camera)); -/* ------------------------------------------------------------------ */ -/* starfield, turntable & global vars */ const starfield = createStarfield(scene); const turntableSpeed = 0.5; let preloadedModels = {}; -/* ------------------------------------------------------------------ */ -/* post-processing: fluid distortion */ const dpr = renderer.getPixelRatio ? renderer.getPixelRatio() : Math.min(window.devicePixelRatio || 1, 2); -const fluid = createFluidSimulation(renderer, dpr); -const distortionPass = new ShaderPass(FluidDistortionShader); -distortionPass.material.uniforms.tSim.value = fluid.getTexture(); +const inkSim = createInkSimulation(renderer, dpr); +const distortionPass = new ShaderPass(InkDistortionShader); +distortionPass.material.uniforms.tSim.value = inkSim.getTexture(); distortionPass.material.uniforms.iResolution.value.set(window.innerWidth * dpr, window.innerHeight * dpr); -distortionPass.material.uniforms.amount.value = 0.005; -distortionPass.material.uniforms.chromaticAmount.value = 0.002; -distortionPass.material.uniforms.lightIntensity.value = 0; -distortionPass.material.uniforms.lightColor.value.set(1, 1, 1); -distortionPass.material.uniforms.normalStrength.value = 2.0; -distortionPass.material.uniforms.ambientLight.value = 1; -distortionPass.material.uniforms.rippleWhiteness.value = 0.025; -distortionPass.material.uniforms.rippleBrightness.value = 1; +distortionPass.material.uniforms.amount.value = 0.025; +distortionPass.material.uniforms.chromaticAmount.value = 0.100; +distortionPass.material.uniforms.noiseScale.value = 2.5; +distortionPass.material.uniforms.flowSpeed.value = 1.2; +distortionPass.material.uniforms.inkDensity.value = 0.35; +distortionPass.material.uniforms.chaosAmount.value = 1.5; composer.addPass(distortionPass); -/* ------------------------------------------------------------------ */ -/* pointer + mouse utilities */ const pointer = { x: -1, y: -1, strength: 0, prevX: -1, prevY: -1 }; const mouse = new THREE.Vector2(); const raycaster = new THREE.Raycaster(); -/* ------------------------------------------------------------------ */ -/* GLB cursor repulsion system */ const glbRepulsion = { radius: 30, maxDistance: 2, @@ -84,8 +65,6 @@ const glbRepulsion = { }; setGLBRepulsionSystem(glbRepulsion); -/* ------------------------------------------------------------------ */ -/* helper: convert DOM coords → simulation coords */ function toSimPixels(e) { const rect = renderer.domElement.getBoundingClientRect(); const x = (e.clientX - rect.left) * dpr; @@ -93,21 +72,19 @@ function toSimPixels(e) { return { x, y }; } -/* ------------------------------------------------------------------ */ -/* pointer events */ renderer.domElement.addEventListener('pointermove', (e) => { const { x, y } = toSimPixels(e); const dx = pointer.prevX < 0 ? 0 : Math.abs(x - pointer.prevX); const dy = pointer.prevY < 0 ? 0 : Math.abs(y - pointer.prevY); - const speed = Math.min(Math.sqrt(dx * dx + dy * dy) / (6 * dpr), 1); - pointer.x = x; pointer.y = y; pointer.strength = speed * 1.2; - pointer.prevX = x; pointer.prevY = y; - + const speed = Math.min(Math.sqrt(dx * dx + dy * dy) / (3 * dpr), 1); + pointer.x = x; + pointer.y = y; + pointer.strength = speed * 4.0; + pointer.prevX = x; + pointer.prevY = y; const rect = renderer.domElement.getBoundingClientRect(); const nx = (e.clientX - rect.left) / rect.width; const ny = 1 - (e.clientY - rect.top) / rect.height; - distortionPass.material.uniforms.lightPosition.value.set(nx, ny, 1); - mouse.x = nx * 2 - 1; mouse.y = -ny * 2 + 1; }, { passive: true }); @@ -115,14 +92,10 @@ renderer.domElement.addEventListener('pointermove', (e) => { renderer.domElement.addEventListener('pointerleave', () => { Object.assign(pointer, { x: -1, y: -1, strength: 0 }); mouse.set(-999, -999); - distortionPass.material.uniforms.lightPosition.value.set(0.5, 0.5, 1); }, { passive: true }); -/* ------------------------------------------------------------------ */ -/* GLB repulsion update */ function updateGLBRepulsion(camera, mouse, dt) { if (mouse.x === -999) { - // return objects to original pos [currentModel, nextModel].forEach(m => { if (!m) return; const orig = glbRepulsion.originalPositions.get(m); @@ -134,22 +107,18 @@ function updateGLBRepulsion(camera, mouse, dt) { }); return; } - raycaster.setFromCamera(mouse, camera); const mouseWorld = raycaster.ray.direction.clone().multiplyScalar(50).add(raycaster.ray.origin); - [currentModel, nextModel].forEach(m => { if (!m) return; if (!glbRepulsion.originalPositions.has(m)) glbRepulsion.originalPositions.set(m, m.position.clone()); - const orig = glbRepulsion.originalPositions.get(m); const dx = m.position.x - mouseWorld.x; const dy = m.position.y - mouseWorld.y; const dz = m.position.z - mouseWorld.z; const dist = Math.sqrt(dx * dx + dy * dy + dz * dz); let target = orig.clone(); - if (dist < glbRepulsion.radius && dist > 0) { const force = (1 - dist / glbRepulsion.radius) * glbRepulsion.strength; target.add(new THREE.Vector3(dx, dy, dz).normalize().multiplyScalar(force)); @@ -157,14 +126,11 @@ function updateGLBRepulsion(camera, mouse, dt) { if (offset.length() > glbRepulsion.maxDistance) target = orig.clone().add(offset.normalize().multiplyScalar(glbRepulsion.maxDistance)); } - glbRepulsion.currentTargets.set(m, target); m.position.lerp(target, Math.min(glbRepulsion.interpolationSpeed * dt, 1)); }); } -/* ------------------------------------------------------------------ */ -/* first scene setup */ function initializeScene() { const { model, animMixer } = createModelFromPreloaded('bold', preloadedModels, camera, controls); setCurrentModel(model); @@ -174,54 +140,42 @@ function initializeScene() { startBoldRoughnessAnimation(true); } -/* ------------------------------------------------------------------ */ -/* animation loop */ const clock = new THREE.Clock(); function animate() { requestAnimationFrame(animate); const dt = clock.getDelta(); - + const elapsedTime = clock.getElapsedTime(); if (mixer) mixer.update(dt); if (nextMixer) nextMixer.update(dt); - if (isTransitioning) updateTransition(dt, scene); else updateGLBRepulsion(camera, mouse, dt); - - // turntable if (currentModel) currentModel.rotation.y += turntableSpeed * dt; if (nextModel) nextModel.rotation.y += turntableSpeed * dt; - - // material anims updateBoldRoughnessAnimation(); updateInnovationGlassAnimation(); - - // stars + fluid starfield.animateStars(camera, mouse, dt); - fluid.update(pointer.x, pointer.y, pointer.strength, performance.now() / 1000); - distortionPass.material.uniforms.tSim.value = fluid.getTexture(); - + inkSim.update(pointer.x, pointer.y, pointer.strength, elapsedTime); + distortionPass.material.uniforms.tSim.value = inkSim.getTexture(); + distortionPass.material.uniforms.time.value = elapsedTime; controls.update(); composer.render(); } -/* ------------------------------------------------------------------ */ -/* init workflow */ async function init() { try { preloadedModels = await sceneLoader.loadAllModels(); initializeScene(); animate(); - window.addEventListener('wheel', (e) => onMouseScroll(e, preloadedModels, scene, camera, controls), { passive: true }); - window.addEventListener('resize', () => { const w = window.innerWidth, h = window.innerHeight; - camera.aspect = w / h; camera.updateProjectionMatrix(); + camera.aspect = w / h; + camera.updateProjectionMatrix(); renderer.setSize(w, h); composer.setSize(w, h); const pr = renderer.getPixelRatio ? renderer.getPixelRatio() : Math.min(window.devicePixelRatio || 1, 2); distortionPass.material.uniforms.iResolution.value.set(w * pr, h * pr); - fluid.resize(w, h, pr); + inkSim.resize(w, h, pr); }); } catch (err) { console.error('Failed to initialise:', err); @@ -229,5 +183,4 @@ async function init() { } } -/* ------------------------------------------------------------------ */ init();