Tree Generator V2
How do I make an tree generator v2?
An improved version of my random-walk tree generator, now in true 3D using THREE.js. I also added a way to export to an OBJ or an SDL file courtesy of Kevin Lubick at https://gist.github.com/kjlubick. What is a tree generator v2? How do you make a tree generator v2? This script and codes were developed by Ben Matthews on 20 December 2022, Tuesday.
Tree Generator V2 - Script Codes HTML Codes
<!DOCTYPE html>
<html >
<head> <meta charset="UTF-8"> <title>Tree Generator V2</title> <link rel='stylesheet prefetch' href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css'> <link rel="stylesheet" href="css/style.css">
</head>
<body> <div id="controls"> <button id="generate" class="btn btn-secondary" onclick="generateTree()">New Tree</button><br><br> <button id="saveOBJ" class="btn btn-secondary" onclick="exportSceneOBJ()">Save as OBJ file</button><br><br> <button id="saveSTL" class="btn btn-secondary" onclick="exportSceneSTL()">Save as STL file</button>
</div>
</div>
<div id="ThreeJS" style="z-index: 0; position: absolute; left:0px; top:30vh; height:70vh"></div> <!-- Trigger/Open The Modal -->
<button id="myBtn" class="btn btn-primary">
Tree Generator V2 - Script Codes CSS Codes
body
{ font-family: Monospace; font-weight: bold; background-color: black; margin: 0px; overflow: hidden;
}
#controls{ position:absolute; top:0; left:0; z-index:1; margin:20px;
}
.dg.ac{ position: absolute; z-index:2;
}
#myBtn{ position:absolute; bottom: 20px; right: 20px;
} /* The Modal (background) */
.modal { display: none; /* Hidden by default */ position: fixed; /* Stay in place */ z-index: 2; /* Sit on top */ left: 0; top: 0; width: 100%; /* Full width */ height: 100%; /* Full height */ overflow: auto; /* Enable scroll if needed */ background-color: rgb(0,0,0); /* Fallback color */ background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}
/* Modal Content/Box */
.modal-content { background-color: #fefefe; margin: 15% auto; /* 15% from the top and centered */ padding: 20px; border: 1px solid #888; width: 80%; /* Could be more or less, depending on screen size */
}
/* The Close Button */
.close { color: #aaa; float: right; font-size: 28px; font-weight: bold;
}
.close:hover,
.close:focus { color: black; text-decoration: none; cursor: pointer;
}
Tree Generator V2 - Script Codes JS Codes
var container, scene, camera, renderer, controls, stats;
var keyboard = new THREEx.KeyboardState();
var clock = new THREE.Clock();
var slices = 0;
var maxSlices = 2500;
var angleMod = 0.05;
var splitChance = .15;
var heightMod = 1;
var widthMod = .2;
var startingSize = 1;
var branchVariance = .3;
var sizeMod = 4;
var sizeDec = .03;
var sections = 10;
var objects = [];
var gui;
window.onload = function() { gui = new dat.GUI(); var controllers = []; controllers.push(gui.add(this, 'maxSlices', 100, 10000)); controllers.push(gui.add(this, 'splitChance', 0, 1, .01)); controllers.push(gui.add(this, 'angleMod', 0, .2, .01)); controllers.push(gui.add(this, 'heightMod', .1, 4, .1)); controllers.push(gui.add(this, 'widthMod', .1, 1, .05)); controllers.push(gui.add(this, 'startingSize', 0, 10, .01)); controllers.push(gui.add(this, 'sizeDec', .01, 1, .01)); controllers.push(gui.add(this, 'branchVariance', 0, 1, .01)); controllers.push(gui.add(this, 'sections', 3, 30, 1)); gui.add(this, 'randomizeVars'); gui.add(this, 'resetVars'); for (var i = 0; i < controllers.length; i++){ controllers[i].onFinishChange(function(){ generateTree(); }); }
};
function RW(x, y, z, size, tickOffset){ this.x = x; this.y = y; this.z = z; this.prevX = x; this.prevY = y; this.prevZ = z; this.prevSize = this.size; this.size = size; this.numTicks = tickOffset; this.speed = Math.random()*widthMod + .05; this.angle = Math.random()*2*Math.PI; this.angleMod = Math.random()*angleMod + .05; this.angleMod *= 2*Math.PI; this.geom = new THREE.Geometry(); this.update = function(){ slices++; this.prevX = this.x; this.prevY = this.y; this.prevZ = this.z; this.prevSize = this.size; this.x += Math.cos(this.angle)*this.speed*sizeMod; this.y += Math.sin(this.angle)*this.speed*sizeMod; this.z += heightMod; this.size -= sizeDec; if (this.size < 0) return; if (Math.random() < .5) this.angleMod *= -1; this.angle += Math.random()*this.angleMod; var vertices = []; for (var i = 0; i < sections; i++){ var mod = 0 if (this.numTicks%2 == 0) mod = .5; var ratio = (i+mod)/sections; var ratio2 = (i + .5 + mod)/sections; var a1 = ratio*2*Math.PI; var a2 = ratio2*2*Math.PI; vertices.push(new THREE.Vector3( (Math.cos(a1)*this.prevSize + this.prevX)*sizeMod, this.prevZ*sizeMod, (Math.sin(a1)*this.prevSize + this.prevY)*sizeMod )); vertices.push(new THREE.Vector3( (Math.cos(a2)*this.size + this.x)*sizeMod, this.z*sizeMod, (Math.sin(a2)*this.size + this.y)*sizeMod )); } var base = this.geom.vertices.length; for (var i = 0; i < vertices.length; i++){ this.geom.vertices.push(vertices[i]); } for (var i = 0; i < vertices.length; i++){ if (i%2 == 1){ this.geom.faces.push(new THREE.Face3( // base + i, base + (i+2)%vertices.length, base + (i+1)%vertices.length, base + i, )); } else { this.geom.faces.push(new THREE.Face3( base + i, base + (i+1)%vertices.length, base + (i+2)%vertices.length )); } } this.numTicks++; }
}
init();
animate();
function init()
{ scene = new THREE.Scene(); var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight; var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000; camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR); scene.add(camera); camera.position.set(0,150,400); camera.lookAt(scene.position); ////////////// // RENDERER // ////////////// if ( Detector.webgl ) renderer = new THREE.WebGLRenderer( {antialias:true} ); else renderer = new THREE.CanvasRenderer(); renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT); container = document.getElementById( 'ThreeJS' ); container.appendChild( renderer.domElement ); //////////// // EVENTS // //////////// THREEx.WindowResize(renderer, camera); THREEx.FullScreen.bindKey({ charCode : 'm'.charCodeAt(0) }); ////////////// // CONTROLS // ////////////// controls = new THREE.OrbitControls( camera, renderer.domElement ); controls.autoRotate = true; /////////// // STATS // /////////// stats = new Stats(); stats.domElement.style.position = 'absolute'; stats.domElement.style.bottom = '0px'; stats.domElement.style.zIndex = 100; container.appendChild( stats.domElement ); /////////// // LIGHT // /////////// var light = new THREE.DirectionalLight(0xffffff); light.position.set(200,1000,200); scene.add(light); var ambientLight = new THREE.AmbientLight(0x111111); scene.add(ambientLight); //generate a tree: generateTree();
}
function clearScene(){ while(scene.children.length > 0){ scene.remove(scene.children[0]); }
}
function generateTree(){ slices = 0; for (var i = 0; i < objects.length; i++){ scene.remove(objects[i]); } objects = []; var rws = []; rws.push(new RW(0, 0, 0, startingSize, 0)); while(slices < maxSlices && rws.length > 0){ for (var i = rws.length-1; i > -1; i--){ rws[i].update(); if (rws[i].size < 0){ rws.splice(i, 0); continue; } if (slices < maxSlices && Math.random() < splitChance) rws.push(new RW( rws[i].x, rws[i].y, rws[i].z, rws[i].size*(Math.random()*branchVariance + (1 - branchVariance)), rws[i].numTicks%2 )); } } for (var i = 0; i < rws.length; i++){ rws[i].geom.computeFaceNormals(); // var material = new THREE.MeshPhongMaterial({color: 0xffffff}); var material = new THREE.MeshNormalMaterial(); // material.side = THREE.DoubleSide; material.perPixel = true; var object = new THREE.Mesh(rws[i].geom, material); object.name = "" + performance.now(); objects.push(object); scene.add(object); }
}
function animate()
{ requestAnimationFrame( animate ); render(); update();
}
function update()
{ // delta = change in time since last call (in seconds) var delta = clock.getDelta(); // functionality provided by THREEx.KeyboardState.js if ( keyboard.pressed("1") ) document.getElementById('message').innerHTML = ' Have a nice day! - 1'; if ( keyboard.pressed("2") ) document.getElementById('message').innerHTML = ' Have a nice day! - 2 '; controls.update(); stats.update();
}
function randomizeVars(){ for (var i = 0; i < gui.__controllers.length - 2; i++){ var controller = gui.__controllers[i]; var range = controller.__max - controller.__min; console.log(range); var value = controller.__min + Math.random()*range; if (controller.__step > 1) value = Math.floor(value); controller.setValue(value); } generateTree();
}
function resetVars(){ for (var i = 0; i < gui.__controllers.length; i++){ gui.__controllers[i].setValue(gui.__controllers[i].initialValue); } generateTree();
}
function exportSceneOBJ(){ var date = new Date(); var exporter = new THREE.OBJExporter(); var output = exporter.parse(scene); var blob = new Blob([output], {type: "text/plain;charset=utf-8"}); saveAs(blob, "Tree_" + date.getTime() + ".obj");
}
function exportSceneSTL(){ var date = new Date(); saveSTL(scene, "TreeGeneratorSTL_" + date.getTime());
}
document.body.onmousedown = function() { controls.autoRotate = false;
}
document.body.onmouseup = function() { controls.autoRotate = true;
}
function render()
{ renderer.render( scene, camera );
}
// Get the modal
var modal = document.getElementById('myModal');
// Get the button that opens the modal
var btn = document.getElementById("myBtn");
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];
// When the user clicks on the button, open the modal
btn.onclick = function() { modal.style.display = "block";
}
// When the user clicks on <span> (x), close the modal
span.onclick = function() { modal.style.display = "none";
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) { if (event.target == modal) { modal.style.display = "none"; }
}
Developer | Ben Matthews |
Username | tsuhre |
Uploaded | December 20, 2022 |
Rating | 4 |
Size | 5,891 Kb |
Views | 8,096 |
Find the perfect freelance services for your business! Fiverr's mission is to change how the world works together. Fiverr connects businesses with freelancers offering digital services in 500+ categories. Find Developer!
Name | Size |
Changing Terrain Experiment | 2,337 Kb |
Sand Traveler | 2,467 Kb |
Diffusion Limited Aggregation | 3,361 Kb |
Circuit Board Generator | 3,100 Kb |
Constellations | 2,961 Kb |
A Pen by Ben Matthews | 3,008 Kb |
Zelda BOTW Sheikah Language | 4,039 Kb |
Ellipses | 2,312 Kb |
Snow | 2,078 Kb |
Conways Fireworks | 2,960 Kb |
Jasper is the AI Content Generator that helps you and your team break through creative blocks to create amazing, original content 10X faster. Discover all the ways the Jasper AI Content Platform can help streamline your creative workflows. Start For Free!
Name | Username | Size |
Table Exercise | Fresco | 9,585 Kb |
CSS 3D Radio buttons | Andreasnylin | 1,650 Kb |
Drag and Drop Quiz | Cgspicer | 3,837 Kb |
Ball Physics | Getsetbro | 3,149 Kb |
SVG hamburger menu button | Elifitch | 2,602 Kb |
Adding Items | Valhead | 4,008 Kb |
Page Transitions in Backbone | Mikefowler | 3,691 Kb |
A Pen by Mohomed Anees | Mohomedanees | 12,597 Kb |
SVG Hover Animations | Kjbrum | 10,557 Kb |
Brent Burns Tribute Page | Nevada48 | 2,569 Kb |
Surf anonymously, prevent hackers from acquiring your IP address, send anonymous email, and encrypt your Internet connection. High speed, ultra secure, and easy to use. Instant setup. Hide Your IP Now!