Почему это означает, что WebGL является 2D API, а не 3D API?
Согласно HTML5 Rocks, WebGL на самом деле является 2D API, а не 3D API. Почему они говорят это и что это значит?
Мы можем указать координаты X, Y, Z в вершинных шейдерах WebGL и шейдерах фрагментов. Я не могу понять разницу между API 2D и 3D графики. Не могли бы вы объяснить, почему они говорят, что это 2D API?
Ответы
Ответ 1
WebGL - это API растрирования, а не 3D-api. Вы должны предоставить ему проецируемые координаты. Это много отличается от Холста. Это просто быстрее. Давайте сравним.
Здесь 3D в холсте
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 < cubeVertices.length; ii += 3) {
points.push(m.transformPoint(
worldViewProjection,
[cubeVertices[ii + 0], cubeVertices[ii + 1], cubeVertices[ii + 2]]));
}
for (var 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();
}
}
и здесь же 3D в WebGL
<script>
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();
}
</script>
<!-- vertex shader -->
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec4 a_position;
uniform mat4 u_worldViewProjection;
void main() {
//
// transform points from 3D to 2D.
//
gl_Position = u_worldViewProjection * a_position;
}
</script>
<!-- fragment shader -->
<script id="2d-fragment-shader" type="x-shader/x-fragment">
void main() {
gl_FragColor = vec4(0,0,0,1);
}
</script>
Если вы хотите увидеть их в режиме реального времени здесь версия холста и здесь версия webgl.
Единственное отличие между Canvas и WebGL заключается в Canvas. Я сделал проекцию преобразования в JavaScript и в WebGL. Я сделал проекцию в шейдере. В обоих случаях код , который я написал, сделал проецирование.
В версии Canvas этот код:
m.transformPoint(
worldViewProjection,
[cubeVertices[ii + 0], cubeVertices[ii + 1], cubeVertices[ii + 2]);
В версии WebGL этот код:
gl_Position = u_worldViewProjection * a_position
Сам API только растеризуется. Я должен предоставить проекцию в любом случае. В WebGL нет ничего, что бы делало 3D. Существует только растеризация api и 2 функции, шейдер вершин и шейдер фрагмента, написанный в GLSL, который я должен предоставить для этого запуска очень быстро и включить математическую библиотеку. Я все равно должен предоставить код в 3D для API в обоих случаях.
WebGL - это НЕ 3D-API
Я считаю важным подчеркнуть это. Существуют различные версии OpenGL. Оригинальный OpenGL с 1993 года был 3D-апи. Вы дали ему 3D-данные, вы сказали, какие цвета делать вещи, вы рассказали о различных огнях. Вы дали ему модельную матрицу и матрицу проекций, и она привлекла 3D для вас.
OpenGL ES 2.0 и WebGL избавились от всего этого. Они предоставляют API-интерфейс растеризации и шейдеры и позволяют вам программировать аппаратное обеспечение. Но вам решать написать все прогнозы. Вы должны вычислить проецируемые координаты из 3D. Вы вычисляете уравнения освещения, цвета и все остальное.
Это делает WebGL и OpenGL ES 2.0 намного сложнее старой фиксированной функции OpenGL, но в то же время делает их более гибкими. Если вам удобно делать все эти преобразования и математику, или если вы не возражаете, изучая это, тогда прыгайте и делайте это. Если вам не удобно делать все, тогда есть много библиотек WebGL 3D, которые сделают это для вас.
Для вас, кто утверждает, что WebGL представляет собой 3D-библиотеку, попробуйте продуманную игру.
Здесь находится библиотека физики, box2d.js. Вы даете ему формы, массы и силы, и он вычисляет физику для вас. Если бы все это было на самом деле, это была математическая библиотека, и вам приходилось самим задавать все физические уравнения, если бы вы по-прежнему называли это библиотекой физики? То, что называется физикой, должно снабжать физическое знание, иначе оно не является библиотекой физики. Точно так же что-то, называемое 3D-библиотекой, должно поставлять 3D-знания, иначе это не 3D-библиотека.
OpenGL 1.0 была трехмерной библиотекой. Вы дали ему 3D-позиции, цвета вершин, огни, и это привлекло 3D для вас. Вы не нуждались в 3D-знаниях. С другой стороны, WebGL не предоставляет никаких 3D-знаний. Вы должны знать, как делать 3D-прогнозы, вы должны знать, как пробовать текстуры, вы должны знать, как выполнять вычисления освещения. Это уже не 3D-библиотека, а просто API растеризации. Назвать его 3D-библиотекой - ложь и плохая услуга для тех, кто действительно ищет 3D-библиотеку, то есть библиотеку, предоставляющую 3D.
Вызов 2D-библиотеки может быть гиперболом, но называть его 3D-библиотекой не так.
Вот еще одна статья об этом.
Ответ 2
WebGL - фактически 2D API, а не 3D API. Что это значит?
Это означает, что вы должны прекратить слушать какой-либо веб-сайт, или человек сказал вам это. Когда люди говорят такие идиотские вещи, лучше их игнорировать и переходить к более разумным учебным материалам/информации/дискуссиям.
Вы можете работать с WebGL в чисто двумерных терминах. Вы можете передавать двумерные позиции в вершинные шейдеры. Вы можете полностью отключить тестирование глубины. И так далее. Но вывод вашего вершинного шейдера является 4D однородной координатой, даже если ваш W равен 1, а ваш Z равен 0. Таким образом, система рендеринга будет делать все 3D-математика, которую она обычно выполняет для 3D-сцены.
Да, растеризация - это в основном 2D-процесс, с глубинным тестированием, как "взломать", чтобы разрешить скрытое удаление поверхности. Но это верно для всех рендерингов, основанных на растеризации. D3D, OpenGL, GLIDE и каждый программный растеризатор также будут "2D API" по этой логике.
И если все они являются 2D-API, то утверждение бессмысленно. Он ставит OpenGL/D3D на тот же уровень, что и фактические "2D API" , такие как SDL и Direct2D. Тем не менее эти "2D API" не могут вообще выполнять 3D-рендеринг (или не без значительной боли).
Таким образом, утверждение является фактически неверным и невероятно ошибочным. Тот, кто сказал, что это не стоит вашего времени или внимания.
из комментариев:
Человек, который изначально написал этот материал "WebGL - 2D", соизволил объяснить свои рассуждения, поэтому я рассмотрю эти моменты здесь.
Пусть используется его определение размерности API. Его точная цитата:
Вы дали им 3D-данные и ничего больше, и они дали вам 3D-дисплей. OpenGL ES 2.0 - это 2D api. Вы должны сами поместить все 3D-преобразования в 2D-математику.
Из этого можно сделать вывод, что "3D API" означает "API, который" вы загружаете 3D-значения в 3D-рендеринг ". Аналогичным образом, "2D API" означает "API ", который" вы передаете 2D-значения для вызывания 2D-рендеринга".
Предположим, что "вы" означает не просто размерность значений, полученных из объекта-буфера. "Вы" означает каждый фрагмент кода, которым вы управляете напрямую, включая ваш шейдер. Хорошо. Итак, "вы", для WebGL, останавливается в конце шейдера вершин. Поэтому WebGL начинает делать свои вещи с выводами шейдера вершин.
Выход из вершинного шейдера представляет собой 4D-однородную координату. Я предполагаю, что аргумент состоит в том, что 4D-однородная координата каким-то образом идентична двумерной координате. Хотя это явно не так, поскольку у него есть еще два компонента, и различные математические операции, которые вы делаете с ними, очень разные.
Я позволю вам решить, хотите ли вы считать однородную координату 4D идентичной 2D-координате.
Вместо этого я посмотрю, как WebGL рассматривает выход 4D. Преобразует ли он его в двумерную координату? В спецификации OpenGL нет.
Из OpenGL ES 2.0, раздел 2.12, folio стр. 44:
Выполнение вершинного шейдера дает координату вершины gl_Position
, которая предполагается в координатах клипа. Перспективное деление выполняется по координатам клипа, чтобы получить нормализованные координаты устройства, а затем преобразование видового экрана для преобразования этих координат в координаты окна (см. Рисунок 2.4).
Координаты клипа представляют собой четырехмерные однородные векторы, состоящие из x, y, z и w (в этом порядке). Если координаты клипов вершин:
(x c, y c, z c, w c)
то согласованные координаты устройства вершин
(x d, y d, z d) = (x c/w c, y c/, z c/w c)
Нормализованное координатное пространство устройства имеет 3 компонента. Следовательно, это не двумерное пространство. Но как насчет последующих преобразований?
Хорошо, из раздела 2.12.1 той же спецификации (folio pages 44-45):
Преобразование видового экрана определяется шириной и высотой видовых экранов в пикселях, p x и p y, соответственно, и ее центром (o x, o y) (также в пикселях). Координаты окна вершин, (x w, y w, z w), даются выражением
x w= (p x/2) x d + o x
y w= (p y/2) y d + o y
z w= ((f - n)/2) z d + (n + f)/2
Итак, да, даже оконное пространство представляет собой трехмерную систему координат. Окно - это конечное пространство, которое OpenGL использует при его вычислении; оконное пространство идет прямо к растеризатору. Это то, что получается.
Следовательно, по спецификации OpenGL ES 2.0 во всем конвейе рендеринга нет смысла, когда что-либо преобразуется в чисто двумерное пространство.
WebGL - это API, в который вы загружаете однородные координаты 4D. Ни в коем случае WebGL не выполняет любое "преобразование в 3D-2D-математику", равно как и пользователь. Никто не преобразует ничего в 2D-координаты в любой точке WebGL. 2D-значения не подаются через 2D-конвейер; Значения 4D подаются через трехмерный конвейер.
Поэтому, по его собственному определению, WebGL не является 2D-API.
QED.
Ответ 3
По моему мнению (как разработчик игры с опытом работы с 3D-графикой более 15 лет), gman-характеристика WebGL как 2D API в лучшем случае вводит в заблуждение, и я бы склонен был спорить, это просто неверно. Николь Болас указывает на большинство причин, почему в его ответе, но для меня основной момент в том, что просто невозможно получить правильно отображаемую трехмерную сцену, как только вы перейдете от графики каркаса. Gman использует в своих примерах canvas/WebGL для текстурирования треугольники, если WebGL не был снабжен информацией z и w на выходе вершинного шейдера, и если он не использовал их во время растеризации, чтобы получить правильную интерполяцию перспективы и выполнить скрытое удаление поверхности с использованием z-буфера.
Кажется, что точка gman, похоже, пытается сделать так, что WebGL не является фиксированной функциональной 3D-графикой API, как старые API-интерфейсы 3D-графики, но имеет программируемый конвейер. Однако это относится ко всем современным API-интерфейсам 3D-графики (Direct3D 8, 9, 10, 11, OpenGL 2.0 и выше, проприетарные API-интерфейсы, которые вы найдете на консолях, таких как PS3, PS4, Wii U...). Все они работают по-разному: вершинные шейдеры выводят однородные координаты, а растеризатор использует информацию z и w для правильной интерполяции трехмерных треугольников, проецируемых в 2D-изображение, и для удаления скрытой поверхности с использованием z-буфера. Это сильно отличается от 2D API, которые не имеют координат z и w, не имеют понятия правильной интерполяции перспективы и нет z-буфера для скрытого удаления поверхности. Чтобы визуализировать 3D-сцену текстурированных треугольников правильно в 2D API, таком как холст, вам нужно будет реализовать все это в программном обеспечении самостоятельно.
[ Обновлено] В одной из своих статей gman использует 'API' и 'Library' более или менее взаимозаменяемо, Я не думаю, что существует четкое и хорошо установленное определение этих двух терминов, но я думаю, что разное понимание терминов может способствовать некоторым разногласиям здесь.
Хронос описывает WebGL:
WebGL ™ - это API-интерфейс рендеринга в режиме реального времени, разработанный для Интернета.
и я думаю, что это точное описание. Одним из обычно используемых значений "API" является определенный программный интерфейс для доступа к базовому оборудованию или службам ОС и относится к программному интерфейсу, ориентированному на общественность, а не к какой-либо конкретной реализации. В этом смысле все основные современные API-интерфейсы, предназначенные для доступа к аппаратным средствам 3D-графики, можно рассматривать как низкоуровневые "API-интерфейсы 3D-рендеринга немедленного режима". Я бы включил OpenGL, OpenGL ES, WebGL, Direct3D и проприетарные API-интерфейсы, найденные на консолях этой категории.
В отрасли нормально относиться ко всем этим как "3D API", потому что они предназначены для обеспечения доступа к графическим процессорам, основная функция которых заключается в рендеринг 3D-графики, и они раскрывают низкоуровневую функциональность, поддерживающую эту функцию (с точки зрения перспективы интерполяция и удаление скрытой поверхности на основе z-буфера во время растеризации, анизотропная фильтрация текстур, в некоторых случаях аппаратное обеспечение тесселяции и т.д.), а также средство программирования программируемых частей 3D-конвейера (вершины, пиксели, геометрические шейдеры, корпус и домен шейдеры и т.д.).
Я склонен думать о том, что "библиотека" имеет несколько иное значение для "API" . Что-то вроде three.js описывает себя как "библиотека", а не "API" :
Three.js - это библиотека, которая делает WebGL-3D в браузере - очень легко. В то время как простой куб в необработанном WebGL получал сотни строки кода Javascript и шейдера, эквивалент Three.js - это только часть этого.
и, хотя нет жестких и быстрых определений этих двух терминов, я склонен думать о библиотеке, ссылаясь скорее на конкретную реализацию функциональности и подразумевая, возможно, более функциональные вспомогательные функции более высокого уровня, чем прямой API.
Другие трехмерные "библиотеки" более высокого уровня могут описывать себя как "двигатели" или "рамки", например
OGRE (Object-Oriented Graphics Rendering Engine) - это ориентированный на сцену, гибкий 3D-движок, написанный на С++, разработанный для упрощения и интуитивно понятный разработчикам для создания приложений, использующих 3D-графика с аппаратным ускорением.
Существует целая группа функциональных возможностей, которая не является частью API-интерфейсов с фиксированной функцией старого стиля, таких как pre 2.0 OpenGL или pre DX8 DirectX, но очень полезна, если вы просто хотите отображать некоторые 3D-объекты, не требуя подробного понимания 3D-графики - такие вещи, как граф сцены, функции загрузки и рендеринга моделей с прикрепленными материалами, поддержка высокого уровня огней и теней и т.д., но это не то, на что нацелены API-интерфейсы низкого уровня 3D, такие как Direct3D или WebGL. Это не проблема, которую они пытаются решить. Я могу понять, как было бы полезно попытаться передать это новичкам, которые просто хотят отображать некоторые 3D-объекты в браузере, но я не думаю, что утверждение, что WebGL является "2D API", является полезным или точным способом получить это через.
Ответ 4
Ну, я не знаю о всех остальных - я был бы склонен пойти с тем, что сказал Кронос на своем сайте. Кажется совершенно ясным для меня.: Пожимает плечами:
WebGL ™ - это API-интерфейс рендеринга в режиме реального времени, разработанный для Интернета. Это получена из OpenGL® ES 2.0 и обеспечивает аналогичный рендеринг функциональности, но в контексте HTML. WebGL разработан как контекста рендеринга для элемента HTML Canvas. HTML-холст обеспечивает назначение программной рендеринга на веб-страницах и позволяет выполнять этот рендеринг с использованием различных API-интерфейсов рендеринга. Единственный такой интерфейс, описанный как часть спецификации Canvas это 2D-рендеринг контекста CanvasRenderingContext2D. Эта документ описывает другой такой интерфейс, WebGLRenderingContext, который представляет API WebGL.
https://www.khronos.org/registry/webgl/specs/1.0/
Ответ 5
Это точка зрения.
Ничто не обязано в WebGL моделировать мир в 3d, создавать камеру, устанавливать огни и т.д. В конце рендеринг касается только точек, линий и треугольников, чьи 4 координаты относятся к |w*x|<w, |w*y|<w, |w*z|<w.
Также по умолчанию один может передать шейдеру только две координаты x и y, тогда как каркас устанавливает z = 0 и w = 1.
Можно также использовать opengl es для рисования 2d спрайтов без каких-либо проблем с настройкой некоторой матрицы прогноза. Можно опустить z-буфер и обработку z-координаты вместе до точки, где необходимо удержать: | z * w | <= w для всего, что нужно сделать.
Но также совершенно ясно, что это не совпадение, что API хорошо подходит для рендеринга 3D-моделей.
Ответ 6
Ничего себе, ваш вопрос просто отличный! Вы совершили все эти гуру, как в последнем бою O.o
Ну, может быть, вам также хотелось бы получить ответ от парня с 1-летним опытом WebGL и almoast без навыков программирования OpenGL, так что сделайте это!:)
Во-первых, я должен сказать то, что я еще не читал, и считаю это важным. @gman sais, что:
API предоставляет решение, поэтому у вас нет знание.
Хорошо, я действительно не согласен с этим утверждением. API предоставляет некоторое решение, но это не значит, что вам не нужны эти знания.
Теперь вернемся к вашему вопросу, как вы сказали:
Мы можем указать координаты x, y, z в вершинном шейдере webGL и fragement шейдер. Я не мог понять разницу между 2D и 3D-графикой API.
Как говорят другие, вы можете указать (я думаю, что вы даже должны указывать) gl_Position
в шейдере, который является 4D-вектором. Раньше был только javascript и некоторые отделенные gpu. Затем появляется WebGL с новыми параметрами. Сам WebGL не предлагает каких-либо решений для 3D-поведения, но он включает эту опцию, чтобы указать gl_Position
в шейдере.
И я считаю новые варианты, а не целые решения. Поэтому я думаю, что этот вопрос касается и того, что API действительно для вас. Для меня? В этом случае он позволяет создавать 3D-приложения через шейдер. Так что это 3D API.
Надеюсь, это поможет...