// HelloPoint2.js (c) 2012 matsuda, 2022 Jonathon Doran "use strict"; // Vertex shader program const vertex_shader = ` attribute vec4 a_Position; // attribute variables are assigned by the main program void main() { gl_Position = a_Position; gl_PointSize = 1.0; } `; // Fragment shader program const fragment_shader = ` void main() { gl_FragColor = vec4(0.2, 0.8, 1.0, 1.0); // Set the point color to a nice cyan } `; // // Chaos Game // // Classes // vec2: 2D vectors class vec2 { constructor(x = 0, y = 0) { this.x = x; this.y = y; } add(rhs) { if (rhs) return new vec2(this.x + rhs.x, this.y + rhs.y); return null; } sub(rhs) { if (rhs) return new vec2(this.x - rhs.x, this.y - rhs.y); return null; } copy() { return new vec2(this.x, this.y); } move_halfway(rhs) { // Calculate the vector direction to move in, and change in that direction. this.x += (rhs.x - this.x) / 2; this.y += (rhs.y - this.y) / 2; } } // triangle2 class: Holds 3 vertices, represented as vectors from the origin class triangle2 { // constructor: Make a new triangle constructor({ v0 = null, v1 = null, v2 = null, type = "scalene", radius = 0, center = {x: 0, y: 0}} = {}) { this.v = [, ,] this.v[0] = v0; this.v[1] = v1; this.v[2] = v2; if (type === "equilateral") { this.make_equilateral(radius, center); } } // make_equilateral: construct an equilateral triangle // @param radius: Distance from center of triangle to vertices make_equilateral(radius, center = {x: 0, y: 0}) { // compute the math constants const r_sin_120 = Math.sin(Math.PI / 3) * radius; const r_cos_120 = 0.5 * radius; // Equilateral triangle centered on origin this.v[0] = new vec2(-r_sin_120, -r_cos_120).add(center); this.v[1] = new vec2(0, radius).add(center); this.v[2] = new vec2(r_sin_120, -r_cos_120).add(center); } get_vertex(index) { return this.v[index]; } get_rand_vertex() { return this.v[Math.floor(Math.random() * 3)]; } } // function draw_point: draw a point function draw_point(gl, a_Position, p) { // Pass vertex position to attribute variable gl.vertexAttrib3f(a_Position, p.x, p.y, 0.0); // Draw gl.drawArrays(gl.POINTS, 0, 1); } function main() { // Retrieve element var canvas = document.getElementById('webgl'); // Get the rendering context for WebGL var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } // Initialize shaders if (!initShaders(gl, vertex_shader, fragment_shader)) { console.log('Failed to intialize shaders.'); return; } // Get the storage location of a_Position var a_Position = gl.getAttribLocation(gl.program, 'a_Position'); if (a_Position < 0) { console.log('Failed to get the storage location of a_Position'); return; } // Specify the color for clearing canvas as black, and clear canvas gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); // make an equilateral triangle of radius 0.8, centered in the clip space const radius = 0.8; var triangle = new triangle2({type: "equilateral", radius: radius, center: {x: 0, y: -radius/4}}); // initialize point p to a copy of one of the vectors var i, p = triangle.get_vertex(0)?.copy(); // loop for ten thousand years for (i = 0; i < 50000; i++) { // get a random vertex var random_vertex = triangle.get_rand_vertex(); // move to the midpoint p.move_halfway(random_vertex); // draw point draw_point(gl, a_Position, p); } }