A Pen by Nexuscompute on CodePen.
Created
January 31, 2022 01:18
-
-
Save NOUIY/7a9b1d0a3a5440454bb1ede489b328ab to your computer and use it in GitHub Desktop.
3D Fractal 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
<!-- #CodePenChallenge: Fractals --> |
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
import * as THREE from "https://cdn.skypack.dev/three@0.136.0"; | |
import OrbitControls from "https://cdn.skypack.dev/threejs-orbit-controls@1.0.3"; | |
let getWindowWidth = () => window.innerWidth; | |
let getWindowHeight = () => window.innerHeight; | |
let getCamAspect = () => getWindowWidth() / getWindowHeight(); | |
let cam_fov = 75; | |
let cam_near = 0.1; | |
let cam_far = 1000; | |
const scene = new THREE.Scene(); | |
const camera = new THREE.PerspectiveCamera( | |
cam_fov, | |
getCamAspect(), | |
cam_near, | |
cam_far | |
); | |
const renderer = new THREE.WebGLRenderer({ alpha: false, antialias: true }); | |
let controls = new OrbitControls(camera, renderer.domElement); | |
//////////////////////////////////////////////////////////////////////////////// | |
let lineSegments = 16; | |
let lineSegmentLength = 1; | |
let segmentRatio = 1 / 1.3; | |
let lineStartPoint = new THREE.Vector3(0, -3, 0); | |
let branchesPerNode = 3; | |
let maxBranchesCount = 1000; | |
let lineGeometrySet = []; | |
controls.autoRotate = true; | |
function createLinePositions(lineStartPoint, lineSegments, lineSegmentLength) { | |
let postionsCount = (lineSegments + 1) * 3; | |
let postions = new Float32Array(postionsCount); | |
let angle = Math.PI / 3; | |
let angleDirection = () => (Math.random() < 0.5 ? -1 : 1); | |
postions[0] = lineStartPoint.x; | |
postions[1] = lineStartPoint.y; | |
postions[2] = lineStartPoint.z; | |
for (let i = 3; i < postionsCount; i = i + 3) { | |
lineSegmentLength = lineSegmentLength * segmentRatio; | |
postions[i] = | |
lineSegmentLength * angleDirection() * Math.cos(angle) + postions[i - 3]; | |
postions[i + 1] = lineSegmentLength * Math.sin(angle) + postions[i - 2]; | |
postions[i + 2] = | |
lineSegmentLength * angleDirection() * Math.cos(angle) + postions[i - 1]; | |
} | |
return new THREE.BufferAttribute(postions, 3); | |
} | |
function createLine( | |
lineStartPoint, | |
lineSegments, | |
lineSegmentLength, | |
branchesPerNode | |
) { | |
const lineBasicMaterial = new THREE.LineBasicMaterial({ | |
color: `hsl(${Math.random() * 30}, 50%, 50%)`, | |
transparent: true, | |
opacity: 0.5 | |
}); | |
const lineGeometry = new THREE.BufferGeometry(); | |
const linePositions = createLinePositions( | |
lineStartPoint, | |
lineSegments, | |
lineSegmentLength | |
); | |
lineGeometry.setAttribute("position", linePositions); | |
lineGeometry.setDrawRange(0, 0); | |
lineGeometrySet.push(lineGeometry); | |
const line = new THREE.Line(lineGeometry, lineBasicMaterial); | |
scene.add(line); | |
let branchSegmentLength = lineSegmentLength * segmentRatio; | |
let branchLineSegments = lineSegments / 2; | |
branchesPerNode = branchesPerNode / 2; | |
for (let i = 1; i < linePositions.count; i++) { | |
if (branchLineSegments < 1) break; | |
if (branchesPerNode < 1) break; | |
if (maxBranchesCount <= 0) break; | |
let startPoint = new THREE.Vector3( | |
linePositions.getX(i), | |
linePositions.getY(i), | |
linePositions.getZ(i) | |
); | |
// console.log(startPoint); | |
for (let j = 0; j < branchesPerNode; j++) { | |
createLine( | |
startPoint, | |
branchLineSegments, | |
branchSegmentLength, | |
branchesPerNode | |
); | |
maxBranchesCount--; | |
} | |
} | |
} | |
createLine(lineStartPoint, lineSegments, lineSegmentLength, branchesPerNode); | |
//////////////////////////////////////////////////////////////////////////////// | |
camera.position.set(0, 0, 5); | |
camera.lookAt(0, 0, 0); | |
controls.update(); | |
let linesCount = lineGeometrySet.length; | |
let currentLine = 0; | |
let postionsCount = lineGeometrySet[0].attributes.position.count; | |
let drawPoints = 0; | |
function animate() { | |
if (drawPoints++ >= postionsCount + 1) { | |
drawPoints = 0; | |
currentLine++; | |
} | |
if (currentLine < linesCount) { | |
lineGeometrySet[currentLine].setDrawRange(0, drawPoints); | |
} | |
renderer.render(scene, camera); | |
controls.update(); | |
requestAnimationFrame(animate); | |
} | |
window.addEventListener("resize", () => { | |
renderer.setSize(getWindowWidth(), getWindowHeight()); | |
camera.aspect = getCamAspect(); | |
camera.updateProjectionMatrix(); | |
}); | |
renderer.setSize(getWindowWidth(), getWindowHeight()); | |
var canvas = document.body.appendChild(renderer.domElement); | |
animate(); |
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
* { | |
box-sizing: border-box; | |
} | |
body, | |
html { | |
height: 100vh; | |
display: grid; | |
margin: 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment