Skip to content

Instantly share code, notes, and snippets.

@kioku-systemk
Created September 23, 2014 17:30
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 kioku-systemk/97dde853001ec7323115 to your computer and use it in GitHub Desktop.
Save kioku-systemk/97dde853001ec7323115 to your computer and use it in GitHub Desktop.
Interactive WebGL aobench
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<title>WebGL aobench</title>
<!--
aobench project : https://code.google.com/p/aobench/
original GLSL version http://kioku.sys-k.net/4kgfxmon/
based on ported WebGL version by h013 : http://glsl.heroku.com/e#3159.0
// porting to QC by george toledo, then some tweaks on random func
// by psonice to get rid of abberant dots, then some more tweaks
// to get rid of vertex shader dependencies and transfer to webGL, george toledo.
Update by kioku. [2014/09/23]
-->
<script id="shader" type="x-shader/x-fragment">
#ifdef GL_ES
precision highp float;
#endif
uniform float time;
uniform vec2 resolution;
uniform vec2 eyerot;
struct Ray
{
vec3 org;
vec3 dir;
};
struct Sphere
{
vec3 center;
float radius;
};
struct Plane
{
vec3 p;
vec3 n;
};
struct Intersection
{
float t;
vec3 p; // hit point
vec3 n; // normal
int hit;
};
void shpere_intersect(Sphere s, Ray ray, inout Intersection isect)
{
// rs = ray.org - sphere.center
vec3 rs = ray.org - s.center;
float B = dot(rs, ray.dir);
float C = dot(rs, rs) - (s.radius * s.radius);
float D = B * B - C;
if (D > 0.0)
{
float t = -B - sqrt(D);
if ( (t > 0.0) && (t < isect.t) )
{
isect.t = t;
isect.hit = 1;
// calculate normal.
vec3 p = vec3(ray.org.x + ray.dir.x * t,
ray.org.y + ray.dir.y * t,
ray.org.z + ray.dir.z * t);
vec3 n = p - s.center;
n = normalize(n);
isect.n = n;
isect.p = p;
}
}
}
void plane_intersect(Plane pl, Ray ray, inout Intersection isect)
{
// d = -(p . n)
// t = -(ray.org . n + d) / (ray.dir . n)
float d = -dot(pl.p, pl.n);
float v = dot(ray.dir, pl.n);
if (abs(v) < 1.0e-6)
return; // the plane is parallel to the ray.
float t = -(dot(ray.org, pl.n) + d) / v;
if ( (t > 0.0) && (t < isect.t) )
{
isect.hit = 1;
isect.t = t;
isect.n = pl.n;
vec3 p = vec3(ray.org.x + t * ray.dir.x,
ray.org.y + t * ray.dir.y,
ray.org.z + t * ray.dir.z);
isect.p = p;
}
}
Sphere sphere[3];
Plane plane;
void Intersect(Ray r, inout Intersection i)
{
for (int c = 0; c < 3; c++)
{
shpere_intersect(sphere[c], r, i);
}
plane_intersect(plane, r, i);
}
void orthoBasis(out vec3 basis[3], vec3 n)
{
basis[2] = vec3(n.x, n.y, n.z);
basis[1] = vec3(0.0, 0.0, 0.0);
if ((n.x < 0.6) && (n.x > -0.6))
basis[1].x = 1.0;
else if ((n.y < 0.6) && (n.y > -0.6))
basis[1].y = 1.0;
else if ((n.z < 0.6) && (n.z > -0.6))
basis[1].z = 1.0;
else
basis[1].x = 1.0;
basis[0] = cross(basis[1], basis[2]);
basis[0] = normalize(basis[0]);
basis[1] = cross(basis[2], basis[0]);
basis[1] = normalize(basis[1]);
}
float random(float seed)
{
float seed2 = (mod((seed)*1364.0+626.0, 509.0));
return seed2/509.0;
}
vec3 computeAO(inout Intersection isect)
{
int ntheta = 6;//irritating, guess I cant use a variable in a loop in webGL? Maybe I heard this already. -gtoledo
int nphi = 6;
float eps = 0.0001;
// Slightly move ray org towards ray dir to avoid numerical probrem.
vec3 p = vec3(isect.p.x + eps * isect.n.x,
isect.p.y + eps * isect.n.y,
isect.p.z + eps * isect.n.z);
// Calculate orthogonal basis.
vec3 basis[3];
orthoBasis(basis, isect.n);
float occlusion = 0.0;
for (int j = 0; j < 6; j++)//woulda used ntheta.-gtoledo
{
for (int i = 0; i < 6; i++)//woulda used nphi.-gtoledo
{
float s = isect.p.x += isect.p.y * 57. + isect.p.z * 21.;
s = sin(cos(s) * s)*.5+.5;
// Pick a random ray direction with importance sampling.
// p = cos(theta) / 3.141592
float r = random(s*0.7);
float phi = 2.0 * 3.141592 * random(s*3000.);
vec3 ref;
ref.x = cos(phi) * sqrt(1.0 - r);
ref.y = sin(phi) * sqrt(1.0 - r);
ref.z = sqrt(r);
// local -> global
vec3 rray;
rray.x = ref.x * basis[0].x + ref.y * basis[1].x + ref.z * basis[2].x;
rray.y = ref.x * basis[0].y + ref.y * basis[1].y + ref.z * basis[2].y;
rray.z = ref.x * basis[0].z + ref.y * basis[1].z + ref.z * basis[2].z;
vec3 raydir = vec3(rray.x, rray.y, rray.z);
Ray ray;
ray.org = p;
ray.dir = raydir;
Intersection occIsect;
occIsect.hit = 0;
occIsect.t = 1.0e+30;
occIsect.n = occIsect.p = vec3(0, 0, 0);
Intersect(ray, occIsect);
if (occIsect.hit != 0)
occlusion += 1.0;
}
}
// [0.0, 1.0]
occlusion = (float(ntheta * nphi) - occlusion) / float(ntheta * nphi);
return vec3(occlusion, occlusion, occlusion);
}
void main()
{
sphere[0].center = vec3(-2.0, 0.0, -0.5);
sphere[0].radius = 0.5;
sphere[1].center = vec3(-0.5, 0.0, 0.0);
sphere[1].radius = 0.5;
sphere[2].center = vec3(1.0, 0.0, 0.8);
sphere[2].radius = 0.5;
plane.p = vec3(0,-0.5, 0);
plane.n = vec3(0, 1.0, 0);
Intersection i;
i.hit = 0;
i.t = 1.0e+30;
i.n = i.p = vec3(0, 0, 0);
vec3 org = vec3(0,0,3);
vec2 pixel = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy;
float asp = resolution.x / resolution.y;
vec3 dir = normalize(vec3(asp*pixel.x, pixel.y, 2.0) - org);
float xcs = cos(-eyerot.x / 180.0 * 3.1415926);
float xsn = sin(-eyerot.x / 180.0 * 3.1415926);
float ycs = cos(-eyerot.y / 180.0 * 3.1415926);
float ysn = sin(-eyerot.y / 180.0 * 3.1415926);
mat3 rotX = mat3(1.0, 0.0, 0.0,
0.0, ycs, ysn,
0.0,-ysn, ycs);
mat3 rotY = mat3(xcs, 0.0, -xsn,
0.0, 1.0, 0.0,
xsn, 0.0, xcs);
dir = rotY * rotX * dir;
org = rotY * rotX * org;
Ray r;
r.org = org;
r.dir = normalize(dir);
vec4 col = vec4(0,0,0,0);
Intersect(r, i);
if (i.hit != 0)
{
col.rgb = computeAO(i);
}
gl_FragColor = col;
gl_FragColor.a =1.0;
}
</script>
<script>
var mx, my,
ex = 0, ey = 0,
mpress = false;
window.onmousedown = function (e) {
mx = e.clientX;
my = e.clientY;
mpress = true;
}
window.onmouseup = function (e) {
mpress = false;
}
window.onmousemove = function (e) {
if (mpress) {
ex += e.clientX - mx;
ey += e.clientY - my;
}
mx = e.clientX;
my = e.clientY;
}
window.ontouchstart = function (e) {
e.preventDefault();
mx = e.touches[0].pageX;
my = e.touches[0].pageY;
mpress = true;
}
window.ontouchend = function (e) {
e.preventDefault();
mpress = false;
}
window.ontouchmove = function (e) {
e.preventDefault();
if (mpress) {
ex += e.touches[0].pageX - mx;
ey += e.touches[0].pageY - my;
}
mx = e.touches[0].pageX;
my = e.touches[0].pageY;
}
window.onload = function(){
var c = document.getElementById('c'),
g = c.getContext('webgl') || c.getContext('experimental-webgl');
c.style.position = "fixed";
c.style.left = c.style.top = 0;
with(g){
var fs= createShader(FRAGMENT_SHADER),
vs= createShader(VERTEX_SHADER),
shader = document.getElementById("shader").text;
shaderSource(vs, "attribute vec4 p;void main(){gl_Position=p;}");
shaderSource(fs, shader);
compileShader(vs);
compileShader(fs);
if(!g.getShaderParameter(fs, g.COMPILE_STATUS)){
console.log(g.getShaderInfoLog(fs));
//return;
}
pr = createProgram();
attachShader(pr, vs);
attachShader(pr, fs);
linkProgram(pr);
bindBuffer(ARRAY_BUFFER, createBuffer());
bufferData(ARRAY_BUFFER, new Float32Array([1,1,1,-3,-3,1]), STATIC_DRAW);
var stm = new Date().getTime();
var mW, mH, frameCount = 0, oldDate = new Date();
function draw(){with(g){
var w = window.innerWidth,
h = window.innerHeight,
date = new Date(),
fps = document.getElementById('fps');
// fps
frameCount = frameCount + 1;
if (date - oldDate > 1000) {
fps.innerHTML = frameCount + 'fps';
frameCount = 0;
oldDate = date;
}
if (w != mW || h != mH) {
mW = c.width = w;
mH = c.height = h;
g.viewport(0, 0, w, h);
}
useProgram(pr);
uniform2fv(getUniformLocation(pr,"resolution"),[mW,mH]);
uniform1f(getUniformLocation(pr,"time"),(new Date().getTime() - stm)/1000.0);
uniform2fv(getUniformLocation(pr,"eyerot"),[ex,ey]);
enableVertexAttribArray(0);
vertexAttribPointer(0, 2, FLOAT, false, 0, 0);
drawArrays(TRIANGLES, 0, 3);
}}
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
(function animloop(){
requestAnimFrame(animloop);
draw();
})();
}
}
</script>
</head>
<body>
<canvas id="c" ></canvas>
<p id="fps" style="position:absolute;left:5px;top:5px;color:red">0fps</p>
<p style="position:absolute;right:5px;bottom:5px">Interactive WebGL aobench [coded by <a href="https://twitter.com/kioku_systemk">@kioku_systemk</a>] /
<a href="https://code.google.com/p/aobench/" >about aobench</a>
</p>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment