infinite-agents-public/threejs_viz/threejs_viz_5.html

349 lines
12 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Three.js Visualization 5: Geometry Morphing</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<style>
body {
margin: 0;
padding: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a2e 100%);
color: #ffffff;
overflow-x: hidden;
}
#container {
width: 100vw;
height: 100vh;
position: relative;
}
#info {
position: absolute;
top: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.7);
padding: 20px;
border-radius: 10px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
max-width: 350px;
z-index: 100;
}
#info h1 {
margin: 0 0 15px 0;
font-size: 24px;
color: #00d9ff;
text-shadow: 0 0 10px rgba(0, 217, 255, 0.5);
}
#info p {
margin: 8px 0;
font-size: 14px;
line-height: 1.6;
}
#info strong {
color: #00d9ff;
}
canvas {
display: block;
}
footer {
position: absolute;
bottom: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.7);
padding: 15px;
border-radius: 10px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
max-width: 400px;
font-size: 12px;
z-index: 100;
}
footer h3 {
margin: 0 0 10px 0;
font-size: 16px;
color: #00d9ff;
}
footer ul {
margin: 0;
padding-left: 20px;
}
footer li {
margin: 5px 0;
line-height: 1.4;
}
</style>
</head>
<body>
<div id="container"></div>
<div id="info">
<h1>Geometry Morphing</h1>
<p><strong>Technique:</strong> Dynamic geometry transformation and scaling</p>
<p><strong>Learning:</strong> Geometry properties, scale/rotation/position animation with easing</p>
<p><strong>Web Source:</strong> Three.js Animation Examples</p>
</div>
<footer>
<h3>Iteration 5 - Foundation Level</h3>
<ul>
<li><strong>Focus:</strong> Geometry transformation and morphing</li>
<li><strong>Technique:</strong> Smooth easing functions with synchronized transformations</li>
<li><strong>Enhancement:</strong> Organic motion through combined scale, rotation, and material changes</li>
</ul>
</footer>
<script>
// Scene setup
const scene = new THREE.Scene();
scene.fog = new THREE.Fog(0x0a0a0a, 10, 50);
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.z = 25;
const renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.getElementById('container').appendChild(renderer.domElement);
// Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.3);
scene.add(ambientLight);
const pointLight1 = new THREE.PointLight(0x00d9ff, 1.5, 100);
pointLight1.position.set(10, 10, 10);
scene.add(pointLight1);
const pointLight2 = new THREE.PointLight(0xff00d9, 1.5, 100);
pointLight2.position.set(-10, -10, 10);
scene.add(pointLight2);
// Create morphing geometries
const morphingObjects = [];
// Central morphing sphere that transitions between shapes
const sphereGeometry = new THREE.SphereGeometry(3, 32, 32);
const sphereMaterial = new THREE.MeshPhongMaterial({
color: 0x00d9ff,
emissive: 0x001a2e,
shininess: 100,
transparent: true,
opacity: 0.9
});
const centralSphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(centralSphere);
morphingObjects.push({
mesh: centralSphere,
baseScale: 1,
phaseOffset: 0,
rotationSpeed: { x: 0.002, y: 0.003, z: 0.001 }
});
// Create orbiting morphing cubes
const cubeCount = 8;
for (let i = 0; i < cubeCount; i++) {
const angle = (i / cubeCount) * Math.PI * 2;
const radius = 12;
const geometry = new THREE.BoxGeometry(1.5, 1.5, 1.5);
const material = new THREE.MeshPhongMaterial({
color: new THREE.Color().setHSL(i / cubeCount, 1, 0.5),
emissive: new THREE.Color().setHSL(i / cubeCount, 1, 0.2),
shininess: 80,
transparent: true,
opacity: 0.8
});
const cube = new THREE.Mesh(geometry, material);
cube.position.x = Math.cos(angle) * radius;
cube.position.y = Math.sin(angle) * radius;
cube.position.z = Math.sin(angle * 2) * 3;
scene.add(cube);
morphingObjects.push({
mesh: cube,
baseScale: 1,
angle: angle,
radius: radius,
orbitSpeed: 0.3,
phaseOffset: i * Math.PI / 4,
rotationSpeed: {
x: 0.01 + i * 0.002,
y: 0.015 + i * 0.001,
z: 0.008
}
});
}
// Create floating tetrahedrons with wave motion
const tetraCount = 12;
for (let i = 0; i < tetraCount; i++) {
const geometry = new THREE.TetrahedronGeometry(0.8, 0);
const material = new THREE.MeshPhongMaterial({
color: new THREE.Color().setHSL(0.6 + i * 0.03, 0.8, 0.6),
emissive: new THREE.Color().setHSL(0.6 + i * 0.03, 0.8, 0.3),
shininess: 60,
transparent: true,
opacity: 0.7,
wireframe: i % 2 === 0
});
const tetra = new THREE.Mesh(geometry, material);
tetra.position.x = (Math.random() - 0.5) * 30;
tetra.position.y = (Math.random() - 0.5) * 30;
tetra.position.z = (Math.random() - 0.5) * 20;
scene.add(tetra);
morphingObjects.push({
mesh: tetra,
baseScale: 1,
phaseOffset: Math.random() * Math.PI * 2,
waveSpeed: 0.5 + Math.random() * 0.5,
waveAmplitude: 0.5 + Math.random() * 0.5,
rotationSpeed: {
x: 0.02,
y: 0.03,
z: 0.01
}
});
}
// Animation variables
let time = 0;
// Easing functions
function easeInOutSine(t) {
return -(Math.cos(Math.PI * t) - 1) / 2;
}
function easeInOutQuad(t) {
return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
}
function elasticPulse(t) {
return Math.sin(t * Math.PI * 2) * Math.exp(-t * 0.5);
}
// Animation loop
function animate() {
requestAnimationFrame(animate);
time += 0.016; // Approximate 60fps
// Animate each morphing object
morphingObjects.forEach((obj, index) => {
const mesh = obj.mesh;
// Apply rotations
mesh.rotation.x += obj.rotationSpeed.x;
mesh.rotation.y += obj.rotationSpeed.y;
mesh.rotation.z += obj.rotationSpeed.z;
// Calculate phase with offset
const phase = time * 0.5 + obj.phaseOffset;
// Pulsing scale with sine wave
const pulseScale = 1 + Math.sin(phase * 2) * 0.3;
// Secondary breathing effect
const breathScale = 1 + Math.sin(phase * 0.8) * 0.15;
// Combined scale with easing
const finalScale = obj.baseScale * pulseScale * breathScale;
mesh.scale.set(finalScale, finalScale, finalScale);
// Update material opacity with wave
if (mesh.material.transparent) {
const opacityWave = 0.5 + Math.sin(phase * 1.5) * 0.3;
mesh.material.opacity = Math.max(0.4, Math.min(1.0, opacityWave));
}
// Orbital motion for cubes
if (obj.angle !== undefined) {
const orbitPhase = time * obj.orbitSpeed + obj.angle;
mesh.position.x = Math.cos(orbitPhase) * obj.radius;
mesh.position.y = Math.sin(orbitPhase) * obj.radius;
mesh.position.z = Math.sin(orbitPhase * 2) * 3 + Math.cos(orbitPhase * 3) * 2;
}
// Wave motion for tetrahedrons
if (obj.waveSpeed !== undefined) {
const wavePhase = time * obj.waveSpeed + obj.phaseOffset;
const waveY = Math.sin(wavePhase) * obj.waveAmplitude * 5;
const waveZ = Math.cos(wavePhase * 1.3) * obj.waveAmplitude * 3;
mesh.position.y += waveY * 0.05;
mesh.position.z += waveZ * 0.05;
}
// Color shifting for central sphere
if (index === 0) {
const hue = (time * 0.1) % 1;
mesh.material.color.setHSL(hue, 0.8, 0.5);
mesh.material.emissive.setHSL(hue, 0.8, 0.2);
// Complex morphing: combine multiple sine waves
const morph1 = Math.sin(time * 0.7) * 0.4;
const morph2 = Math.cos(time * 1.3) * 0.3;
const morph3 = Math.sin(time * 0.5) * 0.2;
const morphScale = 1 + morph1 + morph2 + morph3;
mesh.scale.set(
morphScale,
morphScale * (1 + Math.sin(time * 1.1) * 0.2),
morphScale * (1 + Math.cos(time * 0.9) * 0.2)
);
}
});
// Animate lights for dynamic atmosphere
pointLight1.position.x = Math.cos(time * 0.5) * 15;
pointLight1.position.y = Math.sin(time * 0.5) * 15;
pointLight1.intensity = 1.5 + Math.sin(time * 2) * 0.5;
pointLight2.position.x = Math.cos(time * 0.3 + Math.PI) * 15;
pointLight2.position.y = Math.sin(time * 0.3 + Math.PI) * 15;
pointLight2.intensity = 1.5 + Math.cos(time * 1.5) * 0.5;
// Subtle camera movement for immersion
camera.position.x = Math.sin(time * 0.1) * 2;
camera.position.y = Math.cos(time * 0.15) * 1.5;
camera.lookAt(scene.position);
renderer.render(scene, camera);
}
// Handle window resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// Start animation
animate();
</script>
</body>
</html>