Почему это означает, что 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.

Надеюсь, это поможет...