JavaScript/WebGL
Aus SELFHTML-Wiki
WebGL (Web Graphics Library) ist eine Programmierschnittstelle, mit der Sie hardwarebeschleunigte 3D-Grafiken im canvas-Element direkt im Browser – ohne zusätzliche Erweiterungen – darstellen können. Während die steuernden Scripte aus JavaScript bestehen, werden die Shader in speziellen Sprachen wie GLSL geschrieben und in Maschinencode für die GPU übersetzt.
WebGL ist keine Spezifikation der W3C, sondern wird von der KhronosGroup und Mozilla aus OpenGL ES (Version 2.0) im Zusammenspiel mit JavaScript als lizenzfreier Standard entwickelt.
Beachten Sie: Da WebGL auf hardwarebeschleunigten 3D-Grafiken beruht, müssen neben den Browsern auch die Videotreiber auf aktuellem Stand sein.
Inhaltsverzeichnis
Anwendung
Aufruf
Beispiel
function initWebGL() {
gl = null;
try {
gl = canvas.getContext("webgl");
}
catch(e) {
}
// Fehlermeldung
if (!gl) {
alert("WebGL konnte nicht initialisiert werden.");
gl = null;
}
return gl;
}
Jupiter und seine Monde
Ein Beispiel von Orlok[1]
Jupiter und seine Monde in WebGL
ansehen …
<script id="vertexshader" type="shader/x-glsl">
attribute vec4 aVertexPosition;
attribute vec3 aVertexNormal;
attribute vec2 aTextureCoord;
uniform mat4 uProjectionMatrix;
uniform mat4 uWorldMatrix;
uniform mat3 uNormalMatrix;
varying vec4 vPosition;
varying vec3 vTransformedNormal;
varying vec2 vTextureCoord;
void main (void) {
vTextureCoord = aTextureCoord;
vTransformedNormal = uNormalMatrix * aVertexNormal;
vPosition = uWorldMatrix * aVertexPosition;
gl_Position = uProjectionMatrix * vPosition;
}
</script>
<script id="fragmentshader" type="shader/x-glsl">
precision highp float;
uniform sampler2D uSampler;
uniform bool uLightingEnabled;
uniform vec3 uLightPosition;
varying vec4 vPosition;
varying vec3 vTransformedNormal;
varying vec2 vTextureCoord;
const vec3 ambientColor = vec3(0.1, 0.1, 0.1);
const vec3 diffuseColor = vec3(0.8, 0.8, 0.8);
void main (void) {
vec3 lightWeighting;
if (uLightingEnabled) {
vec3 direction = normalize(uLightPosition - vPosition.xyz);
float diffuse = max(dot(normalize(vTransformedNormal), direction), 0.0);
lightWeighting = ambientColor + diffuseColor * diffuse;
} else {
lightWeighting = vec3(0.3, 0.3, 0.3);
}
vec4 fragmentColor = texture2D(uSampler, vTextureCoord);
gl_FragColor = vec4(fragmentColor.rgb * lightWeighting, 1.0);
}
</script>
<script>
var SCENE = {
getWebGLContext : function (canvas) {
var i, context = null;
var names = ['webgl', 'experimental-webgl', 'moz-webgl', 'webkit-3d'];
for (i = 0; i < names.length; i += 1) {
try {
context = canvas.getContext(names[i]);
if (context) {
break;
}
} catch (e) { };
}
return context;
},
getShaderSource : function (id) {
var script = document.getElementById(id);
var source = '';
var child = script.firstChild;
while (child) {
if (child.nodeType === 3) {
source += child.textContent;
}
child = child.nextSibling;
}
return source;
},
getSphere : function (bands, radius) {
radius = radius || 1;
var longitudeBands = bands || 50,
latitudeBands = bands || 50;
var l, m;
var sphere = { vertices : [ ], normals : [ ], texCoords : [ ] };
for (l = 0; l <= latitudeBands; l += 1) {
var theta = l * Math.PI / latitudeBands;
var sinTheta = Math.sin(theta),
cosTheta = Math.cos(theta);
for (m = 0; m <= longitudeBands; m += 1) {
var phi = m * 2 * Math.PI / longitudeBands;
var sinPhi = Math.sin(phi),
cosPhi = Math.cos(phi);
var x = cosPhi * sinTheta,
y = cosTheta,
z = sinPhi * sinTheta;
var u = 1 - (m / longitudeBands),
v = 1 - (l / latitudeBands);
sphere.vertices.push(radius * x, radius * y, radius * z);
sphere.normals.push(x, y, z);
sphere.texCoords.push(u, v);
}
}
sphere.indices = [ ];
for (l = 0; l < latitudeBands; l += 1) {
for (m = 0; m < longitudeBands; m += 1) {
var a = (l * (longitudeBands + 1)) + m;
var b = a + longitudeBands + 1;
sphere.indices.push(a, b, a + 1, b, b + 1, a + 1);
}
}
return sphere;
},
createMat3 : function ( ) {
var mat3 = new Float32Array(9);
mat3[0] = 1; mat3[1] = 0; mat3[2] = 0;
mat3[3] = 0; mat3[4] = 1; mat3[5] = 0;
mat3[6] = 0; mat3[7] = 0; mat3[8] = 1;
return mat3;
},
identityMat3 : function (mat3) {
mat3[0] = 1; mat3[1] = 0; mat3[2] = 0;
mat3[3] = 0; mat3[4] = 1; mat3[5] = 0;
mat3[6] = 0; mat3[7] = 0; mat3[8] = 1;
return mat3;
},
normalMat3FromMat4 : function (mat4, mat3) {
var a00 = mat4[0], a01 = mat4[1], a02 = mat4[2], a03 = mat4[3],
a10 = mat4[4], a11 = mat4[5], a12 = mat4[6], a13 = mat4[7],
a20 = mat4[8], a21 = mat4[9], a22 = mat4[10], a23 = mat4[11],
a30 = mat4[12], a31 = mat4[13], a32 = mat4[14], a33 = mat4[15];
var b00 = a00 * a11 - a01 * a10, b01 = a00 * a12 - a02 * a10,
b02 = a00 * a13 - a03 * a10, b03 = a01 * a12 - a02 * a11,
b04 = a01 * a13 - a03 * a11, b05 = a02 * a13 - a03 * a12,
b06 = a20 * a31 - a21 * a30, b07 = a20 * a32 - a22 * a30,
b08 = a20 * a33 - a23 * a30, b09 = a21 * a32 - a22 * a31,
b10 = a21 * a33 - a23 * a31, b11 = a22 * a33 - a23 * a32;
var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
if (!det) {
return null;
}
det = 1.0 / det;
mat3[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
mat3[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
mat3[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
mat3[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
mat3[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
mat3[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
mat3[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
mat3[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
mat3[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
return mat3;
},
createMat4 : function ( ) {
var mat4 = new Float32Array(16);
mat4[0] = 1; mat4[1] = 0; mat4[2] = 0; mat4[3] = 0;
mat4[4] = 0; mat4[5] = 1; mat4[6] = 0; mat4[7] = 0;
mat4[8] = 0; mat4[9] = 0; mat4[10] = 1; mat4[11] = 0;
mat4[12] = 0; mat4[13] = 0; mat4[14] = 0; mat4[15] = 1;
return mat4;
},
identityMat4 : function (mat4) {
mat4[0] = 1; mat4[1] = 0; mat4[2] = 0; mat4[3] = 0;
mat4[4] = 0; mat4[5] = 1; mat4[6] = 0; mat4[7] = 0;
mat4[8] = 0; mat4[9] = 0; mat4[10] = 1; mat4[11] = 0;
mat4[12] = 0; mat4[13] = 0; mat4[14] = 0; mat4[15] = 1;
return mat4;
},
translateMat4 : function (vec3, mat4) {
var x = vec3[0], y = vec3[1], z = vec3[2];
var a = mat4;
mat4[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
mat4[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
mat4[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
mat4[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
return mat4;
},
rotateMat4 : function (angle, vec3, mat4) {
var x = vec3[0], y = vec3[1], z = vec3[2];
var len = Math.sqrt(x * x + y * y + z * z);
if (!len) {
return null;
}
if (len != 1) {
len = 1 / len; x *= len; y *= len; z *= len;
}
var s = Math.sin(angle * Math.PI / 180),
c = Math.cos(angle * Math.PI / 180),
t = 1 - c;
var a00 = mat4[0], a01 = mat4[1], a02 = mat4[2], a03 = mat4[3],
a10 = mat4[4], a11 = mat4[5], a12 = mat4[6], a13 = mat4[7],
a20 = mat4[8], a21 = mat4[9], a22 = mat4[10], a23 = mat4[11];
var b00 = x * x * t + c,
b01 = y * x * t + z * s,
b02 = z * x * t - y * s,
b10 = x * y * t - z * s,
b11 = y * y * t + c,
b12 = z * y * t + x * s,
b20 = x * z * t + y * s,
b21 = y * z * t - x * s,
b22 = z * z * t + c;
mat4[0] = a00 * b00 + a10 * b01 + a20 * b02;
mat4[1] = a01 * b00 + a11 * b01 + a21 * b02;
mat4[2] = a02 * b00 + a12 * b01 + a22 * b02;
mat4[3] = a03 * b00 + a13 * b01 + a23 * b02;
mat4[4] = a00 * b10 + a10 * b11 + a20 * b12;
mat4[5] = a01 * b10 + a11 * b11 + a21 * b12;
mat4[6] = a02 * b10 + a12 * b11 + a22 * b12;
mat4[7] = a03 * b10 + a13 * b11 + a23 * b12;
mat4[8] = a00 * b20 + a10 * b21 + a20 * b22;
mat4[9] = a01 * b20 + a11 * b21 + a21 * b22;
mat4[10] = a02 * b20 + a12 * b21 + a22 * b22;
mat4[11] = a03 * b20 + a13 * b21 + a23 * b22;
return mat4;
},
scaleMat4 : function (vec3, mat4) {
var x = vec3[0], y = vec3[1], z = vec3[2], a = mat4;
mat4[0] = a[0] * x;
mat4[1] = a[1] * x;
mat4[2] = a[2] * x;
mat4[3] = a[3] * x;
mat4[4] = a[4] * y;
mat4[5] = a[5] * y;
mat4[6] = a[6] * y;
mat4[7] = a[7] * y;
mat4[8] = a[8] * z;
mat4[9] = a[9] * z;
mat4[10] = a[10] * z;
mat4[11] = a[11] * z;
return mat4;
},
multiplyMat4 : function (a, b, mat4) {
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
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],
b10 = b[4], b11 = b[5], b12 = b[6], b13 = b[7],
b20 = b[8], b21 = b[9], b22 = b[10], b23 = b[11],
b30 = b[12], b31 = b[13], b32 = b[14], b33 = b[15];
mat4[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30;
mat4[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31;
mat4[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32;
mat4[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33;
mat4[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30;
mat4[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31;
mat4[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32;
mat4[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33;
mat4[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30;
mat4[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31;
mat4[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32;
mat4[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33;
mat4[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30;
mat4[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31;
mat4[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32;
mat4[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33;
return mat4;
},
perspectiveMat4 : function (aspect, angle, near, far, mat4) {
var top = near * Math.tan(angle * Math.PI / 360.0);
var bottom = -top;
var right = top * aspect;
var left = -right;
var a = (near * 2) / (right - left),
b = (near * 2) / (top - bottom),
c = (right + left) / (right - left),
d = (top + bottom) / (top - bottom),
e = -(far + near) / (far - near),
f = -(far * near * 2) / (far - near);
mat4[0] = a; mat4[1] = 0; mat4[2] = 0; mat4[3] = 0;
mat4[4] = 0; mat4[5] = b; mat4[6] = 0; mat4[7] = 0;
mat4[8] = c; mat4[9] = d; mat4[10] = e; mat4[11] = -1;
mat4[12] = 0; mat4[13] = 0; mat4[14] = f; mat4[15] = 0;
return mat4;
},
init : function (canvas) {
var gl = this.getWebGLContext(canvas);
var that = this, i;
var getShader = function (type, source) {
var shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.log(gl.getShaderInfoLog(shader));
}
return shader;
};
var getShaderProgram = function (vertexshader, fragmentshader) {
var program = gl.createProgram( );
gl.attachShader(program, vertexshader);
gl.attachShader(program, fragmentshader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.log(gl.getProgramInfoLog(program));
} else {
gl.useProgram(program);
}
return program;
};
var program = getShaderProgram(
getShader(gl.VERTEX_SHADER, that.getShaderSource('vertexshader')),
getShader(gl.FRAGMENT_SHADER, that.getShaderSource('fragmentshader'))
);
var attributes = ['aVertexPosition', 'aVertexNormal', 'aTextureCoord'];
attributes.forEach(function (attribute) {
program[attribute] = gl.getAttribLocation(program, attribute);
gl.enableVertexAttribArray(program[attribute]);
});
var uniforms = [
'uProjectionMatrix', 'uWorldMatrix', 'uNormalMatrix',
'uSampler', 'uLightingEnabled', 'uLightPosition'
];
uniforms.forEach(function (uniform) {
program[uniform] = gl.getUniformLocation(program, uniform);
});
var textureImagesLoaded = 0, numTextureImages = 6;
var handleLoadedTexture = function (texture) {
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);
gl.texParameteri(
gl.TEXTURE_2D,
gl.TEXTURE_MAG_FILTER,
gl.LINEAR
);
gl.texParameteri(
gl.TEXTURE_2D,
gl.TEXTURE_MIN_FILTER,
gl.LINEAR_MIPMAP_LINEAR
);
gl.generateMipmap(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, null);
};
var loadTexture = function (texture, source) {
texture.image = new Image( );
texture.image.addEventListener('load', function ( ) {
handleLoadedTexture(texture);
textureImagesLoaded += 1;
if (textureImagesLoaded === numTextureImages) {
start( );
}
});
texture.image.src = source;
};
var projectionMatrix = this.createMat4( );
var worldMatrix = this.createMat4( );
var setWorldMatrix = function (mat4) {
if (mat4) {
that.identityMat4(worldMatrix);
that.multiplyMat4(cameraMatrix, mat4, worldMatrix);
} else {
worldMatrix = cameraMatrix;
}
};
var normalMatrix = this.createMat3( );
var setNormalMatrix = function ( ) {
that.identityMat3(normalMatrix);
that.normalMat3FromMat4(worldMatrix, normalMatrix);
};
var cameraMatrix = this.createMat4( );
var setCameraMatrix = function ( ) {
that.identityMat4(cameraMatrix);
that.translateMat4([0, 0, translateZ], cameraMatrix);
that.rotateMat4(rotateX, [1, 0, 0], cameraMatrix);
};
var lightPosition = [10.0, 0.0, 3.0];
var setShaderUniforms = function (lighting) {
gl.uniformMatrix4fv(program.uProjectionMatrix, false, projectionMatrix);
gl.uniformMatrix4fv(program.uWorldMatrix, false, worldMatrix);
gl.uniformMatrix3fv(program.uNormalMatrix, false, normalMatrix);
gl.uniform3f(
program.uLightPosition,
parseFloat(lightPosition[0]),
parseFloat(lightPosition[1]),
parseFloat(lightPosition[2])
);
gl.uniform1i(program.uLightingEnabled, lighting);
};
var getBuffer = function (type, data, size) {
var buffer = gl.createBuffer( );
gl.bindBuffer(type, buffer);
data = type === gl.ARRAY_BUFFER ? new Float32Array(data) : new Uint16Array(data);
gl.bufferData(type, data, gl.STATIC_DRAW);
buffer.numItems = data.length / size;
buffer.itemSize = size;
return buffer;
};
var objects = [ ], images = [ ];
var Sphere = function (animation) {
var localMatrix = that.createMat4( );
this.lightingEnabled = true;
var texture = gl.createTexture( );
this.initTexture = function (source) {
loadTexture(texture, source);
};
this.bindTexture = function ( ) {
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.uniform1i(program.uSampler, 0);
};
var geometry = that.getSphere( );
var buffers = [
getBuffer(gl.ARRAY_BUFFER, geometry.vertices, 3),
getBuffer(gl.ARRAY_BUFFER, geometry.normals, 3),
getBuffer(gl.ARRAY_BUFFER, geometry.texCoords, 2),
getBuffer(gl.ELEMENT_ARRAY_BUFFER, geometry.indices, 1)
];
var elements = buffers[3].numItems;
this.bindBuffers = function ( ) {
buffers.forEach(function (buffer, index) {
if (buffer.itemSize !== 1) {
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.vertexAttribPointer(
program[attributes[index]],
buffer.itemSize, gl.FLOAT, false, 0, 0
);
} else {
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
}
});
};
this.animation = animation || false;
if (animation) {
this.animation.matrix = localMatrix;
}
var last = 0;
this.animate = function ( ) {
if (this.animation) {
var elapsed, now = new Date( ).getTime( );
if (last !== 0) {
elapsed = (last - now) * speed;
this.animation.run(elapsed);
}
last = now;
}
};
this.drawElements = function ( ) {
setCameraMatrix( );
if (this.animation) {
setWorldMatrix(localMatrix);
} else {
setWorldMatrix( );
}
setNormalMatrix( );
setShaderUniforms(this.lightingEnabled);
this.bindBuffers( );
gl.drawElements(gl.TRIANGLES, elements, gl.UNSIGNED_SHORT, 0);
};
};
var milkyway = new Sphere({
run : function ( ) {
that.identityMat4(this.matrix);
that.scaleMat4([30.0, 30.0, 30.0], this.matrix);
}
});
milkyway.lightingEnabled = false;
objects.push(milkyway);
images.push('http://wiki.selfhtml.org/images/4/4e/Milkyway.jpg');
var jupiter = new Sphere({
angle : 0.0,
speed : 10.0,
run : function (elapsed) {
this.angle -= (this.speed * elapsed) / 1000.0;
that.identityMat4(this.matrix);
that.rotateMat4(this.angle, [0, 1, 0], this.matrix);
}
});
objects.push(jupiter);
images.push('http://wiki.selfhtml.org/images/e/e2/Jupiter.jpg');
var io = new Sphere({
angle : 0.0,
run : function (elapsed) {
this.angle -= 0.05 * elapsed;
that.identityMat4(this.matrix);
that.rotateMat4(this.angle, [0, 1, 0], this.matrix);
that.translateMat4([-1.5, 0, 0], this.matrix);
that.scaleMat4([0.07, 0.07, 0.07], this.matrix);
}
});
objects.push(io);
images.push('http://wiki.selfhtml.org/images/8/87/Io.jpg');
var europa = new Sphere({
angle : 0.0,
run : function (elapsed) {
this.angle -= 0.04 * elapsed;
that.identityMat4(this.matrix);
that.rotateMat4(this.angle, [0, 1, 0], this.matrix);
that.translateMat4([2.5, 0, 0], this.matrix);
that.scaleMat4([0.06, 0.06, 0.06], this.matrix);
}
});
objects.push(europa);
images.push('http://wiki.selfhtml.org/images/e/e0/Europa.jpg');
var ganymede = new Sphere({
angle : 0.0,
run : function (elapsed) {
this.angle -= 0.02 * elapsed;
that.identityMat4(this.matrix);
that.rotateMat4(this.angle, [0, 1, 0], this.matrix);
that.translateMat4([3.2, 0, 0], this.matrix);
that.scaleMat4([0.08, 0.08, 0.08], this.matrix);
}
});
objects.push(ganymede);
images.push('http://wiki.selfhtml.org/images/1/14/Ganymede.jpg');
var callisto = new Sphere({
angle : 0.0,
run : function (elapsed) {
this.angle -= 0.01 * elapsed;
that.identityMat4(this.matrix);
that.rotateMat4(this.angle, [0, 1, 0], this.matrix);
that.translateMat4([0, 0, -4.5], this.matrix);
that.scaleMat4([0.1, 0.1, 0.1], this.matrix);
}
});
objects.push(callisto);
images.push('http://wiki.selfhtml.org/images/e/e9/Callisto.jpg');
for (i = 0; i < objects.length; i += 1) {
objects[i].initTexture(images[i]);
}
var rotateX = 10.0, translateZ = -10.0, speed = 0.5;
var activeKeys = { };
var handleKeyEvents = function (e) {
if (e.keyCode === 37 || e.keyCode === 38 || e.keyCode === 39 || e.keyCode === 40) {
e.preventDefault( );
}
activeKeys[e.keyCode] = e.type === 'keydown' ? true : false;
};
window.addEventListener('keydown', handleKeyEvents, true);
window.addEventListener('keyup', handleKeyEvents, true);
var handleKeys = function ( ) {
if ((activeKeys[37] || activeKeys[65]) && translateZ <= -2.0) {
translateZ += 0.05;
lightPosition[2] += 0.05;
} else if ((activeKeys[39] || activeKeys[68]) && translateZ >= -30.0) {
translateZ -= 0.05;
lightPosition[2] -= 0.05;
}
if (activeKeys[38] || activeKeys[87]) {
rotateX += 0.5;
} else if (activeKeys[40] || activeKeys[83]) {
rotateX -= 0.5;
}
};
var slider = document.getElementById('slider');
slider.addEventListener('input', function ( ) {
speed = slider.value / 100;
});
var draw = function ( ) {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
var aspect = canvas.clientWidth / canvas.clientHeight;
that.perspectiveMat4(aspect, 45, 0.1, 100.0, projectionMatrix);
objects.forEach(function (object) {
object.animate( );
object.bindTexture( );
object.drawElements( );
});
};
var resize = function ( ) {
var height = canvas.clientHeight,
width = canvas.clientWidth;
if (canvas.height !== height || canvas.width !== width) {
canvas.height = height;
canvas.width = width;
}
};
var tick = function ( ) {
handleKeys( );
resize( );
draw( );
window.requestAnimationFrame(tick);
};
var start = function ( ) {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
tick( );
};
}
};
document.addEventListener('DOMContentLoaded', function ( ) {
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
SCENE.init(canvas);
});
Weblinks
- khronos.org: WebGL
- MDN: Tutorial: Einführung in WebGL
Tutorials:
- Peter Strohm: WebGL - 3D im Browser deutschsprachiges Tutorial mit 8 Kapiteln
- learning WebGL umfangreiches Tutorial (auf Englisch) mit 16 Einheiten
- WebGL Fundamentals sehr aktuell und umfangreich
- WebGL Academy interaktive IDE, um WebGL und 3D-Algorithmen zu lernen
Demos:
- chromeexperiments: WebGL
- David Walsh: 9 More Mind-Blowing WebGL Demos mit Link auf die ersten 9 Demos