当前位置: 首页 > 知识库问答 >
问题:

如何将一系列纹理绑定到WebGL着色器?

郭俊人
2023-03-14

我需要处理许多只共享少数纹理的对象。手动定义和加载纹理一个接一个(如SO上的另一篇文章中所述)感觉不太对劲...尤其是因为WebGL中没有开关(索引){case:...}语句。

因此,我想将用于顶点的纹理作为顶点属性传递,并将该数字用作fragement着色器中某些“纹理数组”的索引。但是采样器上的OpenGL wiki(不是WebGL的完美参考,但我找到的那个)说:

取样器的变量只能用两种方式之一来定义。它可以定义为函数参数或均匀变量。

均匀采样2D纹理1;

对我来说,这听起来像是我无法拥有一系列的采样器。我读过几页关于纹理单位的书,但直到现在,这对我来说仍然是个谜。

在上面引用的SO帖子中,东芝暗示了一个解决方案,但想要一个单独的问题——瞧!

谢谢,诺比

附言:我知道使用“纹理图谱”的另一种可能性——如果这更有效或更简单——我很乐意听到经验!

共有1个答案

微生景胜
2023-03-14

必须用常量值为采样器数组编制索引,这样才能执行类似的操作

#define numTextures 4

precision mediump float;
varying float v_textureIndex;
uniform sampler2D u_textures[numTextures];

vec4 getSampleFromArray(sampler2D textures[4], int ndx, vec2 uv) {
    vec4 color = vec4(0);
    for (int i = 0; i < numTextures; ++i) {
      vec4 c = texture2D(u_textures[i], uv);
      if (i == ndx) {
        color += c;
      }
    }
    return color;
}

void main() {
    gl_FragColor = getSampleFromArray(u_textures, int(v_textureIndex), vec2(0.5, 0.5));
}

您还需要告诉它要使用哪些纹理单元

var textureLoc = gl.getUniformLocation(program, "u_textures");
// Tell the shader to use texture units 0 to 3
gl.uniform1iv(textureLoc, [0, 1, 2, 3]);

上面的示例使用恒定的纹理坐标只是为了保持简单,但当然您可以使用任何纹理坐标。

这是一个示例:

var canvas = document.getElementById("c");
var gl = canvas.getContext('webgl');

// Note: createProgramFromScripts will call bindAttribLocation
// based on the index of the attibute names we pass to it.
var program = webglUtils.createProgramFromScripts(
    gl, 
    ["vshader", "fshader"], 
    ["a_position", "a_textureIndex"]);
gl.useProgram(program);
var textureLoc = gl.getUniformLocation(program, "u_textures[0]");
// Tell the shader to use texture units 0 to 3
gl.uniform1iv(textureLoc, [0, 1, 2, 3]);

var positions = [
      1,  1,  
     -1,  1,  
     -1, -1,  
      1,  1,  
     -1, -1,  
      1, -1,  
];
    
var textureIndex = [
    0, 1, 2, 3, 0, 1,
];

var vertBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);

var vertBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(textureIndex), gl.STATIC_DRAW);
gl.enableVertexAttribArray(1);
gl.vertexAttribPointer(1, 1, gl.UNSIGNED_BYTE, false, 0, 0);

var colors = [
    [0, 0, 255, 255],
    [0, 255, 0, 255],
    [255, 0, 0, 255],
    [0, 255, 255, 255],
];

// make 4 textures
colors.forEach(function(color, ndx) {
    gl.activeTexture(gl.TEXTURE0 + ndx);
    var tex = gl.createTexture();
   gl.bindTexture(gl.TEXTURE_2D, tex);
   gl.texImage2D(
      gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0,
      gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(color));
});


gl.drawArrays(gl.TRIANGLES, 0, positions.length / 2);
canvas { border: 1px solid black; }
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<script id="vshader" type="whatever">
    attribute vec4 a_position;
    attribute float a_textureIndex;
    varying float v_textureIndex;
    void main() {
      gl_Position = a_position;
      v_textureIndex = a_textureIndex;
    }    
</script>
<script id="fshader" type="whatever">
#define numTextures 4
precision mediump float;
varying float v_textureIndex;
uniform sampler2D u_textures[numTextures];
    
vec4 getSampleFromArray(sampler2D textures[4], int ndx, vec2 uv) {
    vec4 color = vec4(0);
    for (int i = 0; i < numTextures; ++i) {
      vec4 c = texture2D(u_textures[i], uv);
      if (i == ndx) {
        color += c;
      }
    }
    return color;
}
    
void main() {
    gl_FragColor = getSampleFromArray(u_textures, int(v_textureIndex + 0.5), vec2(0.5, 0.5));
}
</script>
<canvas id="c" width="300" height="300"></canvas>
 类似资料:
  • 我是OpenGL的新手,在整理如何将纹理和着色器绑定到VBOs时遇到了困难。 我正在使用Cinder的纹理和着色器类。以下是我绘制方法的一部分: 在上面的代码中,如果我注释掉对mShader的调用。bind(),我的球体VBO将显示纹理(myImage)。我的着色器适用于普通(无纹理)形状,但当我在绘制任何带有包裹纹理的形状之前绑定着色器时,它会阻止纹理显示。 这是我使用的着色器的问题,还是我不理

  • 我在Mac OSX下工作,试图通过GLSL着色器在立方体上映射图像。 我显示立方体(以及图像,当它不通过着色器时)的方法是: 正如你所看到的,我正在检查,在这个测试中,是否有一个着色器应用到我的对象上(它是一个包装,效果非常好) 如果没有着色器,我只启用GL_纹理_坐标_数组,如果有,我尝试将图像绑定到着色器中的采样2D均匀。 我使用的着色器非常简单:它只显示纹理。我在Quartz Compose

  • 我一直在尝试渲染到一个FBO,并将两个FBO渲染到屏幕上,但在合并两个FBO时进行深度测试失败。我尝试使用计算着色器合并纹理,但无法读取深度纹理的值(所有值都是值1,但渲染到FBO时深度测试有效)。有人知道我做错了什么,或者知道其他方法来合并两个FBO吗? 以下是我创建FBO的方式: 以下是我向FBO渲染的方式: 我尝试用glBindTexture绑定纹理(所有值均为1): 计算着色器: 我已尝试

  • 我正在写一个带有纹理的webgl程序。 只要图像没有加载,纹理2D-函数就会返回一个vec4(0.0, 0.0, 0.0, 1.0)。所以所有对象都是黑色的。 所以我想检查一下,我的取样器2D是否可用。 我已经尝试过: 但这当然没有意义,因为纹理可能是黑色的。 有人能帮我吗?我如何检查,我的纹理图像是否已经加载到片段着色器中?

  • 标准着色器 Unity 标准着色器是一个内置着色器,具有非常全面的功能。它可以用于渲染『真实世界』的对象,例如,石头、木材、玻璃、塑料和金属,并支持各种各样的着色器类型和组合。通过使用或不使用材质编辑器中的各种纹理插槽和参数,可以很容易地启动或禁用其功能。 标准着色器还包括一个称为 物理着色器(Physically Based Shading,PBS) 的高级光照模型。物理着色器以模拟真实世界的方

  • 我想知道顶点经过一些处理后在片元着色器中的使用方式和映射关系,目前我梳理了以下知识,但是我不能肯定其中的一部分,详情见如下: 着色器的代码如下: 问题是这个着色器中的这一行解释,如果说vColor只是从上面着色器传递了3个顶点数据过来,那么这三个值肯定不能产生如下图的分割效果,只有当vColor是实时的每个像素的位置,产生分割,所以我不理解这其中到底是一种什么样的变更。因为直觉给我的感觉就是vCo