13

HTML5 Rocks によると、WebGL は実際には 2D API であり、3D API ではありません。なぜ彼らはそれを言うのですか、それはどういう意味ですか?

WebGL 頂点シェーダーとフラグメント シェーダーで X、Y、Z 座標を指定できます。2D グラフィック API と 3D グラフィック API の違いがわかりません。これが 2D API であると彼らが言う理由を説明していただけますか?

4

6 に答える 6

25

WebGL は実際には 2D API であり、3D API ではありません。どういう意味ですか?

それは、ウェブサイトや人があなたに言ったことに耳を傾けるのをやめるべきであることを意味します. 人々がそのようなばかげたことを言うときは、それらを無視して、より合理的なチュートリアル/情報/議論に移るのが最善です.

純粋な 2D 用語で WebGL を使用することは確かに可能です。2D 位置を頂点シェーダーに渡すことができます。深度テストを完全にオフにすることができます。などなど。ただし、頂点シェーダーからの出力は、たとえ W が 1 で Z が 0 であっても、4D 同次座標です。したがって、レンダリング システムは、通常 3D シーンに対して行うすべての 3D 計算を行います。

はい、ラスタライゼーションは基本的に 2D プロセスであり、深度テストは「ハック」として隠面の除去を可能にします。しかし、これはすべてのラスター化ベースのレンダリングに当てはまります。D3D、OpenGL、GLIDE、およびすべてのソフトウェア ラスタライザー、このロジックによって「2D API」になります。

そして、それらすべてが 2D API である場合、このステートメントは無意味です。OpenGL/D3D を、SDL や Direct2D などの実際の「2D API」と同じレベルに置きます。しかし、これらの「2D API」は 3D レンダリングをまったく行うことができません (または、かなりの苦痛を伴います)。

したがって、この声明は事実に反しており、信じられないほど誤解を招くものです。誰が言ったとしても、あなたの時間や注意を払う価値はありません。

コメントから:

この「WebGL は 2D である」というものを最初に書いた人は、彼の推論を説明するように設計されているので、ここでそれらの点に対処します。

API 次元の彼の定義を使用しましょう。彼の正確な引用は次のとおりです。

あなたは彼らに 3D データだけを渡し、3D ディスプレイを渡しました。OpenGL ES 2.0 は 2D API です。3D から 2D への数学変換はすべて自分で行う必要があります。

このことから、「3D API」とは「3D 値を入力して 3D レンダリングを発生させる API」を意味すると推測できます。同様に、「2D API」とは、「2D 値を入力して 2D レンダリングを発生させる API」を意味します。

「あなた」が単にバッファオブジェクトからフェッチされた値の次元を意味しないと仮定しましょう。「ユーザー」とは、シェーダーを含む、直接制御できるすべてのコードを意味します。いいよ。したがって、WebGL の場合、「あなた」は頂点シェーダーの最後で停止します。したがって、WebGL は頂点シェーダー出力を使用して処理を開始します。

頂点シェーダーからの出力は、4D 同次座標です。議論は、4D同次座標が2D座標と何らかの形で同一であるということだと推測しています。明らかにそうではありませんが、さらに 2 つのコンポーネントがあり、それらを使用して行うさまざまな数学演算が大きく異なるためです。

4D 同次座標を 2D 座標と同一であるとみなすかどうかは、あなたに決めてもらいます。

代わりに、 WebGLが 4D 出力をどのように扱うかを見ていきます。それを2D座標に変換しますか?OpenGL の仕様ではノーと言われています。

OpenGL ES 2.0、セクション 2.12、フォリオ ページ 44 から:

頂点シェーダーを実行するgl_Positionと、クリップ座標にあると想定される頂点座標が生成されます。クリップ座標に対して透視分割が実行され、正規化されたデバイス座標が生成されます。続いて、これらの座標をウィンドウ座標に変換するビューポート変換が行われます (図 2.4 を参照)。

クリップ座標は、x、y、z、および w 座標 (この順序) で構成される 4 次元の同次ベクトルです。頂点のクリップ座標が次の場合:

(x c , y c , z c , w c )

頂点の正規化されたデバイス座標は

(x d , y d , z d ) = (x c /w c , y c /w c , z c /w c )

正規化されたデバイス座標空間には 3 つのコンポーネントがあります。したがって、2D 空間ではありません。しかし、その後の変換はどうですか?

さて、同じ仕様のセクション 2.12.1 (フォリオの 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

そうです、ウィンドウ空間も3D 座標系です。ウィンドウ スペースは、OpenGL が計算で使用する最終的なスペースです。ウィンドウ スペースは直接ラスタライザに送られます。それがレンダリングされるものです。

したがって、OpenGL ES 2.0 仕様では、レンダリング パイプライン全体で純粋な2D 空間に変換されるポイントはありません。

WebGL は、4D 同次座標をフィードする API です。WebGL が「3D から 2D への数学変換」を実行することはありません。また、ユーザーも実行しません。WebGL のどの時点でも、誰も何も 2D 座標に変換しません。2D 値は 2D パイプラインを介して供給されません。4D 値は 3D パイプラインを介して供給されます。

したがって、彼自身の定義によると、WebGL は 2D API ではありません。

QED。

于 2012-10-30T16:26:31.867 に答える
16

私の意見では (3D グラフィックスの経験が 15 年以上あるゲーム開発者として)、gman による 2D API としての WebGL の特徴付けは、せいぜい非常に誤解を招くものであり、完全に間違っていると主張したいと思います。Nicol Bolas は彼の回答で理由のほとんどを指摘していますが、私にとっての重要な点は、gman が彼のキャンバスで使用するワイヤーフレーム グラフィックス/WebGL の例からテクスチャに移行すると、正しくレンダリングされた 3D シーンを取得することは単に不可能だということです。頂点シェーダーの出力で WebGL に z および w 情報が提供されず、ラスタライズ中にそれらを使用して遠近法の正しい補間を取得し、z バッファーを使用して隠面除去を実行した場合の三角形。

gman が実際に行おうとしているように見える点は、WebGL は、古い古代の 3D グラフィックス API のような固定機能の 3D グラフィックス API ではなく、プログラム可能なパイプラインを備えているということです。ただし、これはすべての最新の 3D グラフィックス API に当てはまります (Direct3D 8、9、10、11、OpenGL 2.0 以降、PS3、PS4、Wii U などのコンソールにある独自の API など)。それらはすべて基本的に同じように機能します。頂点シェーダーは同次座標を出力し、ラスタライザーは z および w 情報を使用して、2D イメージに投影された 3D 三角形を正しく補間し、z バッファーを使用して隠面除去を実行します。これは、z 座標と w 座標がなく、遠近法の正しい補間の概念がなく、隠面消去用の z バッファがない 2D API とは大きく異なります。

[更新] 彼の記事の 1 つで、 gman は「API」と「ライブラリ」を多かれ少なかれ同じ意味で使用しています。2 つの用語の明確で十分に確立された定義があるとは思いませんが、用語の異なる理解がここでの不一致の一部に寄与している可能性があると思います。

クロノスは WebGL について次のように説明しています。

WebGL™ は、Web 用に設計された即時モード 3D レンダリング API です。

それは正確な説明だと思います。「API」の一般的に使用される意味の 1 つは、基盤となるハードウェアまたは OS サービスにアクセスするための定義済みのソフトウェア インターフェイスであり、特定の実装ではなく、公開されているソフトウェア インターフェイスを指します。この意味で、3D グラフィックス ハードウェアにアクセスすることを目的としたすべての主流の最新 API は、低レベルの「即時モード 3D レンダリング API」と見なすことができます。このカテゴリには、OpenGL、OpenGL ES、WebGL、Direct3D、およびコンソールにある独自の API が含まれます。

業界では、これらすべてを「3D API」と呼ぶのが普通です。これらの API は、3D グラフィックスのレンダリングを主な機能とする GPU へのアクセスを提供するように設計されており、その機能をサポートする低レベルの機能を公開するためです (視点の正しい補間と z -ラスタライズ中のバッファベースの隠面除去、異方性テクスチャ フィルタリング、場合によってはテッセレーション ハードウェアなど)、および 3D パイプラインのプログラム可能な部分 (頂点、ピクセル、ジオメトリ シェーダ、ハルおよびドメイン シェーダなど) をプログラムする手段。 )。

「ライブラリ」は「API」とは少し異なる意味を持つと考える傾向があります。three.js のようなものは、自身を「API」ではなく「ライブラリ」と表現しています。

Three.js は WebGL (ブラウザーでの 3D) を非常に簡単にするライブラリーです。生の WebGL の単純な立方体は、数百行の Javascript とシェーダー コードを生成しますが、Three.js の同等物はそのほんの一部にすぎません。

この 2 つの用語の明確で明確な定義はありませんが、私はライブラリを、機能の特定の実装をより参照し、単純な API よりも高レベルのヘルパー機能を暗示していると考える傾向があります。

他の高レベルの 3D「ライブラリ」は、「エンジン」または「フレームワーク」として記述される場合があります。

OGRE (Object-Oriented Graphics Rendering Engine) は、C++ で記述されたシーン指向の柔軟な 3D エンジンであり、開発者がハードウェア アクセラレーション 3D グラフィックスを利用したアプリケーションをより簡単かつ直感的に作成できるように設計されています。

2.0 より前の OpenGL や DX8 より前の DirectX のような古いスタイルの固定関数 'API' の一部ではない機能がたくさんありますが、3D グラフィックスの詳細な理解を必要とせずにいくつかの 3D オブジェクトをレンダリングしたい場合には非常に便利です。シーン グラフ、アタッチされたマテリアルを含むモデルをロードおよびレンダリングする関数、ライトとシャドウの高レベル サポートなどがありますが、それは Direct3D や WebGL などの低レベル 3D 'API' が目指しているものではありません。それは彼らが解決しようとしている問題ではありません。ブラウザで3Dオブジェクトをレンダリングしたいだけの初心者にそれを伝えてみることがどのように役立つかはわかりますが、WebGLが「2D API」であると主張することは、それを理解するのに役立つまたは正確な方法ではないと思います. .

于 2014-01-06T23:57:12.613 に答える
6

ええと、私は他のみんなについては知りません-クロノスが彼らのウェブサイトで言ったことは何でもやりたいと思います。私には完全に明らかなようです。:肩をすくめる:

WebGL™は、Web用に設計された即時モードの3DレンダリングAPIです。OpenGL®ES2.0から派生し、同様のレンダリング機能を提供しますが、HTMLコンテキストで提供されます。WebGLは、HTMLCanvas要素のレンダリングコンテキストとして設計されています。HTML Canvasは、Webページでのプログラムによるレンダリングの宛先を提供し、さまざまなレンダリングAPIを使用してそのレンダリングを実行できるようにします。Canvas仕様の一部として説明されているこのようなインターフェイスは、2DキャンバスレンダリングコンテキストであるCanvasRenderingContext2Dのみです。このドキュメントでは、WebGLAPIを提供する別のそのようなインターフェイスであるWebGLRenderingContextについて説明します。

https://www.khronos.org/registry/webgl/specs/1.0/

于 2012-11-02T14:53:41.793 に答える
5

それは視点です。

WebGL では、世界を 3D でモデル化したり、カメラを作成したり、ライトを設定したりする必要はありません。最後に、レンダラーは、点、線、および三角形のみを考慮します。これらの 4 つの座標|w*x|<w, |w*y|<w, |w*z|<w.は、シェーダーにのみ渡すことができます。 x と y の 2 つの座標、フレームワークは z=0 と w=1 を設定します。

射影行列の設定を気にせずに、opengl es を使用して 2D スプライトを描画することもできます。|z*w| を保持する必要があるポイントまで、z バッファーと z 座標の処理をすべて一緒に省略できます。<= w レンダリングされるものすべて。

しかし、API が 3D モデルのレンダリングに適しているのは偶然ではないことも明らかです。

于 2012-10-30T09:28:32.777 に答える
4

WebGL はラスタレーション API であり、3D API ではありません。投影座標を提供する必要があります。このように多くの点で Canvas と変わりません。それはただ速いです。比較してみましょう。

これが Canvas の 3D です

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 です

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 ではシェーダーでプロジェクションを行ったことです。どちらの場合も、私が書いたコードは射影を行いました。

Canvas バージョンのコードは次のとおりです。

m4.transformPoint(
    worldViewProjection,
    cubeVertices.slice(ii, ii + 3));

WebGL バージョンでは、そのコードは次のとおりです。

gl_Position = u_worldViewProjection * a_position

API 自体はラスタライズのみを行います。どちらの場合も、投影コードを提供する必要があります。3D を行う WebGL には何もありません。ラスタライゼーション API と 2 つの関数 (頂点シェーダーとフラグメント シェーダー) だけがあり、どちらも GLSL で記述されており、非常に高速に実行され、数学ライブラリが含まれている必要があります。どちらの場合も、3D を実行するためのコードを API に提供する必要があります。

WebGL は 3D API **ではない*

これを指摘することは重要だと思います。OpenGL にはさまざまなバージョンがあります。1993 年のオリジナルの OpenGL は 3D API でした。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 が描画されます。3D の知識は必要ありません。一方、WebGL は 3D の知識を提供しません。3D プロジェクションを行う方法、テクスチャをサンプリングする方法、ライティングの計算方法を知る必要があります。これはもはや 3D ライブラリではなく、単なるラスタライズ API です。これを 3D ライブラリと呼ぶのは嘘であり、実際に 3D ライブラリ、つまり 3D を提供するライブラリを探している人にとっては不利益です。

それを 2D ライブラリと呼ぶのは誇張かもしれませんが、3D ライブラリと呼ぶのは間違っています。

これについての別の記事があります。

于 2012-11-01T09:01:14.950 に答える
0

うわー、あなたの質問は素晴らしいです!あなたは最後の戦いのようにこれらすべての達人を戦わせました Oo

WebGL の経験が 1 年ほどあり、OpenGL プログラミングのスキルがほとんどない人からの回答も読みたいと思うかもしれません。そうしましょう。:)

最初に、まだ読んでいない重要なことを言わなければなりません。@gman は次のように述べています。

API はソリューションを提供するため、個人的にその知識を持っている必要はありません。

ええと、私はこの声明に本当に同意しません。API はいくつかのソリューションを提供しますが、その知識が必要ないという意味ではありません。

あなたが言ったように、あなたの質問に戻ります:

webGL 頂点シェーダーとフラグメント シェーダーで x、y、z 座標を指定できます。2D と 3D グラフィックス API の違いがわかりませんでした。

他の人が言うように、 4D ベクトルであるシェーダーで指定できます (指定する必要さえあると思います) 。gl_Position以前は、javascript と分離された GPU だけでした。次に、WebGL が新しいオプションとともに表示されます。WebGL 自体は3D 動作の解決策を提供しませんがgl_Position、シェーダーで指定するオプションを提供します。

また、ソリューション全体だけでなく、新しいオプションも数えます。ですから、この質問は、あなたにとって本当に API とは何かということでもあると思います。私のため?この場合、シェーダーを介して 3D アプリケーションを作成する可能性がもたらされます。つまり、3D API です。

それが役立つことを願っています...

于 2014-01-13T18:35:58.273 に答える