Last active
April 30, 2025 01:43
-
-
Save ShaneBrumback/8e05a9dcf4f810c7688ac95c80aba6fc to your computer and use it in GitHub Desktop.
Threejs Examples Interactive Image Particle System
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--//////////////////////////////////////////////////////////////////////////////////////// | |
/// /// | |
/// Example Using Three.js Library, HTML, CSS & JavaScript /// | |
// 3D Interactive Web Apps & Games 2021-2024 /// | |
/// Contact Shane Brumback https://www.shanebrumback.com /// | |
/// Send a message if you have questions about this code /// | |
/// I am a freelance developer. I develop any and all web. /// | |
/// Apps Websites 3D 2D CMS Systems etc. Contact me anytime :) /// | |
/// /// | |
////////////////////////////////////////////////////////////////////////////////////////////--> | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Three.js Examples - Interactive Image Particle System</title> | |
<style> | |
body { | |
color: white; | |
text-align: center; | |
margin: 0; | |
background-color: black | |
} | |
a { | |
text-decoration: none; | |
color: white; | |
} | |
h1 { | |
padding: 10px; | |
} | |
</style> | |
</head> | |
<body> | |
<!--Load the latest version of Three.js from CDN--> | |
<script src="https://cdn.jsdelivr.net/npm/three@latest/build/three.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/three@latest/examples/js/controls/OrbitControls.js"></script> | |
<script type="module"> | |
// Initialize variables | |
var scene, camera, renderer; | |
var particles = []; | |
let mouseX = 0, mouseY = 0; | |
let windowHalfX = window.innerWidth / 2; | |
let windowHalfY = window.innerHeight / 2; | |
// Initialize Three.js scene | |
function initScene() { | |
// Create the scene | |
scene = new THREE.Scene(); | |
// Create the camera | |
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); | |
camera.position.z = 5; | |
// Create the renderer | |
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); | |
renderer.setPixelRatio(window.devicePixelRatio); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
renderer.toneMapping = THREE.ReinhardToneMapping; | |
renderer.setClearColor(0x000000); | |
renderer.domElement.style.position = 'fixed'; | |
renderer.domElement.style.zIndex = '0'; | |
renderer.domElement.style.left = '0'; | |
renderer.domElement.style.top = '0'; | |
document.body.appendChild(renderer.domElement); | |
// Add ambient light to the scene | |
var ambientLight = new THREE.AmbientLight(0xffffff, 5); // White light with intensity 1 | |
scene.add(ambientLight); | |
window.addEventListener('pointermove', onPointerMove); | |
// Add event listener for mouse movement | |
document.addEventListener('mousemove', onMouseMove, false); | |
window.addEventListener('resize', onWindowResize); | |
//handles pc and mobile pointer movement | |
function onPointerMove(event) { | |
if (event.isPrimary === false) return; | |
mouseX = event.clientX - windowHalfX; | |
mouseY = event.clientY - windowHalfY; | |
} | |
//handles window resize events | |
function onWindowResize() { | |
windowHalfX = window.innerWidth / 2; | |
windowHalfY = window.innerHeight / 2; | |
camera.aspect = window.innerWidth / window.innerHeight; | |
camera.updateProjectionMatrix(); | |
// composer.setSize(window.innerWidth, window.innerHeight); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
} | |
// Add particles to the scene | |
for (var i = 0; i < 75; i++) { | |
var particle = new THREE.Mesh( | |
new THREE.PlaneGeometry(.75, .75), // Use PlaneGeometry instead of SphereGeometry | |
new THREE.MeshPhongMaterial({ | |
color: getRandomColor(), | |
transparent: true, | |
depthTest: true | |
}) | |
); | |
// Load the texture | |
var textureLoader = new THREE.TextureLoader(); | |
var texture = textureLoader.load('../images/smiley.png'); | |
particle.material.map = texture; | |
particle.position.set(Math.random() * 8 - 4, Math.random() * 8 - 4, Math.random() * 6 - 3); | |
particle.velocity = new THREE.Vector3(); | |
// Initialize originalPosition property | |
particle.originalPosition = particle.position.clone(); | |
particle.position.set(Math.random() * 8 - 4, Math.random() * 8 - 4, Math.random() * 6 - 3); | |
particle.velocity = new THREE.Vector3(); | |
particles.push(particle); | |
scene.add(particle); | |
} | |
function getRandomColor() { | |
var colors = ['red', 'yellow', 'green', 'blue', 'orange', 'purple']; | |
var weights = [1, 5, 1, 1, 1, 1]; // Adjust the weights to prioritize yellow (increase its value) | |
// Generate a weighted random index | |
var totalWeight = weights.reduce((a, b) => a + b, 0); | |
var randomWeight = Math.random() * totalWeight; | |
var cumulativeWeight = 0; | |
var randomIndex = 0; | |
for (var i = 0; i < colors.length; i++) { | |
cumulativeWeight += weights[i]; | |
if (randomWeight < cumulativeWeight) { | |
randomIndex = i; | |
break; | |
} | |
} | |
return colors[randomIndex]; | |
} | |
} | |
// Handle mouse movement event | |
function onMouseMove(event) { | |
var mouse = new THREE.Vector2(); | |
mouse.x = (event.clientX / window.innerWidth) * 2 - 1; | |
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; | |
// Create a raycaster from the mouse coordinates | |
var raycaster = new THREE.Raycaster(); | |
raycaster.setFromCamera(mouse, camera); | |
// Check for intersection between the raycaster and particles | |
var intersects = raycaster.intersectObjects(particles); | |
if (intersects.length > 0) { | |
// Move particles away from the mouse position if the ray intersects with them | |
intersects.forEach(function (intersect) { | |
var particle = intersect.object; | |
var distance = particle.position.distanceTo(intersect.point); | |
if (distance < 0.5) { | |
var direction = new THREE.Vector3().subVectors(particle.position, intersect.point).normalize(); | |
particle.velocity.copy(direction).multiplyScalar(0.02); | |
} | |
}); | |
} | |
} | |
// Update particle positions | |
function updateParticles() { | |
particles.forEach(function (particle) { | |
particle.position.add(particle.velocity); | |
particle.velocity.multiplyScalar(0.98); | |
// Calculate the displacement factor based on time | |
var displacementFactor = Math.sin(Date.now() * 0.002); | |
// Calculate the target position | |
var targetPosition = new THREE.Vector3( | |
particle.originalPosition.x + displacementFactor * 0.04, | |
particle.originalPosition.y + displacementFactor * 0.1, | |
particle.originalPosition.z + displacementFactor * 0.04 | |
); | |
// Adjust the target position based on mouse position | |
var mouseDistance = particle.position.distanceTo(new THREE.Vector3(mouseX, mouseY, 0)); | |
if (mouseDistance < 2) { | |
var direction = new THREE.Vector3().subVectors(particle.position, new THREE.Vector3(mouseX, mouseY, 0)).normalize(); | |
targetPosition.addScaledVector(direction, 0.2); | |
} | |
// Adjust the lerp factor for smoother movement | |
var lerpFactor = 0.003; // Experiment with different values (e.g., 0.001, 0.005) for desired smoothness | |
// Check if particle has reached the target position | |
if (particle.position.distanceTo(targetPosition) < 0.01) { | |
// Particle has reached the target, reset to original position | |
targetPosition.copy(particle.originalPosition); | |
} | |
particle.position.lerp(targetPosition, lerpFactor); | |
}); | |
} | |
// Render the scene | |
function render() { | |
requestAnimationFrame(render); | |
updateParticles(); | |
renderer.render(scene, camera); | |
} | |
// Call the initialization function and start rendering | |
initScene(); | |
render(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment