Instantly share code, notes, and snippets.

Embed
What would you like to do?
<html>
<head>
<title>Will's quick mandelbulb GLSL</title>
<script type="application/javascript">
var canvas, gl, program;
function start() {
window.onerror = function(msg, url, lineno) {
alert(url + '(' + lineno + '): ' + msg);
};
canvas = document.getElementById("game-canvas");
try {
gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
} catch(e) {}
if(!gl) {
alert("Unable to initialize WebGL. Your browser may not support it.");
return;
}
gl.clearColor(0,0,0,1);
var vs =
'uniform mat4 inv_mvp;\n' +
'attribute vec2 vertex;\n' +
'varying vec2 pos;\n' +
'varying vec3 near, far;\n'+
'void main() {\n'+
' gl_Position = vec4(vertex,0,1);\n' +
' pos = vertex;\n' +
' vec4 p = (inv_mvp * vec4(pos,0,1));\n' +
' near = p.xyz / p.w;\n' +
' p = (inv_mvp * vec4(pos,1,1));\n' +
' far = p.xyz / p.w;\n' +
'}\n';
var fs =
'precision mediump float;\n' +
'varying vec2 pos;\n' +
'varying vec3 near, far;\n' +
'const float Power = 8.0;\n' +
'const float BailOut = 7.0;\n' +
'const int Iterations = 5;\n' +
'float DE(vec3 pos) {\n' +
' vec3 z = pos;\n' +
' float dr = 1.0;\n' +
' float r = 0.0;\n' +
' for(int i = 0; i < Iterations; i++) {\n' +
' r = length(z);\n' +
' if (r>BailOut) break;\n' +
' // convert to polar coordinates\n' +
' float theta = acos(z.z/r);\n' +
' float phi = atan(z.y,z.x);\n' +
' dr = pow(r,Power-1.0)*Power*dr + 1.0;\n' +
' // scale and rotate the point\n' +
' float zr = pow(r,Power);\n' +
' theta = theta*Power;\n' +
' phi = phi*Power;\n' +
' // convert back to cartesian coordinates\n' +
' z = zr*vec3(sin(theta)*cos(phi), sin(phi)*sin(theta), cos(theta));\n' +
' z+=pos;\n' +
' }\n' +
' return 0.5*log(r)*r/dr;\n' +
'}\n' +
'const int MaxRaySteps = 100;\n' +
'const float MinimumDistance = 0.00001;\n' +
'void main() {\n' +
' vec3 direction = far-near;\n' +
' float maximumDistance = length(direction);\n' +
' direction = normalize(direction);\n' +
' float totalDistance = 0.0, distance;\n' +
' int steps = 0;\n' +
' for(int i=0; i<MaxRaySteps; i++) {\n' +
' distance = DE(near + totalDistance * direction);\n' +
' totalDistance += distance;\n' +
' if(distance < MinimumDistance) break;\n' +
' if(totalDistance > maximumDistance) discard;\n' +
' steps++;\n' +
' }\n' +
' // super simple colouring based on number of steps\n' +
' distance = 1.0-float(steps)/float(MaxRaySteps);\n' +
' gl_FragColor = vec4(distance,distance,distance,1.0);\n' +
'}\n';
program = createProgram(vs,fs);
gl.useProgram(program);
var vertexPosBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,vertexPosBuffer);
var vertices = [-1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1]; // two triangles that fill the screen, promise
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(vertices),gl.STATIC_DRAW);
program.vertexPosAttrib = gl.getAttribLocation(program,'vertex');
gl.enableVertexAttribArray(program.vertexPosAttrib);
gl.vertexAttribPointer(program.vertexPosAttrib,2,gl.FLOAT,false,0,0);
render();
}
var start_time = (new Date()).getTime();
function render() {
var elapsed = (((new Date()).getTime() - start_time) / 1000) / 2;
gl.clear(gl.COLOR_BUFFER_BIT);
// we swing and spin a bit
var distance = 2,
modelview = createLookAt([Math.cos(elapsed)*Math.sin(elapsed)*distance,Math.sin(elapsed)*distance,Math.cos(elapsed)*1.1],[0,0,0],[0,0,1]),
perspective = createPerspective(60.0,canvas.width/canvas.height,0.1,distance+2),
inv_mvp = mat4_inverse(mat4_multiply(perspective,modelview));
gl.uniformMatrix4fv(gl.getUniformLocation(program,"inv_mvp"),false,new Float32Array(inv_mvp));
gl.drawArrays(gl.TRIANGLES,0,6);
window.requestAnimFrame(render);
}
function createShader(str,type) {
var shader = gl.createShader(type);
gl.shaderSource(shader,str);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader,gl.COMPILE_STATUS))
throw gl.getShaderInfoLog(shader);
return shader;
}
function createProgram(vstr,fstr) {
var program = gl.createProgram();
var vshader = createShader(vstr,gl.VERTEX_SHADER);
var fshader = createShader(fstr,gl.FRAGMENT_SHADER);
gl.attachShader(program,vshader);
gl.attachShader(program,fshader);
gl.linkProgram(program);
return program;
}
function createLookAt(eye,centre,up) {
if (eye[0] == centre[0] && eye[1] == centre[1] && eye[2] == centre[2])
return [1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1];
var z0,z1,z2,x0,x1,x2,y0,y1,y2,len;
//vec3.direction(eye, center, z);
z0 = eye[0] - centre[0];
z1 = eye[1] - centre[1];
z2 = eye[2] - centre[2];
// normalize (no check needed for 0 because of early return)
len = 1/Math.sqrt(z0*z0 + z1*z1 + z2*z2);
z0 *= len;
z1 *= len;
z2 *= len;
//vec3.normalize(vec3.cross(up, z, x));
x0 = up[1]*z2 - up[2]*z1;
x1 = up[2]*z0 - up[0]*z2;
x2 = up[0]*z1 - up[1]*z0;
len = Math.sqrt(x0*x0 + x1*x1 + x2*x2);
if (!len) {
x0 = 0;
x1 = 0;
x2 = 0;
} else {
len = 1/len;
x0 *= len;
x1 *= len;
x2 *= len;
};
//vec3.normalize(vec3.cross(z, x, y));
y0 = z1*x2 - z2*x1;
y1 = z2*x0 - z0*x2;
y2 = z0*x1 - z1*x0;
len = Math.sqrt(y0*y0 + y1*y1 + y2*y2);
if (!len) {
y0 = 0;
y1 = 0;
y2 = 0;
} else {
len = 1/len;
y0 *= len;
y1 *= len;
y2 *= len;
}
return [x0, y0, z0, 0,
x1, y1, z1, 0,
x2, y2, z2, 0,
-(x0*eye[0] + x1*eye[1] + x2*eye[2]), -(y0*eye[0] + y1*eye[1] + y2*eye[2]), -(z0*eye[0] + z1*eye[1] + z2*eye[2]), 1];
}
function createPerspective(fovy,aspect,near,far) {
var top = near*Math.tan(fovy*Math.PI/360.0);
var right = top*aspect, left = -right, bottom = -top;
var rl = (right-left);
var tb = (top-bottom);
var fn = (far-near);
return [(near*2)/rl, 0, 0, 0,
0, (near*2)/tb, 0, 0,
(right+left)/rl, (top+bottom)/tb, -(far+near)/fn, -1,
0, 0, -(far*near*2)/fn, 0];
}
function mat4_multiply(a,b) {
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
var b00 = b[0], b01 = b[1], b02 = b[2], b03 = b[3];
var b10 = b[4], b11 = b[5], b12 = b[6], b13 = b[7];
var b20 = b[8], b21 = b[9], b22 = b[10], b23 = b[11];
var b30 = b[12], b31 = b[13], b32 = b[14], b33 = b[15];
return [b00*a00 + b01*a10 + b02*a20 + b03*a30,
b00*a01 + b01*a11 + b02*a21 + b03*a31,
b00*a02 + b01*a12 + b02*a22 + b03*a32,
b00*a03 + b01*a13 + b02*a23 + b03*a33,
b10*a00 + b11*a10 + b12*a20 + b13*a30,
b10*a01 + b11*a11 + b12*a21 + b13*a31,
b10*a02 + b11*a12 + b12*a22 + b13*a32,
b10*a03 + b11*a13 + b12*a23 + b13*a33,
b20*a00 + b21*a10 + b22*a20 + b23*a30,
b20*a01 + b21*a11 + b22*a21 + b23*a31,
b20*a02 + b21*a12 + b22*a22 + b23*a32,
b20*a03 + b21*a13 + b22*a23 + b23*a33,
b30*a00 + b31*a10 + b32*a20 + b33*a30,
b30*a01 + b31*a11 + b32*a21 + b33*a31,
b30*a02 + b31*a12 + b32*a22 + b33*a32,
b30*a03 + b31*a13 + b32*a23 + b33*a33];
}
function mat4_inverse(mat) {
var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3];
var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7];
var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11];
var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15];
var b00 = a00*a11 - a01*a10;
var b01 = a00*a12 - a02*a10;
var b02 = a00*a13 - a03*a10;
var b03 = a01*a12 - a02*a11;
var b04 = a01*a13 - a03*a11;
var b05 = a02*a13 - a03*a12;
var b06 = a20*a31 - a21*a30;
var b07 = a20*a32 - a22*a30;
var b08 = a20*a33 - a23*a30;
var b09 = a21*a32 - a22*a31;
var b10 = a21*a33 - a23*a31;
var b11 = a22*a33 - a23*a32;
var invDet = 1/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);
return [
(a11*b11 - a12*b10 + a13*b09)*invDet,
(-a01*b11 + a02*b10 - a03*b09)*invDet,
(a31*b05 - a32*b04 + a33*b03)*invDet,
(-a21*b05 + a22*b04 - a23*b03)*invDet,
(-a10*b11 + a12*b08 - a13*b07)*invDet,
(a00*b11 - a02*b08 + a03*b07)*invDet,
(-a30*b05 + a32*b02 - a33*b01)*invDet,
(a20*b05 - a22*b02 + a23*b01)*invDet,
(a10*b10 - a11*b08 + a13*b06)*invDet,
(-a00*b10 + a01*b08 - a03*b06)*invDet,
(a30*b04 - a31*b02 + a33*b00)*invDet,
(-a20*b04 + a21*b02 - a23*b00)*invDet,
(-a10*b09 + a11*b07 - a12*b06)*invDet,
(a00*b09 - a01*b07 + a02*b06)*invDet,
(-a30*b03 + a31*b01 - a32*b00)*invDet,
(a20*b03 - a21*b01 + a22*b00)*invDet];
}
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 0);
};
})();
</script>
</head>
<body onload="start()">
<canvas id="game-canvas" style="width:100%;height:100%;">
Your browser does not support WebGL :(
</canvas>
</body>
</html>
@adammaj1

This comment has been minimized.

Show comment
Hide comment
@adammaj1

adammaj1 Jun 28, 2015

it works on firefox 38.0.5 and ubuntu

adammaj1 commented Jun 28, 2015

it works on firefox 38.0.5 and ubuntu

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment