// ThreeD-Tree Template // 872a Model Based Design // 10.18.03 float RANDOM_ANGLE_FACTOR = 0; float BRANCH_ANGLE = 1; float BRANCH_SCALE = 0.8; float MAX_DEPTH = 6; float BRANCH_LENGTH = 120; float BRANCH_THICKNESS = 3; float LEAF_SIZE = 40; float MOUSE_COUNTER = 0; void setup() { size(400, 400); arcball = new ArcBall(width/2, height/2, (width+height)/2); } void loop() { background(255); translate(width*.7, height*.7, -200); arcball.run(); fill(#FF0000); rotateX(-.2*PI); rotateZ(-.1*PI); rotateY(.2*PI); if (MOUSE_COUNTER<6) { MAX_DEPTH = MOUSE_COUNTER; } else { MAX_DEPTH = 6; } drawBranch1(0); } void drawBranch1(int depth) { if (depth >= MAX_DEPTH) { //drawLeaf(); return; } noStroke(); fill(100,100); push(); scale((MAX_DEPTH-depth) * BRANCH_THICKNESS, -BRANCH_LENGTH, (MAX_DEPTH-depth) * BRANCH_THICKNESS); //translate(0, (.5+.0015*mouseX), 0); translate(0, (.5), 0); box(1); //draw a branch (first a trunk) that gets smaller each time you draw it. pop(); push(); translate(0, -BRANCH_LENGTH, 0); scale(BRANCH_SCALE); push(); rotateZ(BRANCH_ANGLE + random(RANDOM_ANGLE_FACTOR) - RANDOM_ANGLE_FACTOR/2); drawBranch1(depth+1); pop(); push(); rotateZ(-BRANCH_ANGLE + random(RANDOM_ANGLE_FACTOR) - RANDOM_ANGLE_FACTOR/2); drawBranch1(depth+1); pop(); push(); rotateX(BRANCH_ANGLE + random(RANDOM_ANGLE_FACTOR) - RANDOM_ANGLE_FACTOR/2); drawBranch1(depth+1); pop(); push(); rotateX(-BRANCH_ANGLE + random(RANDOM_ANGLE_FACTOR) - RANDOM_ANGLE_FACTOR/2); drawBranch1(depth+1); pop(); pop(); } // ------------------- IGNORE BUT COPY ALL OF THE BELOW!!! ---------------------------------------- ArcBall arcball; void mousePressed() { arcball.mousePressed(); } void mouseDragged() { arcball.mouseDragged(); } // Copy what's below exactly. class ArcBall { float center_x, center_y, radius; Vec3 v_down, v_drag; Quat q_now, q_down, q_drag; Vec3[] axisSet; int axis; ArcBall(float center_x, float center_y, float radius) { this.center_x = center_x; this.center_y = center_y; this.radius = radius; v_down = new Vec3(); v_drag = new Vec3(); q_now = new Quat(); q_down = new Quat(); q_drag = new Quat(); axisSet = new Vec3[] {new Vec3(1.0f, 0.0f, 0.0f), new Vec3(0.0f, 1.0f, 0.0f), new Vec3(0.0f, 0.0f, 1.0f)}; axis = -1; // no constraints... } void mousePressed() { v_down = mouse_to_sphere(mouseX, mouseY); q_down.set(q_now); q_drag.reset(); } void mouseDragged() { v_drag = mouse_to_sphere(mouseX, mouseY); q_drag.set(Vec3.dot(v_down, v_drag), Vec3.cross(v_down, v_drag)); } void run() { q_now = Quat.mul(q_drag, q_down); applyQuat2Matrix(q_now); } Vec3 mouse_to_sphere(float x, float y) { Vec3 v = new Vec3(); v.x = (x - center_x) / radius; v.y = (y - center_y) / radius; float mag = v.x * v.x + v.y * v.y; if (mag > 1.0f) { v.normalize(); } else { v.z = sqrt(1.0f - mag); } return (axis == -1) ? v : constrain_vector(v, axisSet[axis]); } Vec3 constrain_vector(Vec3 vector, Vec3 axis) { Vec3 res = new Vec3(); res.sub(vector, Vec3.mul(axis, Vec3.dot(axis, vector))); res.normalize(); return res; } void applyQuat2Matrix(Quat q) { // instead of transforming q into a matrix and applying it... float[] aa = q.getValue(); rotate(aa[0], aa[1], aa[2], aa[3]); } } static class Vec3 { float x, y, z; Vec3() { } Vec3(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } void normalize() { float length = length(); x /= length; y /= length; z /= length; } float length() { return (float) Math.sqrt(x * x + y * y + z * z); } static Vec3 cross(Vec3 v1, Vec3 v2) { Vec3 res = new Vec3(); res.x = v1.y * v2.z - v1.z * v2.y; res.y = v1.z * v2.x - v1.x * v2.z; res.z = v1.x * v2.y - v1.y * v2.x; return res; } static float dot(Vec3 v1, Vec3 v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; } static Vec3 mul(Vec3 v, float d) { Vec3 res = new Vec3(); res.x = v.x * d; res.y = v.y * d; res.z = v.z * d; return res; } void sub(Vec3 v1, Vec3 v2) { x = v1.x - v2.x; y = v1.y - v2.y; z = v1.z - v2.z; } } static class Quat { float w, x, y, z; Quat() { reset(); } Quat(float w, float x, float y, float z) { this.w = w; this.x = x; this.y = y; this.z = z; } void reset() { w = 1.0f; x = 0.0f; y = 0.0f; z = 0.0f; } void set(float w, Vec3 v) { this.w = w; x = v.x; y = v.y; z = v.z; } void set(Quat q) { w = q.w; x = q.x; y = q.y; z = q.z; } static Quat mul(Quat q1, Quat q2) { Quat res = new Quat(); res.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z; res.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y; res.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z; res.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x; return res; } float[] getValue() { // transforming this quat into an angle and an axis vector... float[] res = new float[4]; float sa = (float) Math.sqrt(1.0f - w * w); if (sa < EPSILON) { sa = 1.0f; } res[0] = (float) Math.acos(w) * 2.0f; res[1] = x / sa; res[2] = y / sa; res[3] = z / sa; return res; } } void mouseReleased() { MOUSE_COUNTER ++; }