Created
December 27, 2020 13:31
-
-
Save akella/0659fccd1946d83faf37f15b65d1c22d to your computer and use it in GitHub Desktop.
christmas tree
This file contains 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
// 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; |
This file contains 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
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