Skip to content

Instantly share code, notes, and snippets.

@seangeleno
Created December 9, 2024 15:45
Show Gist options
  • Save seangeleno/ec1176230cc870b8e3f083bbdf256b17 to your computer and use it in GitHub Desktop.
Save seangeleno/ec1176230cc870b8e3f083bbdf256b17 to your computer and use it in GitHub Desktop.
Trippy polygons
<div id="demos">
<span class="demo" data-id="0">Demo 1</span>
<span class="demo" data-id="1">Demo 2</span>
<span class="demo" data-id="2">Demo 3</span>
<span class="demo" data-id="3">Demo 4</span>
<span class="demo" data-id="4">Demo 5</span>
</div>
let scene, camera, cameraCtrl, renderer;
let width, height, cx, cy;
let objects = [];
const defaultConf = {
white: false,
nbVertexes: 5,
nbObjects: 25,
objectMinRadius: 1,
objectRadiusCoef: 2,
objectThickness: 0.5,
objectDepth: 0.5,
rotationX: 0,
rotationY: 360,
rotationZ: 360,
animationDuration: 9,
animationDelay: 0.1,
cameraZ: 75
};
let demos = [
{ ...defaultConf, white: false, nbVertexes: 7, objectRadiusCoef: 4, objectThickness: 1, rotationX:360, rotationY:0, rotationZ:0, animationDuration: 5 },
{ ...defaultConf, white: true, nbObjects: 50, objectRadiusCoef: 10, objectThickness: 0.2, objectDepth: 1, animationDuration: 11 },
{ ...defaultConf, objectRadiusCoef: 3, objectThickness: 1, objectDepth: 0.2, rotationY:180 },
{ ...defaultConf, white: true, nbVertexes: 7, nbObjects: 70, objectRadiusCoef: 3, objectThickness: 0.2, objectDepth:0.2, rotationX:0, rotationY:0, rotationZ:360, animationDuration: 7 },
{ ...defaultConf, white: false, nbVertexes: 4, objectRadiusCoef: 10, objectThickness: 2, objectDepth: 0.5, rotationX:0, rotationY:360, rotationZ:0, animationDuration: 7 },
];
let conf = { ...demos[0] };
function init() {
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
initScene();
initGui();
initEventHandlers();
animate();
};
function initGui() {
const gui = new dat.GUI();
gui.add(conf, 'white').onChange(initScene).listen();
gui.add(conf, 'nbVertexes', 3, 12, 1).onChange(initScene).listen();
gui.add(conf, 'nbObjects', 10, 100, 1).onChange(initScene).listen();
gui.add(conf, 'objectRadiusCoef', 1, 20, 0.2).onChange(initScene).listen();
gui.add(conf, 'objectThickness', 0.2, 5, 0.2).onChange(initScene).listen();
gui.add(conf, 'objectDepth', 0.2, 5, 0.2).onChange(initScene).listen();
gui.add(conf, 'rotationX', 0, 720, 30).onChange(initScene).listen();
gui.add(conf, 'rotationY', 0, 720, 30).onChange(initScene).listen();
gui.add(conf, 'rotationZ', 0, 720, 30).onChange(initScene).listen();
gui.add(conf, 'animationDuration', 2, 20, 1).onChange(initScene).listen();
gui.add(conf, 'animationDelay', 0.1, 2, 0.1).onChange(initScene).listen();
gui.close();
}
function initEventHandlers() {
onWindowResize();
window.addEventListener('resize', onWindowResize, false);
document.getElementById('demos').addEventListener('click', function (evt) {
if (evt.target.className === 'demo') {
let id = evt.target.getAttribute('data-id');
for(let propertyName in demos[id]) {
console.log(propertyName);
conf[propertyName] = demos[id][propertyName];
}
initScene();
}
});
}
function initScene() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = conf.cameraZ;
cameraCtrl = new THREE.OrbitControls(camera);
if (conf.white) scene.background = new THREE.Color(0xffffff);
else initLights();
initObjects();
}
function initLights() {
const lightIntensity = 0.5;
const lightDistance = 200;
scene.add(new THREE.AmbientLight(0xeeeeee));
var light;
light = new THREE.PointLight(randomColor(), lightIntensity, lightDistance);
light.position.set(0, 100, 0);
scene.add(light);
light = new THREE.PointLight(randomColor(), lightIntensity, lightDistance);
light.position.set(0, -100, 0);
scene.add(light);
light = new THREE.PointLight(randomColor(), lightIntensity, lightDistance);
light.position.set(100, 0, 0);
scene.add(light);
light = new THREE.PointLight(randomColor(), lightIntensity, lightDistance);
light.position.set(-100, 0, 0);
scene.add(light);
light = new THREE.PointLight(randomColor(), lightIntensity, lightDistance);
light.position.set(0, 0, 100);
scene.add(light);
light = new THREE.PointLight(randomColor(), lightIntensity, lightDistance);
light.position.set(0, 0, -100);
scene.add(light);
}
function initObjects() {
let geo, mat, mesh;
if (!conf.white) mat = new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 0.4, metalness: 0.9 });
for (let i = 0; i < conf.nbObjects; i++) {
geo = polygonGeometry(conf.nbVertexes, 0, 0, conf.objectMinRadius + conf.objectRadiusCoef * i, 0);
if (conf.white) mat = new THREE.MeshBasicMaterial({ color: randomColor({ luminosity: 'light' }) });
mesh = new THREE.Mesh(geo, mat);
mesh.position.z = -conf.objectDepth * i;
TweenMax.to(mesh.rotation, conf.animationDuration, {
x: conf.rotationX * Math.PI / 180,
y: conf.rotationY * Math.PI / 180,
z: conf.rotationZ * Math.PI / 180,
ease: Power1.easeInOut,
repeat: -1,
yoyo: true,
delay: i * conf.animationDelay
});
scene.add(mesh);
}
}
function animate() {
requestAnimationFrame(animate);
cameraCtrl.update();
renderer.render(scene, camera);
};
function onWindowResize() {
width = window.innerWidth; cx = width / 2;
height = window.innerHeight; cy = height / 2;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
}
function polygonGeometry(n, x, y, s, r) {
let points = ppoints(n, x, y, s + conf.objectThickness, r);
let shape = new THREE.Shape();
points.forEach((p, i) => {
if (i === 0) shape.moveTo(p[0], p[1]);
else shape.lineTo(p[0], p[1]);
});
shape.lineTo(points[0][0], points[0][1]);
points = ppoints(n, x, y, s, r);
let hole = new THREE.Path();
points.forEach((p, i) => {
if (i === 0) hole.moveTo(p[0], p[1]);
else hole.lineTo(p[0], p[1]);
});
hole.lineTo(points[0][0], points[0][1]);
shape.holes.push(hole);
let extrudeSettings = { steps: 1, depth: conf.objectDepth, bevelEnabled: false };
let geometry = new THREE.ExtrudeBufferGeometry(shape, extrudeSettings);
geometry.translate(0, 0, -conf.objectDepth / 2);
return geometry;
}
function ppoints(n, x, y, s, r) {
const dt = 2 * Math.PI / n;
let points = [], t, px, py;
for (let i = 0; i < n; i++) {
t = Math.PI / 2 + r + i * dt;
px = x + Math.cos(t) * s;
py = y + Math.sin(t) * s;
points.push([px, py]);
}
return points;
}
function rnd(max, negative) {
return negative ? Math.random() * 2 * max - max : Math.random() * max;
}
init();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/100/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.5/dat.gui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/randomcolor/0.5.2/randomColor.min.js"></script>
<script src="https://klevron.github.io/codepen/three.js/OrbitControls.js"></script>
html, body {
margin: 0;
width: 100%;
height: 100%;
font-family: 'Poppins', sans-serif;
}
canvas {
position: fixed;
z-index: -1;
width: 100%;
height: 100%;
}
#demos {
position: absolute;
z-index: 0;
width: 100%;
display: flex;
justify-content: center;
background: rgba(0, 0, 0, 0.5);
color: #fff;
}
#demos span {
margin: 0 2rem;
cursor: pointer;
}
<link href="https://fonts.googleapis.com/css?family=Poppins" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment