Tutorial WebGL Sample: Unterschied zwischen den Versionen
Aus DGL Wiki
I0n0s (Diskussion | Beiträge) K (Rechtschreibung korrigiert) |
(Anpassung an die aktuelle Spezifikation) |
||
(6 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
− | Dies ist eine Beispielanwendung zum [[ | + | Dies ist eine Beispielanwendung zum [[Tutorial_WebGL|WebGL-Tutorial]]. Zum Ausprobieren den Quelltext in eine Datei kopieren und mit einem [[Tutorial_WebGL|WebGL-fähigen Browser]] öffnen. Es wird eine Textur von der URL <tt><nowiki>"http://wiki.delphigl.com/wiki.png"</nowiki></tt> geladen. Sollte die Anwendung nicht funktionieren, stelle sicher, dass die Textur erreichbar ist. |
Das Ganze sollte ungefähr so aussehen: | Das Ganze sollte ungefähr so aussehen: | ||
Zeile 22: | Zeile 22: | ||
<head> | <head> | ||
− | + | <script type="text/javascript"> | |
var gl = null; // our WebGL rendering context | var gl = null; // our WebGL rendering context | ||
var viewportWidth; | var viewportWidth; | ||
var viewportHeight; | var viewportHeight; | ||
− | + | ||
var program; // shader program object | var program; // shader program object | ||
var vbo; // vertexbufferobject | var vbo; // vertexbufferobject | ||
+ | var ibo; // indexbufferobject | ||
var texture; // texture object | var texture; // texture object | ||
Zeile 37: | Zeile 38: | ||
viewportWidth = canvas.width; | viewportWidth = canvas.width; | ||
viewportHeight = canvas.height; | viewportHeight = canvas.height; | ||
− | + | ||
− | + | var names = [ "webgl", "experimental-webgl", "moz-webgl", "webkit-3d" ]; | |
− | + | for (var i=0; names.length>i; i++) { | |
− | + | try { | |
− | + | gl = canvas.getContext(names[i]); | |
− | + | if (gl) { break; } | |
− | + | } catch (e) { } | |
− | + | } | |
− | |||
if (!gl) { | if (!gl) { | ||
alert("No known OpenGL context detected! Is it enabled?"); | alert("No known OpenGL context detected! Is it enabled?"); | ||
return; | return; | ||
} | } | ||
+ | // since WebGL is still experimental, we need some compatibility code | ||
+ | compatibilityCode(); | ||
// basic settings | // basic settings | ||
Zeile 64: | Zeile 66: | ||
var fragmentShader = loadShader(gl.FRAGMENT_SHADER, fragmentShaderSource); | var fragmentShader = loadShader(gl.FRAGMENT_SHADER, fragmentShaderSource); | ||
if (!vertexShader || !fragmentShader) { | if (!vertexShader || !fragmentShader) { | ||
− | + | return; | |
} | } | ||
− | + | ||
// create program object | // create program object | ||
program = gl.createProgram(); | program = gl.createProgram(); | ||
− | + | ||
// attach our two shaders to the program | // attach our two shaders to the program | ||
gl.attachShader(program, vertexShader); | gl.attachShader(program, vertexShader); | ||
gl.attachShader(program, fragmentShader); | gl.attachShader(program, fragmentShader); | ||
− | + | ||
− | // setup attributes | + | // setup attributes (optional) |
gl.bindAttribLocation(program, 0, "aPosition"); | gl.bindAttribLocation(program, 0, "aPosition"); | ||
gl.bindAttribLocation(program, 1, "aNormal"); | gl.bindAttribLocation(program, 1, "aNormal"); | ||
gl.bindAttribLocation(program, 2, "aTexCoord"); | gl.bindAttribLocation(program, 2, "aTexCoord"); | ||
− | + | ||
− | |||
// linking | // linking | ||
gl.linkProgram(program); | gl.linkProgram(program); | ||
− | if (!gl. | + | if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { |
alert(gl.getProgramInfoLog(program)); | alert(gl.getProgramInfoLog(program)); | ||
+ | return; | ||
} | } | ||
+ | |||
+ | // setup uniforms (optional) | ||
+ | gl.useProgram(program); | ||
+ | gl.uniform1i(gl.getUniformLocation(program, "uTexture"), 0); | ||
// setup VBO | // setup VBO | ||
Zeile 96: | Zeile 102: | ||
-0.5, -0.5, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, | -0.5, -0.5, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, | ||
0.5, -0.5, 0.0, 0.0, 0.6, 0.8, 1.0, 1.0, | 0.5, -0.5, 0.0, 0.0, 0.6, 0.8, 1.0, 1.0, | ||
− | + | ]; | |
− | + | // we need also some indices because of this annoying Firefox-Bug: | |
− | + | // https://bugzilla.mozilla.org/show_bug.cgi?id=521667 | |
− | + | var indices = [ | |
− | ]; | + | 0, 1, 2, 2, 1, 3 |
− | // create VBO | + | ]; |
+ | // create VBO and IBO | ||
vbo = gl.createBuffer(); | vbo = gl.createBuffer(); | ||
gl.bindBuffer(gl.ARRAY_BUFFER, vbo); | gl.bindBuffer(gl.ARRAY_BUFFER, vbo); | ||
− | gl.bufferData(gl.ARRAY_BUFFER, new | + | gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(vertices), gl.STATIC_DRAW); |
− | + | ibo = gl.createBuffer(); | |
+ | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo); | ||
+ | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedShortArray(indices), gl.STATIC_DRAW); | ||
+ | |||
// create texture | // create texture | ||
// ================================================= | // ================================================= | ||
texture = loadTexture("http://wiki.delphigl.com/wiki.png"); | texture = loadTexture("http://wiki.delphigl.com/wiki.png"); | ||
+ | |||
+ | // draw scene every 33 milliseconds | ||
+ | setInterval(draw, 33); | ||
+ | } | ||
+ | |||
+ | function compatibilityCode() { | ||
+ | // Firefox compatibility code | ||
+ | // The WebGL*Array where named Canvas*Array in the past. | ||
+ | // However, this will only affect old nightly builds. The current nightly does already | ||
+ | // support the new names. (13 Dec 2009). | ||
+ | try { | ||
+ | WebGLFloatArray; | ||
+ | } | ||
+ | catch (e) { | ||
+ | try { | ||
+ | WebGLArrayBuffer = CanvasArrayBuffer; | ||
+ | WebGLByteArray = CanvasByteArray; | ||
+ | WebGLUnsignedByteArray = CanvasUnsignedByteArray; | ||
+ | WebGLShortArray = CanvasShortArray; | ||
+ | WebGLUnsignedShortArray = CanvasUnsignedShortArray; | ||
+ | WebGLIntArray = CanvasIntArray; | ||
+ | WebGLUnsignedIntArray = CanvasUnsignedIntArray; | ||
+ | WebGLFloatArray = CanvasFloatArray; | ||
+ | } | ||
+ | catch (e) { | ||
+ | alert("Could not find Canvas array types for WebGL."); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Google Chrome compatibility code | ||
+ | // Since a JavaScript function may have multiple return types, functions | ||
+ | // 'getProgrami' and 'getShaderi' where renamed. However, Chrome does still | ||
+ | // use the old names. (30 Nov 2009) | ||
+ | if (!gl.getProgramParameter) { | ||
+ | gl.getProgramParameter = gl.getProgrami; | ||
+ | } | ||
+ | if (!gl.getShaderParameter) { | ||
+ | gl.getShaderParameter = gl.getShaderi; | ||
+ | } | ||
} | } | ||
Zeile 114: | Zeile 163: | ||
var script = document.getElementById(id); | var script = document.getElementById(id); | ||
if (!script) { return null; } | if (!script) { return null; } | ||
− | + | ||
var source = ""; | var source = ""; | ||
var child = script.firstChild; | var child = script.firstChild; | ||
Zeile 126: | Zeile 175: | ||
return source; | return source; | ||
} | } | ||
− | + | ||
function loadShader(shaderType, shaderSource) { | function loadShader(shaderType, shaderSource) { | ||
var shader = gl.createShader(shaderType); | var shader = gl.createShader(shaderType); | ||
Zeile 132: | Zeile 181: | ||
gl.shaderSource(shader, shaderSource); | gl.shaderSource(shader, shaderSource); | ||
gl.compileShader(shader); | gl.compileShader(shader); | ||
− | + | ||
− | if (!gl. | + | if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { |
alert(gl.getShaderInfoLog(shader)); | alert(gl.getShaderInfoLog(shader)); | ||
return null; | return null; | ||
} | } | ||
− | + | ||
return shader; | return shader; | ||
} | } | ||
Zeile 148: | Zeile 197: | ||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); | ||
var image = new Image(); | var image = new Image(); | ||
− | + | ||
// register event handlers | // register event handlers | ||
image.onload = function() { | image.onload = function() { | ||
Zeile 159: | Zeile 208: | ||
alert("error while loading image '"+filename+"'."); | alert("error while loading image '"+filename+"'."); | ||
} | } | ||
− | + | ||
// request image from server | // request image from server | ||
image.src = filename; | image.src = filename; | ||
− | + | ||
// return texture object (asynchronous loading, texture NOT available yet!) | // return texture object (asynchronous loading, texture NOT available yet!) | ||
return texture; | return texture; | ||
Zeile 174: | Zeile 223: | ||
gl.useProgram(program); | gl.useProgram(program); | ||
− | // setup interleaved VBO | + | // setup interleaved VBO and IBO |
− | gl.bindBuffer(gl.ARRAY_BUFFER, vbo); | + | gl.bindBuffer(gl.ARRAY_BUFFER, vbo); |
+ | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo); | ||
gl.enableVertexAttribArray(0); | gl.enableVertexAttribArray(0); | ||
gl.enableVertexAttribArray(1); | gl.enableVertexAttribArray(1); | ||
gl.enableVertexAttribArray(2); | gl.enableVertexAttribArray(2); | ||
− | gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 8, 0); // position | + | gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 8*4, 0*4); // position |
− | gl.vertexAttribPointer(1, 3, gl.FLOAT, false, 8, 3); // normal | + | gl.vertexAttribPointer(1, 3, gl.FLOAT, false, 8*4, 3*4); // normal |
− | gl.vertexAttribPointer(2, 2, gl.FLOAT, false, 8, 6); // texcoord | + | gl.vertexAttribPointer(2, 2, gl.FLOAT, false, 8*4, 6*4); // texcoord |
// setup texture | // setup texture | ||
gl.activeTexture(gl.TEXTURE0); | gl.activeTexture(gl.TEXTURE0); | ||
gl.bindTexture(gl.TEXTURE_2D, texture); | gl.bindTexture(gl.TEXTURE_2D, texture); | ||
− | + | ||
// draw the buffer | // draw the buffer | ||
− | gl. | + | gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); |
} | } | ||
</script> | </script> | ||
− | + | ||
<script id="shader-vs" type="x-shader/x-vertex"> | <script id="shader-vs" type="x-shader/x-vertex"> | ||
attribute vec3 aPosition; | attribute vec3 aPosition; | ||
attribute vec3 aNormal; | attribute vec3 aNormal; | ||
− | attribute | + | attribute vec2 aTexCoord; |
varying vec3 vNormal; | varying vec3 vNormal; | ||
varying vec2 vTexCoord; | varying vec2 vTexCoord; | ||
Zeile 204: | Zeile 254: | ||
} | } | ||
</script> | </script> | ||
− | + | ||
<script id="shader-fs" type="x-shader/x-fragment"> | <script id="shader-fs" type="x-shader/x-fragment"> | ||
varying vec3 vNormal; | varying vec3 vNormal; |
Aktuelle Version vom 13. Dezember 2009, 13:00 Uhr
Dies ist eine Beispielanwendung zum WebGL-Tutorial. Zum Ausprobieren den Quelltext in eine Datei kopieren und mit einem WebGL-fähigen Browser öffnen. Es wird eine Textur von der URL "http://wiki.delphigl.com/wiki.png" geladen. Sollte die Anwendung nicht funktionieren, stelle sicher, dass die Textur erreichbar ist.
Das Ganze sollte ungefähr so aussehen:
<html>
<!--
* WebGL-Test
*
* This sample is part of the WebGL Tutorial at http://delphigl.com
*
* Author:
* Coolcat (Martin Weusten)
* see: http://wiki.delphigl.com/index.php/Benutzer:Coolcat
*
* Licence for this file:
* Creative Commons Attribution 3.0 (CC-BY 3.0)
* see: http://creativecommons.org/licenses/by/3.0/
-->
<head>
<script type="text/javascript">
var gl = null; // our WebGL rendering context
var viewportWidth;
var viewportHeight;
var program; // shader program object
var vbo; // vertexbufferobject
var ibo; // indexbufferobject
var texture; // texture object
function init() {
// request rendering context from the canvas
// =================================================
var canvas = document.getElementById("canvas");
viewportWidth = canvas.width;
viewportHeight = canvas.height;
var names = [ "webgl", "experimental-webgl", "moz-webgl", "webkit-3d" ];
for (var i=0; names.length>i; i++) {
try {
gl = canvas.getContext(names[i]);
if (gl) { break; }
} catch (e) { }
}
if (!gl) {
alert("No known OpenGL context detected! Is it enabled?");
return;
}
// since WebGL is still experimental, we need some compatibility code
compatibilityCode();
// basic settings
// =================================================
gl.clearColor(0, 0, 0, 1);
gl.enable(gl.DEPTH_TEST);
// setup shaders
// =================================================
var vertexShaderSource = getShaderSource("shader-vs");
var fragmentShaderSource = getShaderSource("shader-fs");
var vertexShader = loadShader(gl.VERTEX_SHADER, vertexShaderSource);
var fragmentShader = loadShader(gl.FRAGMENT_SHADER, fragmentShaderSource);
if (!vertexShader || !fragmentShader) {
return;
}
// create program object
program = gl.createProgram();
// attach our two shaders to the program
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
// setup attributes (optional)
gl.bindAttribLocation(program, 0, "aPosition");
gl.bindAttribLocation(program, 1, "aNormal");
gl.bindAttribLocation(program, 2, "aTexCoord");
// linking
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
alert(gl.getProgramInfoLog(program));
return;
}
// setup uniforms (optional)
gl.useProgram(program);
gl.uniform1i(gl.getUniformLocation(program, "uTexture"), 0);
// setup VBO
// =================================================
// define some vertexdata
var vertices = [
// position XYZ, normal XYZ, texcoord UV => 8 floats per vertex
-0.5, 0.5, 0.0, 0.6, 0.0, 0.8, 0.0, 0.0,
0.5, 0.5, 0.0, 0.6, 0.0, 0.8, 1.0, 0.0,
-0.5, -0.5, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0,
0.5, -0.5, 0.0, 0.0, 0.6, 0.8, 1.0, 1.0,
];
// we need also some indices because of this annoying Firefox-Bug:
// https://bugzilla.mozilla.org/show_bug.cgi?id=521667
var indices = [
0, 1, 2, 2, 1, 3
];
// create VBO and IBO
vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(vertices), gl.STATIC_DRAW);
ibo = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedShortArray(indices), gl.STATIC_DRAW);
// create texture
// =================================================
texture = loadTexture("http://wiki.delphigl.com/wiki.png");
// draw scene every 33 milliseconds
setInterval(draw, 33);
}
function compatibilityCode() {
// Firefox compatibility code
// The WebGL*Array where named Canvas*Array in the past.
// However, this will only affect old nightly builds. The current nightly does already
// support the new names. (13 Dec 2009).
try {
WebGLFloatArray;
}
catch (e) {
try {
WebGLArrayBuffer = CanvasArrayBuffer;
WebGLByteArray = CanvasByteArray;
WebGLUnsignedByteArray = CanvasUnsignedByteArray;
WebGLShortArray = CanvasShortArray;
WebGLUnsignedShortArray = CanvasUnsignedShortArray;
WebGLIntArray = CanvasIntArray;
WebGLUnsignedIntArray = CanvasUnsignedIntArray;
WebGLFloatArray = CanvasFloatArray;
}
catch (e) {
alert("Could not find Canvas array types for WebGL.");
}
}
// Google Chrome compatibility code
// Since a JavaScript function may have multiple return types, functions
// 'getProgrami' and 'getShaderi' where renamed. However, Chrome does still
// use the old names. (30 Nov 2009)
if (!gl.getProgramParameter) {
gl.getProgramParameter = gl.getProgrami;
}
if (!gl.getShaderParameter) {
gl.getShaderParameter = gl.getShaderi;
}
}
function getShaderSource(id) {
var script = document.getElementById(id);
if (!script) { return null; }
var source = "";
var child = script.firstChild;
while (child) {
// node is a "textnode" ?
if (child.nodeType == 3) {
source += child.textContent;
}
child = child.nextSibling;
}
return source;
}
function loadShader(shaderType, shaderSource) {
var shader = gl.createShader(shaderType);
if (!shader) { return null; }
gl.shaderSource(shader, shaderSource);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
function loadTexture(filename) {
// preparations
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();
// register event handlers
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+"'.");
}
// request image from server
image.src = filename;
// return texture object (asynchronous loading, texture NOT available yet!)
return texture;
}
function draw() {
gl.viewport(0, 0, viewportWidth, viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
// setup shader
gl.useProgram(program);
// setup interleaved VBO and IBO
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
gl.enableVertexAttribArray(0);
gl.enableVertexAttribArray(1);
gl.enableVertexAttribArray(2);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 8*4, 0*4); // position
gl.vertexAttribPointer(1, 3, gl.FLOAT, false, 8*4, 3*4); // normal
gl.vertexAttribPointer(2, 2, gl.FLOAT, false, 8*4, 6*4); // texcoord
// setup texture
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
// draw the buffer
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
}
</script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aPosition;
attribute vec3 aNormal;
attribute vec2 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>
</head>
<body onload="init()">
<div style="text-align: center">
<canvas id="canvas" width="512" height="512"></canvas>
</div>
</body>
</html>