为什么说 WebGL 是 2D API,而不是 3D API?
根据 HTML5 Rocks,WebGL 实际上是 2D API,而不是 3D API.他们为什么这么说,这是什么意思?
According to HTML5 Rocks, WebGL is actually a 2D API, not a 3D API. Why do they say that, and what does it mean?
我们可以在 WebGL 顶点着色器和片段着色器中指定 X、Y、Z 坐标.我无法理解 2D 和 3D 图形 API 之间的区别.你能解释一下为什么他们说这是一个 2D API 吗?
We can specify X, Y, Z coordinates in WebGL vertex shaders and fragment shaders. I can't understand the difference between a 2D and 3D graphics API. Could you explain why they say this is a 2D API?
推荐答案
WebGL 是光栅化 API 而不是 3D api.您必须为其提供投影坐标.在很多方面它与 Canvas 没有什么不同.它只是更快.让我们比较一下.
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.
这是 Canvas 中的 3D
Here's 3D in Canvas
const 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,
];
const 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,
];
const canvas = document.querySelector("#c");
const ctx = canvas.getContext("2d");
function render(time) {
time *= 0.001;
const 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";
const fieldOfView = Math.PI * 0.25;
const aspect = canvas.width / canvas.height;
const projection = m4.perspective(fieldOfView, aspect, 1, 500);
const radius = 5;
const eye = [
Math.sin(time) * radius,
2,
Math.cos(time) * radius];
const target = [0, 0, 0];
const up = [0, 1, 0];
const camera = m4.lookAt(eye, target, up);
const view = m4.inverse(camera);
const worldViewProjection = m4.multiply(projection, view);
drawLines(cubeVertices, indices, worldViewProjection);
ctx.restore();
requestAnimationFrame(render);
}
requestAnimationFrame(render);
function drawLines(cubeVertices, indices, worldViewProjection) {
ctx.beginPath();
//
// transform points from 3D to 2D.
//
const points = [];
for (let ii = 0; ii < cubeVertices.length; ii += 3) {
points.push(m4.transformPoint(
worldViewProjection,
cubeVertices.slice(ii, ii + 3)));
}
for (let ii = 0; ii < 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();
}
canvas { border: 1px solid red; }
<!-- just a math lib -->
<script src="https://webglfundamentals.org/webgl/resources/m4.js"></script>
<canvas id="c"></canvas>
这是 WebGL 中的相同 3D
and here's the same 3D in WebGL
const 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,
];
const 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,
];
const canvas = document.querySelector('#c');
const gl = canvas.getContext('webgl');
const vs = `
attribute vec4 a_position;
uniform mat4 u_worldViewProjection;
void main() {
//
// transform points from 3D to 2D.
//
gl_Position = u_worldViewProjection * a_position;
}
`;
const fs = `
void main() {
gl_FragColor = vec4(0,0,0,1);
}
`;
const program = webglUtils.createProgramFromSources(
gl, [vs, fs]);
gl.useProgram(program);
const positionLoc = gl.getAttribLocation(program, "a_position");
const worldViewProjectionLoc =
gl.getUniformLocation(program, "u_worldViewProjection");
const 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);
const buffer2 = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer2);
gl.bufferData(
gl.ELEMENT_ARRAY_BUFFER,
new Uint16Array(indices),
gl.STATIC_DRAW);
function render(time) {
time *= 0.001;
const scale = 4;
const fieldOfView = Math.PI * 0.25;
const aspect = canvas.width / canvas.height;
const projection = m4.perspective(fieldOfView, aspect, 0.0001, 500);
const radius = 5;
const eye = [
Math.sin(time) * radius,
2,
Math.cos(time) * radius];
const target = [0, 0, 0];
const up = [0, 1, 0];
const camera = m4.lookAt(eye, target, up);
const view = m4.inverse(camera);
const worldViewProjection = m4.multiply(projection, view);
gl.uniformMatrix4fv(
worldViewProjectionLoc, false, worldViewProjection);
gl.drawElements(gl.LINES, indices.length, gl.UNSIGNED_SHORT, 0);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
canvas { border: 1px solid red; }
<!-- just a math lib -->
<script src="https://webglfundamentals.org/webgl/resources/m4.js"></script>
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<canvas id="c"></canvas>
Canvas 和 WebGL 之间的唯一区别是在 Canvas 中我使用 JavaScript 进行投影,而在 WebGL 中我在着色器中进行投影.在这两种情况下,我编写的代码都进行了投影.
The only difference between the Canvas one and the WebGL one is in Canvas I did the projection in JavaScript and in WebGL I did the projection in the shader. In both cases the code I wrote did the projection.
在 Canvas 版本中,代码是:
In the Canvas version that code is:
m4.transformPoint(
worldViewProjection,
cubeVertices.slice(ii, ii + 3));
在 WebGL 版本中,代码是:
In the WebGL version that code is:
gl_Position = u_worldViewProjection * a_position
API 本身只进行光栅化.无论哪种情况,我都必须提供投影代码.WebGL 中没有任何东西可以做 3D.只有一个光栅化 api 和 2 个函数,顶点着色器和片段着色器,它们都是用 GLSL 编写的,我必须提供它们运行速度非常快并包含一个数学库.在这两种情况下,我仍然需要提供对 API 进行 3D 处理的代码.
The API itself only rasterizes. I have to supply the projection code 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, both 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 do the 3D to the API in both cases.
WebGL **不是* 3D API
WebGL is **NOT* a 3D API
我认为指出这一点很重要.有各种版本的 OpenGL.1993 年的原始 OpenGL 是一个 3D api.你给了它 3D 数据,你告诉它用什么颜色来制作东西,你告诉它各种灯光.你给它一个模型矩阵和一个投影矩阵,它会为你绘制 3D.
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.
OpenGL ES 2.0 和 WebGL 摆脱了这一切.它们提供光栅化 API 和着色器,让您对硬件进行编程.但是由你来写所有的预测.您必须从 3D 计算投影坐标.您可以计算照明方程、颜色和其他所有内容.
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.
这使得 WebGL 和 OpenGL ES 2.0 可以说比旧的固定函数 OpenGL 更难,但同时也使它们更加灵活.如果您对所有这些转换和数学操作感到满意,或者如果您不介意学习它,那么就开始做吧.如果您对所有这些都感到不自在,那么有很多 WebGL 3D 库可以为您完成.
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.
对于那些声称 WebGL 是 3D 库的你,让我们来尝试一个思维游戏.
To you who claim WebGL is a 3D library let's try a thought game.
这是一个物理库,box2d.js.你给它形状、质量和力,它会为你计算物理.如果它真的只是一个数学库,而你必须自己提供所有物理方程,你还会称它为物理库吗?一个叫做物理库的东西必须提供物理知识,否则它就不是物理库.同样,一个叫做 3D 库的东西必须提供 3D 知识,否则它就不是 3D 库.
Here's a physics library, box2d.js. 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.
OpenGL 1.0 是一个 3D 库.你给它 3D 位置、顶点颜色、灯光,它会为你绘制 3D.您不需要 3D 知识.另一方面,WebGL 不提供任何 3D 知识.你必须知道如何进行 3D 投影,你必须知道如何采样纹理,你必须知道如何进行光照计算.它不再是一个 3D 库,它只是一个光栅化 API.将其称为 3D 图书馆是谎言,对那些真正寻找 3D 图书馆(即提供 3D 的图书馆)的人来说是一种伤害.
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.
称它为 2D 库可能有点夸张,但称它为 3D 库是错误的.
Calling it a 2D library might be hyperbole but calling it a 3D library is wrong.
这是另一篇关于它的文章.
相关文章