Skip to content

Instantly share code, notes, and snippets.

@williame
Created November 27, 2012 11:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save williame/4153824 to your computer and use it in GitHub Desktop.
Save williame/4153824 to your computer and use it in GitHub Desktop.
function Sphere(iterations) {
// returns an object with a 'draw' method
// we cache ready-built spheres
if(!Sphere.spheres)
Sphere.spheres = [];
if(iterations in Sphere.spheres)
return Sphere.spheres[iterations];
// we have to create it...
var vertices = [],
vIndex = {},
indices = [],
addTriangle = function(a,b,c) {
indices.push(a);
indices.push(b);
indices.push(c);
},
addVertex = function(v) {
if(!(v in vIndex)) {
vIndex[v] = vertices.length/3;
vertices.push(v[0]);
vertices.push(v[1]);
vertices.push(v[2]);
}
return vIndex[v];
},
halfway = function(a,b) {
a = [vertices[a*3],vertices[a*3+1],vertices[a*3+2]];
b = [vertices[b*3],vertices[b*3+1],vertices[b*3+2]];
return addVertex(vec3_normalise(vec3_add(a,vec3_scale(vec3_sub(b,a),0.5))));
},
bisect = function(a,b,c,iteration) {
var ab = halfway(a,b),
ac = halfway(a,c),
bc = halfway(b,c),
func = iteration==iterations? addTriangle: bisect;
func(a,ab,ac,iteration+1);
func(b,bc,ab,iteration+1);
func(c,ac,bc,iteration+1);
func(ab,bc,ac,iteration+1);
},
top = addVertex([0,-1,0]),
bottom = addVertex([0,1,0]),
leftFront = addVertex(vec3_normalise([-1,0,-1])),
leftBack = addVertex(vec3_normalise([-1,0,1])),
rightFront = addVertex(vec3_normalise([1,0,-1])),
rightBack = addVertex(vec3_normalise([1,0,1]));
bisect(leftFront,top,rightFront,0);
bisect(rightFront,bottom,leftFront,0);
bisect(leftBack,top,leftFront,0);
bisect(bottom,leftBack,leftFront,0);
bisect(rightFront,top,rightBack,0);
bisect(bottom,rightFront,rightBack,0);
bisect(rightBack,top,leftBack,0);
bisect(bottom,rightBack,leftBack,0);
// and now all the code below is to actually draw it...
// do we have to create our (shared) program for rendering the spheres?
if(!Sphere.program) {
Sphere.program = createProgram(
"precision mediump float;\n"+
"uniform mat4 mvMatrix, pMatrix, nMatrix;\n"+
"attribute vec3 vertex;\n"+
"varying vec3 lighting;\n"+
"void main() {\n"+
" vec3 normal = vertex;\n"+
" gl_Position = pMatrix * mvMatrix * vec4(vertex,1.0);\n"+
" vec3 ambientLight = vec3(0.6,0.6,0.6);\n"+
" vec3 lightColour = vec3(0.8,0.9,0.75);\n"+
" vec3 lightDir = vec3(0.85,0.8,0.75);\n"+
" vec3 transformed = normalize(nMatrix * vec4(normal,1.0)).xyz;\n"+
" float directional = clamp(dot(transformed,lightDir),0.0,1.0);\n"+
" lighting = ambientLight + (lightColour*directional);\n"+
"}",
"precision mediump float;\n"+
"uniform vec4 colour;\n"+
"varying vec3 lighting;\n"+
"void main() {\n"+
" gl_FragColor = vec4(lighting*colour.rgb,colour.a);\n"+
"}");
Sphere.program.vertex = gl.getAttribLocation(Sphere.program,"vertex");
Sphere.program.nMatrix = gl.getUniformLocation(Sphere.program,"nMatrix");
Sphere.program.mvMatrix = gl.getUniformLocation(Sphere.program,"mvMatrix");
Sphere.program.pMatrix = gl.getUniformLocation(Sphere.program,"pMatrix");
Sphere.program.colour = gl.getUniformLocation(Sphere.program,"colour");
}
// return an object that actually can be drawn
var self = {
vVbo: gl.createBuffer(),
iVbo: gl.createBuffer(),
indexCount: indices.length,
draw: function(pMatrix,mvMatrix,sphere,colour,invert) {
var frontFace = gl.getParameter(gl.FRONT_FACE);
gl.frontFace(invert? gl.CCW: gl.CW); // we support inverting so you can draw the sphere as seen from the inside
mvMatrix = mat4_multiply(mvMatrix,mat4_translation(sphere));
mvMatrix = mat4_multiply(mvMatrix,mat4_scale(sphere[3]));
gl.useProgram(Sphere.program);
gl.uniformMatrix4fv(Sphere.program.pMatrix,false,pMatrix);
gl.uniformMatrix4fv(Sphere.program.mvMatrix,false,mvMatrix);
gl.uniformMatrix4fv(Sphere.program.nMatrix,false,mat4_transpose(mvMatrix));
gl.uniform4fv(Sphere.program.colour,colour||[1,1,1,1]);
gl.enableVertexAttribArray(Sphere.program.vertex);
gl.bindBuffer(gl.ARRAY_BUFFER,self.vVbo);
gl.vertexAttribPointer(Sphere.program.vertex,3,gl.FLOAT,false,3*4,0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,self.iVbo);
gl.drawElements(gl.TRIANGLES,self.indexCount,gl.UNSIGNED_SHORT,0);
gl.disableVertexAttribArray(Sphere.program.vertex);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,null);
gl.bindBuffer(gl.ARRAY_BUFFER,null);
gl.useProgram(null);
gl.frontFace(frontFace);
},
};
gl.bindBuffer(gl.ARRAY_BUFFER,self.vVbo);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(vertices),gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER,null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,self.iVbo);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,new Uint16Array(indices),gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,null);
Sphere.spheres[iterations] = self;
return self;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment