1- Title: WebGL2 Pulling Vertices
2- Description: Using independent indices
3- TOC: Pulling Vertices
1+ Title: WebGL2 顶点拉取
2+ Description: 使用独立索引
3+ TOC: 顶点拉取
44
5- This article assumes you've read many of the other articles
6- starting with [ the fundamentals] ( webgl-fundamentals.html ) .
7- If you have not read them please start there first.
5+ 本文假设你已经阅读了其他许多文章,从 [ 基础知识] ( webgl-fundamentals.html ) 开始。如果你还没有阅读它们,请先从那里开始。
86
9- Traditionally, WebGL apps put geometry data in buffers.
10- They then use attributes to automatically supply vertex data from those buffers
11- to the vertex shader where the programmer provides code to convert them to clip space.
7+ 传统上,WebGL应用会将几何数据放入缓冲区中,然后通过属性(attributes)自动将这些缓冲区中的顶点数据传递给顶点着色器,由程序员编写代码将其转换为裁剪空间(clip space)坐标。
128
13- The word ** traditionally** is important. It's only a ** tradition**
14- to do it this way. It is in no way a requirement. WebGL doesn't
15- care how we do it, it only cares that our vertex shaders
16- assign clip space coordinates to ` gl_Position ` .
9+ 这里的 ** “传统上”** 非常重要。
10+ 这只是一种** 传统做法** ,并不是必须如此。
11+ WebGL 并不关心我们是如何处理的,它只关心顶点着色器是否为 ` gl_Position ` 赋予了裁剪空间坐标。
1712
18- Let's draw a texture mapped cube using code like the examples in [ the article on textures] ( webgl-3d-textures.html ) .
19- We're told we need at least 24 unique vertices. This is because even though there are only 8 corner
20- positions the same corner gets used on 3 different faces of the
21- cube and each face needs different texture coordinates.
13+ 让我们使用类似于 [ 纹理] ( webgl-3d-textures.html ) 中示例的方式,绘制一个带纹理映射的立方体。我们通常会说需要至少 24 个唯一顶点,这是因为虽然立方体只有 8 个角点位置,但每个角点会出现在立方体的 3 个不同面上,而每个面又需要不同的纹理坐标。
2214
2315<div class =" webgl_center " ><img src =" resources/cube-vertices-uv.svg " style =" width : 400px ;" ></div >
2416
25- In the diagram above we can see that the left face's use of corner 3 needs
26- texture coordinates 1,1 but the right face's use of corner 3 needs texture coordinates
27- 0,1. The top face would need different texture coordinates as well.
17+ 在上面的图示中,我们可以看到左侧面的角点 3 需要的纹理坐标是 (1,1),而右侧面对角点 3 的使用则需要纹理坐标 (0,1)。顶部面则会需要另一组不同的纹理坐标。
18+
19+ 通常,我们是通过将 8 个角点位置扩展为 24 个顶点来实现这一点的。
2820
29- This is usually accomplished by expanding from 8 corner positions
30- to 24 vertices
3121
3222``` js
3323 // front
@@ -62,13 +52,10 @@ to 24 vertices
6252 { pos: [- 1 , - 1 , - 1 ], uv: [1 , 0 ], }, // 23
6353```
6454
65- Those positions and texture coordinates are
66- put into buffers and provided to the vertex shader
67- via attributes.
55+ 这些位置和纹理坐标通常会被放入缓冲区中,并通过属性传递给顶点着色器。
6856
69- But do we really need to do it this way? What if
70- we wanted to actually have just the 8 corners
71- and 4 texture coordinates. Something like
57+ 但我们真的需要以这种方式来做吗?如果我们实际上只想保留 8 个角点和 4 个纹理坐标,会怎样?
58+ 类似于下面这样:
7259
7360``` js
7461positions = [
@@ -89,8 +76,7 @@ uvs = [
8976];
9077```
9178
92- And then for each of the 24 vertices we'd specify which of those
93- to use.
79+ 然后,对于这 24 个顶点中的每一个,我们指定要使用哪一个位置和哪一个纹理坐标。
9480
9581``` js
9682positionIndexUVIndex = [
@@ -127,11 +113,9 @@ positionIndexUVIndex = [
127113];
128114```
129115
130- Could we use this on the GPU? Why not!?
116+ 我们能在 GPU 上使用这种方式吗?为什么不可以!
131117
132- We'll upload the positions and texture coordinates
133- each to their own textures like
134- we covered in [ the article on data textures] ( webgl-data-textures.html ) .
118+ 我们会将位置和纹理坐标分别上传到各自的纹理中,就像我们在 [ 数据纹理] ( webgl-data-textures.html ) 中讲到的那样。
135119
136120``` js
137121function makeDataTexture (gl , data , numComponents ) {
@@ -168,10 +152,10 @@ const positionTexture = makeDataTexture(gl, positions, 3);
168152const texcoordTexture = makeDataTexture (gl, uvs, 2 );
169153```
170154
171- Since textures have up to 4 values per pixel ` makeDataTexture `
172- expands whatever data we give it to 4 values per pixel.
155+ 由于纹理每个像素最多可以存储 4 个值,` makeDataTexture ` 会将我们提供的数据扩展为每像素 4 个值。
156+
157+ 接着,我们会创建一个顶点数组对象(vertex array)来保存我们的属性状态。
173158
174- Then we'll create a vertex array to hold our attribute state
175159
176160``` js
177161// create a vertex array object to hold attribute state
@@ -191,7 +175,7 @@ gl.bindBuffer(gl.ARRAY_BUFFER, positionIndexUVIndexBuffer);
191175gl .bufferData (gl .ARRAY_BUFFER , new Uint32Array (positionIndexUVIndex), gl .STATIC_DRAW );
192176```
193177
194- and setup the attribute
178+ 接下来,我们需要将位置索引和纹理坐标索引上传到一个缓冲区。
195179
196180``` js
197181// Turn on the position index attribute
@@ -209,14 +193,13 @@ gl.enableVertexAttribArray(posTexIndexLoc);
209193}
210194```
211195
212- Notice we're calling ` gl.vertexAttribIPointer ` not ` gl.vertexAttribPointer ` .
213- The ` I ` is for integer and is used for integer and unsigned integer attributes.
214- Also note the size is 2, since there is 1 position index and 1 texcoord
215- index per vertex.
196+ 注意这里调用的是 ` gl.vertexAttribIPointer ` ,而不是 ` gl.vertexAttribPointer ` 。
197+ 其中的 ` I ` 表示整数,用于整数和无符号整数类型的属性。
198+ 另外,` size ` 设置为 2,因为每个顶点包含 1 个位置索引和 1 个纹理坐标索引。
199+
200+ 虽然我们只需要 24 个顶点,但绘制 6 个面,每个面 12 个三角形,每个三角形 3 个顶点,总共 36 个顶点。
201+ 为了指定每个面使用哪 6 个顶点,我们将使用 [ 顶点索引] ( webgl-indexed-vertices.html ) 。
216202
217- Even though we only need 24 vertices we still need draw 6 faces, 12 triangles
218- each, 3 vertices per triangle for 36 vertices. To tell it which 6 vertices
219- to use for each face we'll use [ vertex indices] ( webgl-indexed-vertices.html ) .
220203
221204``` js
222205const indices = [
@@ -234,9 +217,10 @@ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
234217gl .bufferData (gl .ELEMENT_ARRAY_BUFFER , new Uint16Array (indices), gl .STATIC_DRAW );
235218```
236219
237- As we want to draw an image on the cube itself we need a 3rd texture
238- with that image. Let's just make another 4x4 data texture with a checkerboard.
239- We'll use ` gl.LUMINANCE ` as the format since then we only need one byte per pixel.
220+ 由于我们想要在立方体上绘制一张图像,因此还需要第三个纹理存储这张图像。
221+ 这里我们用一个 4x4 的数据纹理,内容是棋盘格图案。
222+ 纹理格式使用 ` gl.LUMINANCE ` ,因为这样每个像素只需要一个字节。
223+
240224
241225``` js
242226// Create a checker texture.
@@ -263,17 +247,16 @@ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
263247gl .texParameteri (gl .TEXTURE_2D , gl .TEXTURE_MAG_FILTER , gl .NEAREST );
264248```
265249
266- On to the vertex shader... We can look up a pixel from the texture like
267- this
250+ 接下来是顶点着色器……
251+ 我们可以像这样从纹理中查找一个像素:
268252
269253``` glsl
270254vec4 color = texelFetch(sampler2D tex, ivec2 pixelCoord, int mipLevel);
271255```
272256
273- So given an integer pixel coordinate the code above will pull out a pixel value.
257+ 因此,给定一个整数像素坐标,上述代码将提取出对应的像素值。
274258
275- Using the ` texelFetch ` function we can take a 1D array index
276- and lookup a value out of a 2D texture like this
259+ 使用 ` texelFetch ` 函数,我们可以将一维数组索引转换为二维纹理坐标,并从二维纹理中查找对应的值,方式如下:
277260
278261``` glsl
279262vec4 getValueByIndexFromTexture(sampler2D tex, int index) {
@@ -284,7 +267,7 @@ vec4 getValueByIndexFromTexture(sampler2D tex, int index) {
284267}
285268```
286269
287- So given that function here is our shader
270+ 有了这个函数,我们的着色器如下所示:
288271
289272``` glsl
290273#version 300 es
@@ -321,16 +304,11 @@ void main() {
321304}
322305```
323306
324- At the bottom it's effectively the same shader we used
325- in [ the article on textures] ( webgl-3d-textures.html ) .
326- We multiply a ` position ` by ` u_matrix ` and we output
327- a texcoord to ` v_texcoord ` to pass on the fragment shader.
307+ 在底部,它实际上和我们在 [ 纹理] ( webgl-3d-textures.html ) 中使用的着色器是一样的。我们将 ` position ` 与 ` u_matrix ` 相乘,并将纹理坐标输出到 ` v_texcoord ` ,以传递给片元着色器。
328308
329- The difference is only in how we get the position and
330- texcoord. We're using the indices passed in and getting
331- those values from their respective textures.
309+ 不同之处仅在于我们获取 ` position ` 和 ` texcoord ` 的方式。我们使用传入的索引,从各自的纹理中提取这些值。
332310
333- To use the shader we need to lookup all the locations
311+ 要使用这个着色器,我们需要查找所有相关的变量位置。
334312
335313``` js
336314// setup GLSL program
@@ -347,7 +325,7 @@ const program = webglUtils.createProgramFromSources(gl, [vs, fs]);
347325+ const u_textureLoc = gl .getUniformLocation (program, " u_texture" );
348326```
349327
350- At render time we setup the attributes
328+ 在渲染阶段,我们设置属性( attributes)。
351329
352330``` js
353331// Tell it to use our program (pair of shaders)
@@ -357,8 +335,7 @@ gl.useProgram(program);
357335gl .bindVertexArray (vao);
358336```
359337
360- Then we need to bind all 3 textures and setup all the
361- uniforms
338+ 然后,我们需要绑定全部 3 个纹理,并设置所有的 uniform。
362339
363340``` js
364341// Set the matrix.
@@ -383,74 +360,69 @@ gl.bindTexture(gl.TEXTURE_2D, checkerTexture);
383360gl .uniform1i (u_textureLoc, 2 );
384361```
385362
386- And finally draw
363+ 最后,执行绘制操作。
387364
388365``` js
389366// Draw the geometry.
390367gl .drawElements (gl .TRIANGLES , 6 * 6 , gl .UNSIGNED_SHORT , 0 );
391368```
392369
393- And we get a textured cube using only 8 positions and
394- 4 texture coordinates
370+ 最终,我们只使用了 8 个位置和 4 个纹理坐标,就得到了一个带贴图的立方体。
395371
396372{{{example url="../webgl-pulling-vertices.html"}}}
397373
398- Some things to note. The code is lazy and uses 1D
399- textures for the positions and texture coordinates.
400- Textures can only be so wide. [ How wide is machine
401- specific] ( https://web3dsurvey.com/webgl/parameters/MAX_TEXTURE_SIZE ) which you can query with
374+ 有几点需要注意:代码实现较为简化,使用了 1D 纹理来存储位置和纹理坐标。
375+ 但纹理的宽度是有限的,[ 具体有多宽依赖于硬件] ( https://web3dsurvey.com/webgl/parameters/MAX_TEXTURE_SIZE ) ,
376+ 你可以通过以下方式查询:
402377
403378``` js
404379const maxSize = gl .getParameter (gl .MAX_TEXTURE_SIZE );
405380```
406381
407- If we wanted to handle more data than that we'd need
408- to pick some texture size that fits our data, and spread
409- the data across multiple rows possibly
410- padding the last row to make a rectangle.
382+ 如果我们想处理比最大纹理宽度还多的数据,就需要选择一个合适的纹理尺寸,并将数据分布到多行中,可能还需要对最后一行进行填充以保持矩形结构。
383+
384+ 我们在这里还做了另一件事:使用了两张纹理,一张存储位置,另一张存储纹理坐标。
385+ 其实我们完全可以将这两类数据存储在同一张纹理中,例如交错(interleaved)存储。
411386
412- Another thing we're doing here is using 2 textures,
413- one for positions, one for texture coordinates.
414- There is no reason we couldn't put both data in the
415- same texture either interleaved
416387
417388 pos,uv,pos,uv,pos,uv...
418389
419- or in different places in the texture
390+ 或者将它们存储在纹理的不同区域。
420391
421392 pos,pos,pos,...
422393 uv, uv, uv,...
423394
424- We'd just have to change the math in the vertex shader
425- that computes how to pull them out of the texture.
395+ 我们只需要修改顶点着色器中的数学逻辑,以正确地从纹理中提取对应的数据。
396+
397+ 那么问题来了:是否应该用这种方式?
398+ 答案是“视情况而定”。具体效果可能因 GPU 而异,有些情况下这比传统方式还慢。
399+
400+ 本文的重点再次强调:
401+ WebGL 并不在意你是如何为 ` gl_Position ` 设置裁剪空间坐标的,也不在意你是如何输出颜色的。它只关心你是否设置了这些值。纹理,本质上只是可以随机访问的二维数组。
402+
403+ 当你在 WebGL 中遇到问题时,请记住,WebGL 只是运行一些着色器程序,而这些着色器可以通过以下方式访问数据。
426404
427- The question comes up, should you do things like this?
428- The answer is "it depends". Depending on the GPU this
429- might be slower than the more traditional way.
405+ - uniforms(全局变量)
406+ - attributes(每个顶点着色器执行时接收的数据)
407+ - textures(可以随机访问的二维数组)
430408
431- The point of this article was to point out yet again,
432- WebGL doesn't care how you set ` gl_Position ` with
433- clip space coordinates nor does it care how you
434- output a color. All it cares is that you set them.
435- Textures are really just 2D arrays of random access
436- data.
409+ 不要让传统的 WebGL 使用方式限制了你的思维。
410+ WebGL 实际上具有极强的灵活性。
437411
438- When you have a problem you want to solve in WebGL
439- remember that WebGL just runs shaders and those shaders
440- have access to data via uniforms (global variables),
441- attributes (data that comes per vertex shader iteration),
442- and textures (random access 2D arrays). Don't let the
443- traditional ways of using WebGL prevent you from
444- seeing the real flexibility that's there.
412+ 当你想在 WebGL 中解决问题时,请记住 WebGL 只是运行着色器,
413+ 这些着色器可以通过 uniforms(全局变量)、attributes(每次顶点着色器执行时传入的数据)
414+ 以及 textures(可随机访问的二维数组)来访问数据。
415+ 不要让传统的 WebGL 使用方式阻碍你发现它真正的灵活性。
445416
446417<div class =" webgl_bottombar " >
447- <h3 >Why is it called Vertex Pulling?</h3 >
448- <p >I'd actually only heard the term recently (July 2019)
449- even though I'd used the technique before. It comes
450- from <a href =' https://www.google.com/search?q=OpenGL+Insights+"Programmable+Vertex+Pulling"+article+by+Daniel+Rakos ' >OpenGL Insights "Programmable Vertex Pulling" article by Daniel Rakos</a >.
418+ <h3 >为什么叫做顶点拉取(Vertex Pulling)?</h3 >
419+ <p >实际上我最近(2019年7月)才听到这个术语,
420+ 尽管我之前就用过这种技术。
421+ 它来源于
422+ <a href =' https://www.google.com/search?q=OpenGL+Insights+"Programmable+Vertex+Pulling"+article+by+Daniel+Rakos ' >
423+ OpenGL Insights 中 Daniel Rakos 撰写的“可编程顶点拉取”文章</a >。
451424</p >
452- <p >It's called vertex *pulling* since it's the vertex shader
453- that decides which vertex data to read vs the traditional way where
454- vertex data is supplied automatically via attributes. Effectively
455- the vertex shader is * pulling* data out of memory.</p >
425+ <p >之所以叫做顶点*拉取*,是因为顶点着色器决定读取哪个顶点数据,
426+ 而传统方式是通过属性自动提供顶点数据。
427+ 实际上,顶点着色器是在* 拉取* 内存中的数据。</p >
456428</div >
0 commit comments