Skip to content

Instantly share code, notes, and snippets.

@bellbind
Created October 21, 2009 14:05
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bellbind/215124 to your computer and use it in GitHub Desktop.
Save bellbind/215124 to your computer and use it in GitHub Desktop.
[WebGL] modelview 3d example with no libraries
<!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