You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从GLSL着色器读取VAO,或向着色器传递不定长数组?

问题背景与疑问

我已经实现了基于单个索引的渲染:将索引加载至VAO,设置布局并通过glDrawArrays传递数据。测试阶段我在GLSL着色器内硬编码了顶点、纹理坐标和法线数组,代码如下:

#version 330 core

// Positions/Coordinates
layout (location = 0) in int V_Indices;
// Colors
layout (location = 1) in int T_Indices;
// Texture Coordinates
layout (location = 2) in int N_Indices;

vec3 Vertices[8] = vec3[8]( 
vec3(- 1.000000, -1.000000, 1.000000),
vec3(-1.000000,  1.000000, 1.000000 ),
vec3(-1.000000, -1.000000, -1.000000),
vec3(-1.000000,  1.000000, -1.000000),
vec3( 1.000000, -1.000000, 1.000000),
vec3( 1.000000,  1.000000, 1.000000),
vec3( 1.000000, -1.000000, -1.000000),
vec3( 1.000000,  1.000000, -1.000000));
//
vec2 Texcoords[] = vec2[22](

    vec2( 0.333333, 0.333333),
    vec2( 0.666667, 0.000000),
    vec2( 0.666667, 0.333333),
    vec2( 0.000000, 0.666667),
    vec2( 0.333333, 0.333333),
    vec2( 0.333333, 0.666667),
    vec2( 0.000000, 0.333333),
    vec2( 0.333333, 0.000000),
    vec2( 0.333333, 0.333333),
    vec2( 0.666667, 0.666667),
    vec2( 0.333333, 0.666667),
    vec2( 0.666667, 0.333333),
    vec2( 1.000000, 0.000000),
    vec2( 1.000000, 0.333333),
    vec2( 0.333333, 1.000000),
    vec2( 0.000000, 0.666667),
    vec2( 0.333333, 0.666667),
    vec2( 0.333333, 0.000000),
    vec2( 0.000000, 0.000000),
    vec2( 0.666667, 0.333333),
    vec2( 0.666667, 0.000000),
    vec2( 0.000000, 1.000000)
);

vec3 Normals[] = vec3[6](
     vec3(-1.0000,  0.0000, 0.0000),
     vec3( 0.0000,  0.0000, -1.0000),
     vec3( 1.0000,  0.0000, 0.00000),
     vec3( 0.0000,  0.0000, 1.00000),
     vec3( 0.0000, -1.0000, 0.0000),
     vec3( 0.0000,  1.0000, 0.0000)
);

out vec2 texCoord;

uniform mat4 camMatrix;


void main()
{
    // Outputs the positions/coordinates of all vertices
    gl_Position = camMatrix * vec4(Vertices[V_Indices], 1.0);
    // Assigns the colors from the Vertex Data to "color"

    // Assigns the texture coordinates from the Vertex Data to "texCoord"
    texCoord = Texcoords[T_Indices];
}

但这种硬编码数组的方式无法适配实际场景,因为实际使用的数组长度各不相同。现提出两个疑问:

  1. 是否可将顶点数组加载至VBO后,从GLSL着色器中以数组形式获取VBO,或通过索引读取其元素?
  2. 若上述方案不可行,能否在GLSL着色器中创建动态数组并传递顶点数据?

解答

问题1:从VBO中通过索引读取元素

完全可以实现,推荐使用着色器存储缓冲区对象(SSBO, Shader Storage Buffer Object)(OpenGL 4.3及以上支持),或者兼容性更好的纹理缓冲区对象(TBO, Texture Buffer Object)。

SSBO实现(最优方案)

SSBO允许直接在着色器中以数组形式访问缓冲区数据,支持动态长度,完全适配你的需求:

  1. CPU端操作:
    • 创建SSBO,分别将顶点、纹理坐标、法线数据传入不同的SSBO,绑定到指定的绑定点。
  2. 着色器端操作:
    #version 430 core
    layout (location = 0) in int V_Indices;
    layout (location = 1) in int T_Indices;
    layout (location = 2) in int N_Indices;
    
    // 声明SSBO,绑定点0存储顶点数据
    layout(std430, binding = 0) buffer VertexData {
        vec3 vertices[]; // 不指定长度,由CPU端数据决定
    };
    // 绑定点1存储纹理坐标数据
    layout(std430, binding = 1) buffer TexcoordData {
        vec2 texcoords[];
    };
    
    out vec2 texCoord;
    uniform mat4 camMatrix;
    
    void main() {
        // 直接通过索引访问数组元素
        gl_Position = camMatrix * vec4(vertices[V_Indices], 1.0);
        texCoord = texcoords[T_Indices];
    }
    

TBO实现(兼容旧版本OpenGL)

如果需要兼容OpenGL 3.3,可使用TBO:

  1. CPU端操作:
    • 创建VBO并传入数据,再创建纹理对象,将VBO绑定到纹理的缓冲区绑定点,设置对应的数据格式(比如GL_RGB32F对应vec3)。
  2. 着色器端操作:
    #version 330 core
    layout (location = 0) in int V_Indices;
    layout (location = 1) in int T_Indices;
    
    uniform samplerBuffer vertexBuffer;
    uniform samplerBuffer texcoordBuffer;
    
    out vec2 texCoord;
    uniform mat4 camMatrix;
    
    void main() {
        // 通过texelFetch按索引读取数据
        vec3 pos = texelFetch(vertexBuffer, V_Indices).rgb;
        gl_Position = camMatrix * vec4(pos, 1.0);
        texCoord = texelFetch(texcoordBuffer, T_Indices).rg;
    }
    

问题2:GLSL中创建动态数组并传递数据

GLSL本身不支持运行时创建动态长度数组,但可以通过SSBO实现等效效果:

  • SSBO的数组无需指定固定长度,其实际长度由CPU端传入的数据大小决定,完全适配不同长度的数据集。
  • 不推荐使用Uniform数组:Uniform数组的长度必须在编译着色器时确定,无法动态修改,且Uniform总容量有限,不适合存储大量顶点数据。

综上,SSBO是处理动态长度顶点数据的最优选择,既支持数组式访问,又能灵活适配不同长度的数据集。


内容的提问来源于stack exchange,提问作者izzy and simple

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 17:20:35