Benutzer:Coolcat/Tutorial WebGL
Dieser Artikel befindet sich noch im Aufbau! |
WebGL ist der neue Standard für OpenGL im Browser. Der Standard ermöglicht es hardwarebeschleunigte 3D-Grafik im Browser darzustellen, ohne dabei auf spezielle Plugins angewiesen zu sein. Bisher wird der Standard von den folgenden Browsern unterstützt:
- Mozilla Firefox 3.7a1pre (Nightly Build, "Minefield")
- WebGL muss über die Einstellung about:config -> webgl.enabled_for_all_sites aktiviert werden. Unter Windows kann es einige Probleme geben, wenn kein OpenGL verfügbar ist, in dem Fall muss in den Softwaremodus geschaltet werden.
- WebKit (Nightly Build)
- Google Chrome 4.0.221.8 (Nightly Build, siehe hier)
- ...bitte ergänzen...
Inhaltsverzeichnis
WebGL Context
Um WebGL nutzen zu können benötigt man zunächst einmal natürlich ein HTML5 Canvas-Element, welchem wir passenderweise die ID "canvas" geben. Von diesem Canvas erhalten wir zum einen die spätere Viewportgröße und zum anderen einen sogenannten Context. Das Context-Objekt erlaubt uns sämtliche OpenGL ES 2.0 Funktionen aufzurufen.
// our WebGL rendering context, it might be useful to use a global variable for this
var gl = null;
// grab the canvas object and its dimensions
var canvas = document.getElementById("canvas");
var viewportWidth = canvas.width;
var viewportHeight = canvas.height;
// request rendering context from the canvas
try {
// using Mozilla? (e.g. Firefox, ...)
if (!gl) { gl = canvas.getContext("moz-webgl"); }
} catch (e) { }
try {
// using Webkit? (e.g. Google Chrome, ...)
if (!gl) { gl = canvas.getContext("webkit-3d"); }
} catch (e) { }
if (!gl) {
alert("No known OpenGL context detected! Is it enabled?");
return;
}
Shader
In OpenGL ES 2.0 herrscht Shader-Zwang, eine feste Funktionspipeline existiert nicht. Das laden von GLSL-Shadern geschieht wie gewohnt. Zuerst werden Vertex- und Fragmentshader geladen und compiliert. Beide Shader werden dann an ein Program-Objekt angehängt und gelinkt.
function loadShader(shaderType, shaderSource) {
var shader = gl.createShader(shaderType);
if (!shader) { return null; }
gl.shaderSource(shader, shaderSource);
gl.compileShader(shader);
if (!gl.getShaderi(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
var vertexShaderSource = "...Vertexshader als String...";
var fragmentShaderSource = "...Fragmentshader als String...";
var vertexShader = loadShader(gl.VERTEX_SHADER, vertexShaderSource);
var fragmentShader = loadShader(gl.FRAGMENT_SHADER, fragmentShaderSource);
if (!vertexShader || !fragmentShader) {
alert("Shader problem");
}
// create program object
var program = gl.createProgram();
// attach our two shaders to the program
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
// setup attributes and uniforms (optional)
gl.bindAttribLocation(program, 0, "aPosition");
gl.bindAttribLocation(program, 1, "aNormal");
gl.bindAttribLocation(program, 2, "aTexCoord");
gl.uniform1i(gl.getUniformLocation(program, "uTexture"), 0);
// linking
gl.linkProgram(program);
if (!gl.getProgrami(program, gl.LINK_STATUS)) {
alert(gl.getProgramInfoLog(program));
}
Im obigen Beispiel wird der Shader-Quellcode fest als String in den JavaScript-Code integriert. Das ist natürlich ziemlich unübersichtlich. Vom Prinzip spielt es keine Rolle wo der String herkommt. Beispielsweise kann man ihn mit einem HTTP-Request in einer Shader-Datei vom Server laden. Es ist aber auch möglich den Shader-Code als spezielles Script-Element in die HTML-Datei einzubinden.
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aPosition;
attribute vec3 aNormal;
attribute vec3 aTexCoord;
varying vec3 vNormal;
varying vec2 vTexCoord;
void main() {
gl_Position = vec4(aPosition, 1.0);
vTexCoord = aTexCoord;
vNormal = aNormal;
}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
varying vec3 vNormal;
varying vec2 vTexCoord;
uniform sampler2D uTexture;
void main() {
gl_FragColor = texture2D(uTexture, vTexCoord);
}
</script>
Der Browser hat vom Script-Typ "x-shader/x-vertex" natürlich noch nie etwas gehört und wird das Element entsprechend einfach ignorieren. Mit einer einfachen JavaScript-Funktion kann man aber trotzdem an den Inhalt gelangen.
function getShaderSource(id) {
var script = document.getElementById(id);
if (!script) { return null; }
var source = "";
var child = script.firstChild;
while (child) {
if (child.nodeType == 3) {
source += child.textContent;
}
child = child.nextSibling;
}
return source;
}
var vertexShaderSource = getShaderSource("shader-vs");
var fragmentShaderSource = getShaderSource("shader-fs");
VertexBufferObjects
...demnächst...
Texturen
Das Laden von Texturen ist relativ einfach, da der Browser bereits über die nötige Infrastruktur zum Laden von Bildern in vielen Formaten bereitstellt. Etwas ungewohnt ist der asynchrone Ladevorgang: Ein Bild steht nicht sofort zur Verfügung, da dieses ja möglicherweise zuerst vom Server geladen werden muss. Sobald aber das Bild verfügbar ist wird das onload-Event ausgelöst.
function loadTexture(filename) {
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
var image = new Image();
image.onload = function() {
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, image);
gl.generateMipmap(gl.TEXTURE_2D);
draw(); // texture now available, we can redraw the scene
}
image.onerror = function() {
alert("error while loading image '"+filename+"'.");
}
image.src = filename;
return texture;
}
Links
- Spore Creature Viewer, ein Viewer für COLLADA-Meshes, allerdings nur für aus dem Spiel Spore exportierte Meshes.
- Beispiele für Chromium, funktionieren nicht mit Firefox