diff --git a/public/bold.glb b/public/bold.glb new file mode 100644 index 0000000..a097aa6 Binary files /dev/null and b/public/bold.glb differ diff --git a/public/storytelling.glb b/public/storytelling.glb index a1e7a8d..87d2b5b 100644 Binary files a/public/storytelling.glb and b/public/storytelling.glb differ diff --git a/src/main.js b/src/main.js index 9319170..ba21212 100644 --- a/src/main.js +++ b/src/main.js @@ -18,7 +18,7 @@ const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); // Transition state management -let currentScene = 0; // 0: innovation, 1: agility, 2: storytelling +let currentScene = 0; // 0: bold, 1: innovation, 2: agility, 3: storytelling let isTransitioning = false; let isTwisting = false; let twistProgress = 0; @@ -39,6 +39,17 @@ let mixer = null; let nextMixer = null; let autoRotationAngle = 0; +// Bold scene roughness animation state +let boldRoughnessAnimation = { + isActive: false, + startTime: 0, + delayDuration: 1.0, // 1 second delay + transitionDuration: 1.0, // 1 second transition + startRoughness: 0.9, + endRoughness: 0.05, + materials: [] // Store references to bold materials +}; + // Renderer setup const renderer = new THREE.WebGLRenderer({ antialias: true }); @@ -140,6 +151,26 @@ controls.dampingFactor = 0.25; controls.enableZoom = false; // Disable zoom // Material definitions +// Bold glass material (starts rough, will transition to clear) +const boldGlassMaterial = new THREE.MeshPhysicalMaterial({ + color: 0xffffff, + metalness: 0.2, + roughness: 0.4, // Start with rough glass + transmission: 1, + ior: 2, + thickness: 2, + clearcoat: 1.0, + clearcoatRoughness: 0.1, + attenuationColor: new THREE.Color(0xffffff), + attenuationDistance: 0.8, + envMapIntensity: 0, + specularIntensity: 1.0, + specularColor: new THREE.Color(0x000000), + transparent: true, + depthWrite: false, + alphaTest: 0 +}); + // Clear thick glass for innovation const innovationGlassMaterial = new THREE.MeshPhysicalMaterial({ color: 0xffffff, @@ -210,7 +241,25 @@ function applyMaterials(model, modelType) { object.castShadow = true; object.receiveShadow = true; - if (modelType === 'innovation') { + if (modelType === 'bold') { + // Bold-specific material logic - apply bold glass material to Cube mesh + if (object.name === 'Cube') { + console.log(` → Applying bold glass material to "${object.name}"`); + object.material = boldGlassMaterial.clone(); + object.material.side = THREE.DoubleSide; + object.material.depthWrite = false; + object.renderOrder = 2; + + // Store material reference for roughness animation + boldRoughnessAnimation.materials.push(object.material); + } else { + console.log(` → Applying bold glass material (fallback) to "${object.name}"`); + object.material = boldGlassMaterial.clone(); + + // Store material reference for roughness animation + boldRoughnessAnimation.materials.push(object.material); + } + } else if (modelType === 'innovation') { // Innovation-specific material logic const orangeMeshes = ['dblsc', 'ec', 'gemini', 'infinity', 'star', 'dpd']; const targetGlassNames = ['Cube.alt90.df']; @@ -278,19 +327,16 @@ function centerAndFrameModel(model, targetCamera = camera) { model.position.sub(center); model.updateMatrixWorld(true); - const size = box.getSize(new THREE.Vector3()); - const maxDim = Math.max(size.x, size.y, size.z); - // Only set camera position if it's not already positioned (avoid reset during transitions) - // Increased distance multiplier from 2 to 2.5 for further camera position + // Use fixed camera distance that's further away from the origin if (!isTransitioning) { - const cameraDistance = maxDim * 2.5; - targetCamera.position.set(0, 0, cameraDistance); + const fixedCameraDistance = 50; // Fixed distance, much further than before + targetCamera.position.set(0, 0, fixedCameraDistance); controls.target.set(0, 0, 0); // Set distance limits to lock the camera at this distance - controls.minDistance = cameraDistance; - controls.maxDistance = cameraDistance; + controls.minDistance = fixedCameraDistance; + controls.maxDistance = fixedCameraDistance; controls.update(); } @@ -304,7 +350,12 @@ function setupAnimations(model, gltf, modelType) { gltf.animations.forEach((clip) => { const action = animMixer.clipAction(clip); - if (modelType === 'innovation') { + if (modelType === 'bold') { + // Play once for bold + action.loop = THREE.LoopOnce; + action.clampWhenFinished = true; + action.play(); + } else if (modelType === 'innovation') { // PingPong loop for innovation action.loop = THREE.LoopPingPong; action.play(); @@ -351,11 +402,15 @@ function loadModel(filename, modelType, onLoadCallback) { }); } -// Load initial innovation model -loadModel('innovation.glb', 'innovation', (model, animMixer) => { +// Load initial bold model (now the first scene) +loadModel('bold.glb', 'bold', (model, animMixer) => { currentModel = model; mixer = animMixer; scene.add(currentModel); + + // Start the roughness animation for bold scene + boldRoughnessAnimation.isActive = true; + boldRoughnessAnimation.startTime = performance.now(); }); // Twist animation function - Updated to twist around world center (0,0,0) @@ -442,9 +497,9 @@ function resetMeshGeometry(mesh) { function startTransition(direction = 1) { if (isTransitioning) return; - // Check bounds - if (direction > 0 && currentScene >= 2) return; // Can't go forward from storytelling - if (direction < 0 && currentScene <= 0) return; // Can't go backward from innovation + // Check bounds - now 4 scenes (0-3) + if (direction > 0 && currentScene >= 3) return; // Can't go forward from storytelling + if (direction < 0 && currentScene <= 0) return; // Can't go backward from bold isTransitioning = true; isTwisting = true; @@ -452,25 +507,31 @@ function startTransition(direction = 1) { transitionStartTime = performance.now(); transitionDirection = direction; - // Determine next model based on direction + // Determine next model based on direction and current scene let nextModelFile = ''; let nextModelType = ''; if (direction > 0) { // Moving forward if (currentScene === 0) { + nextModelFile = 'innovation.glb'; + nextModelType = 'innovation'; + } else if (currentScene === 1) { nextModelFile = 'agility.glb'; nextModelType = 'agility'; - } else if (currentScene === 1) { + } else if (currentScene === 2) { nextModelFile = 'storytelling.glb'; nextModelType = 'storytelling'; } } else { // Moving backward if (currentScene === 1) { + nextModelFile = 'bold.glb'; + nextModelType = 'bold'; + } else if (currentScene === 2) { nextModelFile = 'innovation.glb'; nextModelType = 'innovation'; - } else if (currentScene === 2) { + } else if (currentScene === 3) { nextModelFile = 'agility.glb'; nextModelType = 'agility'; } @@ -515,7 +576,7 @@ function updateTransition(deltaTime) { if (currentModel) { // Move current model up and fade out - currentModel.position.y = easedProgress * 10; + // currentModel.position.y = easedProgress * 10; currentModel.traverse((obj) => { if (obj.material) { @@ -580,7 +641,7 @@ function updateTransition(deltaTime) { if (Array.isArray(obj.material)) { obj.material.forEach(mat => { mat.opacity = 1; - if (currentScene === 2) { // Keep transparency for storytelling glass + if (currentScene === 3) { // Keep transparency for storytelling glass mat.transparent = mat.transmission > 0; } else { mat.transparent = mat.transmission > 0; @@ -588,7 +649,7 @@ function updateTransition(deltaTime) { }); } else { obj.material.opacity = 1; - if (currentScene === 2) { // Keep transparency for storytelling glass + if (currentScene === 3) { // Keep transparency for storytelling glass obj.material.transparent = obj.material.transmission > 0; } else { obj.material.transparent = obj.material.transmission > 0; @@ -680,6 +741,36 @@ function animate() { } } + // Update bold roughness animation + if (boldRoughnessAnimation.isActive) { + const elapsed = (performance.now() - boldRoughnessAnimation.startTime) / 1000; + + if (elapsed >= boldRoughnessAnimation.delayDuration) { + // Delay period is over, start roughness transition + const transitionElapsed = elapsed - boldRoughnessAnimation.delayDuration; + const transitionProgress = Math.min(transitionElapsed / boldRoughnessAnimation.transitionDuration, 1); + + // Smooth easing function (ease-in-out) + const easeInOut = (t) => t * t * (3 - 2 * t); + const easedProgress = easeInOut(transitionProgress); + + // Interpolate roughness from 0.9 to 0.05 + const currentRoughness = boldRoughnessAnimation.startRoughness + + (boldRoughnessAnimation.endRoughness - boldRoughnessAnimation.startRoughness) * easedProgress; + + // Apply to all bold materials + boldRoughnessAnimation.materials.forEach(material => { + material.roughness = currentRoughness; + material.needsUpdate = true; + }); + + // End animation when complete + if (transitionProgress >= 1) { + boldRoughnessAnimation.isActive = false; + } + } + } + // Turntable rotation for current model if (currentModel && !isTransitioning) { autoRotationAngle += delta * 0.5;