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 数组进行操作?!
最后:
- 用新标志覆盖着色器
- 编译着色器
新 material 已更新
你想要完成什么?
使用大量纹理的正常方法是使用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 所以您可能想检查用户拥有多少纹理单元,并警告他们如果少于您的应用所需,您的应用将无法运行。
我想准备着色器组件(用于多采样器 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 数组进行操作?!
最后:
- 用新标志覆盖着色器
- 编译着色器 新 material 已更新
你想要完成什么?
使用大量纹理的正常方法是使用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 所以您可能想检查用户拥有多少纹理单元,并警告他们如果少于您的应用所需,您的应用将无法运行。