264 lines
9.2 KiB
HTML
264 lines
9.2 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 - Animated Lighting</title>
|
|
<style>
|
|
body {
|
|
margin: 0;
|
|
overflow: hidden;
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
background: #000;
|
|
}
|
|
canvas {
|
|
display: block;
|
|
width: 100vw;
|
|
height: 100vh;
|
|
}
|
|
#info {
|
|
position: absolute;
|
|
top: 10px;
|
|
left: 10px;
|
|
color: white;
|
|
background: rgba(0, 0, 0, 0.7);
|
|
padding: 15px;
|
|
border-radius: 8px;
|
|
font-size: 14px;
|
|
max-width: 400px;
|
|
z-index: 100;
|
|
}
|
|
#info h2 {
|
|
margin: 0 0 10px 0;
|
|
font-size: 18px;
|
|
}
|
|
#info .web-source {
|
|
margin-top: 10px;
|
|
padding-top: 10px;
|
|
border-top: 1px solid rgba(255,255,255,0.3);
|
|
font-size: 12px;
|
|
opacity: 0.8;
|
|
}
|
|
#info a {
|
|
color: #4fc3f7;
|
|
text-decoration: none;
|
|
}
|
|
#info a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="info">
|
|
<h2>Animated Lighting</h2>
|
|
<p><strong>Technique:</strong> Dynamic lighting with moving light sources</p>
|
|
<p><strong>Learning:</strong> AmbientLight, DirectionalLight, PointLight configuration and animation</p>
|
|
<div class="web-source">
|
|
<strong>Web Source:</strong><br>
|
|
<a href="https://threejs.org/examples/#webgl_lights_pointlights" target="_blank">Three.js Lighting Examples</a><br>
|
|
<em>Applied: Multiple animated point lights with visible light spheres and material reactivity</em>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="importmap">
|
|
{
|
|
"imports": {
|
|
"three": "https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js",
|
|
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/"
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<script type="module">
|
|
import * as THREE from 'three';
|
|
|
|
// Scene setup
|
|
let camera, scene, renderer;
|
|
let centralObject, lightHelpers = [];
|
|
let pointLights = [];
|
|
let clock;
|
|
|
|
init();
|
|
animate();
|
|
|
|
function init() {
|
|
// Clock for time-based animations
|
|
clock = new THREE.Clock();
|
|
|
|
// Camera setup
|
|
camera = new THREE.PerspectiveCamera(
|
|
75,
|
|
window.innerWidth / window.innerHeight,
|
|
0.1,
|
|
1000
|
|
);
|
|
camera.position.set(0, 5, 10);
|
|
camera.lookAt(0, 0, 0);
|
|
|
|
// Scene
|
|
scene = new THREE.Scene();
|
|
scene.background = new THREE.Color(0x0a0a0a);
|
|
scene.fog = new THREE.Fog(0x0a0a0a, 20, 50);
|
|
|
|
// Renderer
|
|
renderer = new THREE.WebGLRenderer({ antialias: true });
|
|
renderer.setPixelRatio(window.devicePixelRatio);
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
document.body.appendChild(renderer.domElement);
|
|
|
|
// Create visualization
|
|
createVisualization();
|
|
|
|
// Handle resize
|
|
window.addEventListener('resize', onWindowResize);
|
|
}
|
|
|
|
function createVisualization() {
|
|
// Ambient light - provides subtle base illumination
|
|
const ambientLight = new THREE.AmbientLight(0x222244, 0.3);
|
|
scene.add(ambientLight);
|
|
|
|
// Central object - complex geometry that shows lighting beautifully
|
|
const geometry = new THREE.IcosahedronGeometry(2, 1);
|
|
|
|
// MeshStandardMaterial reacts realistically to lights
|
|
const material = new THREE.MeshStandardMaterial({
|
|
color: 0x666666,
|
|
roughness: 0.4,
|
|
metalness: 0.6,
|
|
flatShading: false
|
|
});
|
|
|
|
centralObject = new THREE.Mesh(geometry, material);
|
|
scene.add(centralObject);
|
|
|
|
// Create three point lights with different colors
|
|
const lightConfigs = [
|
|
{ color: 0xff3366, distance: 0, decay: 2, intensity: 2 }, // Pink/Red
|
|
{ color: 0x3366ff, distance: 0, decay: 2, intensity: 2 }, // Blue
|
|
{ color: 0xffaa00, distance: 0, decay: 2, intensity: 2 } // Orange
|
|
];
|
|
|
|
lightConfigs.forEach((config, index) => {
|
|
// Create point light
|
|
const pointLight = new THREE.PointLight(
|
|
config.color,
|
|
config.intensity,
|
|
config.distance,
|
|
config.decay
|
|
);
|
|
|
|
// Initial position (will be animated)
|
|
const angle = (index / lightConfigs.length) * Math.PI * 2;
|
|
const radius = 5;
|
|
pointLight.position.set(
|
|
Math.cos(angle) * radius,
|
|
Math.sin(angle * 1.5) * 2,
|
|
Math.sin(angle) * radius
|
|
);
|
|
|
|
scene.add(pointLight);
|
|
pointLights.push(pointLight);
|
|
|
|
// Create visible sphere at light position
|
|
const sphereGeometry = new THREE.SphereGeometry(0.2, 16, 16);
|
|
const sphereMaterial = new THREE.MeshBasicMaterial({
|
|
color: config.color,
|
|
transparent: true,
|
|
opacity: 0.9
|
|
});
|
|
const lightHelper = new THREE.Mesh(sphereGeometry, sphereMaterial);
|
|
pointLight.add(lightHelper);
|
|
lightHelpers.push(lightHelper);
|
|
|
|
// Add a subtle glow effect around each light
|
|
const glowGeometry = new THREE.SphereGeometry(0.4, 16, 16);
|
|
const glowMaterial = new THREE.MeshBasicMaterial({
|
|
color: config.color,
|
|
transparent: true,
|
|
opacity: 0.2
|
|
});
|
|
const glow = new THREE.Mesh(glowGeometry, glowMaterial);
|
|
pointLight.add(glow);
|
|
});
|
|
|
|
// Add a ground plane to show light falloff
|
|
const planeGeometry = new THREE.PlaneGeometry(30, 30);
|
|
const planeMaterial = new THREE.MeshStandardMaterial({
|
|
color: 0x111122,
|
|
roughness: 0.8,
|
|
metalness: 0.2
|
|
});
|
|
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
|
|
plane.rotation.x = -Math.PI / 2;
|
|
plane.position.y = -3;
|
|
scene.add(plane);
|
|
|
|
// Add some additional objects to show lighting effects
|
|
const smallSphereGeometry = new THREE.SphereGeometry(0.5, 32, 32);
|
|
const smallSphereMaterial = new THREE.MeshStandardMaterial({
|
|
color: 0xcccccc,
|
|
roughness: 0.3,
|
|
metalness: 0.7
|
|
});
|
|
|
|
for (let i = 0; i < 5; i++) {
|
|
const smallSphere = new THREE.Mesh(smallSphereGeometry, smallSphereMaterial);
|
|
const angle = (i / 5) * Math.PI * 2;
|
|
const radius = 4;
|
|
smallSphere.position.set(
|
|
Math.cos(angle) * radius,
|
|
-1,
|
|
Math.sin(angle) * radius
|
|
);
|
|
scene.add(smallSphere);
|
|
}
|
|
}
|
|
|
|
function onWindowResize() {
|
|
camera.aspect = window.innerWidth / window.innerHeight;
|
|
camera.updateProjectionMatrix();
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
}
|
|
|
|
function animate() {
|
|
requestAnimationFrame(animate);
|
|
|
|
const time = clock.getElapsedTime();
|
|
|
|
// Rotate central object slowly
|
|
centralObject.rotation.y = time * 0.3;
|
|
centralObject.rotation.x = Math.sin(time * 0.2) * 0.2;
|
|
|
|
// Animate each point light in orbit around the central object
|
|
pointLights.forEach((light, index) => {
|
|
// Each light has different orbit characteristics
|
|
const speed = 0.5 + index * 0.15;
|
|
const radius = 5 + Math.sin(time * 0.3 + index) * 0.5;
|
|
const verticalSpeed = 0.8 + index * 0.2;
|
|
|
|
// Calculate orbital position
|
|
const angle = time * speed + (index / pointLights.length) * Math.PI * 2;
|
|
|
|
light.position.x = Math.cos(angle) * radius;
|
|
light.position.z = Math.sin(angle) * radius;
|
|
light.position.y = Math.sin(time * verticalSpeed + index * 2) * 2;
|
|
|
|
// Vary light intensity slightly for dynamic effect
|
|
light.intensity = 2 + Math.sin(time * 2 + index) * 0.5;
|
|
});
|
|
|
|
// Slowly rotate camera around the scene
|
|
const cameraAngle = time * 0.1;
|
|
const cameraRadius = 10;
|
|
camera.position.x = Math.cos(cameraAngle) * cameraRadius;
|
|
camera.position.z = Math.sin(cameraAngle) * cameraRadius;
|
|
camera.position.y = 5 + Math.sin(cameraAngle * 0.5) * 2;
|
|
camera.lookAt(0, 0, 0);
|
|
|
|
renderer.render(scene, camera);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|