From ca702ba92756f5a1fc25785a24dcd61bf8a42533 Mon Sep 17 00:00:00 2001 From: Gregg Tavares Date: Tue, 14 Jan 2025 20:49:01 -0800 Subject: [PATCH] fixes for new lesson-builder --- webgl/lessons/ja/webgl-how-it-works.md | 8 ++++---- webgl/lessons/ja/webgl1-to-webgl2.md | 12 +++++------ webgl/lessons/ko/webgl-2d-drawimage.md | 4 ++-- webgl/lessons/ko/webgl-2d-vs-3d-library.md | 8 ++++---- webgl/lessons/ko/webgl-3d-orthographic.md | 4 ++-- webgl/lessons/ko/webgl-how-it-works.md | 8 ++++---- webgl/lessons/ko/webgl-less-code-more-fun.md | 8 ++++---- .../ko/webgl-planar-projection-mapping.md | 16 +++++++-------- webgl/lessons/ko/webgl1-to-webgl2.md | 16 +++++++-------- webgl/lessons/pt-br/webgl-2d-vs-3d-library.md | 8 ++++---- webgl/lessons/pt-br/webgl1-to-webgl2.md | 20 +++++++++---------- webgl/lessons/webgl-2d-drawimage.md | 4 ++-- webgl/lessons/webgl-2d-vs-3d-library.md | 8 ++++---- webgl/lessons/webgl-less-code-more-fun.md | 8 ++++---- webgl/lessons/webgl-load-obj-w-mtl.md | 4 ++-- .../webgl-planar-projection-mapping.md | 16 +++++++-------- webgl/lessons/webgl-scene-graph.md | 8 ++++---- webgl/lessons/webgl1-to-webgl2.md | 12 +++++------ webgl/lessons/zh_cn/webgl-2d-drawimage.md | 4 ++-- .../lessons/zh_cn/webgl-3d-geometry-lathe.md | 12 +++++------ webgl/lessons/zh_cn/webgl-3d-orthographic.md | 8 ++++---- webgl/lessons/zh_cn/webgl-how-it-works.md | 8 ++++---- .../lessons/zh_cn/webgl-less-code-more-fun.md | 8 ++++---- webgl/lessons/zh_cn/webgl-load-obj-w-mtl.md | 4 ++-- .../zh_cn/webgl-planar-projection-mapping.md | 12 +++++------ webgl/lessons/zh_cn/webgl1-to-webgl2.md | 12 +++++------ 26 files changed, 120 insertions(+), 120 deletions(-) diff --git a/webgl/lessons/ja/webgl-how-it-works.md b/webgl/lessons/ja/webgl-how-it-works.md index 1a0bd4603..653812a7f 100644 --- a/webgl/lessons/ja/webgl-how-it-works.md +++ b/webgl/lessons/ja/webgl-how-it-works.md @@ -333,16 +333,16 @@ trueにした場合、BYTE型 (-128 〜 127) なら-1.0 〜 +1.0 、UNSIGNED_BYT これで頂点ごとに1色につき4バイトしか必要なくなり、75%の節約になります。

実際にコーディングしてみましょう。データの取り出し方を指定する部分は以下のコードになります。

-
+
{{#escapehtml}}
   var size = 4;
 *  var type = gl.UNSIGNED_BYTE;
 *  var normalize = true;
   var stride = 0;
   var offset = 0;
   gl.vertexAttribPointer(colorLocation, size, type, normalize, stride, offset);
-
+{{/escapehtml}}

バッファを色で塗りつぶす時は次のようにします。

-
+
{{#escapehtml}}
 // Fill the buffer with colors for the 2 triangles
 // that make the rectangle.
 function setColors(gl) {
@@ -365,7 +365,7 @@ function setColors(gl) {
           r2, b2, g2, 255]),
       gl.STATIC_DRAW);
 }
-
+{{/escapehtml}}

実行結果はこのようになります。

diff --git a/webgl/lessons/ja/webgl1-to-webgl2.md b/webgl/lessons/ja/webgl1-to-webgl2.md index aa00aa3fc..041a0b165 100644 --- a/webgl/lessons/ja/webgl1-to-webgl2.md +++ b/webgl/lessons/ja/webgl1-to-webgl2.md @@ -354,7 +354,7 @@ var someVAO = gl.createVertexArray();

WebGL1とWebGL2の両方で実行したい場合は、いくつかの課題があります。

1つの回避策は、初期化時にWebGL1の拡張機能をWebGLコンテキストにコピーする事です。そうすると残りのコードをそのままにできます。以下が例です。

-
+
{{#escapehtml}}
 const gl = someCanvas.getContext("webgl");
 const haveVAOs = getAndApplyExtension(gl, "OES_vertex_array_object");
 
@@ -393,18 +393,18 @@ function getAndApplyExtension(gl, name) {
   }
   return ext;
 }
-
+{{/escapehtml}}

コードが両方で同じように動作するようになりました。例:

-
+
{{#escapehtml}}
 if (haveVAOs) {
   var someVAO = gl.createVertexArray();
   ...
 } else {
   ... do whatever for no VAOs.
 }
-
+{{/escapehtml}}

代替案は次のような事をしなければならないでしょう。

-
+
{{#escapehtml}}
 if (haveVAOs) {
   if (isWebGL2)
      someVAO = gl.createVertexArray();
@@ -415,7 +415,7 @@ if (haveVAOs) {
 } else {
   ... do whatever for no VAOs.
 }
-
+{{/escapehtml}}

注意点: 特に頂点配列オブジェクトの場合、ポリフィルを使用する事をお勧めします。 VAOはほとんどのシステムで利用可能です。 VAOが利用可能ではない場合、ポリフィルが処理しコードがシンプルになります。 diff --git a/webgl/lessons/ko/webgl-2d-drawimage.md b/webgl/lessons/ko/webgl-2d-drawimage.md index e2fc0c949..1e6d2a1aa 100644 --- a/webgl/lessons/ko/webgl-2d-drawimage.md +++ b/webgl/lessons/ko/webgl-2d-drawimage.md @@ -467,7 +467,7 @@ WebGL을 창의적으로 사용하기 위한 것이라는 점을 강조하고 혹시 눈치챘을지 모르지만 우리는 위치 좌표에 사용한 단위 사각형은 정확히 텍스쳐 좌표의 단위 사각형과 크기가 일치합니다. 따라서 우리는 위치좌표를 바로 텍스쳐 좌표로 사용할 수 있습니다.

-
+
{{#escapehtml}}
 #version 300 es
 in vec4 a_position;
 -in vec2 a_texcoord;
@@ -481,7 +481,7 @@ void main() {
    gl_Position = u_matrix * a_position;
 *   v_texcoord = (u_textureMatrix * a_position).xy;
 }
-
+{{/escapehtml}}

이제 텍스쳐 좌표를 설정하는 코드를 삭제해도 됩니다. 삭제하더라도 이전과 완전히 동일하게 동작할 것입니다.

diff --git a/webgl/lessons/ko/webgl-2d-vs-3d-library.md b/webgl/lessons/ko/webgl-2d-vs-3d-library.md index 0f98ac7b8..79280a629 100644 --- a/webgl/lessons/ko/webgl-2d-vs-3d-library.md +++ b/webgl/lessons/ko/webgl-2d-vs-3d-library.md @@ -28,7 +28,7 @@ WebGL(그리고 OpenGL ES 2.0+)도 3D 장면을 그릴 때 사용하긴 하지 three.js를 사용하는 경우 코드는 아래와 같습니다. -
+
{{#escapehtml}}
   // 설정
   renderer = new THREE.WebGLRenderer({canvas: document.querySelector("#canvas")});
   c.appendChild(renderer.domElement);
@@ -64,7 +64,7 @@ three.js를 사용하는 경우 코드는 아래와 같습니다.
   light2 = new THREE.PointLight(0x0040ff, 2, 0);
   light2.position.set(-200, 100, 300);
   scene.add(light2);
-
+{{/escapehtml}}
그러면 아래와 같이 표시됩니다. @@ -72,7 +72,7 @@ three.js를 사용하는 경우 코드는 아래와 같습니다. OpenGL(ES가 아닌)을 사용해 2개의 조명과 육면체를 그리는 유사한 코드입니다. -
+
{{#escapehtml}}
   // 설정
   glViewport(0, 0, width, height);
   glMatrixMode(GL_PROJECTION);
@@ -125,7 +125,7 @@ OpenGL(ES가 아닌)을 사용해 2개의 조명과 육면체를 그리는 유
   */
 
   glEnd();
-
+{{/escapehtml}}
이 두 예제를 작성하는데 있어서 거의 3D 수학 지식이 필요하지 않다는 것에 주목하십시오. WebGL과 비교해서요. WebGL로 그리기 위한 코드는 작성하지 않을겁니다. 코드는 그렇게 길어지지는 않을겁니다. 코드 라인이 얼마나 필요한지가 중요한 것이 아닙니다. diff --git a/webgl/lessons/ko/webgl-3d-orthographic.md b/webgl/lessons/ko/webgl-3d-orthographic.md index 0ef63c37f..db9c5191a 100644 --- a/webgl/lessons/ko/webgl-3d-orthographic.md +++ b/webgl/lessons/ko/webgl-3d-orthographic.md @@ -639,7 +639,7 @@ in vec4 a_position; in vec4 a_color;

둘 다 'vec4'지만, 우리가 버퍼에서 데이터를 가져오는 방법을 WebGL에 알려줄 때에는 아래와 같이 정의하였습니다.

-
+
{{#escapehtml}}
 // attribute에게 positionBuffer (ARRAY_BUFFER)로부터 데이터를 가져오는 법을 알려줍니다. 
 var size = 3;          // iteration마다 3 개의 component
 var type = gl.FLOAT;   // 데이터는 32bit floats
@@ -658,7 +658,7 @@ var stride = 0;        // 0 = 각 iteration마다 다음 색상값을 얻기 위
 var offset = 0;        // 버퍼의 맨 앞부분부터 시작
 gl.vertexAttribPointer(
     colorAttributeLocation, size, type, normalize, stride, offset);
-
+{{/escapehtml}}

위에 써있는 '3'들은 버퍼에서 iteration마다, attribute마다 3개의 값을 가져오라는 뜻입니다. 이래도 되는 이유는 WebGL의 정점 쉐이더는 입력하지 않는 값에 대해 기본값을 사용하기 때문입니다. diff --git a/webgl/lessons/ko/webgl-how-it-works.md b/webgl/lessons/ko/webgl-how-it-works.md index 2ce781a7e..0ba615585 100644 --- a/webgl/lessons/ko/webgl-how-it-works.md +++ b/webgl/lessons/ko/webgl-how-it-works.md @@ -278,16 +278,16 @@ attribute의 위치를 알게 되면 두개의 명령문을 실행합니다. 정규화된 데이터의 가장 일반적인 용도는 색상입니다. 대부분의 경우 색상은 0.0에서 1.0 사이의 값으로 정의됩니다. 빨강, 초록, 파랑 그리고 알파에 대해 완전한 부동소수점을 사용하면 각 정점의 각 색상을 위해 16바이트를 사용하게 됩니다. 복잡한 geometry가 있는 경우 더 많은 바이트가 추가될 수 있습니다. 그 대신 색상들을 0이 0.0으로, 255가 1.0을 표현하는 UNSIGNED_BYTE로 변환 할 수 있습니다. 이제 정점당 색상에 4 바이트만 필요하므로 75%의 메모리 절감 효과가 있습니다.

이를 위해 코드를 변경해 보겠습니다. WebGL에게 우리가 사용할 색상을 가져오는 방법을 알려줄 때,

-
+
{{#escapehtml}}
   var size = 4;
 *  var type = gl.UNSIGNED_BYTE;
 *  var normalize = true;
   var stride = 0;
   var offset = 0;
   gl.vertexAttribPointer(colorLocation, size, type, normalize, stride, offset);
-
+{{/escapehtml}}

그 다음 버퍼를 사용할 색상으로 채울때 입니다.

-
+
{{#escapehtml}}
 // 사각형을 구성하는 두 개의 삼각형의 색상으로 버퍼를 채움
 function setColors(gl) {
   // 2 개의 랜덤 색상 선택
@@ -309,7 +309,7 @@ function setColors(gl) {
           r2, b2, g2, 255]),
       gl.STATIC_DRAW);
 }
-
+{{/escapehtml}}

아래는 결과 예제입니다.

diff --git a/webgl/lessons/ko/webgl-less-code-more-fun.md b/webgl/lessons/ko/webgl-less-code-more-fun.md index 1c5de347f..662e2f066 100644 --- a/webgl/lessons/ko/webgl-less-code-more-fun.md +++ b/webgl/lessons/ko/webgl-less-code-more-fun.md @@ -439,19 +439,19 @@ objects.forEach(function(object) {

자바스크립트에 익숙하신 분은들 setter를 아래와 같이 직접 호출해서 사용할 수 있는지 궁금하실 겁니다.

-
+
{{#escapehtml}}
 // 초기화 시점에
 var uniformSetters = twgl.createUniformSetters(program);
 
 // 그리는 시점에
 uniformSetters.u_ambient([1, 0, 0, 1]); // ambient color를 빨간색으로 설정.
-
+{{/escapehtml}}

이렇게 하는것이 좋지 않은 이유는 GLSL 프로그램을 작성할 때 셰이더를 변경하는 경우가 종종 생긴다는 겁니다. 주로 디버깅 목적으로요. 예를들어 프로그램을 사용했더니 화면에 아무것도 보이지 않는다고 합시다. 저같은 경우 이렇게 아무것도 나타나지 않을때 때 제일 먼저 하는 작업은 셰이더를 단순화 하는 것입니다. 예를들어 프래그먼트 셰이더의 출력을 아주 간단하게 바꿔봅니다.

-
+
{{#escapehtml}}
 #version 300 es
 precision highp float;
 
@@ -491,7 +491,7 @@ void main() {
       diffuseColor.a);
 *  outColor = vec4(0,1,0,1);  // <!--- 단순한 초록색으로
 }
-
+{{/escapehtml}}

outColor를 단색으로 설정하는 라인을 추가한 것에 주목하세요. 대부분의 드라이버는 위쪽 라인의 코드들이 최종 결과에 영향을 주지 않는다는 것을 알아냅니다. 그래서 모든 uniform들을 최적화합니다. 프로그램을 다시 실행하여 twgl.createUniformSetters를 호출하면 u_ambient를 위한 setter를 생성하지 못하고 위 코드에서 uniformSetters.u_ambient()를 호출하는 부분이 실패하면서 아래와 같은 메시지가 나타납니다. diff --git a/webgl/lessons/ko/webgl-planar-projection-mapping.md b/webgl/lessons/ko/webgl-planar-projection-mapping.md index 929a82d67..82f914c7f 100644 --- a/webgl/lessons/ko/webgl-planar-projection-mapping.md +++ b/webgl/lessons/ko/webgl-planar-projection-mapping.md @@ -740,21 +740,21 @@ Geometry를 생성하는 것이 올바른 방법인데, 그렇지 않으면 2개

조건부 텍스처 참조

위의 프래그먼트 셰이더에서는 항상 두 개의 텍스처를 모두 읽게 됩니다.

-

+
{{#escapehtml}}
   vec4 projectedTexColor = texture(u_projectedTexture, projectedTexcoord.xy);
   vec4 texColor = texture(u_texture, v_texcoord) * u_colorMult;
 
   float projectedAmount = inRange ? 1.0 : 0.0;
   gl_FragColor = mix(texColor, projectedTexColor, projectedAmount);
-
+{{/escapehtml}}

왜 아래와 같이 하지 않았을까요?

-

+
{{#escapehtml}}
   if (inRange) {
     gl_FragColor = texture(u_projectedTexture, projectedTexcoord.xy);
   } else {
     gl_FragColor = texture(u_texture, v_texcoord) * u_colorMult;
   }
-
+{{/escapehtml}}

GLSL ES 3.0 명세의 Section 8.8에 따르면

Texture Lookup Functions

@@ -767,7 +767,7 @@ derivatives are undefined within non-uniform control flow and for vertex texture 다시 말해 텍스처를 사용하는 경우 항상 텍스처에 접근할 수 있어야 한다는 것입니다. 결과를 조건부로 사용할 수는 있습니다. 예를 들어 아래와 같이 작성하거나

-

+
{{#escapehtml}}
   vec4 projectedTexColor = texture(u_projectedTexture, projectedTexcoord.xy);
   vec4 texColor = texture(u_texture, v_texcoord) * u_colorMult;
 
@@ -776,14 +776,14 @@ derivatives are undefined within non-uniform control flow and for vertex texture
   } else {
     gl_FragColor = texColor;
   }
-
+{{/escapehtml}}

아래와 같이 작성할 수 있습니다.

-

+
{{#escapehtml}}
   vec4 projectedTexColor = texture(u_projectedTexture, projectedTexcoord.xy);
   vec4 texColor = texture(u_texture, v_texcoord) * u_colorMult;
 
   gl_FragColor = inRange ? projectedTexColor : texColor;
-
+{{/escapehtml}}

하지만 텍스처 접근 자체를 조건부로 만들 수는 없습니다. 어떤 GPU에서는 작동될 수 있지만 모든 GPU에서 작동이 보장되지는 않습니다. diff --git a/webgl/lessons/ko/webgl1-to-webgl2.md b/webgl/lessons/ko/webgl1-to-webgl2.md index 5cd9de1e3..5b68e11e6 100644 --- a/webgl/lessons/ko/webgl1-to-webgl2.md +++ b/webgl/lessons/ko/webgl1-to-webgl2.md @@ -355,14 +355,14 @@ extension을 사용하는 것처럼 작성하시면 안되고 조금은 수정

WebGL1 extension을 WebGL2처럼 만들기

WebGL1의 extension에 있던 함수들은, WebGL2에서는 extension 없이 사용할 수 있습니다. 예를 들면, WebGL1에서는 아래와 같았지만

-
+
{{#escapehtml}}
 var ext = gl.getExtension("OES_vertex_array_object");
 if (!ext) {
   // tell user they don't have the required extension or work around it
 } else {
   var someVAO = ext.createVertexArrayOES();
 }
-
+{{/escapehtml}}

WebGL2 에서는 이렇죠.

@@ -373,7 +373,7 @@ var someVAO = gl.createVertexArray(); 좀 어려울 수 있습니다.

한 가지 해결 방법은, 초기화할 때 WebGL1 extension을 WebGL context에 복사하는 것입니다. 그렇게 하면 나머지 코드는 그대로입니다. 예시:

-
+
{{#escapehtml}}
 const gl = someCanvas.getContext("webgl");
 const haveVAOs = getAndApplyExtension(gl, "OES_vertex_array_object");
 
@@ -412,18 +412,18 @@ function getAndApplyExtension(gl, name) {
   }
   return ext;
 }
-
+{{/escapehtml}}

이제 이 코드는 WebGL1과 WebGL2 에서 대부분 똑같이 동작할 겁니다. 예시:

-
+
{{#escapehtml}}
 if (haveVAOs) {
   var someVAO = gl.createVertexArray();
   ...
 } else {
   ... do whatever for no VAOs.
 }
-
+{{/escapehtml}}

아니면 이런식으로 적어야겠죠.

-
+
{{#escapehtml}}
 if (haveVAOs) {
   if (isWebGL2)
      someVAO = gl.createVertexArray();
@@ -434,7 +434,7 @@ if (haveVAOs) {
 } else {
   ... do whatever for no VAOs.
 }
-
+{{/escapehtml}}

참고: Vertex Array Objects를 사용하는 경우에는, polyfill을 사용하는 것을 권장합니다. VAO는 대부분의 시스템에서 지원되지만, 지원하지 않는 몇 시스템에서는 polyfill로 해결할 수 있습니다. 코드의 변경 없이 말이죠.

diff --git a/webgl/lessons/pt-br/webgl-2d-vs-3d-library.md b/webgl/lessons/pt-br/webgl-2d-vs-3d-library.md index 7beb4db89..530f12e7c 100644 --- a/webgl/lessons/pt-br/webgl-2d-vs-3d-library.md +++ b/webgl/lessons/pt-br/webgl-2d-vs-3d-library.md @@ -35,7 +35,7 @@ com luzes. Aqui está o código em three.js para fazer isso -
+
{{#escapehtml}}
   // Setup.
   renderer = new THREE.WebGLRenderer({canvas: document.querySelector("#canvas")});
   c.appendChild(renderer.domElement);
@@ -71,7 +71,7 @@ Aqui está o código em three.js para fazer isso
   light2 = new THREE.PointLight(0x0040ff, 2, 0);
   light2.position.set(-200, 100, 300);
   scene.add(light2);
-
+{{/escapehtml}}
e aqui é exibido. @@ -79,7 +79,7 @@ e aqui é exibido. Aqui está o código similar em OpenGL (não ES) para exibir um cubo com 2 luzes. -
+
{{#escapehtml}}
   // Setup
   glViewport(0, 0, width, height);
   glMatrixMode(GL_PROJECTION);
@@ -132,7 +132,7 @@ Aqui está o código similar em OpenGL (não ES) para exibir um cubo com 2 luzes
   */
 
   glEnd();
-
+{{/escapehtml}}
Observe como precisamos quase nenhum conhecimento de matemática para 3D para qualquer um desses diff --git a/webgl/lessons/pt-br/webgl1-to-webgl2.md b/webgl/lessons/pt-br/webgl1-to-webgl2.md index 311eb0b12..2fd8441b2 100644 --- a/webgl/lessons/pt-br/webgl1-to-webgl2.md +++ b/webgl/lessons/pt-br/webgl1-to-webgl2.md @@ -346,25 +346,25 @@ de WebGL1 para WebGL2. [Há ainda mais coisas que você pode fazer no WebGL2 emb

Fazendo as extensões WebGL1 parecer WebGL2

As funções que estavam em extensões no WebGL1 estão agora no contexto principal no WebGL2. Por exemplo, no WebGL

-
+
{{#escapehtml}}
 var ext = gl.getExtension("OES_vertex_array_object");
 if (!ext) {
   // Diga ao usuário que ele não têm a extensão necessária ou trabalhar em torno dela
 } else {
   var someVAO = ext.createVertexArrayOES();
 }
-
+{{/escapehtml}}

vs em webgl2

-
+
{{#escapehtml}}
 var someVAO = gl.createVertexArray();
-
+{{/escapehtml}}

Acomo você pode ver se você deseja que seu código seja executado tanto no WebGL1 quanto no WebGL2, que pode apresentar alguns desafios.

Uma solução seria copiar extensões WebGL1 ao contexto WebGL em tempo de inicialização. Dessa forma, o resto do seu código pode permanecer o mesmo. Exemplo:

-
+
{{#escapehtml}}
 var gl = someCanvas.getContext("webgl");
 var haveVAOs = getAndApplyExtension(gl, "OES_vertex_array_object"));
 
@@ -389,18 +389,18 @@ function getAndApplyExtension(gl, name) {
       gl[unprefixedKey] = ext[key];
     }
   }
-
+{{/escapehtml}}

Agora, seu código pode funcionar da mesma forma em ambos. Exemplo:

-
+
{{#escapehtml}}
 if (haveVAOs) {
   var someVAO = gl.createVertexArray();
   ...
 } else {
   ... do whatever for no VAOs.
 }
-
+{{/escapehtml}}

A alternativa seria ter que fazer algo assim

-
+
{{#escapehtml}}
 if (haveVAOs) {
   if (isWebGL2)
      someVAO = gl.createVertexArray();
@@ -411,7 +411,7 @@ if (haveVAOs) {
 } else {
   ... do whatever for no VAOs.
 }
-
+{{/escapehtml}}

Nota: No caso dos objetos Vertex Array em particular, sugiro que você use a polyfill para que você os tenha em todos os lugares. Os VAOs estão disponíveis na maioria dos sistemas. Aqueles poucos sistemas onde eles não estão disponíveis o polyfill irá lidar com você e seu código diff --git a/webgl/lessons/webgl-2d-drawimage.md b/webgl/lessons/webgl-2d-drawimage.md index 2da2fc716..da055016d 100644 --- a/webgl/lessons/webgl-2d-drawimage.md +++ b/webgl/lessons/webgl-2d-drawimage.md @@ -467,7 +467,7 @@ it provides.

You might have noticed we're using a unit quad for our positions and those positions of a unit quad exactly match our texture coordinates. As such we can use the positions as the texture coordinates.

-
+
{{#escapehtml}}
 #version 300 es
 in vec4 a_position;
 -in vec2 a_texcoord;
@@ -481,7 +481,7 @@ void main() {
    gl_Position = u_matrix * a_position;
 *   v_texcoord = (u_textureMatrix * a_position).xy;
 }
-
+{{/escapehtml}}

We can now remove the code that setup the texture coordinates and it will work just the same as before.

{{{example url="../webgl-2d-drawimage-08.html" }}} diff --git a/webgl/lessons/webgl-2d-vs-3d-library.md b/webgl/lessons/webgl-2d-vs-3d-library.md index c65b13ff5..a262e1ae7 100644 --- a/webgl/lessons/webgl-2d-vs-3d-library.md +++ b/webgl/lessons/webgl-2d-vs-3d-library.md @@ -35,7 +35,7 @@ with lights. Here's the code in three.js to display this -
+
{{#escapehtml}}
   // Setup.
   renderer = new THREE.WebGLRenderer({canvas: document.querySelector("#canvas")});
   c.appendChild(renderer.domElement);
@@ -71,7 +71,7 @@ Here's the code in three.js to display this
   light2 = new THREE.PointLight(0x0040ff, 2, 0);
   light2.position.set(-200, 100, 300);
   scene.add(light2);
-
+{{/escapehtml}}
and here it is displayed. @@ -79,7 +79,7 @@ and here it is displayed. Here's similar code in OpenGL (not ES) to display a cube with 2 lights. -
+
{{#escapehtml}}
   // Setup
   glViewport(0, 0, width, height);
   glMatrixMode(GL_PROJECTION);
@@ -132,7 +132,7 @@ Here's similar code in OpenGL (not ES) to display a cube with 2 lights.
   */
 
   glEnd();
-
+{{/escapehtml}}
Notice how we need almost no knowledge of 3D math for either of those examples. Compare that to WebGL. I'm not going to write the code diff --git a/webgl/lessons/webgl-less-code-more-fun.md b/webgl/lessons/webgl-less-code-more-fun.md index 33dc8b9c8..3511740a2 100644 --- a/webgl/lessons/webgl-less-code-more-fun.md +++ b/webgl/lessons/webgl-less-code-more-fun.md @@ -440,19 +440,19 @@ Next up, [drawing multiple things](webgl-drawing-multiple-things.html). For those of you familiar with JavaScript you might be wondering if you can use the setters directly like this.

-
+
{{#escapehtml}}
 // At initialization time
 var uniformSetters = twgl.createUniformSetters(program);
 
 // At draw time
 uniformSetters.u_ambient([1, 0, 0, 1]); // set the ambient color to red.
-
+{{/escapehtml}}

The reason this is not a good idea is because when you're working with GLSL you might modify the shaders from time to time, often to debug. Let's say we were not seeing anything on the screen in our program. One of the first things I do when nothing is appearing is to simplify my shaders. For example I might change the fragment shader to the simplest thing possible

-
+
{{#escapehtml}}
 #version 300 es
 precision highp float;
 
@@ -492,7 +492,7 @@ void main() {
       diffuseColor.a);
 *  outColor = vec4(0,1,0,1);  // <!--- just green
 }
-
+{{/escapehtml}}

Notice I just added a line that sets outColor to a constant color. Most drivers will see that none of the previous lines in the file actually contribute to the result. As such they'll optimize out all of our uniforms. The next time we run the program diff --git a/webgl/lessons/webgl-load-obj-w-mtl.md b/webgl/lessons/webgl-load-obj-w-mtl.md index 1e923ef9a..71a6bb845 100644 --- a/webgl/lessons/webgl-load-obj-w-mtl.md +++ b/webgl/lessons/webgl-load-obj-w-mtl.md @@ -867,7 +867,7 @@ the types of things involved in displaying arbitrary 3D content.

Avoid conditionals in shaders where possible

The traditional advice is to avoid conditionals in shaders. As an example we could have done something like this

-

+
{{#escapehtml}}
 uniform bool hasDiffuseMap;
 uniform vec4 diffuse;
 uniform sampler2D diffuseMap
@@ -878,7 +878,7 @@ uniform sampler2D diffuseMap
     effectiveDiffuse *= texture2D(diffuseMap, texcoord);
   }
 ...
-
+{{/escapehtml}}

Conditionals like that are generally discouraged because depending on the GPU/driver they are often not very performant.

Either do like we did above and try to make the code have no conditionals. We used diff --git a/webgl/lessons/webgl-planar-projection-mapping.md b/webgl/lessons/webgl-planar-projection-mapping.md index 2a6af6afb..4d42e8916 100644 --- a/webgl/lessons/webgl-planar-projection-mapping.md +++ b/webgl/lessons/webgl-planar-projection-mapping.md @@ -791,21 +791,21 @@ One other thing this type of projection is useful for is

Conditional Texture References

In the fragment shader above we get read both textures in all cases.

-

+
{{#escapehtml}}
   vec4 projectedTexColor = texture(u_projectedTexture, projectedTexcoord.xy);
   vec4 texColor = texture(u_texture, v_texcoord) * u_colorMult;
 
   float projectedAmount = inRange ? 1.0 : 0.0;
   gl_FragColor = mix(texColor, projectedTexColor, projectedAmount);
-
+{{/escapehtml}}

Why didn't we do something like this?

-

+
{{#escapehtml}}
   if (inRange) {
     gl_FragColor = texture(u_projectedTexture, projectedTexcoord.xy);
   } else {
     gl_FragColor = texture(u_texture, v_texcoord) * u_colorMult;
   }
-
+{{/escapehtml}}

From the GLSL ES 3.0 spec Section 8.8

Texture Lookup Functions

@@ -816,7 +816,7 @@ derivatives are undefined within non-uniform control flow and for vertex texture

In other words, if we are going to use textures we must always access them. We can use the results conditionally. For example we could have written this:

-

+
{{#escapehtml}}
   vec4 projectedTexColor = texture(u_projectedTexture, projectedTexcoord.xy);
   vec4 texColor = texture(u_texture, v_texcoord) * u_colorMult;
 
@@ -825,14 +825,14 @@ conditionally. For example we could have written this:

} else { gl_FragColor = texColor; } -
+{{/escapehtml}}

or this

-

+
{{#escapehtml}}
   vec4 projectedTexColor = texture(u_projectedTexture, projectedTexcoord.xy);
   vec4 texColor = texture(u_texture, v_texcoord) * u_colorMult;
 
   gl_FragColor = inRange ? projectedTexColor : texColor;
-
+{{/escapehtml}}

But we can't access the textures themselves conditionally. It might work on your GPU but it won't work on all GPUs.

In any case it's important to know.

diff --git a/webgl/lessons/webgl-scene-graph.md b/webgl/lessons/webgl-scene-graph.md index fa9029001..29c9c0064 100644 --- a/webgl/lessons/webgl-scene-graph.md +++ b/webgl/lessons/webgl-scene-graph.md @@ -439,22 +439,22 @@ function whereas above I made a node.setParent function. Which way is arguably a matter of style but I'd argue one objectively better reason setParent is better than addChild is because it makes code like this impossible.

-
+
{{#escapehtml}}
     someParent.addChild(someNode);
     ...
     someOtherParent.addChild(someNode);
-
+{{/escapehtml}}

What does that mean? Does someNode get added to both someParent and someOtherParent? In most scene graphs that's impossible. Does the second call generate an error? ERROR: Already have parent. Does it magically remove someNode from someParent before adding it to someOtherParent? If it does it's certainly not clear from the name addChild.

setParent on the other hand has no such issue

-
+
{{#escapehtml}}
     someNode.setParent(someParent);
     ...
     someNode.setParent(someOtherParent);
-
+{{/escapehtml}}

It's 100% obvious what's happening in this case. Zero ambiguity.

diff --git a/webgl/lessons/webgl1-to-webgl2.md b/webgl/lessons/webgl1-to-webgl2.md index f882c7c35..ec46c39e0 100644 --- a/webgl/lessons/webgl1-to-webgl2.md +++ b/webgl/lessons/webgl1-to-webgl2.md @@ -390,7 +390,7 @@ var someVAO = gl.createVertexArray(); that can present some challenges.

One workaround would be to copy WebGL1 extensions to the WebGL context at init time. That way the rest of your code can stay the same. Example:

-
+
{{#escapehtml}}
 const gl = someCanvas.getContext("webgl");
 const haveVAOs = getAndApplyExtension(gl, "OES_vertex_array_object");
 
@@ -429,18 +429,18 @@ function getAndApplyExtension(gl, name) {
   }
   return ext;
 }
-
+{{/escapehtml}}

Now your code can mostly just work the same on both. Example:

-
+
{{#escapehtml}}
 if (haveVAOs) {
   var someVAO = gl.createVertexArray();
   ...
 } else {
   ... do whatever for no VAOs.
 }
-
+{{/escapehtml}}

The alternative would be having to do something like this

-
+
{{#escapehtml}}
 if (haveVAOs) {
   if (isWebGL2)
      someVAO = gl.createVertexArray();
@@ -451,7 +451,7 @@ if (haveVAOs) {
 } else {
   ... do whatever for no VAOs.
 }
-
+{{/escapehtml}}

Note: In the case of Vertex Array Objects in particular I suggest you use a polyfill so you'll have them everywhere. VAOs are available on most systems. On those few systems where they aren't available, the polyfill will handle it for you, and your code diff --git a/webgl/lessons/zh_cn/webgl-2d-drawimage.md b/webgl/lessons/zh_cn/webgl-2d-drawimage.md index 3726a578e..4e6a64bab 100644 --- a/webgl/lessons/zh_cn/webgl-2d-drawimage.md +++ b/webgl/lessons/zh_cn/webgl-2d-drawimage.md @@ -448,7 +448,7 @@ WebGL 需要上传`x, y`, `x + width, y`, `x, y + height`, 和 就是利用它提供的特性去做创意。

你可能会注意到我们使用的位置单位矩形和纹理坐标刚好匹配,所以我们就可以使用位置作为纹理坐标。

-
+
{{#escapehtml}}
 #version 300 es
 in vec4 a_position;
 -in vec2 a_texcoord;
@@ -463,7 +463,7 @@ gl_Position = u_matrix \* a_position;
 
 -   v_texcoord = (u_textureMatrix \* a_position).xy;
 }
-
+{{/escapehtml}}

现在移除关于纹理坐标设置的代码,得到的结果和之前是相同的。

{{{example url="../webgl-2d-drawimage-08.html" }}}
diff --git a/webgl/lessons/zh_cn/webgl-3d-geometry-lathe.md b/webgl/lessons/zh_cn/webgl-3d-geometry-lathe.md index 42c910d2c..471af8d6b 100644 --- a/webgl/lessons/zh_cn/webgl-3d-geometry-lathe.md +++ b/webgl/lessons/zh_cn/webgl-3d-geometry-lathe.md @@ -715,7 +715,7 @@ for (let division = 0; division <= numDivisions; ++division) {

你可以看到它们在共享处没有被当作相同点,因为它们不是100%的相等。

起初我想通过提供一个误差范围,检查顶点的距离是否在范围内,如果小于误差范围就认为是同一点。 就像这样。 -

+
{{#escapehtml}}
 const epsilon = 0.0001;
 const tempVerts = [];
 function getVertIndex(position) {
@@ -740,7 +740,7 @@ function getVertIndex(position) {
   tempVerts.push(position);
   return tempVerts.length - 1;
 }
-
+{{/escapehtml}}

它成功了,我解决了接缝问题。但是它消耗的时间太长,导致UI交互不稳定。 这是因为它是一个复杂度为 O^2 的解决方法,如果你滑动滑块在最多的情况下就会创建大约 20000 个点, 再加上 O^2 的复杂度就是 3 亿次迭代。 @@ -767,17 +767,17 @@ function getVertIndex(position) {

使用矩阵运算是不是大材小用了?

当我们旋转点的时候使用这样的代码

-
+
{{#escapehtml}}
 const mat = m4.yRotation(angle);
 ...
 points.forEach((p, ndx) => {
   const tp = m4.transformPoint(mat, [...p, 0]);
   ...
-
+{{/escapehtml}}

使用 4x4 矩阵转换一个任意三维点需要 16 次乘法,12 次加法,和 3 次除法。 我们可以只使用 单位圆形式的旋转运算

-
+
{{#escapehtml}}
 const s = Math.sin(angle);
 const c = Math.cos(angle);
 ...
@@ -791,7 +791,7 @@ points.forEach((p, ndx) => {
     x * s + z * c,
   ];
   ...
-
+{{/escapehtml}}

这样就只有 4 次乘法和 2 次加法,没有方法调用,应该至少要快 6 倍。

diff --git a/webgl/lessons/zh_cn/webgl-3d-orthographic.md b/webgl/lessons/zh_cn/webgl-3d-orthographic.md index d3d363039..866c32dfd 100644 --- a/webgl/lessons/zh_cn/webgl-3d-orthographic.md +++ b/webgl/lessons/zh_cn/webgl-3d-orthographic.md @@ -580,12 +580,12 @@ gl.enable(gl.DEPTH_TEST)

注意细节的你可能发现,我们定义了这样两个属性

-
+
{{#escapehtml}}
 in vec4 a_position;
 in vec4 a_color;
-
+{{/escapehtml}}

两个都是 'vec4' 类型,当我们告诉WebGL如何从缓冲中获取数据时使用

-
+
{{#escapehtml}}
 // 告诉属性怎么从 positionBuffer (ARRAY_BUFFER) 中读取位置
 var size = 3;          // 每次迭代使用 3 个单位的数据
 var type = gl.FLOAT;   // 单位数据类型是32位的浮点型
@@ -607,7 +607,7 @@ var offset = 0; // 从绑定缓冲的起始处开始
 gl.vertexAttribPointer(
 colorAttributeLocation, size, type, normalize, stride, offset);
 
-
+{{/escapehtml}}

这里的 '3' 表示的时每次迭代从缓冲中提取三个值给顶点着色器中的属性。 能正常运行是因为WebGL会给这些值设定默认值,默认值是0, 0, 0, 1 diff --git a/webgl/lessons/zh_cn/webgl-how-it-works.md b/webgl/lessons/zh_cn/webgl-how-it-works.md index 886df5506..83f685fea 100644 --- a/webgl/lessons/zh_cn/webgl-how-it-works.md +++ b/webgl/lessons/zh_cn/webgl-how-it-works.md @@ -307,16 +307,16 @@ UNSIGNED_BYTE(0至255)变为0.0至+1.0。标准化的SHORT INTEGER也从-1.0 (其中0代表0.0,255代表1.0)。 现在每种颜色只需要4个字节,每个顶点可节省75%的空间。

让我们更改代码以执行此操作。 当我们告诉WebGL如何提取颜色时,我们将使用如下代码:

-
+
{{#escapehtml}}
   var size = 4;
 *  var type = gl.UNSIGNED_BYTE;
 *  var normalize = true;
   var stride = 0;
   var offset = 0;
   gl.vertexAttribPointer(colorLocation, size, type, normalize, stride, offset);
-
+{{/escapehtml}}

当我们用颜色填充缓冲区时,我们将使用如下代码:

-
+
{{#escapehtml}}
 // Fill the buffer with colors for the 2 triangles
 // that make the rectangle.
 function setColors(gl) {
@@ -340,7 +340,7 @@ r2, b2, g2, 255]),
 gl.STATIC_DRAW);
 }
 
-
+{{/escapehtml}}

下面是实例演示:

diff --git a/webgl/lessons/zh_cn/webgl-less-code-more-fun.md b/webgl/lessons/zh_cn/webgl-less-code-more-fun.md index c2d54c144..f96a8bdc7 100644 --- a/webgl/lessons/zh_cn/webgl-less-code-more-fun.md +++ b/webgl/lessons/zh_cn/webgl-less-code-more-fun.md @@ -424,16 +424,16 @@ WebGL 会自动设置 `w = 1`。所以这就意味着我们不能轻易推断出

熟悉JavaScript的人可能会想,我能像这样直接使用 setter 么?

-
+
{{#escapehtml}}
 // 初始化时
 var uniformSetters = twgl.createUniformSetters(program);
 
 // 绘制时
 uniformSetters.u_ambient([1, 0, 0, 1]); // 设置环境光为红色
 
-
+{{/escapehtml}}

这样做不好的原因就是,在使用GLSL的过程中经常会修改,调试。假设屏幕上什么都没有出现,首先我会简化着色器,例如我会尽可能简化片断着色器。

-
+
{{#escapehtml}}
 #version 300 es
 precision highp float;
 
@@ -474,7 +474,7 @@ diffuseColor.a);
 
 -   outColor = vec4(0,1,0,1); // <!--- just green
 }
-
+{{/escapehtml}}

注意到我添加了一行,直接将 outColor 设置为固定颜色。 大多数驱动会发现之前的行没有为结果做贡献,优化后就会把没用的变量移除, 下次我运行程序调用 twgl.createUniformSetters 就不会为u_ambient 创建 setter,所以 uniformSetters.u_ambient() 就会报错。

diff --git a/webgl/lessons/zh_cn/webgl-load-obj-w-mtl.md b/webgl/lessons/zh_cn/webgl-load-obj-w-mtl.md index e357865b7..39b74eaaa 100644 --- a/webgl/lessons/zh_cn/webgl-load-obj-w-mtl.md +++ b/webgl/lessons/zh_cn/webgl-load-obj-w-mtl.md @@ -843,7 +843,7 @@ void main () {

尽可能避免在着色器中使用条件语句

通常的建议是避免在着色器中使用条件语句。比如我们可能写这样的代码

-

+
{{#escapehtml}}
 uniform bool hasDiffuseMap;
 uniform vec4 diffuse;
 uniform sampler2D diffuseMap
@@ -854,7 +854,7 @@ if (hasDiffuseMap) {
 effectiveDiffuse \*= texture2D(diffuseMap, texcoord);
 }
 ...
-
+{{/escapehtml}}

这样的条件语句一般是不鼓励的,因为依赖于 GPU 或者驱动,它们没有很好的性能。

当没有纹理时我们用一个 1x1 像素的白点纹理,这样就不用考虑条件语句了。

diff --git a/webgl/lessons/zh_cn/webgl-planar-projection-mapping.md b/webgl/lessons/zh_cn/webgl-planar-projection-mapping.md index cfa17f7cd..2d8055422 100644 --- a/webgl/lessons/zh_cn/webgl-planar-projection-mapping.md +++ b/webgl/lessons/zh_cn/webgl-planar-projection-mapping.md @@ -780,24 +780,24 @@ derivatives are undefined within non-uniform control flow and for vertex texture

换句话说,如果我们要使用纹理,那我们就必须确保总是能够访问到它们。 我们可以在条件语句内使用访问纹理的结果。例如我们可以写成这样:

-

+
{{#escapehtml}}
   vec4 projectedTexColor = texture(u_projectedTexture, projectedTexcoord.xy);
   vec4 texColor = texture(u_texture, v_texcoord) * u_colorMult;
 
 if (inRange) {
-gl_FragColor = projectedTexColor;
+  gl_FragColor = projectedTexColor;
 } else {
-gl_FragColor = texColor;
+  gl_FragColor = texColor;
 }
-
+{{/escapehtml}}

或者这样

-

+
{{#escapehtml}}
   vec4 projectedTexColor = texture(u_projectedTexture, projectedTexcoord.xy);
   vec4 texColor = texture(u_texture, v_texcoord) * u_colorMult;
 
 gl_FragColor = inRange ? projectedTexColor : texColor;
-
+{{/escapehtml}}

但是我们不能在条件语句内访问纹理本身。这样做在你的 GPU 上可能是可行的, 但并不是在所有的 GPUs 上都能行。

diff --git a/webgl/lessons/zh_cn/webgl1-to-webgl2.md b/webgl/lessons/zh_cn/webgl1-to-webgl2.md index b06603f67..3fe42d198 100644 --- a/webgl/lessons/zh_cn/webgl1-to-webgl2.md +++ b/webgl/lessons/zh_cn/webgl1-to-webgl2.md @@ -307,7 +307,7 @@ var someVAO = gl.createVertexArray();

如你所见,如果你希望代码在WebGL1和WebGL2中都能运行,这会带来一些挑战。

一种解决方法是在初始时将WebGL1扩展复制到WebGL上下文。这种方法余下的代码可以保持不变。示例:

-
+
{{#escapehtml}}
 const gl = someCanvas.getContext("webgl");
 const haveVAOs = getAndApplyExtension(gl, "OES_vertex_array_object");
 
@@ -346,18 +346,18 @@ function getAndApplyExtension(gl, name) {
   }
   return ext;
 }
-
+{{/escapehtml}}

现在你的代码大部分可以同样工作,像这样

-
+
{{#escapehtml}}
 if (haveVAOs) {
   var someVAO = gl.createVertexArray();
   ...
 } else {
   ... do whatever for no VAOs.
 }
-
+{{/escapehtml}}

替代方法是像这样做

-
+
{{#escapehtml}}
 if (haveVAOs) {
   if (isWebGL2)
      someVAO = gl.createVertexArray();
@@ -368,7 +368,7 @@ if (haveVAOs) {
 } else {
   ... do whatever for no VAOs.
 }
-
+{{/escapehtml}}

注意:特别对于顶点数组对象我建议你使用polyfill, 所以任何时候你都能得到它们。VAO大多数设备都提供。少数设备不提供,polyfill会让你的代码保持简单。