Skip to content

Commit 6b43b6e

Browse files
committed
Translate webgl-texture-units.md into Chinese
1 parent 89171aa commit 6b43b6e

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
Title: WebGL2 纹理单元(Texture Units)
2+
Description: WebGL 中的纹理单元是什么?
3+
TOC: 纹理单元(Texture Units)
4+
5+
本文旨在帮助你直观理解 WebGL 中纹理单元是如何设置的。
6+
关于[属性(attributes)](webgl-attributes.html)的使用,另有一篇专门文章进行了详细讲解。
7+
8+
在阅读本文之前,你可能需要先阅读:
9+
- [WebGL 是如何工作的](webgl-how-it-works.html)
10+
- [WebGL 着色器与 GLSL](webgl-shaders-and-glsl.html)
11+
- [WebGL 纹理](webgl-3d-textures.html)
12+
13+
## 纹理单元(Texture Units)
14+
15+
在 WebGL 中有纹理。纹理是可以传入着色器的 2D 数据数组。
16+
在着色器中你会这样声明一个 *uniform 采样器*
17+
18+
```glsl
19+
uniform sampler2D someTexture;
20+
```
21+
22+
但着色器如何知道 `someTexture` 对应的是哪一张纹理呢?
23+
24+
这就是纹理单元(Texture Unit)登场的地方了。
25+
纹理单元是一个**全局数组**,保存着对纹理的引用。
26+
你可以想象,如果 WebGL 是用 JavaScript 编写的,它可能拥有如下的全局状态:
27+
28+
```js
29+
const gl = {
30+
activeTextureUnit: 0,
31+
textureUnits: [
32+
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, TEXTURE_3D: null, TEXTURE_2D_ARRAY: null, },
33+
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, TEXTURE_3D: null, TEXTURE_2D_ARRAY: null, },
34+
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, TEXTURE_3D: null, TEXTURE_2D_ARRAY: null, },
35+
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, TEXTURE_3D: null, TEXTURE_2D_ARRAY: null, },
36+
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, TEXTURE_3D: null, TEXTURE_2D_ARRAY: null, },
37+
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, TEXTURE_3D: null, TEXTURE_2D_ARRAY: null, },
38+
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, TEXTURE_3D: null, TEXTURE_2D_ARRAY: null, },
39+
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, TEXTURE_3D: null, TEXTURE_2D_ARRAY: null, },
40+
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, TEXTURE_3D: null, TEXTURE_2D_ARRAY: null, },
41+
];
42+
}
43+
```
44+
45+
如上所示,`textureUnits` 是一个数组。你可以把纹理绑定到这个纹理单元数组中某个位置的 *绑定点(bind point)* 上。
46+
例如,将 `ourTexture` 绑定到纹理单元 5 上:
47+
48+
```js
49+
// at init time
50+
const ourTexture = gl.createTexture();
51+
// insert code it init texture here.
52+
53+
...
54+
55+
// at render time
56+
const indexOfTextureUnit = 5;
57+
gl.activeTexture(gl.TEXTURE0 + indexOfTextureUnit);
58+
gl.bindTexture(gl.TEXTURE_2D, ourTexture);
59+
```
60+
61+
然后你需要告诉着色器这个纹理变量(uniform)使用的是哪一个纹理单元:
62+
63+
```js
64+
gl.uniform1i(someTextureUniformLocation, indexOfTextureUnit);
65+
```
66+
67+
如果 `activeTexture``bindTexture` 函数是用 JavaScript 实现的,可能看起来像这样:
68+
69+
```js
70+
// PSEUDO CODE!!!
71+
gl.activeTexture = function(unit) {
72+
gl.activeTextureUnit = unit - gl.TEXTURE0; // convert to 0 based index
73+
};
74+
75+
gl.bindTexture = function(target, texture) {
76+
const textureUnit = gl.textureUnits[gl.activeTextureUnit];
77+
textureUnit[target] = texture;
78+
}:
79+
```
80+
81+
你甚至可以想象其它纹理相关函数是如何运作的。这些函数都接受一个 `target` 参数,
82+
比如 `gl.texImage2D(target, ...)``gl.texParameteri(target)`,它们的实现可能像这样:
83+
84+
```js
85+
// PSEUDO CODE!!!
86+
gl.texImage2D = function(target, level, internalFormat, width, height, border, format, type, data) {
87+
const textureUnit = gl.textureUnits[gl.activeTextureUnit];
88+
const texture = textureUnit[target];
89+
texture.mips[level] = convertDataToInternalFormat(internalFormat, width, height, format, type, data);
90+
}
91+
92+
gl.texParameteri = function(target, pname, value) {
93+
const textureUnit = gl.textureUnits[gl.activeTextureUnit];
94+
const texture = textureUnit[target];
95+
texture[pname] = value;
96+
}
97+
```
98+
99+
从以上示例可以清楚地看到,`gl.activeTexture` 会设置 WebGL 内部的一个全局变量,
100+
表示当前使用哪个纹理单元(在纹理单元数组中的索引)。
101+
102+
从此之后,所有其它纹理函数中传入的 `target` 参数实际上就是当前激活的纹理单元中要操作的绑定点。
103+
104+
## 最大纹理单元数(Maximum Texture Units)
105+
106+
WebGL 要求实现至少支持 32 个纹理单元。你可以通过如下方式查询实际支持的数量:
107+
108+
```js
109+
const maxTextureUnits = gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS);
110+
```
111+
112+
需要注意的是,顶点着色器 和 片段着色器 对可用纹理单元数可能有不同限制。
113+
你可以分别用如下方式查询:
114+
115+
116+
```js
117+
const maxVertexShaderTextureUnits = gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS);
118+
const maxFragmentShaderTextureUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
119+
```
120+
它们都至少需要支持 16 个纹理单元。
121+
122+
例如:
123+
124+
```js
125+
maxTextureUnits = 32
126+
maxVertexShaderTextureUnits = 16
127+
maxFragmentShaderTextureUnits = 32
128+
```
129+
130+
这意味着,如果你在顶点着色器中使用了 2 个纹理单元,那么片段着色器最多只能再使用 30 个纹理单元,
131+
因为两个着色器合起来总共不能超过 MAX_COMBINED_TEXTURE_IMAGE_UNITS 的限制(即 32)。

0 commit comments

Comments
 (0)