almost final
This commit is contained in:
parent
8d52d89024
commit
6bd4a96e2d
|
@ -8,7 +8,7 @@ const FluidSimShader = {
|
|||
iResolution: { value: new THREE.Vector2() },
|
||||
iTime: { value: 0.0 },
|
||||
mouse: { value: new THREE.Vector3(-1, -1, 0.0) },
|
||||
dissipation: { value: 0.950 }, // Slightly more persistent for trails
|
||||
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
|
||||
|
@ -80,7 +80,7 @@ const FluidSimShader = {
|
|||
|
||||
// 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 * 8.0 + timeOffset) * g;
|
||||
float ripple = sin(dist * 0.2 - iTime * 16.0 + timeOffset) * g;
|
||||
|
||||
// Diminishing strength for trailing ripples
|
||||
float strength = mouse.z * (1.0 - i * 0.2) * 0.8;
|
||||
|
|
147
src/main.js
147
src/main.js
|
@ -12,7 +12,8 @@ import {
|
|||
updateTransition,
|
||||
onMouseScroll,
|
||||
setCurrentModel,
|
||||
setMixer
|
||||
setMixer,
|
||||
setGLBRepulsionSystem
|
||||
} from './transitionManager.js';
|
||||
import {
|
||||
startBoldRoughnessAnimation,
|
||||
|
@ -48,7 +49,6 @@ let preloadedModels = {};
|
|||
// Enhanced fluid simulation + distortion pass
|
||||
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();
|
||||
distortionPass.material.uniforms.iResolution.value.set(window.innerWidth * dpr, window.innerHeight * dpr);
|
||||
|
@ -64,7 +64,6 @@ distortionPass.material.uniforms.ambientLight.value = 1;
|
|||
// New ripple whiteness parameters
|
||||
distortionPass.material.uniforms.rippleWhiteness.value = 0.025; // Amount of white tint
|
||||
distortionPass.material.uniforms.rippleBrightness.value = 1; // Brightness boost for ripples
|
||||
|
||||
composer.addPass(distortionPass);
|
||||
|
||||
// Enhanced pointer tracking
|
||||
|
@ -78,8 +77,22 @@ const pointer = {
|
|||
maxTrailLength: 5
|
||||
};
|
||||
|
||||
// Mouse coordinates for starfield
|
||||
// Mouse coordinates for starfield and GLB interaction
|
||||
const mouse = new THREE.Vector2();
|
||||
const raycaster = new THREE.Raycaster();
|
||||
|
||||
// GLB cursor repulsion parameters
|
||||
const glbRepulsion = {
|
||||
radius: 30, // Repulsion radius
|
||||
maxDistance: 2, // Maximum distance GLB can move from original position
|
||||
strength: 8, // Repulsion strength
|
||||
originalPositions: new Map(), // Store original positions for each model
|
||||
currentTargets: new Map(), // Store current target positions
|
||||
interpolationSpeed: 3 // Speed of position interpolation
|
||||
};
|
||||
|
||||
// Connect GLB repulsion system to transition manager
|
||||
setGLBRepulsionSystem(glbRepulsion);
|
||||
|
||||
function toSimPixels(e) {
|
||||
const rect = renderer.domElement.getBoundingClientRect();
|
||||
|
@ -93,7 +106,6 @@ renderer.domElement.addEventListener('pointermove', (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.0 * dpr), 1.0); // More sensitive
|
||||
|
||||
pointer.x = x;
|
||||
pointer.y = y;
|
||||
pointer.strength = speed * 1.2; // Enhanced strength
|
||||
|
@ -106,7 +118,7 @@ renderer.domElement.addEventListener('pointermove', (e) => {
|
|||
const normalizedY = 1.0 - (e.clientY - rect.top) / rect.height; // Flip Y
|
||||
distortionPass.material.uniforms.lightPosition.value.set(normalizedX, normalizedY, 1.0);
|
||||
|
||||
// Update mouse coordinates for starfield
|
||||
// Update mouse coordinates for starfield and GLB interaction
|
||||
mouse.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
|
||||
mouse.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
|
||||
}, { passive: true });
|
||||
|
@ -117,11 +129,119 @@ renderer.domElement.addEventListener('pointerleave', () => {
|
|||
pointer.strength = 0.0;
|
||||
mouse.x = -999;
|
||||
mouse.y = -999;
|
||||
|
||||
// Reset light to center when mouse leaves
|
||||
distortionPass.material.uniforms.lightPosition.value.set(0.5, 0.5, 1.0);
|
||||
}, { passive: true });
|
||||
|
||||
// GLB cursor repulsion function
|
||||
function updateGLBRepulsion(camera, mouse, deltaTime) {
|
||||
if (!mouse || mouse.x === -999 || mouse.y === -999) {
|
||||
// Mouse is not active, return models to original positions
|
||||
if (currentModel) {
|
||||
const originalPos = glbRepulsion.originalPositions.get(currentModel);
|
||||
if (originalPos) {
|
||||
const currentTarget = glbRepulsion.currentTargets.get(currentModel) || new THREE.Vector3();
|
||||
currentTarget.copy(originalPos);
|
||||
glbRepulsion.currentTargets.set(currentModel, currentTarget);
|
||||
// Interpolate to original position
|
||||
const lerpFactor = Math.min(glbRepulsion.interpolationSpeed * deltaTime, 1.0);
|
||||
currentModel.position.lerp(currentTarget, lerpFactor);
|
||||
}
|
||||
}
|
||||
if (nextModel) {
|
||||
const originalPos = glbRepulsion.originalPositions.get(nextModel);
|
||||
if (originalPos) {
|
||||
const currentTarget = glbRepulsion.currentTargets.get(nextModel) || new THREE.Vector3();
|
||||
currentTarget.copy(originalPos);
|
||||
glbRepulsion.currentTargets.set(nextModel, currentTarget);
|
||||
// Interpolate to original position
|
||||
const lerpFactor = Math.min(glbRepulsion.interpolationSpeed * deltaTime, 1.0);
|
||||
nextModel.position.lerp(currentTarget, lerpFactor);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Get mouse position in 3D world space
|
||||
raycaster.setFromCamera(mouse, camera);
|
||||
const distance = 50; // Project to a plane at fixed distance
|
||||
const mouseWorldPos = raycaster.ray.direction.clone().multiplyScalar(distance).add(raycaster.ray.origin);
|
||||
|
||||
// Handle current model repulsion
|
||||
if (currentModel) {
|
||||
let originalPos = glbRepulsion.originalPositions.get(currentModel);
|
||||
if (!originalPos) {
|
||||
originalPos = currentModel.position.clone();
|
||||
glbRepulsion.originalPositions.set(currentModel, originalPos);
|
||||
}
|
||||
|
||||
// Calculate repulsion
|
||||
const modelPos = currentModel.position.clone();
|
||||
const dx = modelPos.x - mouseWorldPos.x;
|
||||
const dy = modelPos.y - mouseWorldPos.y;
|
||||
const dz = modelPos.z - mouseWorldPos.z;
|
||||
const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
|
||||
let targetPos = originalPos.clone();
|
||||
if (dist < glbRepulsion.radius && dist > 0) {
|
||||
const force = (1 - dist / glbRepulsion.radius) * glbRepulsion.strength;
|
||||
const nx = dx / dist;
|
||||
const ny = dy / dist;
|
||||
const nz = dz / dist;
|
||||
const repulsionVector = new THREE.Vector3(nx * force, ny * force, nz * force);
|
||||
targetPos.add(repulsionVector);
|
||||
// Limit maximum distance from original position
|
||||
const offsetFromOriginal = targetPos.clone().sub(originalPos);
|
||||
if (offsetFromOriginal.length() > glbRepulsion.maxDistance) {
|
||||
offsetFromOriginal.normalize().multiplyScalar(glbRepulsion.maxDistance);
|
||||
targetPos = originalPos.clone().add(offsetFromOriginal);
|
||||
}
|
||||
}
|
||||
|
||||
// Store and interpolate to target position
|
||||
glbRepulsion.currentTargets.set(currentModel, targetPos);
|
||||
const lerpFactor = Math.min(glbRepulsion.interpolationSpeed * deltaTime, 1.0);
|
||||
currentModel.position.lerp(targetPos, lerpFactor);
|
||||
}
|
||||
|
||||
// Handle next model repulsion during transitions
|
||||
if (nextModel) {
|
||||
let originalPos = glbRepulsion.originalPositions.get(nextModel);
|
||||
if (!originalPos) {
|
||||
originalPos = nextModel.position.clone();
|
||||
glbRepulsion.originalPositions.set(nextModel, originalPos);
|
||||
}
|
||||
|
||||
// Calculate repulsion
|
||||
const modelPos = nextModel.position.clone();
|
||||
const dx = modelPos.x - mouseWorldPos.x;
|
||||
const dy = modelPos.y - mouseWorldPos.y;
|
||||
const dz = modelPos.z - mouseWorldPos.z;
|
||||
const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
|
||||
let targetPos = originalPos.clone();
|
||||
if (dist < glbRepulsion.radius && dist > 0) {
|
||||
const force = (1 - dist / glbRepulsion.radius) * glbRepulsion.strength;
|
||||
const nx = dx / dist;
|
||||
const ny = dy / dist;
|
||||
const nz = dz / dist;
|
||||
const repulsionVector = new THREE.Vector3(nx * force, ny * force, nz * force);
|
||||
targetPos.add(repulsionVector);
|
||||
// Limit maximum distance from original position
|
||||
const offsetFromOriginal = targetPos.clone().sub(originalPos);
|
||||
if (offsetFromOriginal.length() > glbRepulsion.maxDistance) {
|
||||
offsetFromOriginal.normalize().multiplyScalar(glbRepulsion.maxDistance);
|
||||
targetPos = originalPos.clone().add(offsetFromOriginal);
|
||||
}
|
||||
}
|
||||
|
||||
// Store and interpolate to target position
|
||||
glbRepulsion.currentTargets.set(nextModel, targetPos);
|
||||
const lerpFactor = Math.min(glbRepulsion.interpolationSpeed * deltaTime, 1.0);
|
||||
nextModel.position.lerp(targetPos, lerpFactor);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize first scene
|
||||
function initializeScene() {
|
||||
console.log('Initializing first scene (bold)');
|
||||
|
@ -129,13 +249,14 @@ function initializeScene() {
|
|||
setCurrentModel(model);
|
||||
setMixer(animMixer);
|
||||
scene.add(currentModel);
|
||||
// Store original position for repulsion
|
||||
glbRepulsion.originalPositions.set(currentModel, currentModel.position.clone());
|
||||
startBoldRoughnessAnimation(true);
|
||||
console.log('Bold scene initialized');
|
||||
}
|
||||
|
||||
// Animation loop
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
function animate() {
|
||||
requestAnimationFrame(animate);
|
||||
const delta = clock.getDelta();
|
||||
|
@ -149,6 +270,11 @@ function animate() {
|
|||
updateTransition(delta, scene);
|
||||
}
|
||||
|
||||
// GLB cursor repulsion (only when not transitioning to avoid conflicts)
|
||||
if (!isTransitioning) {
|
||||
updateGLBRepulsion(camera, mouse, delta);
|
||||
}
|
||||
|
||||
// Turntable rotation
|
||||
if (currentModel) {
|
||||
currentModel.rotation.y += turntableSpeed * delta;
|
||||
|
@ -179,16 +305,13 @@ async function init() {
|
|||
console.log('Starting application initialization');
|
||||
preloadedModels = await sceneLoader.loadAllModels();
|
||||
console.log('All models loaded successfully');
|
||||
|
||||
initializeScene();
|
||||
animate();
|
||||
console.log('Animation loop started');
|
||||
|
||||
window.addEventListener('wheel', (event) => {
|
||||
onMouseScroll(event, preloadedModels, scene, camera, controls);
|
||||
}, { passive: true });
|
||||
console.log('Scroll event listener attached');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize scene:', error);
|
||||
sceneLoader.setLoadingMessage('Error loading experience. Please refresh.');
|
||||
|
@ -200,12 +323,10 @@ window.addEventListener('resize', () => {
|
|||
console.log('Window resized');
|
||||
const w = window.innerWidth;
|
||||
const h = window.innerHeight;
|
||||
|
||||
camera.aspect = w / h;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(w, h);
|
||||
composer.setSize(w, h);
|
||||
|
||||
const pixelRatio = renderer.getPixelRatio ? renderer.getPixelRatio() : Math.min(window.devicePixelRatio || 1, 2);
|
||||
distortionPass.material.uniforms.iResolution.value.set(w * pixelRatio, h * pixelRatio);
|
||||
fluid.resize(w, h, pixelRatio);
|
||||
|
|
|
@ -30,7 +30,6 @@ export function createScene() {
|
|||
const composer = new EffectComposer(renderer);
|
||||
const renderPass = new RenderPass(scene, camera);
|
||||
composer.addPass(renderPass);
|
||||
|
||||
const bloomPass = new UnrealBloomPass(
|
||||
new THREE.Vector2(window.innerWidth, window.innerHeight),
|
||||
1.0, // strength
|
||||
|
@ -54,55 +53,45 @@ export function setupLighting(scene, camera) {
|
|||
// Consistent Lighting Setup
|
||||
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
|
||||
scene.add(ambientLight);
|
||||
|
||||
const hemiLight = new THREE.HemisphereLight(0xffffff, 0x666666, 1.5);
|
||||
hemiLight.position.set(0, 20, 0);
|
||||
scene.add(hemiLight);
|
||||
|
||||
const fillLight = new THREE.DirectionalLight(0xffffff, 1.2);
|
||||
fillLight.position.set(-12, 6, -8);
|
||||
scene.add(fillLight);
|
||||
|
||||
const topLight = new THREE.DirectionalLight(0xffffff, 1.5);
|
||||
topLight.position.set(5, 15, 5);
|
||||
scene.add(topLight);
|
||||
|
||||
const bottomLight = new THREE.DirectionalLight(0xffffff, 0.8);
|
||||
bottomLight.position.set(-3, -8, 3);
|
||||
scene.add(bottomLight);
|
||||
|
||||
const leftLight = new THREE.DirectionalLight(0xffffff, 1.0);
|
||||
leftLight.position.set(-12, 2, 5);
|
||||
scene.add(leftLight);
|
||||
|
||||
const rightLight = new THREE.DirectionalLight(0xffffff, 1.0);
|
||||
rightLight.position.set(12, 2, -5);
|
||||
scene.add(rightLight);
|
||||
|
||||
const frontLight = new THREE.DirectionalLight(0xffffff, 0.8);
|
||||
frontLight.position.set(8, 4, 12);
|
||||
scene.add(frontLight);
|
||||
|
||||
const backLight = new THREE.DirectionalLight(0xffffff, 0.8);
|
||||
backLight.position.set(-8, 4, -12);
|
||||
scene.add(backLight);
|
||||
|
||||
const cameraLight = new THREE.PointLight(0xffffff, 0.8, 0, 2);
|
||||
camera.add(cameraLight);
|
||||
scene.add(camera);
|
||||
}
|
||||
|
||||
export function setupControls(camera, renderer) {
|
||||
// Controls with zoom disabled and camera constraints
|
||||
// Controls with zoom and pan disabled and camera constraints
|
||||
const controls = new OrbitControls(camera, renderer.domElement);
|
||||
controls.enableDamping = true;
|
||||
controls.dampingFactor = 0.25;
|
||||
controls.enableZoom = false; // Disable zoom
|
||||
|
||||
controls.enablePan = false; // Disable panning
|
||||
// Add camera constraints to prevent extreme angles
|
||||
controls.maxPolarAngle = Math.PI * 0.8; // Prevent looking too far up
|
||||
controls.minPolarAngle = Math.PI * 0.2; // Prevent looking too far down
|
||||
|
||||
console.log('Orbit controls initialized with camera constraints');
|
||||
console.log('Orbit controls initialized with camera constraints and pan disabled');
|
||||
return controls;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import * as THREE from 'three';
|
||||
|
||||
export function createStarfield(scene) {
|
||||
const starCount = 12000;
|
||||
const starCount = 16000;
|
||||
const starDistance = 300;
|
||||
|
||||
// Create geometry for stars
|
||||
|
|
Loading…
Reference in a new issue