Skip to content

Instantly share code, notes, and snippets.

@akella
Created December 27, 2020 13:31
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save akella/0659fccd1946d83faf37f15b65d1c22d to your computer and use it in GitHub Desktop.
Save akella/0659fccd1946d83faf37f15b65d1c22d to your computer and use it in GitHub Desktop.
christmas tree
// from https://discourse.threejs.org/t/profiledcontourgeometry/2330
// Author: Prisoner849
function ProfiledContourGeometry(profileShape, contour, contourClosed, openEnded) {
contourClosed = contourClosed !== undefined ? contourClosed : true;
openEnded = openEnded !== undefined ? openEnded : false;
openEnded = contourClosed === true ? false : openEnded;
let profileGeometry = new THREE.ShapeBufferGeometry(profileShape);
let flipProfileGeometry = flipShapeGeometry(profileGeometry);
profileGeometry.rotateX(Math.PI * 0.5);
let profile = profileGeometry.attributes.position;
let addEnds = openEnded === false ? 2 : 0;
let profilePoints = new Float32Array(profile.count * (contour.length + addEnds) * 3);
let endProfiles = [];
for (let i = 0; i < contour.length; i++) {
let v1 = new THREE.Vector2().subVectors(contour[i - 1 < 0 ? contour.length - 1 : i - 1], contour[i]);
let v2 = new THREE.Vector2().subVectors(contour[i + 1 == contour.length ? 0 : i + 1], contour[i]);
let angle = v2.angle() - v1.angle();
let halfAngle = angle * 0.5;
let hA = halfAngle;
let tA = v2.angle() + Math.PI * 0.5;
if (!contourClosed){
if (i == 0 || i == contour.length - 1) {hA = Math.PI * 0.5;}
if (i == contour.length - 1) {tA = v1.angle() - Math.PI * 0.5;}
}
let shift = Math.tan(hA - Math.PI * 0.5);
let shiftMatrix = new THREE.Matrix4().set(
1, 0, 0, 0,
-shift, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
let tempAngle = tA;
let rotationMatrix = new THREE.Matrix4().set(
Math.cos(tempAngle), -Math.sin(tempAngle), 0, 0,
Math.sin(tempAngle), Math.cos(tempAngle), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
let translationMatrix = new THREE.Matrix4().set(
1, 0, 0, contour[i].x,
0, 1, 0, contour[i].y,
0, 0, 1, 0,
0, 0, 0, 1
);
let cloneProfile = profile.clone();
cloneProfile.applyMatrix4(shiftMatrix);
cloneProfile.applyMatrix4(rotationMatrix);
cloneProfile.applyMatrix4(translationMatrix);
profilePoints.set(cloneProfile.array, cloneProfile.count * i * 3);
if (openEnded === false && (i === 0 || i === contour.length - 1)){
endProfiles.push(cloneProfile);
}
}
endProfiles.forEach((ep, idx) => {
profilePoints.set(ep.array, ep.count * (contour.length + idx) * 3)
});
let fullProfileGeometry = new THREE.BufferGeometry();
fullProfileGeometry.setAttribute("position", new THREE.BufferAttribute(profilePoints, 3));
let index = [];
let lastCorner = contourClosed == false ? contour.length - 1: contour.length;
for (let i = 0; i < lastCorner; i++) {
for (let j = 0; j < profile.count; j++) {
let currCorner = i;
let nextCorner = i + 1 == contour.length ? 0 : i + 1;
let currPoint = j;
let nextPoint = j + 1 == profile.count ? 0 : j + 1;
let a = nextPoint + profile.count * currCorner;
let b = currPoint + profile.count * currCorner;
let c = currPoint + profile.count * nextCorner;
let d = nextPoint + profile.count * nextCorner;
index.push(a, b, d);
index.push(b, c, d);
}
}
if (openEnded === false){
// add indices from profile geometries
flipProfileGeometry.index.array.forEach(i => {index.push(i + profile.count * (contour.length))});
profileGeometry.index.array.forEach(i =>{index.push(i + profile.count * (contour.length + 1))});
}
fullProfileGeometry.setIndex(index);
fullProfileGeometry.computeVertexNormals();
return fullProfileGeometry;
}
function flipShapeGeometry(shapeGeometry) {
let flipGeom = shapeGeometry.clone();
for (let i = 0; i < flipGeom.attributes.position.count; i++) {
flipGeom.attributes.position.array[i * 3] *= -1;
}
flipGeom.attributes.position.needsUpdate = true;
var index = flipGeom.index.array;
for (let i = 0; i < index.length; i += 3) {
let v2 = index[i + 1];
let tmp = v2;
let v3 = index[i + 2];
index[i + 1] = index[i + 2];
index[i + 2] = tmp;
}
flipGeom.computeVertexNormals();
return flipGeom;
}
module.exports = ProfiledContourGeometry;
const canvasSketch = require('canvas-sketch');
let random = require("canvas-sketch-util/random");
random = random.createRandom(6)
// Ensure ThreeJS is in global scope for the 'examples/'
global.THREE = require('three');
import ProfiledContourGeometry from './ProfiledContourGeometry'
var colors = require('nice-color-palettes');
let ind = Math.floor(Math.random()*100)
let col = colors[ind];
col = [ '#156a3a','#156a3a','#156a3a','#156a3a','#156a3a','#156a3a','#156a3a','#f7b229','#ea4730','#bb2528']
let col1 = ["#bb2528",'#f7b229','#ea4730','#bb2528']
// 72
// console.log(random.pick(col));
// Include any additional ThreeJS examples below
require('three/examples/js/controls/OrbitControls');
const settings = {
// Make the loop animated
animate: true,
duration: 5,
// Get a WebGL canvas rather than 2D
context: 'webgl',
dimensions: [1024,1024],
// Turn on MSAA
attributes: { antialias: true },
fps: 24
};
const sketch = ({ context }) => {
// Create a renderer
const renderer = new THREE.WebGLRenderer({
context
});
// WebGL background color
renderer.setClearColor('#000', 1);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// Setup a camera
const camera = new THREE.PerspectiveCamera(45, 1, 0.01, 10000);
camera.position.set(0, -2*7, -0.5*7);
camera.lookAt(new THREE.Vector3(0,0,30));
// Setup camera controller
const controls = new THREE.OrbitControls(camera, context.canvas);
// Setup your scene
const scene = new THREE.Scene();
let cubes = new THREE.Group();
scene.add(cubes);
let balls = []
let s = 0.05;
let koef = 1.24;
let shift = 75;
let loop = 30;
let maxnumber = 120;
let length = 1.1*0.1, width = 10*0.1;
let shape = new THREE.Shape();
shape.moveTo( 0,0 );
shape.lineTo( 0, width );
shape.lineTo( length, width );
shape.lineTo( length, 0 );
shape.lineTo( 0, 0 );
let m = new THREE.MeshLambertMaterial( {
roughness:0.6,
metalness: 0.5,
wireframe:false,
color:0xffffff,
flatShading: true,
});
let rands = []
let cols1 = []
let cols = []
for (var i = 0; i < 450; i++) {
rands.push(random.value()-0.5);
cols.push(new THREE.Color(random.pick(col)));
cols1.push(new THREE.Color(random.pick(col1)));
}
function getMesh(level,rotateme){
let detail = 450
let steps = new Array(detail).fill().map((el,i)=>{
return new THREE.Vector2(
Math.sin(2*Math.PI*i/detail),
Math.cos(2*Math.PI*i/detail)
)
}
)
let CG = new ProfiledContourGeometry( shape, steps, true, true );
let mesh = new THREE.Mesh(CG, m.clone());
let ball = new THREE.Mesh(
new THREE.SphereBufferGeometry(0.2,30,30),
new THREE.MeshLambertMaterial({color: cols1[i]})
)
mesh.add(ball);
let angle = 2*Math.PI*rands[level%loop]
ball.position.x = 1.6*Math.sin(angle);
ball.position.y = 1.6*Math.cos(angle);
ball.position.z = 0.3;
mesh.material.color = cols[level%loop];
ball.material.color = cols1[level%loop];
mesh.userData.axis = new THREE.Vector3(rands[level%loop],rands[loop+level%loop]).normalize()
mesh.userData.level = level;
return mesh;
}
for (let i = 0; i < maxnumber; i++) {
let me = getMesh(i);
let scale = 1*1.03**(i-shift-50);
me.position.z = i/2;
cubes.add(me);
}
scene.add(new THREE.AmbientLight('#cccccc'));
// Specify an ambient/unlit colour
var light = new THREE.DirectionalLight( 0xffffff, 1 );
light.position.x = 50;
light.position.y = 50;
light.position.z = 50;
scene.add( light );
camera.updateProjectionMatrix();
// draw each frame
return {
// Handle resize events here
resize ({ pixelRatio, viewportWidth, viewportHeight }) {
renderer.setPixelRatio(pixelRatio);
renderer.setSize(viewportWidth, viewportHeight);
camera.aspect = viewportWidth / viewportHeight;
camera.updateProjectionMatrix();
},
// Update & render your scene here
render ({ time,playhead,totalFrames,...args }) {
playhead /=4;
cubes.children.forEach((c,i)=>{
let progress = (-playhead + 3 + i/maxnumber)%1
c.position.z = -progress*maxnumber/10
let scale = 1*1.02**(maxnumber -5*progress*maxnumber);
c.scale.set(scale,scale,scale)
})
controls.update();
renderer.render(scene, camera);
},
// Dispose of events & renderer for cleaner hot-reloading
unload () {
controls.dispose();
renderer.dispose();
}
};
};
canvasSketch(sketch, settings);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment