Last active
September 4, 2020 12:38
-
-
Save lislis/5065d42755883c76cfbd64f1b82b4f64 to your computer and use it in GitHub Desktop.
Natural Machines
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 DEG_TO_RAD = Math.PI/180; | |
//THREE js variables | |
const scene = new THREE.Scene(); | |
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1500); | |
const renderer = new THREE.WebGLRenderer({antialias:true}); | |
camera.translateY(200); | |
camera.lookAt(new THREE.Vector3(0,0,0)); | |
const cachedMatrix4 = new THREE.Matrix4(); | |
const cachedQuat = new THREE.Quaternion(); | |
var exporter = new THREE.OBJExporter(); | |
// The Tree | |
const tree = new THREE.Group(); | |
// Trunk variables | |
const material = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 5, linecap: 'square' } ); | |
const geometry = new THREE.Geometry(); | |
// Flowers variables | |
const flowersGeometry = new THREE.Geometry(); | |
let flowerGeometry = new THREE.DodecahedronGeometry(5); | |
const flowerMaterial = new THREE.MeshStandardMaterial({color:0xaa2020, metalness: 1, emissive: 0xff2020}); | |
// Leafs variable | |
const leavesGeometry = new THREE.Geometry(); | |
const createLeafGeometry = () => { | |
const points = []; | |
for ( let i = 0; i < 10; i ++ ) { | |
points.push( new THREE.Vector2( Math.sin( i * 0.2 ) * 10 + 5, ( i - 5 ) * 2 ) ); | |
} | |
const geom = new THREE.LatheGeometry( points, 5, 0, 0.2 ); | |
geom.computeBoundingBox(); | |
const bb = geom.boundingBox; | |
const z = bb.max.z - bb.min.z; | |
const y = bb.max.y - bb.min.y; | |
geom.applyMatrix( cachedMatrix4.makeTranslation(0, y/2.0, -z/2.) ); | |
return geom; | |
} | |
const leafGeometry = createLeafGeometry(); | |
const leafMaterial = new THREE.MeshStandardMaterial({color:0x50DD30, metalness: 1}); | |
//L-Systems rules variables | |
const angle = 35; | |
const axiom = "F"; | |
let sentence = axiom; | |
const len = 10; | |
const limit = 4; | |
const rules = []; | |
rules[0] = { | |
// TRY new rules | |
// a: "F", | |
// b: "F[+F]F[-F]F" | |
// a: "F", | |
// b: "F[+F]F[-F][F]" | |
a: "F", | |
b: "FF+[+F-F-F]-[-F+F+F]" | |
} | |
// Let's go! | |
const init = () => { | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
renderer.setClearColor(0x49225a, 1); | |
document.body.style.margin =0; | |
document.body.appendChild(renderer.domElement); | |
camera.position.z = 80; | |
controls = new THREE.OrbitControls( camera, renderer.domElement ); | |
const light = new THREE.PointLight( 0xffffff, 1, 0 ); | |
light.position.set( 100, 200, 0); | |
const light2 = new THREE.PointLight( 0xffffff, 1, 100 ); | |
light2.position.set(0, 100, -200); | |
scene.add( light2 ); | |
const directionalLight = new THREE.DirectionalLight( 0xffffff ); | |
directionalLight.position.set(0, 0.5, -0.5); | |
directionalLight.position.normalize(); | |
scene.add( directionalLight ); | |
// Have a look at the axis | |
let axisHelper = new THREE.AxesHelper( 50 ); | |
scene.add( axisHelper ); | |
window.addEventListener('resize', function() { | |
let WIDTH = window.innerWidth, | |
HEIGHT = window.innerHeight; | |
renderer.setSize(WIDTH, HEIGHT); | |
camera.aspect = WIDTH / HEIGHT; | |
camera.updateProjectionMatrix(); | |
}); | |
createTree(); | |
render(); | |
}; | |
const createTree = () => { | |
const branches = []; | |
const sentence = generate(rules); | |
createBranchesFromSentence(sentence, branches, len); | |
for (const b of branches) { | |
addBranch(geometry, b.start.position, b.end.position); | |
//TRY Add organs | |
if (b.end.position.y > -120 && Math.random() > 0.8) { | |
addFlower(b, flowersGeometry); | |
} | |
//if (Math.random() > 0.4) { | |
// addLeaf(b, leavesGeometry); | |
//} | |
} | |
let flower = new THREE.Mesh(flowersGeometry, flowerMaterial); | |
tree.add(flower) | |
const leaves = new THREE.Mesh(leavesGeometry, leafMaterial); | |
tree.add(leaves); | |
const trunk = new THREE.LineSegments( geometry, material ); | |
tree.add(trunk); | |
scene.add(tree); | |
} | |
const addBranch = (geom,v1, v2) => { | |
geom.vertices.push(new THREE.Vector3( v1.x, v1.y, v1.z) ); | |
geom.vertices.push(new THREE.Vector3( v2.x, v2.y, v2.z) ); | |
} | |
const addFlower = (branch, flowersGeometry) => { | |
let flower = flowerGeometry.clone(); | |
flower.applyMatrix(cachedMatrix4.makeTranslation( | |
branch.end.position.x, | |
branch.end.position.y, | |
branch.end.position.z)); | |
flowersGeometry.merge(flower); | |
} | |
const addLeaf = (branch, leavesGeometry) => { | |
const leaf = leafGeometry.clone(); | |
branch.end.getWorldQuaternion(cachedQuat); | |
cachedMatrix4.makeRotationFromQuaternion(cachedQuat); | |
leaf.applyMatrix(cachedMatrix4); | |
cachedMatrix4.makeTranslation( | |
branch.end.position.x, | |
branch.end.position.y, | |
branch.end.position.z); | |
leaf.applyMatrix(cachedMatrix4); | |
leavesGeometry.merge(leaf); | |
} | |
const generate = (rules) => { | |
for(let l = 0; l < limit; l++){ | |
let nextSentence = ""; | |
for (let i = 0; i < sentence.length; i++) { | |
const current = sentence.charAt(i); | |
let found = false; | |
for (let j = 0; j < rules.length; j++) { | |
if (current == rules[j].a) { | |
found = true; | |
nextSentence += rules[j].b; | |
break; | |
} | |
} | |
if (!found) { | |
nextSentence += current; | |
} | |
} | |
sentence = nextSentence; | |
} | |
return sentence; | |
} | |
const createBranchesFromSentence = (sentence, branches, len) => { | |
const turtle = new THREE.Object3D(); | |
turtle.position.set(0,-200,0); | |
const bookmark = []; | |
for (let i = 0; i < sentence.length; i++) { | |
const current = sentence.charAt(i); | |
let addBranch = false; | |
if (current == "F") { | |
addBranch = true; | |
} else if (current == "+") { | |
turtle.rotateZ(angle * DEG_TO_RAD); | |
} else if (current == "-") { | |
turtle.rotateZ(-angle * DEG_TO_RAD); | |
} else if (current == "[") { | |
bookmark.push(turtle.clone()); | |
} else if (current == "]") { | |
turtle.copy(bookmark.pop(),false); | |
} | |
if (addBranch) { | |
// TRY add random rotation on the y axis | |
turtle.rotateY(Math.random()* Math.PI/6); | |
let end = turtle.clone().translateY(len); | |
let branch = { "start": turtle.clone(), "end": end}; | |
turtle.copy(end); | |
branches.push(branch); | |
} | |
} | |
} | |
const render = () => { | |
// TRY, addo some rotation | |
tree.rotateY(0.001); | |
renderer.render(scene, camera); | |
requestAnimationFrame(render); | |
} | |
init(); |
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
// Coding Rainbow | |
// Daniel Shiffman | |
// http://patreon.com/codingtrain | |
// Code for: https://youtu.be/E1B4UoSQMFw | |
// variables: A B | |
// axiom: A | |
// rules: (A → AB), (B → A) | |
var angle; | |
var axiom = "F"; | |
var sentence = axiom; | |
var len = 140; | |
let lenQuad = 20 | |
var limit = 5; | |
var decrease_percent = 0.5; | |
var rules = []; | |
rules[0] = { | |
a: "F", | |
b: "F[+F]F[-F][FA]", | |
c: "A", | |
d: "FF+[+FA-F-F]-[-FA+F+F]" | |
//a: "F", | |
//b: "F[+F]F[-F]F", | |
// a: "F", | |
// b: "F[+F]F[-F][F]" | |
// a: "F", | |
// b: "FF+[+F-F-F]-[-F+F+F]" | |
} | |
function generate() { | |
if (limit === 0) { return; } | |
len *= 0.5; | |
var nextSentence = ""; | |
for (var i = 0; i < sentence.length; i++) { | |
var current = sentence.charAt(i); | |
var found = false; | |
for (var j = 0; j < rules.length; j++) { | |
if (current == rules[j].a) { | |
found = true; | |
nextSentence += rules[j].b; | |
break; | |
} | |
if (current == rules[j].c) { | |
found = true; | |
nextSentence += rules[j].d | |
break; | |
} | |
} | |
if (!found) { | |
nextSentence += current; | |
} | |
} | |
sentence = nextSentence; | |
createP(sentence); | |
turtleTest(); | |
limit -= 1; | |
} | |
function turtleTest() { | |
background(80, 80, 180); | |
resetMatrix(); | |
translate(width / 2, height); | |
stroke(0, 100); | |
for (var i = 0; i < sentence.length; i++) { | |
var current = sentence.charAt(i); | |
if (current == "F") { | |
line(0, 0, 0, -len); | |
translate(0, -len); | |
} else if (current == "+") { | |
rotate(angle); | |
} else if (current == "-") { | |
rotate(-angle) | |
} else if (current == "[") { | |
push(); | |
} else if (current == "]") { | |
pop(); | |
} else if (current == "A") { | |
fill(20, randomGaussian(200, 50), 20) | |
translate(0, - (lenQuad)) | |
rotate(PI / randomGaussian(3, 4)); | |
rect(0, 0, lenQuad, lenQuad); | |
noFill() | |
} | |
} | |
} | |
function setup() { | |
createCanvas(400, 600); | |
angle = radians(25); | |
background(51); | |
createP(axiom); | |
turtleTest(); | |
var button = createButton("generate"); | |
button.mousePressed(generate); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment