WebGL 着色器检查纹理 sampler2D 的状态

WebGL shader checking status of texture sampler2D

我想准备着色器组件(用于多采样器 tex)

在我目前的状态下,我只使用(激活和绑定)2 个纹理图像。

但是这一行:

gl_FragColor = textureColor + textureColor1 + textureColor2;

我的纹理视图出现问题,因为我从中采样 textureColor2 的纹理未绑定。

在着色器中无法使用 console.log 或任何其他标准调试 methods.I 我有兴趣了解有关着色器的更多信息,但我被卡住了。

代码:

...

precision mediump float;

varying vec2 vTextureCoord;
varying vec3 vLightWeighting;

uniform sampler2D uSampler;
uniform sampler2D uSampler1;
uniform sampler2D uSampler2;
uniform sampler2D uSampler3;
uniform sampler2D uSampler4;
uniform sampler2D uSampler5;
uniform sampler2D uSampler6;
uniform sampler2D uSampler7;
uniform sampler2D uSampler8;
uniform sampler2D uSampler9;
uniform sampler2D uSampler10;
uniform sampler2D uSampler11;
uniform sampler2D uSampler12;
uniform sampler2D uSampler13;


void main(void) {


vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
vec4 textureColor1 = texture2D(uSampler1, vec2(vTextureCoord.s, vTextureCoord.t));
vec4 textureColor2 = texture2D(uSampler2, vec2(vTextureCoord.s, vTextureCoord.t));

// Need help here
gl_FragColor = textureColor + textureColor1 ;

//gl_FragColor = textureColor + textureColor1 + textureColor2;

//更新问题

    if (  ${numTextures} == 1)
        {
            gl_FragColor = textureColor;
        }
    else if (${numTextures} == 2)
        {
            gl_FragColor = textureColor + textureColor1;
        }
    else if (${numTextures} == 3)
        {
            gl_FragColor = textureColor + textureColor1 + textureColor2;
        }

// 我现在使用简单实用的 if else 。

// 我在加载时将值传递给着色器

// 我仍然无法在 运行 时间内更新着色器

//////////////////////////////////////////

// 这是绘制函数的片段:

for (var t=0;t<object.textures.length;t++) {

 eval( "  world.GL.gl.activeTexture(world.GL.gl.TEXTURE"+t+");  " )
    world.GL.gl.bindTexture(world.GL.gl.TEXTURE_2D, object.textures[t]);
    world.GL.gl.pixelStorei(world.GL.gl.UNPACK_FLIP_Y_WEBGL, false);
    world.GL.gl.texParameteri(world.GL.gl.TEXTURE_2D, world.GL.gl.TEXTURE_MAG_FILTER, world.GL.gl.NEAREST);
    world.GL.gl.texParameteri(world.GL.gl.TEXTURE_2D, world.GL.gl.TEXTURE_MIN_FILTER, world.GL.gl.NEAREST);
    world.GL.gl.texParameteri(world.GL.gl.TEXTURE_2D, world.GL.gl.TEXTURE_WRAP_S, world.GL.gl.CLAMP_TO_EDGE);
    world.GL.gl.texParameteri(world.GL.gl.TEXTURE_2D, world.GL.gl.TEXTURE_WRAP_T, world.GL.gl.CLAMP_TO_EDGE);
    // -- Allocate storage for the texture
    //world.GL.gl.texStorage2D(world.GL.gl.TEXTURE_2D, 1, world.GL.gl.RGB8, 512, 512);
    //world.GL.gl.texSubImage2D(world.GL.gl.TEXTURE_2D, 0, 0, 0, world.GL.gl.RGB, world.GL.gl.UNSIGNED_BYTE, image);
    //world.GL.gl.generateMipmap(world.GL.gl.TEXTURE_2D);
    world.GL.gl.uniform1i(object.shaderProgram.samplerUniform, t);

}

...

也许在 运行 时间最好的方法是使用 object.textures 数组进行操作?!

你想要完成什么?

使用大量纹理的正常方法是使用texture atlas which is covered toward the bottom of this article

否则,没有办法检测着色器中是否加载了纹理。您需要传递自己的标志。例如

 uniform bool textureLoaded[NUM_TEXTURES];

 uniform float textureMixAmount[NUM_TEXTURES];

如果我是你,我会使用纹理图集,除非你真的知道你在做一些独特的事情,实际上需要 14 个纹理。

动态生成着色器也很常见。几乎所有的游戏引擎都这样做。 Three.js 也这样做。因此,与其打开和关闭纹理,不如编写一些代码来为 N 个纹理生成着色器。然后,当您只有一个纹理时生成 1 个纹理着色器,当您有 2 个纹理时生成 2 个纹理着色器,等等。对于 GPU 而言,这比拥有 14 个纹理着色器并尝试关闭 13 个纹理要高效得多。

示例:

// note, I'm not recommending this shader, only showing some code
// that generates a shader

function generateShaderSrc(numTextures) {

  return `
    // shader for ${numTextures} textures
    precision mediump float;
    
    varying vec2 vTextureCoord;
    varying vec3 vLightWeighting;

    uniform sampler2D uSampler[${numTextures}];
    uniform float uMixAmount[${numTextures}];
    
    void main() {
      vec4 color = vec4(0);

      for (int i = 0; i < ${numTextures}; ++i) {
        vec4 texColor = texture2D(uSampler[i], vTextureCoord);
        color = mix(color, texColor, uMixAmount[i]);
      }
      
      gl_FragColor = color;
    }
  `;
}

log(generateShaderSrc(1));
log(generateShaderSrc(4));

function log(...args) {
  const elem = document.createElement("pre");
  elem.textContent = [...args].join(' ');
  document.body.appendChild(elem);
}

这是一个非常简单的例子。真正的着色器生成器通常会进行更多的字符串操作。

您还应该知道 WebGL 1.0 只需要支持 8 个纹理单元。 According to webglstats about 15% of devices only support 8 texture units 所以您可能想检查用户拥有多少纹理单元,并警告他们如果少于您的应用所需,您的应用将无法运行。