diff --git a/public/noise.jpg b/public/noise.jpg new file mode 100644 index 0000000..9ebabc3 Binary files /dev/null and b/public/noise.jpg differ diff --git a/public/noisex.jpg b/public/noisex.jpg new file mode 100644 index 0000000..40aa3bb Binary files /dev/null and b/public/noisex.jpg differ diff --git a/public/noisexx.jpg b/public/noisexx.jpg new file mode 100644 index 0000000..a560efb Binary files /dev/null and b/public/noisexx.jpg differ diff --git a/src/fluidDistortion.js b/src/fluidDistortion.js index 1b37217..33c2966 100644 --- a/src/fluidDistortion.js +++ b/src/fluidDistortion.js @@ -1,20 +1,24 @@ import * as THREE from 'three'; +const textureLoader = new THREE.TextureLoader(); +const noiseTexture = textureLoader.load('./noise.jpg'); +noiseTexture.wrapS = THREE.RepeatWrapping; +noiseTexture.wrapT = THREE.RepeatWrapping; + 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.96 }, - turbulence: { value: 2.2 }, + dissipation: { value: 0.97 }, + turbulence: { value: 0.2 }, scale: { value: 0.9 }, - speed: { value: 1.0 }, - octaves: { value: 4 }, + speed: { value: 0.5 }, + octaves: { value: 2 }, lacunarity: { value: 2.0 }, gain: { value: 0.5 }, - mouseRadius: { value: 0.25 }, - globalChaos: { value: 0.15 } + mouseRadius: { value: 0.15 } }, vertexShader: ` varying vec2 vUv; @@ -38,7 +42,6 @@ const InkSimShader = { uniform float lacunarity; uniform float gain; uniform float mouseRadius; - uniform float globalChaos; vec2 hash22(vec2 p) { p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3))); @@ -73,59 +76,34 @@ const InkSimShader = { 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; - - // 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)); - - // Chaotic ink splash effect float inkDistortion = fbm(p + 4.0 * warpR + diff * 8.0) * turbulence; - - // 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; - - // 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; } } - - // 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); } ` @@ -135,6 +113,7 @@ export const InkDistortionShader = { uniforms: { tDiffuse: { value: null }, tSim: { value: null }, + tNoise: { value: noiseTexture }, iResolution: { value: new THREE.Vector2() }, amount: { value: 0.035 }, chromaticAmount: { value: 0.015 }, @@ -142,7 +121,9 @@ export const InkDistortionShader = { noiseScale: { value: 2.0 }, flowSpeed: { value: 1.0 }, inkDensity: { value: 0.4 }, - chaosAmount: { value: 1.3 } + chaosAmount: { value: 1.3 }, + grainStrength: { value: 3.12 }, + grainScale: { value: 8.0 } }, vertexShader: ` varying vec2 vUv; @@ -156,6 +137,7 @@ export const InkDistortionShader = { varying vec2 vUv; uniform sampler2D tDiffuse; uniform sampler2D tSim; + uniform sampler2D tNoise; uniform vec2 iResolution; uniform float amount; uniform float chromaticAmount; @@ -164,6 +146,8 @@ export const InkDistortionShader = { uniform float flowSpeed; uniform float inkDensity; uniform float chaosAmount; + uniform float grainStrength; + uniform float grainScale; vec2 hash22(vec2 p) { p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3))); @@ -195,56 +179,42 @@ export const InkDistortionShader = { void main() { float distortionField = texture2D(tSim, vUv).r; - - // 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) { + if(distortionIntensity > 0.01) { 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; } - - // 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; - 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)); - float r = texture2D(tDiffuse, uvR).r; float g = texture2D(tDiffuse, uvG).g; float b = texture2D(tDiffuse, uvB).b; - vec3 color = vec3(r, g, b); - - // Apply ink effects based on distortion intensity - if(distortionIntensity > 0.005) { + if(distortionIntensity > 0.01) { 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); + vec2 grainUv = vUv * grainScale + vec2(time * 0.05, time * 0.03); + vec3 grainColor = texture2D(tNoise, grainUv).rgb; + grainColor = (grainColor - 0.5) * grainStrength * distortionIntensity; + color += grainColor; } - gl_FragColor = vec4(color, 1.0); } ` @@ -264,7 +234,6 @@ export function createInkSimulation(renderer, dpr = 1) { }) ); simScene.add(quad); - const params = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, @@ -273,27 +242,22 @@ export function createInkSimulation(renderer, dpr = 1) { depthBuffer: false, stencilBuffer: false }; - 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); - renderer.setRenderTarget(rtA); renderer.clear(); renderer.setRenderTarget(rtB); renderer.clear(); renderer.setRenderTarget(null); - quad.material.uniforms.iResolution.value.set(width, height); quad.material.uniforms.tPrev.value = rtA.texture; - function swap() { 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) { @@ -308,11 +272,9 @@ export function createInkSimulation(renderer, dpr = 1) { renderer.setRenderTarget(null); swap(); } - function getTexture() { return rtA.texture; } - function resize(w, h, newDpr = dpr) { width = Math.max(2, Math.floor(w * newDpr * 0.5)); height = Math.max(2, Math.floor(h * newDpr * 0.5)); @@ -320,6 +282,5 @@ export function createInkSimulation(renderer, dpr = 1) { rtB.setSize(width, height); quad.material.uniforms.iResolution.value.set(width, height); } - return { update, getTexture, resize }; } diff --git a/src/main.js b/src/main.js index be5581d..3400881 100644 --- a/src/main.js +++ b/src/main.js @@ -27,34 +27,30 @@ import { createStarfield } from './starfield.js'; const sceneLoader = new SceneLoader(); sceneLoader.setLoadingMessage('Preparing Your Experience...'); - const { scene, camera, renderer, composer } = createScene(); setupLighting(scene, camera); const controls = setupControls(camera, renderer); - controls.addEventListener('change', () => calculateTransitionVectors(camera)); - const starfield = createStarfield(scene); const turntableSpeed = 0.5; let preloadedModels = {}; - const dpr = renderer.getPixelRatio ? renderer.getPixelRatio() : Math.min(window.devicePixelRatio || 1, 2); 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.025; +distortionPass.material.uniforms.amount.value = 0.03; distortionPass.material.uniforms.chromaticAmount.value = 0.100; -distortionPass.material.uniforms.noiseScale.value = 2.5; -distortionPass.material.uniforms.flowSpeed.value = 1.2; +distortionPass.material.uniforms.noiseScale.value = 0.05; +distortionPass.material.uniforms.flowSpeed.value = 2.2; distortionPass.material.uniforms.inkDensity.value = 0.35; -distortionPass.material.uniforms.chaosAmount.value = 1.5; +distortionPass.material.uniforms.chaosAmount.value = 0.05; +distortionPass.material.uniforms.grainStrength.value = 0.8; +distortionPass.material.uniforms.grainScale.value = 5.0; composer.addPass(distortionPass); - const pointer = { x: -1, y: -1, strength: 0, prevX: -1, prevY: -1 }; const mouse = new THREE.Vector2(); const raycaster = new THREE.Raycaster(); - const glbRepulsion = { radius: 30, maxDistance: 2, @@ -64,14 +60,12 @@ const glbRepulsion = { interpolationSpeed: 3 }; setGLBRepulsionSystem(glbRepulsion); - function toSimPixels(e) { const rect = renderer.domElement.getBoundingClientRect(); const x = (e.clientX - rect.left) * dpr; const y = (rect.height - (e.clientY - rect.top)) * dpr; return { x, y }; } - renderer.domElement.addEventListener('pointermove', (e) => { const { x, y } = toSimPixels(e); const dx = pointer.prevX < 0 ? 0 : Math.abs(x - pointer.prevX); @@ -88,12 +82,10 @@ renderer.domElement.addEventListener('pointermove', (e) => { mouse.x = nx * 2 - 1; mouse.y = -ny * 2 + 1; }, { passive: true }); - renderer.domElement.addEventListener('pointerleave', () => { Object.assign(pointer, { x: -1, y: -1, strength: 0 }); mouse.set(-999, -999); }, { passive: true }); - function updateGLBRepulsion(camera, mouse, dt) { if (mouse.x === -999) { [currentModel, nextModel].forEach(m => { @@ -130,7 +122,6 @@ function updateGLBRepulsion(camera, mouse, dt) { m.position.lerp(target, Math.min(glbRepulsion.interpolationSpeed * dt, 1)); }); } - function initializeScene() { const { model, animMixer } = createModelFromPreloaded('bold', preloadedModels, camera, controls); setCurrentModel(model); @@ -139,7 +130,6 @@ function initializeScene() { glbRepulsion.originalPositions.set(currentModel, currentModel.position.clone()); startBoldRoughnessAnimation(true); } - const clock = new THREE.Clock(); function animate() { requestAnimationFrame(animate); @@ -160,7 +150,6 @@ function animate() { controls.update(); composer.render(); } - async function init() { try { preloadedModels = await sceneLoader.loadAllModels(); @@ -182,5 +171,4 @@ async function init() { sceneLoader.setLoadingMessage('Error loading experience. Please refresh.'); } } - init(); diff --git a/src/materialDefinitions.js b/src/materialDefinitions.js index 87daa4c..423e3a3 100644 --- a/src/materialDefinitions.js +++ b/src/materialDefinitions.js @@ -40,7 +40,7 @@ export const boldGlassMaterial = new THREE.MeshPhysicalMaterial({ // Orange wireframe material for bold Cubewire mesh export const boldWireframeMaterial = new THREE.MeshStandardMaterial({ - color: 0xff8600, + color: 0xffa000, metalness: 0.05, roughness: 0.5 }); @@ -69,7 +69,7 @@ export const innovationGlassMaterial = new THREE.MeshPhysicalMaterial({ export const frostedGlassMaterial = new THREE.MeshPhysicalMaterial({ color: 0xffffff, metalness: 0.0, - roughness: 0.25, + roughness: 0.35, transmission: 1.0, ior: 1.5, thickness: 2.0, @@ -87,11 +87,11 @@ export const frostedGlassMaterial = new THREE.MeshPhysicalMaterial({ // Orange material with video shader for innovation export const lightOrangeMaterial = new THREE.MeshStandardMaterial({ - color: 0xff8600, + color: 0xffa000, metalness: 0.05, roughness: 0.4, envMapIntensity: 0, - emissive: new THREE.Color(0xffad47), + emissive: new THREE.Color(0xddbbbb), emissiveMap: videoTexture, emissiveIntensity: 2.25 }); diff --git a/src/sceneSetup.js b/src/sceneSetup.js index a65ccbf..97ab3e2 100644 --- a/src/sceneSetup.js +++ b/src/sceneSetup.js @@ -32,8 +32,8 @@ export function createScene() { composer.addPass(renderPass); const bloomPass = new UnrealBloomPass( new THREE.Vector2(window.innerWidth, window.innerHeight), - 1.0, // strength - 0.45, // radius + 0.8, // strength + 0.4, // radius 0.85 // threshold ); composer.addPass(bloomPass); @@ -51,33 +51,33 @@ export function createScene() { export function setupLighting(scene, camera) { // Consistent Lighting Setup - const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); + const ambientLight = new THREE.AmbientLight(0xffffff, 1); scene.add(ambientLight); - const hemiLight = new THREE.HemisphereLight(0xffffff, 0x666666, 1.5); + const hemiLight = new THREE.HemisphereLight(0xffffff, 0x666666, 2); hemiLight.position.set(0, 20, 0); scene.add(hemiLight); - const fillLight = new THREE.DirectionalLight(0xffffff, 1.2); + const fillLight = new THREE.DirectionalLight(0xffffff, 1.8); fillLight.position.set(-12, 6, -8); scene.add(fillLight); - const topLight = new THREE.DirectionalLight(0xffffff, 1.5); + const topLight = new THREE.DirectionalLight(0xffffff, 2); topLight.position.set(5, 15, 5); scene.add(topLight); - const bottomLight = new THREE.DirectionalLight(0xffffff, 0.8); + const bottomLight = new THREE.DirectionalLight(0xffffff, 2.2); bottomLight.position.set(-3, -8, 3); scene.add(bottomLight); - const leftLight = new THREE.DirectionalLight(0xffffff, 1.0); + const leftLight = new THREE.DirectionalLight(0xffffff, 1.5); leftLight.position.set(-12, 2, 5); scene.add(leftLight); - const rightLight = new THREE.DirectionalLight(0xffffff, 1.0); + const rightLight = new THREE.DirectionalLight(0xffffff, 1.5); rightLight.position.set(12, 2, -5); scene.add(rightLight); - const frontLight = new THREE.DirectionalLight(0xffffff, 0.8); + const frontLight = new THREE.DirectionalLight(0xffffff, 1.2); frontLight.position.set(8, 4, 12); scene.add(frontLight); - const backLight = new THREE.DirectionalLight(0xffffff, 0.8); + const backLight = new THREE.DirectionalLight(0xffffff, 1.2); backLight.position.set(-8, 4, -12); scene.add(backLight); - const cameraLight = new THREE.PointLight(0xffffff, 0.8, 0, 2); + const cameraLight = new THREE.PointLight(0xffffff, 0.8, 0, 3); camera.add(cameraLight); scene.add(camera); }