Created
October 21, 2009 14:05
-
-
Save bellbind/215124 to your computer and use it in GitHub Desktop.
[WebGL] modelview 3d example with no libraries
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<script>//<![CDATA[ | |
// WebGL example | |
top.CanvasFloatArray = top.CanvasFloatArray || WebGLFloatArray; | |
var gl; | |
var program; | |
var start = function () { | |
var canvas = document.getElementById("canvas"); | |
try { | |
gl = canvas.getContext("webkit-3d"); | |
} catch (ex) { | |
gl = canvas.getContext("moz-webgl"); | |
} | |
// settings | |
gl.clearColor(0.0, 0.0, 0.0, 1.0); | |
if (gl.clearDepth) gl.clearDepth(1.0); else gl.clearDepthf(1.0); | |
gl.enable(gl.DEPTH_TEST); | |
gl.enable(gl.CULL_FACE); | |
gl.cullFace(gl.BACK); | |
// start | |
updateShaders(); | |
render(); | |
setInterval(render, 100); | |
}; | |
var updateShaders = function () { | |
var vs = gl.createShader(gl.VERTEX_SHADER); | |
var vsSource = document.getElementById("vs").value; | |
gl.shaderSource(vs, vsSource); | |
gl.compileShader(vs); | |
var fs = gl.createShader(gl.FRAGMENT_SHADER); | |
var fsSource = document.getElementById("fs").value; | |
gl.shaderSource(fs, fsSource); | |
gl.compileShader(fs); | |
program = gl.createProgram(); | |
gl.attachShader(program, vs); | |
gl.attachShader(program, fs); | |
gl.linkProgram(program); | |
gl.useProgram(program); | |
}; | |
var render = function () { | |
// put perspective and lookAt matrix into shader | |
var perspectiveData = perspectiveMatrix(Math.PI / 2, 1.0, 4.0, 6.0); | |
var lookAtData = lookAtMatrix( | |
Vec3(0.5, 0.5, 5), Vec3(0, 0, 0), Vec3(0, 1, 0)); | |
var perspective = gl.getUniformLocation(program, "perspective"); | |
gl.uniformMatrix4fv(perspective, false, | |
new CanvasFloatArray(perspectiveData)); | |
var lookAt = gl.getUniformLocation(program, "lookAt"); | |
gl.uniformMatrix4fv(lookAt, false, | |
new CanvasFloatArray(lookAtData)); | |
// put vertex and normal into shader | |
var verts = [ | |
Vec3(0.0, 0.0, 1.0), Vec3(0.5, -0.5, 0.0), Vec3(0.0, 0.5, 0.0), | |
Vec3(0.0, 0.0, 1.0), Vec3(-0.5, -0.5, 0.0), Vec3(0.5, -0.5, 0.0), | |
Vec3(0.0, 0.0, 1.0), Vec3(0.0, 0.5, 0.0), Vec3(-0.5, -0.5, 0.0), | |
Vec3(0.0, 0.5, 0.0), Vec3(-0.5, -0.5, 0.0), Vec3(0.5, -0.5, 0.0), | |
]; | |
var normals = []; | |
for (var i = 0; i < verts.length; i += 3) { | |
var a = verts[i + 0]; var b = verts[i + 1]; var c = verts[i + 2]; | |
var normal = a.sub(b).cross(c.sub(b)).normalize(); | |
normals.push(normal); normals.push(normal); normals.push(normal); | |
} | |
var buffer = gl.createBuffer(); | |
gl.bindBuffer(gl.ARRAY_BUFFER, buffer); | |
gl.bufferData(gl.ARRAY_BUFFER, | |
new CanvasFloatArray(flatten(verts)), gl.STATIC_DRAW); | |
var position = gl.getAttribLocation(program, "position"); | |
gl.vertexAttribPointer(position, 3, gl.FLOAT, false, 0, 0); | |
gl.enableVertexAttribArray(position); | |
var nbuffer = gl.createBuffer(); | |
gl.bindBuffer(gl.ARRAY_BUFFER, nbuffer); | |
gl.bufferData(gl.ARRAY_BUFFER, | |
new CanvasFloatArray(flatten(normals)), gl.STATIC_DRAW); | |
var normal = gl.getAttribLocation(program, "normal"); | |
gl.vertexAttribPointer(normal, 3, gl.FLOAT, false, 0, 0); | |
gl.enableVertexAttribArray(normal); | |
// clear and draw | |
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); | |
gl.drawArrays(gl.TRIANGLES, 0, verts.length); | |
}; | |
var flatten = function (obj) { | |
if (!(obj instanceof Array)) return [obj]; | |
var ret = []; | |
for (var i = 0; i < obj.length; i += 1) { | |
ret = ret.concat(flatten(obj[i])); | |
} | |
return ret; | |
}; | |
// utilities: vector and matrix | |
var Vec3 = function (x, y, z) { | |
var vec = [x, y, z]; | |
vec.x = x; | |
vec.y = y; | |
vec.z = z; | |
vec.len = function () { | |
return Math.sqrt(x * x + y * y + z * z); | |
}; | |
vec.is_zero = function () { | |
return vec.len() == 0; | |
}; | |
vec.mul = function (a) { | |
return Vec3(a * x, a * y, a * z); | |
}; | |
vec.normalize = function () { | |
return vec.is_zero() ? vec : vec.mul(1 / vec.len()); | |
}; | |
vec.dot = function (other) { | |
return x * other.x + y * other.y + z * other.z; | |
}; | |
vec.add = function (other) { | |
return Vec3(x + other.x, y + other.y, z + other.z); | |
}; | |
vec.sub = function (other) { | |
return Vec3(x - other.x, y - other.y, z - other.z); | |
}; | |
vec.cross = function (other) { | |
return Vec3( | |
y * other.z - z * other.y, | |
z * other.x - x * other.z, | |
x * other.y - y * other.x); | |
}; | |
vec.reflect = function (other) { | |
// TBD: it it ok? | |
var d2 = vec.dot(other) * 2; | |
return Vec3(x - d2 * other.x, y - d2 * other.y, z - d2 * other.z); | |
//return other.add(other.sub(vec)); | |
}; | |
return vec; | |
}; | |
var perspectiveMatrix = function (fov, aspect, near, far) { | |
// as gluPerspective(), but "fov" is radian, aspect = h / w | |
var zoom = 1.0 / Math.tan(fov / 2); | |
return tr([ | |
zoom / aspect, 0, 0, 0, | |
0, zoom, 0, 0, | |
0, 0, (far + near) / (near - far), 2 * far * near / (near - far), | |
0, 0, -1, 0, | |
]); | |
}; | |
var lookAtMatrix = function (eye, center, up) { | |
// as gluLookAt(), but each params are Vec3 | |
var lz = center.sub(eye).normalize(); // z-axis of eye ray | |
var nup = up.normalize(); | |
var lx = lz.cross(nup); // x-axis of eye ray | |
var ly = lx.cross(lz); // y-axis of eye ray | |
return tr([ | |
lx.x, lx.y, lx.z, -eye.x, | |
ly.x, ly.y, ly.z, -eye.y, | |
-lz.x, -lz.y, -lz.z, -eye.z, | |
0, 0, 0, 1, | |
]); // = identity4.rotate(lx, ly, -lz).translate(-eye) | |
}; | |
// for C array layout of OpenGL matrix | |
var tr = function (mat) { | |
return [ | |
mat[0], mat[4], mat[8], mat[12], | |
mat[1], mat[5], mat[9], mat[13], | |
mat[2], mat[6], mat[10], mat[14], | |
mat[3], mat[7], mat[11], mat[15], | |
]; | |
}; | |
//]]></script> | |
</head> | |
<body onload="start()"> | |
<div> | |
<canvas id="canvas" style="width: 300px; height: 300px;" /> | |
</div> | |
<hr /> | |
<form> | |
<textarea id="vs" rows="10" cols="80"> | |
#version 110 | |
// GLSL ES 1.00 is based on GLSL 1.10 | |
uniform mat4 perspective; | |
uniform mat4 lookAt; | |
//attribute is deprecated from GLSL 1.30. => "in" | |
attribute vec3 position; | |
//in vec3 position; | |
attribute vec3 normal; | |
//in vec3 normal; | |
// varying is also deprecated from GLSL 1.30. => "out" in VS / "in" in FS | |
varying vec3 color; | |
//out vec3 color; | |
// struct definition and constructor | |
struct material { | |
vec3 color; | |
float ambient; | |
float diffuse; | |
float specular; | |
}; | |
const material mat = material(vec3(1.0, 0.5, 0.5), 0.3, 0.4, 0.3); | |
const vec3 light = normalize(vec3(10.0, -5.5, 15.5)); | |
vec3 lighting(vec3 position, vec3 normal, vec3 light, material mat); | |
void main(void) | |
{ | |
//gl_Position = vec4(position, 1.0); | |
gl_Position = perspective * lookAt * vec4(position, 1.0); | |
color = lighting(position, normal, light, mat); | |
} | |
vec3 lighting(vec3 position, vec3 normal, vec3 light, material mat) | |
{ | |
vec3 reflectLight = normalize(reflect(-light, normal)); | |
vec3 eyeDir = normalize(-position); | |
float spec = mat.specular * max(dot(eyeDir, reflectLight), 0.0); | |
float diff = mat.diffuse * max(dot(normal, light), 0.0); | |
float d = mat.ambient + diff; | |
return d * mat.color + spec * vec3(1.0, 1.0, 1.0); | |
} | |
</textarea> | |
<button type="button" onclick="updateShaders()">update</button> | |
<hr /> | |
<textarea id="fs" rows="10" cols="80"> | |
#version 110 | |
varying vec3 color; | |
//in vec3 color; | |
// gl_FragColor is deprecated from GLSL 1.30 => user defined "out vec4" | |
//out vec4 fragColor; | |
void main(void) { | |
gl_FragColor = vec4(color, 1.0); | |
//fragColor = vec4(color, 1.0); | |
} | |
</textarea> | |
<button type="button" onclick="updateShaders()">update</button> | |
<hr /> | |
</form> | |
<div id="out"></div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment