Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>WebGL is a rasteration API not a 3D api. You have to provide it with projected coordinates. This many ways it is no different than Canvas. It's just faster. Let's compare. </p> <p>Here's 3D in Canvas</p> <pre><code>window.onload = main; function main() { var cubeVertices = [ -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, ]; var indices = [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7, ]; var canvas = document.getElementById("c"); var ctx = canvas.getContext("2d"); var clock = 0; var then = Date.now() * 0.001; function render() { var now = Date.now() * 0.001; clock += now - then; then = now; var scale = 2; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.save(); ctx.translate(canvas.width / 2, canvas.height / 2); ctx.scale(canvas.width / scale, canvas.height / scale); ctx.lineWidth = scale / canvas.width; ctx.strokeStyle = "black"; var fieldOfView = Math.PI * 0.25; var aspect = canvas.width / canvas.height; var projection = m.perspective(fieldOfView, aspect, 1, 500); var radius = 5; var eye = [ Math.sin(clock) * radius, 1, Math.cos(clock) * radius]; var target = [0, 0, 0]; var up = [0, 1, 0]; var view = m.lookAt(eye, target, up); var worldViewProjection = m.multiplyMatrix(view, projection); drawLines(cubeVertices, indices, worldViewProjection); ctx.restore(); requestAnimFrame(render); } render(); function drawLines(cubeVertices, indices, worldViewProjection) { ctx.beginPath(); // // transform points from 3D to 2D. // var points = []; for (var ii = 0; ii &lt; cubeVertices.length; ii += 3) { points.push(m.transformPoint( worldViewProjection, [cubeVertices[ii + 0], cubeVertices[ii + 1], cubeVertices[ii + 2]])); } for (var ii = 0; ii &lt; indices.length; ii += 2) { var p0 = points[indices[ii + 0]]; var p1 = points[indices[ii + 1]]; ctx.moveTo(p0[0], p0[1]); ctx.lineTo(p1[0], p1[1]); } ctx.stroke(); } } </code></pre> <p>and here's the same 3D in WebGL</p> <pre><code>&lt;script&gt; window.onload = main; function main() { var cubeVertices = [ -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, ]; var indices = [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7, ]; var canvas = document.getElementById("c"); var gl = getWebGLContext(c); var clock = 0; var then = Date.now() * 0.001; var program = createProgramFromScripts( gl, ["2d-vertex-shader", "2d-fragment-shader"]); gl.useProgram(program); var positionLoc = gl.getAttribLocation(program, "a_position"); var worldViewProjectionLoc = gl.getUniformLocation(program, "u_worldViewProjection"); var buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer); gl.bufferData( gl.ARRAY_BUFFER, new Float32Array(cubeVertices), gl.STATIC_DRAW); gl.enableVertexAttribArray(positionLoc); gl.vertexAttribPointer(positionLoc, 3, gl.FLOAT, false, 0, 0); var buffer = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer); gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW); function render() { var now = Date.now() * 0.001; clock += now - then; then = now; var scale = 4; gl.clear(gl.COLOR_BUFFER_BIT); var fieldOfView = Math.PI * 0.25; var aspect = canvas.width / canvas.height; var projection = m.perspective(fieldOfView, aspect, 0.0001, 500); var radius = 5; var eye = [ Math.sin(clock) * radius, 1, Math.cos(clock) * radius]; var target = [0, 0, 0]; var up = [0, 1, 0]; var view = m.lookAt(eye, target, up); var worldViewProjection = m.multiplyMatrix(view, projection); gl.uniformMatrix4fv( worldViewProjectionLoc, false, worldViewProjection); gl.drawElements(gl.LINES, indices.length, gl.UNSIGNED_SHORT, 0); requestAnimFrame(render); } render(); } &lt;/script&gt; &lt;!-- vertex shader --&gt; &lt;script id="2d-vertex-shader" type="x-shader/x-vertex"&gt; attribute vec4 a_position; uniform mat4 u_worldViewProjection; void main() { // // transform points from 3D to 2D. // gl_Position = u_worldViewProjection * a_position; } &lt;/script&gt; &lt;!-- fragment shader --&gt; &lt;script id="2d-fragment-shader" type="x-shader/x-fragment"&gt; void main() { gl_FragColor = vec4(0,0,0,1); } &lt;/script&gt; </code></pre> <p>If you'd like to see them live <a href="http://greggman.com/downloads/examples/3d-in-canvas-vs-webgl/3d-in-canvas.html" rel="nofollow">here's the canvas version</a> and <a href="http://greggman.com/downloads/examples/3d-in-canvas-vs-webgl/3d-in-webgl.html" rel="nofollow">here's the webgl version</a>.</p> <p>The only difference between the Canvas one and the WebGL one is in Canvas I did the conversion projection in JavaScript and in WebGL I did the projection in the shader. In both cases the <strong>code I wrote</strong> did the projection. </p> <p>In the Canvas version that code is:</p> <pre><code>m.transformPoint( worldViewProjection, [cubeVertices[ii + 0], cubeVertices[ii + 1], cubeVertices[ii + 2]); </code></pre> <p>In the WebGL version that code is:</p> <pre><code>gl_Position = u_worldViewProjection * a_position </code></pre> <p>The API itself only rasterizes. I have to supply the projection in either case. There is nothing in WebGL that does 3D. There is just a rasterization api and 2 functions, the vertex shader, and fragment shader, written in GLSL that I have to supply that run very fast and include a math library. I still have to provide the code to the 3D to the API in both cases.</p> <p>WebGL is *<em>NOT</em> a 3D API</p> <p>I believe it's important to point this out. There are various versions of OpenGL. The original OpenGL from 1993 was a 3D api. You gave it 3D data, you told it what colors to make things, you told it about various lights. You gave it a model matrix and a projection matrix and it drew 3D for you.</p> <p>OpenGL ES 2.0 and WebGL got rid of all of that. They provide a rasterization API and shaders and let you program the hardware. But it's up to you to write all the projections. You have to compute projected coordinates from 3D. You have compute lighting equations, and colors and all the rest.</p> <p>This makes WebGL and OpenGL ES 2.0 arguably much harder than the old fixed function OpenGL but at the same time it makes them massively more flexible. If you're comfortable doing all those conversions and math or if you don't mind learning it then jump in and do it. If you aren't comfortable doing all then then there are plenty of WebGL 3D libraries that will do it for you.</p> <p>To you who claim WebGL is a 3D library let's try a thought game.</p> <p>Here's a physics library, <a href="http://box2d-js.sourceforge.net/" rel="nofollow">box2d.js</a>. You give it shapes, masses, and forces and it computes physics for you. If all it really was was a math library and you had to supply all the physics equations yourself would you still call it a physics library? Something called a physics library has to supply the physics knowledge or else it's not a physics library. Similarly, something called a 3D library has to supply the 3D knowledge or else it's not a 3D library.</p> <p>OpenGL 1.0 was a 3D library. You gave it 3D positions, vertex colors, lights and it drew 3D for you. You needed no 3D knowledge. WebGL on the other hand does not provide any 3D knowledge. You have to know how to do 3D projections, you have to know how to sample textures, you have to know how to do lighting calculations. It's no longer a 3D library, it's just a rasterization API. Calling it a 3D library is a lie and a disservice to those actually looking for a 3D library, ie, a library the provides 3D.</p> <p>Calling it a 2D library might be hyperbole but calling it a 3D library is wrong.</p> <p><a href="http://games.greggman.com/game/webgl-2d-vs-3d-libraries/" rel="nofollow">Here's another article about it</a>.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload