“错误:片段着色器中的 GLSL 1.30 及更高版本中禁止使用非常量表达式索引的采样器数组”

问题描述 投票:0回答:4

我正在为游戏引擎编写以下片段着色器:

#version 330 core

layout (location = 0) out vec4 color;

uniform vec4 colour;
uniform vec2 light_pos;

in DATA
{
    vec4 position;
    vec2 uv;
    float tid;
    vec4 color;
} fs_in;

uniform sampler2D textures[32];

void main()
{
    float intensity = 1.0 / length(fs_in.position.xy - light_pos);

    vec4 texColor = fs_in.color;

    if(fs_in.tid > 0.0){
        int tid = int(fs_in.tid + 0.5);
        texColor = texture(textures[tid], fs_in.uv);
    }

    color = texColor * intensity;
}

texColor = texture(textures[tid], fs_in.uv);
导致编译着色器时出现“GLSL 1.30及更高版本中禁止使用非常量表达式索引的采样器数组”表达式。

如果需要的话,顶点着色器是:

#version 330 core

layout (location = 0) in vec4 position;
layout (location = 1) in vec2 uv;
layout (location = 2) in float tid;
layout (location = 3) in vec4 color;

uniform mat4 pr_matrix;
uniform mat4 vw_matrix = mat4(1.0);
uniform mat4 ml_matrix = mat4(1.0);

out DATA
{
    vec4 position;
    vec2 uv;
    float tid;
    vec4 color;
} vs_out;

void main()
{
    gl_Position = pr_matrix * vw_matrix * ml_matrix * position;
    vs_out.position = ml_matrix * position;
    vs_out.uv = uv;
    vs_out.tid = tid;
    vs_out.color = color;
}
c++ opengl glsl
4个回答
4
投票

在 GLSL 3.3 中,采样器数组的索引仅允许通过积分常量表达式(请参阅GLSL 3.3 规范,第 4.1.7 节)。

在更现代的版本中,从 GLSL 4.0 开始,允许通过 动态统一表达式索引采样器数组(请参阅 GLSL 4.0 规范,第 4.1.7 节

您实际上尝试的是通过变量来索引数组,这是根本不可能的。如果这样做绝对不可避免,您可以将 2d 纹理打包到 2d 数组纹理或 3d 纹理中,并使用索引来寻址纹理的图层(或第 3 维)。


2
投票

问题在于,在第

texColor = texture(textures[tid], fs_in.uv)
行中,采样器数组
texturues
被赋予了一个非常量索引。

最简单的解决方法是使用一个大的 switch 语句来替换行

texColor = texture(textures[tid], fs_in.uv)
,以便可以通过常量来评估纹理数组。例如,您可以写这样的内容:

uniform sampler2D textures[32];

void main()
{
    float intensity = 1.0 / length(fs_in.position.xy - light_pos);

    vec4 texColor = fs_in.color;

    if(fs_in.tid > 0.0){

        // texColor = texture(textures[tid], fs_in.uv)
        // replace with large switch

        int tid = int(fs_in.tid + 0.5);
        switch (int(tid)){
            case 0:
                texColor = texture(textures[0], fs_in.uv);
                break;
            case 1:
                texColor = texture(textures[1], fs_in.uv);
                break;
            case 2:
                texColor = texture(textures[2], fs_in.uv);
                break;
    
            // repeat for all textures
        }
    }

    color = texColor * intensity;
}

0
投票

我通过使用一些代码生成克服了这个问题:

在 Javascript 中它看起来像这样:

const maxNumTextures = 32;
function makeSwitchCase (i) {
return `
  case ${i}:
    sum += texture2D(texturesArray[${i}], vUv);
    break;
`
};

const fragmentShader = `
#define numTextures ${maxNumTextures}

uniform sampler2D baseTexture;
uniform sampler2D texturesArray[numTextures];

varying vec2 vUv;

void main() {
  vec4 base = texture2D(baseTexture, vUv);
  vec4 sum = vec4(0.0);

  for (int i = 0; i < numTextures; ++i) {
    switch(i) {
      // we are not allowed to use i as index to access texture in array in current version of GLSL
      ${new Array(maxNumTextures)
        .fill(0)
        .map((_, i) => makeSwitchCase(i))
        .join('')}
      default: break;
    }
  }

  gl_FragColor = base + sum;
}
`;

注意:我们在 JS 中使用 ` 来启动和停止多行字符串,并使用 ${some_value} 为模板提供值


0
投票

我也有类似的问题。切换到较新的版本(准确地说是#460)对我来说有效。

© www.soinside.com 2019 - 2024. All rights reserved.