glsl ball test
by manland
HTML
<script src="https://raw.github.com/gre/glsl.js/master/glsl.min.js"></script>
<canvas id="viewport" width="600" height="400"></canvas>
<script id="fragment" type="x-shader/x-fragment">
#ifdef GL_ES
precision mediump float;
#endif
uniform float time;
uniform vec3 camera;
uniform vec2 mouse;
uniform vec2 resolution;
float deSphere(vec3 p, float r)
{
return length(p) - r;
}
float de(vec3 p)
{
return deSphere(p, 1.0);
}
vec3 normal(in vec3 pos)
{
float f = de(pos);
vec3 e = vec3(0.001, 0.0, 0.0);
vec3 n;
n.x = de(pos + e.xyy) - de(pos - e.xyy);
n.y = de(pos + e.yxy) - de(pos - e.yxy);
n.z = de(pos + e.yyx) - de(pos - e.yyx);
return normalize(n);
}
void main( void )
{
const float epsilon = 0.01;
vec2 position = ((( gl_FragCoord.xy / resolution.xy ) * 2.0) - 1.0) * vec2(resolution.x / resolution.y, 1.0);
vec3 ray = vec3(0.0, 0.0, -2.0);
vec3 cam = vec3(position.x + camera.x, position.y + camera.y, camera.z);
vec3 direction = normalize(cam);
vec4 color = vec4(0.0);
vec2 m = (mouse * 2.0) - 1.0;
vec3 light = vec3(m.x, m.y, -2.5) * vec3(2.0, 2.0, 1.0);
for(int i = 0; i < 10; i++) {
float dist = de(ray);
if(dist < epsilon) {
vec3 n = normal(ray);
vec3 l = normalize(light - ray);
// diffuse
float lt = clamp(dot(l, n), 0.0, 1.0);
color = lt * vec4(1.0);
// light attenuation
float atte = 1.0 / length(light - ray);
color *= atte;
// specular
vec3 e = -direction;
vec3 h = normalize(l + e);
float s = pow(dot(h, n), 20.0) * 0.5;
color += vec4(s);
break;
}
ray += 0.75 * direction * dist;
}
gl_FragColor = vec4(color.xyz, 1.0);
}
</script>
CSS
body {
background-color:black;
}
canvas {
border-radius:50px;
margin:auto;
display:block;
}
JavaScript
var mouse = {"x":0.0,"y":0.0};
var camera = {"x":0.0,"y":0.0,"z":1.0};
var viewport = document.getElementById("viewport");
viewport.onmousemove = function(evt) {
console.log(evt);
mouse.x = (evt.clientX - viewport.offsetLeft) / viewport.clientWidth;
mouse.y = 1 - (evt.clientY / viewport.clientHeight);
}
document.onkeypress = function(e) {
e = e || window.event;
if (e.keyCode == 37) {
camera.x = camera.x + 0.01;
}
if(e.keyCode == 39) {
camera.x = camera.x - 0.01;
}
if(e.keyCode == 38) {
camera.y = camera.y - 0.01;
}
if(e.keyCode == 40) {
camera.y = camera.y + 0.01;
}
//alert("Character typed: " + e.keyCode);
};
viewport.addEventListener('DOMMouseScroll', function(evt) {
var delta=evt.detail? evt.detail*(-120) : evt.wheelDelta;
if(delta > 0) {
camera.z = camera.z + 0.01;
} else {
camera.z = camera.z - 0.01;
}
}, false);
var glsl = Glsl({
canvas: viewport,
fragment: document.getElementById("fragment").innerHTML,
variables: {
time: 0, // The time in ms
mouse: mouse,
camera: camera
},
update: function (time) {
this.sync("mouse");
this.sync("camera");
}
}).start();