紋理

紋理單元是全域性狀態。如果它們是用 JavaScript 實現的,那麼它們看起來就像這樣

// pseudo code
gl = {
  activeTextureUnit: 0,
  textureUnits: [
    { TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? },
    { TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? },
    { TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? },
    { TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? },
    { TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? },
    { TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? },
    { TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? },
    { TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? },
    { TEXTURE_2D: ?, TEXTURE_CUBE_MAP: ? },
  ],
};

你可以選擇使用 gl.activeTexture 索引哪個單位。

// pseudo code
gl.activeTexture = function(textureUnit) {
  gl.activeTextureUnit = textureUnit - gl.TEXTURE0;
};

呼叫 gl.bindTexture 會將紋理繫結到活動紋理單元,就像這樣

// pseudo code
gl.bindTexture = function(target, texture) {
  var textureUnit = gl.textureUnits[gl.activeTextureUnit];
  textureUnit[target] = texture;
}

當你有一個使用紋理的著色器程式時,你必須告訴著色器程式你繫結紋理的紋理單元。例如,如果你有這樣的著色器

uniform sampler2D diffuse;
uniform sampler2D normalMap;
uniform samplerCube environmentMap;

...

你需要查詢統一位置

var diffuseUniformLocation = gl.getUniformLocation(someProgram, "diffuse");
var normalMapUniformLocation = gl.getUniformLocation(someProgram, "normalMap");
var environmmentMapUniformLocation = gl.getUniformLocation(someProgram,
                                                           "environmentMap");

然後,在你的著色器程式成為當前程式之後

gl.useProgram(someProgram);

然後,你需要告訴著色器你執行/將放置紋理的紋理單位。例如

var diffuseTextureUnit = 3;
var normalMapTextureUnit = 5;
var environmentMapTextureUnit = 2;

gl.uniform1i(diffuseUniformLocation, diffuseTextureUnit);
gl.uniform1i(normalMapUniformLocation, normalMapTextureUnit);
gl.uniform1i(environmentMapUniformLocation, environmentMapTextureUnit);

現在你告訴著色器你做/將使用哪些單位。你決定使用哪種紋理單元完全取決於你。

要將紋理實際繫結到紋理單元,你可以執行類似這樣的操作

gl.activeTexture(gl.TEXTURE0 + diffuseTextureUnit);
gl.bindTexture(gl.TEXTURE_2D, diffuseTexture);
gl.activeTexture(gl.TEXTURE0 + normalMapTextureUnit);
gl.bindTexture(gl.TEXTURE_2D, normalMapTexture);
gl.activeTexture(gl.TEXTURE0 + environmentMapTextureUnit);
gl.bindTexture(gl.TEXTURE_CUBE_MAP, environmentMapTexture);

對於僅使用 1 個紋理的非常簡單的 WebGL 示例,從不呼叫 gl.activeTexture 是常見的,因為它預設為紋理單元#0。通常不會呼叫 gl.uniform1i,因為制服預設為 0,因此著色器程式預設情況下會對所有紋理使用紋理單元#0。

所有其他紋理函式也可以處理活動紋理和紋理單元目標。例如,gl.texImage2D 可能看起來像這樣

gl.texImage2D = function(target, level, internalFormat, width, height, 
                         border, format, type, data) {
   var textureUnit = gl.textureUnits[gl.activeTextureUnit];
   var texture = textureUnit[target];

   // Now that we've looked up the texture form the activeTextureUnit and
   // the target we can effect a specific texture
   ...
};