';
return;
}
- // Initialize the scene
+ // init scene
const container = document.getElementById('icosahedron-container');
const containerWidth = container.clientWidth;
const containerHeight = container.clientHeight;
- // Setup renderer
+ // setup renderer
const renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setSize(containerWidth, containerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
- renderer.setClearColor(0x000000, 0); // Transparent frontground
+ renderer.setClearColor(0x000000, 0); // transparent
container.appendChild(renderer.domElement);
- // Setup scene
+ // setup scene and camera
const scene = new THREE.Scene();
-
- // Setup camera
const camera = new THREE.PerspectiveCamera(26, containerWidth / containerHeight, 0.1, 100);
camera.position.z = 4;
- // Create icosahedron with manually defined vertices
+ // icosahedron with manually defined vertices
function createIcosahedron(radius) {
- // Golden ratio for icosahedron vertices
+ // golden ratio
const t = (1 + Math.sqrt(5)) / 2;
-
- // Normalize radius
+ // normalize radius
const normRadius = radius / Math.sqrt(1 + t * t);
- // Create vertices
const vertices = [
[-1, t, 0],
[1, t, 0],
@@ -191,7 +181,7 @@ window.onload = function() {
[-t, 0, 1]
].map(v => new THREE.Vector3(v[0] * normRadius, v[1] * normRadius, v[2] * normRadius));
- // Define edges (pairs of vertex indices)
+ // edges (pairs of vertex indices)
const edges = [
[0, 11],
[0, 5],
@@ -221,8 +211,7 @@ window.onload = function() {
[6, 10],
[7, 8],
[7, 10],
- [8, 9], /*[8, 10],*/
- /*[9, 11],*/
+ [8, 9],
[10, 11]
];
@@ -232,7 +221,7 @@ window.onload = function() {
};
}
- // Convert vertex indices to actual vertices and create a line
+ // convert vertex indices to actual vertices and create a line
function createLine(icosa, edgeIndex, material) {
const startIndex = icosa.edges[edgeIndex][0];
const endIndex = icosa.edges[edgeIndex][1];
@@ -248,49 +237,44 @@ window.onload = function() {
return new THREE.Line(geometry, material);
}
- // Function to create the dual line rendering (thin back lines, thick front lines)
+ // create thin back lines, thick front lines
function createDualLineRendering(radius) {
const group = new THREE.Group();
const icosa = createIcosahedron(radius);
- // Create materials
const backMaterial = new THREE.MeshBasicMaterial({
- color: 0x63a8b8, // green for back lines
- depthTest: false, // Don't test depth for back lines
+ color: 0x63a8b8,
+ depthTest: false, // don't test depth for back lines
transparent: true,
opacity: 0.4,
side: THREE.DoubleSide
});
const frontMaterial = new THREE.MeshBasicMaterial({
- color: 0xffffff, // white for front lines
+ color: 0xffffff,
+ depthTest: true, // depth test for front lines
transparent: true,
- depthTest: true, // Use depth test for front lines
side: THREE.DoubleSide
});
- // For each edge, create:
- // 1. A thin cylindrical tube with back material that ignores depth
- // 2. A cylindrical tube with front material that uses depth testing
- const backRadius = 0.025; // thin for back lines
- const frontRadius = 0.035; // thick for front lines
+ // cylinders for each edge
+ const backRadius = 0.025;
+ const frontRadius = 0.035;
icosa.edges.forEach((edge, index) => {
const start = icosa.vertices[edge[0]];
const end = icosa.vertices[edge[1]];
- // Create back line (thick)
const backLine = createCylinderBetweenPoints(start, end, backRadius, 1, backMaterial);
- backLine.renderOrder = 1; // Render after front lines
+ backLine.renderOrder = 1;
group.add(backLine);
- // Create front line (thin)
const frontLine = createCylinderBetweenPoints(start, end, frontRadius, 0.95, frontMaterial);
- frontLine.renderOrder = 3; // Render before back lines
+ frontLine.renderOrder = 3;
group.add(frontLine);
});
- // Create faces for depth testing (invisible)
+ // invisible face material for depth testing
const faceMaterial = new THREE.MeshBasicMaterial({
color: 0xffffff,
transparent: true,
@@ -299,7 +283,7 @@ window.onload = function() {
side: THREE.DoubleSide
});
- // Create faces for internal icosahedron
+ // internal icosahedra material
const internalMaterial = new THREE.MeshBasicMaterial({
color: 0x63a8b8,
depthTest: false,
@@ -308,7 +292,7 @@ window.onload = function() {
side: THREE.DoubleSide
});
- // Define faces of icosahedron (each is a triangle of vertex indices)
+ // triangles of vertex indices
const faces = [
[0, 11, 5],
[0, 5, 1],
@@ -332,7 +316,7 @@ window.onload = function() {
[9, 8, 1]
];
- // Create invisible faces for depth testing
+ // create depth testing and internal icosahedra
faces.forEach(face => {
const geometry = new THREE.BufferGeometry();
const positions = new Float32Array([
@@ -345,50 +329,46 @@ window.onload = function() {
const faceMesh = new THREE.Mesh(geometry, faceMaterial);
faceMesh.scale.set(0.975, 0.975, 0.975);
- faceMesh.renderOrder = 0; // Render first for depth buffer
+ faceMesh.renderOrder = 0;
group.add(faceMesh);
+ // stack internal icosahedra for volumetric effect
const internalMesh1 = new THREE.Mesh(geometry, internalMaterial);
const internalMesh2 = new THREE.Mesh(geometry, internalMaterial);
const internalMesh3 = new THREE.Mesh(geometry, internalMaterial);
const internalMesh4 = new THREE.Mesh(geometry, internalMaterial);
const internalMesh5 = new THREE.Mesh(geometry, internalMaterial);
internalMesh1.scale.set(0.85, 0.85, 0.85);
- internalMesh1.renderOrder = 1; // Render between front and back
+ internalMesh1.renderOrder = 1;
group.add(internalMesh1);
internalMesh2.scale.set(0.65, 0.65, 0.65);
- internalMesh2.renderOrder = 1; // Render between front and back
+ internalMesh2.renderOrder = 1;
group.add(internalMesh2);
internalMesh3.scale.set(0.5, 0.5, 0.5);
- internalMesh3.renderOrder = 1; // Render between front and back
+ internalMesh3.renderOrder = 1;
group.add(internalMesh3);
internalMesh4.scale.set(0.4, 0.4, 0.4);
- internalMesh4.renderOrder = 1; // Render between front and back
+ internalMesh4.renderOrder = 1;
group.add(internalMesh4);
internalMesh5.scale.set(0.3, 0.3, 0.3);
- internalMesh5.renderOrder = 1; // Render between front and back
+ internalMesh5.renderOrder = 1;
group.add(internalMesh5);
});
return group;
}
- // Function to create a cylinder between two points
function createCylinderBetweenPoints(pointX, pointY, radius, lengthmultiplier, material) {
- // Direction from pointX to pointY
const direction = new THREE.Vector3().subVectors(pointY, pointX);
const length = direction.length();
-
- // Create cylinder
const geometry = new THREE.CylinderGeometry(radius, radius, length * lengthmultiplier, 4, 1);
- // By default, cylinder is along Y-axis, so rotate it
+ // default cylinder is along y-axis, rotate it
geometry.rotateX(Math.PI / 2);
- // Create mesh
const cylinder = new THREE.Mesh(geometry, material);
- // Position and orient cylinder
+ // position and orient cylinder
const midpoint = new THREE.Vector3().addVectors(pointX, pointY).multiplyScalar(0.5);
cylinder.position.copy(midpoint);
cylinder.lookAt(pointY);
@@ -396,11 +376,11 @@ window.onload = function() {
return cylinder;
}
- // Create our icosahedron
+ // create icosahedron
const icosahedronGroup = createDualLineRendering(0.85);
scene.add(icosahedronGroup);
- // Animation state
+ // animation state
let animating = true;
let lastFrameTime = 0;
@@ -408,7 +388,6 @@ window.onload = function() {
const animMultiplier = 30 / targetFPS;
const frameDuration = 1000 / targetFPS;
- // Animation function
function animate(now) {
requestAnimationFrame(animate);
@@ -417,7 +396,6 @@ window.onload = function() {
lastFrameTime = now;
- // Rotate if animation is enabled
if (animating) {
icosahedronGroup.rotation.x -= 0.002 * animMultiplier;
icosahedronGroup.rotation.y += 0.004 * animMultiplier;
@@ -427,12 +405,9 @@ window.onload = function() {
renderer.render(scene, camera);
}
- // Start animation
animate();
- // Handle window resize
window.addEventListener('resize', function() {
- // Only update if container dimensions change
const newWidth = container.clientWidth;
const newHeight = container.clientHeight;
@@ -443,5 +418,5 @@ window.onload = function() {
}
});
- console.log('Icosahedron wireframe created successfully');
+ // console.log('icosahedron wireframe created successfully');
};
diff --git a/public_html/index.html b/public_html/index.html
index 2ee9cc6..aa866d1 100644
--- a/public_html/index.html
+++ b/public_html/index.html
@@ -12,6 +12,8 @@
+
+
@@ -141,7 +143,7 @@
-
+
a specific animation style I had in mind for my music persona lastfuture required objects with transparent flat faces, integer snapping, controlled image noise and visual artefacts. to solve this I wrote the tiny 3d engine “3d simple” that can create this animation style then render it out as a gif.