I wanted to draw a simple 2d fractal tree. This is the result.

#include <iostream> #include <string> #include <GL/glew.h> #include <GL/freeglut.h> #include <GL/glut.h> #include <GL/gl.h> #include "../common/Shader.hpp" #include "../common/ShaderProgram.hpp" #include <vector> #include <cmath> using namespace std; struct Vector { float x; float y; Vector(float _x, float _y) : x(_x), y(_y) {}; Vector operator + (const Vector & rht) const { return Vector(x + rht.x, y + rht.y); }; Vector operator * (float v) const { return Vector(x*v, y*v); }; }; struct Branch { Vector direction; Vector position; float length; Branch(float _x, float _y, float _posX, float _posY, float _length) : direction(Vector(_x, _y)), position(Vector(_posX, _posY)), length(_length) {}; Branch(Vector _direction, Vector _position, float _length) : direction(_direction), position(_position), length(_length) {}; }; vector<Branch> branches; vector<Vector> triangles; float m_BranchingAngle; float m_LengthFactor; size_t m_MaxDepth; /* Since branches have a starting position, length and direction, we will need the end position of the branch. This is the start of the next branch. */ Vector getEndOfBranch(const Branch & branch) { Vector pos = branch.position + branch.direction * branch.length; return pos; } /* Just transforms the angle from degrees to radians */ inline float toRad(float angle) { return angle * M_PI / 180.0f; } /* rotates a vector given an angle in degrees it just multiplies the vector by the matrix cos(x) -sin(x) sin(x) cos(x) */ Vector rotateVector(const Vector & vec, float angle) { angle = toRad(angle); float aSin = sin(angle); float aCos = cos(angle); float newX = aCos * vec.x - aSin * vec.y; float newY = aSin * vec.x + aCos * vec.y; return Vector(newX, newY); } /* Recursive step to generate the branches */ void generateTreeRec(const Branch & parent, size_t currentDepth) { if (currentDepth == m_MaxDepth) return; branches.push_back(parent); Vector endPos = getEndOfBranch(parent); float newLength = parent.length * m_LengthFactor; static float halfAngle = m_BranchingAngle / 2.0f; Vector leftDirection = rotateVector(parent.direction, halfAngle); Vector rightDirection = rotateVector(parent.direction, -halfAngle); Branch leftBranch = Branch(leftDirection, endPos, newLength); Branch rightBranch = Branch(rightDirection, endPos, newLength); generateTreeRec(leftBranch, currentDepth+1); generateTreeRec(rightBranch, currentDepth+1); } /* Creates the tree and starts the recursive call */ void generateTree(float branchingAngle, float lengthFactor, size_t maxDepth) { m_BranchingAngle = branchingAngle; m_LengthFactor = lengthFactor; m_MaxDepth = maxDepth; Branch trunk = Branch(0.0f, 1.0f, 0.0f, -1.0f, 0.8f); generateTreeRec(trunk, 0); } /* Branches are already created but they cannot be drawn directly. We can simple create triangles to draw the brances like: -------- | /| | / | | / | | / | | / | |/ | -------- Basically, we have the direction of the branch and we take the vector which is perpendicular to the direction. Then we create a vertex for the rectangle with a distance DELTA from the initial vertex. That's all. In this way, we have a rectangle and we can very easily triangulate. */ void transformBranchesToTriangles() { for (Branch branch : branches) { Vector start = branch.position; Vector end = getEndOfBranch(branch); Vector perpendicular = rotateVector(branch.direction, -90.0f); static float DELTA = 0.005f; Vector rStart = start + perpendicular * DELTA; Vector rEnd = end + perpendicular * DELTA; triangles.push_back(start); triangles.push_back(rStart); triangles.push_back(rEnd); triangles.push_back(end); triangles.push_back(start); triangles.push_back(rEnd); } } GLuint VAO; GLuint VBA; /* Everything else is standard. Just init the VAO and the VBA and load the shaders. The vertex shader is just a pass shader and the fragment shader just sets some color. Nothing special. */ void init() { generateTree(120.0f, 1.0f / 1.8f, 8); transformBranchesToTriangles(); glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); glGenBuffers(1, &VBA); glBindBuffer(GL_ARRAY_BUFFER, VBA); glBufferData(GL_ARRAY_BUFFER, triangles.size() * sizeof(Vector), &triangles[0], GL_STATIC_DRAW); ShaderProgram program = ShaderProgram(Shader("shader.vert", GL_VERTEX_SHADER), Shader("shader.frag", GL_FRAGMENT_SHADER) ); glUseProgram(program.getProgram()); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(0); } void display() { glClear(GL_COLOR_BUFFER_BIT); glBindVertexArray(VAO); glDrawArrays(GL_TRIANGLES,0, triangles.size()); glFlush(); } int main(int argc, char ** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutInitWindowSize(512, 512); glutInitContextVersion(4,3); // freeglut required glutInitContextProfile(GLUT_CORE_PROFILE); glutCreateWindow(""); glewExperimental=GL_TRUE; if (glewInit()) { cerr << "Problem initializing glew" << endl; exit(EXIT_FAILURE); } init(); glutDisplayFunc(display); glutMainLoop(); return 0; }

Note that instead of making the rectangles using 2 triangles, we could have drawn the GL_LINES primitive and also set the width of the line by changing the state with glLineWidth(float)