Skip to content

Instantly share code, notes, and snippets.

@forksofpower
Created February 14, 2024 04:12
Show Gist options
  • Save forksofpower/c18910c39d793acf7913e81174f9f5c9 to your computer and use it in GitHub Desktop.
Save forksofpower/c18910c39d793acf7913e81174f9f5c9 to your computer and use it in GitHub Desktop.
Sphere animation from BritPop.online
import "./form";
import * as THREE from "three";
const image = new URL("britpop 2.webp", import.meta.url);
const canvas = document.querySelector("canvas")!;
const emailSignup = document.querySelector<HTMLElement>(".email-signup")!;
let scene: THREE.Scene,
camera: THREE.PerspectiveCamera,
renderer: THREE.WebGLRenderer,
sphere: THREE.Mesh;
const manager = new THREE.LoadingManager();
// manager.onLoad = function () {
// // console.log("All resources loaded");
// canvas.style.opacity = "1";
// };
let isDragging = false;
let previousMousePosition = {
x: 0,
y: 0,
};
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(
120,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(0, 0, 4.99);
renderer = new THREE.WebGLRenderer({ antialias: true, canvas });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor("#f4ded4");
// Texture loading with manager
const textureLoader = new THREE.TextureLoader(manager);
textureLoader.load(image.toString(), function (tex) {
tex.wrapS = THREE.ClampToEdgeWrapping;
tex.wrapT = THREE.ClampToEdgeWrapping;
tex.colorSpace = THREE.DisplayP3ColorSpace;
// tex.needsUpdate = true;
const geometry = new THREE.SphereGeometry(5, 120, 120); // Adjusted segment count to 32 as previously discussed
const material = new THREE.MeshBasicMaterial({
map: tex,
side: THREE.DoubleSide,
});
sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
canvas.style.opacity = "1";
});
document.addEventListener("mousedown", startDragging);
document.addEventListener("mousemove", drag);
document.addEventListener("mouseup", stopDragging);
document.addEventListener("contextmenu", (e) => {
stopDragging(e, false);
});
// Add touch event listeners
document.addEventListener(
"touchstart",
(event) => startDragging(event.touches[0]),
false
);
document.addEventListener(
"touchmove",
(event) => drag(event.touches[0]),
false
);
document.addEventListener("touchend", stopDragging, false);
emailSignup.addEventListener("mousedown", ignore);
emailSignup.addEventListener("mouseup", (e) => {
e.stopPropagation();
stopDragging(e, false);
});
emailSignup.addEventListener("touchstart", ignore);
emailSignup.addEventListener("touchend", (e) => {
e.stopPropagation();
stopDragging(e, false);
});
window.addEventListener("resize", onWindowResize, false);
requestAnimationFrame(animate);
}
const last_ω = { x: 0, y: 0 };
const ω = { x: 0, y: 0 };
const target_θ = { x: 0, y: 0 };
const μ = 1 - 0.998; // Adjust for desired "slowing down" effect
function ignore(event: Event) {
event.stopPropagation();
}
function startDragging(event: Touch | MouseEvent) {
// console.log("Start Dragging");
isDragging = true;
[previousMousePosition.x, previousMousePosition.y] = [
event.clientX,
event.clientY,
];
target_θ.x = sphere.rotation.x;
target_θ.y = sphere.rotation.y;
[last_ω.x, last_ω.y] = [0, 0];
}
function drag(event: Touch | MouseEvent) {
if (isDragging) {
const [currentX, currentY] = [event.clientX, event.clientY];
// console.log("Drag Speed:", lastRotationSpeed.x, lastRotationSpeed.y);
const deltaMove = {
y: previousMousePosition.x - currentX,
x: previousMousePosition.y - currentY,
};
// Calculate rotation speed based on delta movement
last_ω.x = (deltaMove.x / window.innerWidth) * Math.PI * 2;
last_ω.y = (deltaMove.y / window.innerHeight) * Math.PI * 2;
target_θ.x += last_ω.x;
target_θ.y += last_ω.y;
previousMousePosition = { x: currentX, y: currentY };
}
}
function stopDragging(_event: Event, adjustVelocity = true) {
isDragging = false;
if (adjustVelocity) {
// Transfer the last rotation speed to the momentum
target_θ.x += last_ω.x * 0.1;
target_θ.y += last_ω.y * 0.1;
// console.log("Momentum Set:", angularVelocity.x, angularVelocity.y);
}
}
let lastTime: DOMHighResTimeStamp = 0;
const dragAmount = 0.3;
function animate(time: DOMHighResTimeStamp) {
requestAnimationFrame(animate);
const δt = (time - lastTime) / 10;
// console.log(δt2);
// const δt = 1;
// console.log("Applying Momentum:", rotationMomentum.x, rotationMomentum.y);
// Apply constant pitch rotation
// sphere.rotation.x += angularVelocity.x * 0.01;
if (!isDragging) {
if (sphere) {
ω.x += (0.01 - ω.x) * 0.002 * δt;
}
// Apply friction to slow down momentum over time
ω.x *= 1 - μ * δt;
ω.y *= 1 - μ * δt;
// console.log("After Friction:", rotationMomentum.x, rotationMomentum.y);
// Optional: stop rotation if momentum is very low
// if (
// Math.abs(rotationMomentum.x) < 0.00001 &&
// Math.abs(rotationMomentum.y) < 0.00001
// ) {
// rotationMomentum.x = 0;
// rotationMomentum.y = 0;
// }
} else {
ω.x = (target_θ.x - sphere.rotation.x) * dragAmount * δt;
ω.y = (target_θ.y - sphere.rotation.y) * dragAmount * δt;
}
if (sphere) {
sphere.rotation.x += ω.x * δt;
sphere.rotation.y += ω.y * δt;
}
renderer.render(scene, camera);
lastTime = time;
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
}
init();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment