Skip to content

Instantly share code, notes, and snippets.

@cwarny
Created July 11, 2015 23:55
Show Gist options
  • Save cwarny/2446f231b7014d414d50 to your computer and use it in GitHub Desktop.
Save cwarny/2446f231b7014d414d50 to your computer and use it in GitHub Desktop.
xGjMOw
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>Twist</title>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
void main() {
gl_Position = vPosition;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
</script>
<script type="text/javascript" src="../Common/webgl-utils.js"></script>
<script type="text/javascript" src="../Common/initShaders.js"></script>
<script type="text/javascript" src="../Common/MV.js"></script>
<script type="text/javascript" src="handlers.js"></script>
<script type="text/javascript" src="index.js"></script>
</head>
<body>
<canvas id="gl-canvas" width="512" height="512">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
<div>
Angle
<input type="number" id="angle-input" min="0" max="5" step="0.25">
</div>
<div>
Subdivision steps
<input type="number" id="subdivision-input" min="1" max="8">
</div>
</body>
</html>
/*
* Copyright 2010, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @fileoverview This file contains functions every webgl program will need
* a version of one way or another.
*
* Instead of setting up a context manually it is recommended to
* use. This will check for success or failure. On failure it
* will attempt to present an approriate message to the user.
*
* gl = WebGLUtils.setupWebGL(canvas);
*
* For animated WebGL apps use of setTimeout or setInterval are
* discouraged. It is recommended you structure your rendering
* loop like this.
*
* function render() {
* window.requestAnimFrame(render, canvas);
*
* // do rendering
* ...
* }
* render();
*
* This will call your rendering function up to the refresh rate
* of your display but will stop rendering if your app is not
* visible.
*/
WebGLUtils = function() {
/**
* Creates the HTLM for a failure message
* @param {string} canvasContainerId id of container of th
* canvas.
* @return {string} The html.
*/
var makeFailHTML = function(msg) {
return '' +
'<table style="background-color: #8CE; width: 100%; height: 100%;"><tr>' +
'<td align="center">' +
'<div style="display: table-cell; vertical-align: middle;">' +
'<div style="">' + msg + '</div>' +
'</div>' +
'</td></tr></table>';
};
/**
* Mesasge for getting a webgl browser
* @type {string}
*/
var GET_A_WEBGL_BROWSER = '' +
'This page requires a browser that supports WebGL.<br/>' +
'<a href="http://get.webgl.org">Click here to upgrade your browser.</a>';
/**
* Mesasge for need better hardware
* @type {string}
*/
var OTHER_PROBLEM = '' +
"It doesn't appear your computer can support WebGL.<br/>" +
'<a href="http://get.webgl.org/troubleshooting/">Click here for more information.</a>';
/**
* Creates a webgl context. If creation fails it will
* change the contents of the container of the <canvas>
* tag to an error message with the correct links for WebGL.
* @param {Element} canvas. The canvas element to create a
* context from.
* @param {WebGLContextCreationAttirbutes} opt_attribs Any
* creation attributes you want to pass in.
* @return {WebGLRenderingContext} The created context.
*/
var setupWebGL = function(canvas, opt_attribs) {
function showLink(str) {
var container = canvas.parentNode;
if (container) {
container.innerHTML = makeFailHTML(str);
}
};
if (!window.WebGLRenderingContext) {
showLink(GET_A_WEBGL_BROWSER);
return null;
}
var context = create3DContext(canvas, opt_attribs);
if (!context) {
showLink(OTHER_PROBLEM);
}
return context;
};
/**
* Creates a webgl context.
* @param {!Canvas} canvas The canvas tag to get context
* from. If one is not passed in one will be created.
* @return {!WebGLContext} The created context.
*/
var create3DContext = function(canvas, opt_attribs) {
var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
var context = null;
for (var ii = 0; ii < names.length; ++ii) {
try {
context = canvas.getContext(names[ii], opt_attribs);
} catch(e) {}
if (context) {
break;
}
}
return context;
}
return {
create3DContext: create3DContext,
setupWebGL: setupWebGL
};
}();
/**
* Provides requestAnimationFrame in a cross browser way.
*/
window.requestAnimFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {
window.setTimeout(callback, 1000/60);
};
})();
//
// initShaders.js
//
function initShaders( gl, vertexShaderId, fragmentShaderId )
{
var vertShdr;
var fragShdr;
var vertElem = document.getElementById( vertexShaderId );
if ( !vertElem ) {
alert( "Unable to load vertex shader " + vertexShaderId );
return -1;
}
else {
vertShdr = gl.createShader( gl.VERTEX_SHADER );
gl.shaderSource( vertShdr, vertElem.text );
gl.compileShader( vertShdr );
if ( !gl.getShaderParameter(vertShdr, gl.COMPILE_STATUS) ) {
var msg = "Vertex shader failed to compile. The error log is:"
+ "<pre>" + gl.getShaderInfoLog( vertShdr ) + "</pre>";
alert( msg );
return -1;
}
}
var fragElem = document.getElementById( fragmentShaderId );
if ( !fragElem ) {
alert( "Unable to load vertex shader " + fragmentShaderId );
return -1;
}
else {
fragShdr = gl.createShader( gl.FRAGMENT_SHADER );
gl.shaderSource( fragShdr, fragElem.text );
gl.compileShader( fragShdr );
if ( !gl.getShaderParameter(fragShdr, gl.COMPILE_STATUS) ) {
var msg = "Fragment shader failed to compile. The error log is:"
+ "<pre>" + gl.getShaderInfoLog( fragShdr ) + "</pre>";
alert( msg );
return -1;
}
}
var program = gl.createProgram();
gl.attachShader( program, vertShdr );
gl.attachShader( program, fragShdr );
gl.linkProgram( program );
if ( !gl.getProgramParameter(program, gl.LINK_STATUS) ) {
var msg = "Shader program failed to link. The error log is:"
+ "<pre>" + gl.getProgramInfoLog( program ) + "</pre>";
alert( msg );
return -1;
}
return program;
}
//////////////////////////////////////////////////////////////////////////////
//
// Angel.js
//
//////////////////////////////////////////////////////////////////////////////
//----------------------------------------------------------------------------
//
// Helper functions
//
function _argumentsToArray( args )
{
return [].concat.apply( [], Array.prototype.slice.apply(args) );
}
//----------------------------------------------------------------------------
function radians( degrees ) {
return degrees * Math.PI / 180.0;
}
//----------------------------------------------------------------------------
//
// Vector Constructors
//
function vec2()
{
var result = _argumentsToArray( arguments );
switch ( result.length ) {
case 0: result.push( 0.0 );
case 1: result.push( 0.0 );
}
return result.splice( 0, 2 );
}
function vec3()
{
var result = _argumentsToArray( arguments );
switch ( result.length ) {
case 0: result.push( 0.0 );
case 1: result.push( 0.0 );
case 2: result.push( 0.0 );
}
return result.splice( 0, 3 );
}
function vec4()
{
var result = _argumentsToArray( arguments );
switch ( result.length ) {
case 0: result.push( 0.0 );
case 1: result.push( 0.0 );
case 2: result.push( 0.0 );
case 3: result.push( 1.0 );
}
return result.splice( 0, 4 );
}
//----------------------------------------------------------------------------
//
// Matrix Constructors
//
function mat2()
{
var v = _argumentsToArray( arguments );
var m = [];
switch ( v.length ) {
case 0:
v[0] = 1;
case 1:
m = [
vec2( v[0], 0.0 ),
vec2( 0.0, v[0] )
];
break;
default:
m.push( vec2(v) ); v.splice( 0, 2 );
m.push( vec2(v) );
break;
}
m.matrix = true;
return m;
}
//----------------------------------------------------------------------------
function mat3()
{
var v = _argumentsToArray( arguments );
var m = [];
switch ( v.length ) {
case 0:
v[0] = 1;
case 1:
m = [
vec3( v[0], 0.0, 0.0 ),
vec3( 0.0, v[0], 0.0 ),
vec3( 0.0, 0.0, v[0] )
];
break;
default:
m.push( vec3(v) ); v.splice( 0, 3 );
m.push( vec3(v) ); v.splice( 0, 3 );
m.push( vec3(v) );
break;
}
m.matrix = true;
return m;
}
//----------------------------------------------------------------------------
function mat4()
{
var v = _argumentsToArray( arguments );
var m = [];
switch ( v.length ) {
case 0:
v[0] = 1;
case 1:
m = [
vec4( v[0], 0.0, 0.0, 0.0 ),
vec4( 0.0, v[0], 0.0, 0.0 ),
vec4( 0.0, 0.0, v[0], 0.0 ),
vec4( 0.0, 0.0, 0.0, v[0] )
];
break;
default:
m.push( vec4(v) ); v.splice( 0, 4 );
m.push( vec4(v) ); v.splice( 0, 4 );
m.push( vec4(v) ); v.splice( 0, 4 );
m.push( vec4(v) );
break;
}
m.matrix = true;
return m;
}
//----------------------------------------------------------------------------
//
// Generic Mathematical Operations for Vectors and Matrices
//
function equal( u, v )
{
if ( u.length != v.length ) { return false; }
if ( u.matrix && v.matrix ) {
for ( var i = 0; i < u.length; ++i ) {
if ( u[i].length != v[i].length ) { return false; }
for ( var j = 0; j < u[i].length; ++j ) {
if ( u[i][j] !== v[i][j] ) { return false; }
}
}
}
else if ( u.matrix && !v.matrix || !u.matrix && v.matrix ) {
return false;
}
else {
for ( var i = 0; i < u.length; ++i ) {
if ( u[i] !== v[i] ) { return false; }
}
}
return true;
}
//----------------------------------------------------------------------------
function add( u, v )
{
var result = [];
if ( u.matrix && v.matrix ) {
if ( u.length != v.length ) {
throw "add(): trying to add matrices of different dimensions";
}
for ( var i = 0; i < u.length; ++i ) {
if ( u[i].length != v[i].length ) {
throw "add(): trying to add matrices of different dimensions";
}
result.push( [] );
for ( var j = 0; j < u[i].length; ++j ) {
result[i].push( u[i][j] + v[i][j] );
}
}
result.matrix = true;
return result;
}
else if ( u.matrix && !v.matrix || !u.matrix && v.matrix ) {
throw "add(): trying to add matrix and non-matrix variables";
}
else {
if ( u.length != v.length ) {
throw "add(): vectors are not the same dimension";
}
for ( var i = 0; i < u.length; ++i ) {
result.push( u[i] + v[i] );
}
return result;
}
}
//----------------------------------------------------------------------------
function subtract( u, v )
{
var result = [];
if ( u.matrix && v.matrix ) {
if ( u.length != v.length ) {
throw "subtract(): trying to subtract matrices" +
" of different dimensions";
}
for ( var i = 0; i < u.length; ++i ) {
if ( u[i].length != v[i].length ) {
throw "subtract(): trying to subtact matrices" +
" of different dimensions";
}
result.push( [] );
for ( var j = 0; j < u[i].length; ++j ) {
result[i].push( u[i][j] - v[i][j] );
}
}
result.matrix = true;
return result;
}
else if ( u.matrix && !v.matrix || !u.matrix && v.matrix ) {
throw "subtact(): trying to subtact matrix and non-matrix variables";
}
else {
if ( u.length != v.length ) {
throw "subtract(): vectors are not the same length";
}
for ( var i = 0; i < u.length; ++i ) {
result.push( u[i] - v[i] );
}
return result;
}
}
//----------------------------------------------------------------------------
function mult( u, v )
{
var result = [];
if ( u.matrix && v.matrix ) {
if ( u.length != v.length ) {
throw "mult(): trying to add matrices of different dimensions";
}
for ( var i = 0; i < u.length; ++i ) {
if ( u[i].length != v[i].length ) {
throw "mult(): trying to add matrices of different dimensions";
}
}
for ( var i = 0; i < u.length; ++i ) {
result.push( [] );
for ( var j = 0; j < v.length; ++j ) {
var sum = 0.0;
for ( var k = 0; k < u.length; ++k ) {
sum += u[i][k] * v[k][j];
}
result[i].push( sum );
}
}
result.matrix = true;
return result;
}
else {
if ( u.length != v.length ) {
throw "mult(): vectors are not the same dimension";
}
for ( var i = 0; i < u.length; ++i ) {
result.push( u[i] * v[i] );
}
return result;
}
}
//----------------------------------------------------------------------------
//
// Basic Transformation Matrix Generators
//
function translate( x, y, z )
{
if ( Array.isArray(x) && x.length == 3 ) {
z = x[2];
y = x[1];
x = x[0];
}
var result = mat4();
result[0][3] = x;
result[1][3] = y;
result[2][3] = z;
return result;
}
//----------------------------------------------------------------------------
function rotate( angle, axis )
{
if ( !Array.isArray(axis) ) {
axis = [ arguments[1], arguments[2], arguments[3] ];
}
var v = normalize( axis );
var x = v[0];
var y = v[1];
var z = v[2];
var c = Math.cos( radians(angle) );
var omc = 1.0 - c;
var s = Math.sin( radians(angle) );
var result = mat4(
vec4( x*x*omc + c, x*y*omc - z*s, x*z*omc + y*s, 0.0 ),
vec4( x*y*omc + z*s, y*y*omc + c, y*z*omc - x*s, 0.0 ),
vec4( x*z*omc - y*s, y*z*omc + x*s, z*z*omc + c, 0.0 ),
vec4()
);
return result;
}
//----------------------------------------------------------------------------
function scalem( x, y, z )
{
if ( Array.isArray(x) && x.length == 3 ) {
z = x[2];
y = x[1];
x = x[0];
}
var result = mat4();
result[0][0] = x;
result[1][1] = y;
result[2][2] = z;
return result;
}
//----------------------------------------------------------------------------
//
// ModelView Matrix Generators
//
function lookAt( eye, at, up )
{
if ( !Array.isArray(eye) || eye.length != 3) {
throw "lookAt(): first parameter [eye] must be an a vec3";
}
if ( !Array.isArray(at) || at.length != 3) {
throw "lookAt(): first parameter [at] must be an a vec3";
}
if ( !Array.isArray(up) || up.length != 3) {
throw "lookAt(): first parameter [up] must be an a vec3";
}
if ( equal(eye, at) ) {
return mat4();
}
var v = normalize( subtract(at, eye) ); // view direction vector
var n = normalize( cross(v, up) ); // perpendicular vector
var u = normalize( cross(n, v) ); // "new" up vector
v = negate( v );
var result = mat4(
vec4( n, -dot(n, eye) ),
vec4( u, -dot(u, eye) ),
vec4( v, -dot(v, eye) ),
vec4()
);
return result;
}
//----------------------------------------------------------------------------
//
// Projection Matrix Generators
//
function ortho( left, right, bottom, top, near, far )
{
if ( left == right ) { throw "ortho(): left and right are equal"; }
if ( bottom == top ) { throw "ortho(): bottom and top are equal"; }
if ( near == far ) { throw "ortho(): near and far are equal"; }
var w = right - left;
var h = top - bottom;
var d = far - near;
var result = mat4();
result[0][0] = 2.0 / w;
result[1][1] = 2.0 / h;
result[2][2] = -2.0 / d;
result[0][3] = (left + right) / w;
result[1][3] = (top + bottom) / h;
result[2][3] = (near + far) / d;
return result;
}
//----------------------------------------------------------------------------
function perspective( fovy, aspect, near, far )
{
var f = 1.0 / Math.tan( radians(fovy) / 2 );
var d = far - near;
var result = mat4();
result[0][0] = f / aspect;
result[1][1] = f;
result[2][2] = -(near + far) / d;
result[2][3] = -2 * near * far / d;
result[3][2] = -1;
result[3][3] = 0.0;
return result;
}
//----------------------------------------------------------------------------
//
// Matrix Functions
//
function transpose( m )
{
if ( !m.matrix ) {
return "transpose(): trying to transpose a non-matrix";
}
var result = [];
for ( var i = 0; i < m.length; ++i ) {
result.push( [] );
for ( var j = 0; j < m[i].length; ++j ) {
result[i].push( m[j][i] );
}
}
result.matrix = true;
return result;
}
//----------------------------------------------------------------------------
//
// Vector Functions
//
function dot( u, v )
{
if ( u.length != v.length ) {
throw "dot(): vectors are not the same dimension";
}
var sum = 0.0;
for ( var i = 0; i < u.length; ++i ) {
sum += u[i] * v[i];
}
return sum;
}
//----------------------------------------------------------------------------
function negate( u )
{
result = [];
for ( var i = 0; i < u.length; ++i ) {
result.push( -u[i] );
}
return result;
}
//----------------------------------------------------------------------------
function cross( u, v )
{
if ( !Array.isArray(u) || u.length < 3 ) {
throw "cross(): first argument is not a vector of at least 3";
}
if ( !Array.isArray(v) || v.length < 3 ) {
throw "cross(): second argument is not a vector of at least 3";
}
var result = [
u[1]*v[2] - u[2]*v[1],
u[2]*v[0] - u[0]*v[2],
u[0]*v[1] - u[1]*v[0]
];
return result;
}
//----------------------------------------------------------------------------
function length( u )
{
return Math.sqrt( dot(u, u) );
}
//----------------------------------------------------------------------------
function normalize( u, excludeLastComponent )
{
if ( excludeLastComponent ) {
var last = u.pop();
}
var len = length( u );
if ( !isFinite(len) ) {
throw "normalize: vector " + u + " has zero length";
}
for ( var i = 0; i < u.length; ++i ) {
u[i] /= len;
}
if ( excludeLastComponent ) {
u.push( last );
}
return u;
}
//----------------------------------------------------------------------------
function mix( u, v, s )
{
if ( typeof s !== "number" ) {
throw "mix: the last paramter " + s + " must be a number";
}
if ( u.length != v.length ) {
throw "vector dimension mismatch";
}
var result = [];
for ( var i = 0; i < u.length; ++i ) {
result.push( s * u[i] + (1.0 - s) * v[i] );
}
return result;
}
//----------------------------------------------------------------------------
//
// Vector and Matrix functions
//
function scale( s, u )
{
if ( !Array.isArray(u) ) {
throw "scale: second parameter " + u + " is not a vector";
}
result = [];
for ( var i = 0; i < u.length; ++i ) {
result.push( s * u[i] );
}
return result;
}
//----------------------------------------------------------------------------
//
//
//
function flatten( v )
{
if ( v.matrix === true ) {
v = transpose( v );
}
var n = v.length;
var elemsAreArrays = false;
if ( Array.isArray(v[0]) ) {
elemsAreArrays = true;
n *= v[0].length;
}
var floats = new Float32Array( n );
if ( elemsAreArrays ) {
var idx = 0;
for ( var i = 0; i < v.length; ++i ) {
for ( var j = 0; j < v[i].length; ++j ) {
floats[idx++] = v[i][j];
}
}
}
else {
for ( var i = 0; i < v.length; ++i ) {
floats[i] = v[i];
}
}
return floats;
}
//----------------------------------------------------------------------------
var sizeof = {
'vec2' : new Float32Array( flatten(vec2()) ).byteLength,
'vec3' : new Float32Array( flatten(vec3()) ).byteLength,
'vec4' : new Float32Array( flatten(vec4()) ).byteLength,
'mat2' : new Float32Array( flatten(mat2()) ).byteLength,
'mat3' : new Float32Array( flatten(mat3()) ).byteLength,
'mat4' : new Float32Array( flatten(mat4()) ).byteLength
};
function setupHandlers() {
var angleInput = document.getElementById("angle-input"),
subdivisionInput = document.getElementById("subdivision-input");
angleInput.value = theta;
subdivisionInput.value = numTimesToSubdivide;
angleInput.onchange = function changeAngle(evt) {
theta = angleInput.value;
init();
}
subdivisionInput.onchange = function changeSubdivision(evt) {
numTimesToSubdivide = subdivisionInput.value;
init();
}
}
var canvas;
var gl;
var points = [];
var numTimesToSubdivide = 5;
var theta = 2.5;
window.onload = init;
function init() {
setupHandlers();
points = [];
canvas = document.getElementById("gl-canvas");
gl = WebGLUtils.setupWebGL(canvas);
if (!gl) { alert("WebGL isn't available"); }
//
// Initialize our data for the Sierpinski Gasket
//
// First, initialize the corners of our gasket with three points.
var vertices = [
vec2(-0.5, -0.5),
vec2(0, 0.5),
vec2(0.5, -0.5)
];
divideTriangle(vertices[0], vertices[1], vertices[2], numTimesToSubdivide);
//
// Configure WebGL
//
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1.0, 1.0, 1.0, 1.0);
// Load shaders and initialize attribute buffers
var program = initShaders(gl, "vertex-shader", "fragment-shader");
gl.useProgram(program);
// Load the data into the GPU
var bufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
gl.bufferData(gl.ARRAY_BUFFER, flatten(points), gl.STATIC_DRAW);
// Associate out shader variables with our data buffer
var vPosition = gl.getAttribLocation(program, "vPosition");
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vPosition);
render();
};
function triangle(a, b, c) {
points.push(a, b, c);
}
function rotateTriangle(a, b, c) {
// var G = vec2((a[0] + b[0] + c[0]) / 3, (a[1] + b[1] + c[1]) / 3);
// var d = Math.sqrt(Math.pow(G[0], 2) + Math.pow(G[1], 2));
// return [a, b, c].map(function(p) {
// return vec2(
// p[0] * Math.cos(d * theta) - p[1] * Math.sin(d * theta),
// p[0] * Math.sin(d * theta) + p[1] * Math.cos(d * theta)
// );
// });
return [a,b,c].map(function(p) {
var x = p[0], y = p[1];
var d = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
var xp = x * Math.cos(d * theta) - y * Math.sin(d * theta);
var yp = x * Math.sin(d * theta) + y * Math.cos(d * theta);
// rotatedPoints.push([xp, yp]);
return [xp, yp];
})
}
function divideTriangle(a, b, c, count) {
// check for end of recursion
if (count === 0) {
triangle.apply(this, rotateTriangle(a, b, c));
}
else {
//bisect the sides
var ab = mix(a, b, 0.5);
var ac = mix(a, c, 0.5);
var bc = mix(b, c, 0.5);
--count;
// three new triangles
divideTriangle(a, ab, ac, count);
divideTriangle(c, ac, bc, count);
divideTriangle(b, bc, ab, count);
divideTriangle(ac, bc, ab, count); // Fourth triangle necessary for the twist
}
}
function render() {
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, points.length);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment