为什么统一变量在 GLSL 中不起作用?
Why are Uniform variables not working in GLSL?
我目前正在尝试使用 LWJGL 创建用于后处理目的的模糊着色器,但偶然发现了一个问题。
我要更改的制服是模糊的分辨率、半径和方向(水平或垂直,因此我可以为两个方向使用一个着色器)。我将输出渲染到 FrameBuffer,然后渲染到屏幕。但不知何故,纹理只是黑色的。当我使用常量值而不是制服时,它完全按预期工作,所以问题一定是制服变量。
这是我的片段着色器的代码:
#version 330 core
out vec4 fragColor;
in vec2 coords;
in vec4 color;
in float samplerIndex;
uniform sampler2D samplers[32]; //Just an Array with ints from 0 to 31
uniform float radius;
uniform vec2 resolution; //Screen Resolution, or width & height of Framebuffer
uniform vec2 direction; //Either 1 or 0 for x and y
void main() {
int index = int(samplerIndex);
vec4 sum = vec4(0.0);
float blurX = radius / resolution.x * direction.x;
float blurY = radius / resolution.y * direction.y;
sum += texture2D(samplers[index], vec2(coords.x - 4.0 * blurX, coords.y - 4.0 * blurY)) * 0.0162162162;
sum += texture2D(samplers[index], vec2(coords.x - 3.0 * blurX, coords.y - 3.0 * blurY)) * 0.0540540541;
sum += texture2D(samplers[index], vec2(coords.x - 2.0 * blurX, coords.y - 2.0 * blurY)) * 0.1216216216;
sum += texture2D(samplers[index], vec2(coords.x - 1.0 * blurX, coords.y - 1.0 * blurY)) * 0.1945945946;
sum += texture2D(samplers[index], vec2(coords.x, coords.y)) * 0.2270270270;
sum += texture2D(samplers[index], vec2(coords.x + 1.0 * blurX, coords.y + 1.0 * blurY)) * 0.1945945946;
sum += texture2D(samplers[index], vec2(coords.x + 2.0 * blurX, coords.y + 2.0 * blurY)) * 0.1216216216;
sum += texture2D(samplers[index], vec2(coords.x + 3.0 * blurX, coords.y + 3.0 * blurY)) * 0.0540540541;
sum += texture2D(samplers[index], vec2(coords.x + 4.0 * blurX, coords.y + 4.0 * blurY)) * 0.0162162162;
fragColor = color * vec4(sum.rgb, 1.0);
}
这是我渲染 FrameBuffer 的方式:
public void render(boolean fixed) {
model.setTextureID(Shader.getTextureID(texture));
model.buffer(vertices);
indices.put(0).put(1).put(2).put(2).put(3).put(0);
vertices.flip();
indices.flip();
shader.bind();
texture.bind();
shader.setUniform1iv("samplers", Shader.SAMPLERS);
shader.setUniform1f("radius", 10.0f);
shader.setUniform2f("resolution", width, height);
shader.setUniform2f("direction", horizontal, vertical);
if(fixed) {
shader.setUniformMatrix4f("camProjection", Camera.fixedProjection);
shader.setUniformMatrix4f("camTranslation", Camera.fixedTranslation);
} else {
shader.setUniformMatrix4f("camProjection", Camera.projection);
shader.setUniformMatrix4f("camTranslation", Camera.translation);
}
vao.bind();
vbo.bind();
vbo.uploadSubData(0, vertices);
ibo.bind();
ibo.uploadSubData(0, indices);
GL11.glDrawElements(GL11.GL_TRIANGLES, Model.INDICES, GL11.GL_UNSIGNED_INT, 0);
vao.unbind();
texture.unbind();
shader.unbind();
vertices.clear();
indices.clear();
}
虽然采样器制服工作得很好,但问题似乎只影响其他三个制服。
我对 OpenGL 和 GLSL 没有太多经验,我缺少什么?
您的着色器代码根本无法工作,因为
samplers[index]
samplers
是 sampler2D
的数组,index
是从顶点着色器输入设置的 samplerIndex
:
int index = int(samplerIndex);
请参阅您使用的 GLSL 版本 3.30(来自 OpenGL Shading Language 3.30 Specification - 4.1.7 Samplers):
Samplers aggregated into arrays
within a shader (using square brackets [ ]) can only be indexed with integral constant expressions
查看 GLSL 版本 4.60(最新)(来自 OpenGL Shading Language 4.60 Specification - 4.1.7. Opaque Types):
(此规则适用于 GLSL 4.00 之后的所有版本)
When aggregated into arrays within a shader, these types can only be indexed with a dynamically uniform expression, or texture lookup will result in undefined values.
因此,无论是在您使用的 GLSL 版本中,还是在最新版本中,采样器数组都不能通过顶点着色器输入(属性)进行索引。
从 GLSL 4.00 开始,可以通过统一索引采样器数组,因为通过统一变量索引是 dynamically uniform expression.
我建议使用 sampler2DArray
(参见 Sampler)而不是 sampler2D
的数组。
当您使用 sampler2DArray
时,您根本不需要任何索引,因为 "index" 在纹理查找时被编码在纹理坐标的第三个分量中(参见 texture
)。
我目前正在尝试使用 LWJGL 创建用于后处理目的的模糊着色器,但偶然发现了一个问题。
我要更改的制服是模糊的分辨率、半径和方向(水平或垂直,因此我可以为两个方向使用一个着色器)。我将输出渲染到 FrameBuffer,然后渲染到屏幕。但不知何故,纹理只是黑色的。当我使用常量值而不是制服时,它完全按预期工作,所以问题一定是制服变量。
这是我的片段着色器的代码:
#version 330 core
out vec4 fragColor;
in vec2 coords;
in vec4 color;
in float samplerIndex;
uniform sampler2D samplers[32]; //Just an Array with ints from 0 to 31
uniform float radius;
uniform vec2 resolution; //Screen Resolution, or width & height of Framebuffer
uniform vec2 direction; //Either 1 or 0 for x and y
void main() {
int index = int(samplerIndex);
vec4 sum = vec4(0.0);
float blurX = radius / resolution.x * direction.x;
float blurY = radius / resolution.y * direction.y;
sum += texture2D(samplers[index], vec2(coords.x - 4.0 * blurX, coords.y - 4.0 * blurY)) * 0.0162162162;
sum += texture2D(samplers[index], vec2(coords.x - 3.0 * blurX, coords.y - 3.0 * blurY)) * 0.0540540541;
sum += texture2D(samplers[index], vec2(coords.x - 2.0 * blurX, coords.y - 2.0 * blurY)) * 0.1216216216;
sum += texture2D(samplers[index], vec2(coords.x - 1.0 * blurX, coords.y - 1.0 * blurY)) * 0.1945945946;
sum += texture2D(samplers[index], vec2(coords.x, coords.y)) * 0.2270270270;
sum += texture2D(samplers[index], vec2(coords.x + 1.0 * blurX, coords.y + 1.0 * blurY)) * 0.1945945946;
sum += texture2D(samplers[index], vec2(coords.x + 2.0 * blurX, coords.y + 2.0 * blurY)) * 0.1216216216;
sum += texture2D(samplers[index], vec2(coords.x + 3.0 * blurX, coords.y + 3.0 * blurY)) * 0.0540540541;
sum += texture2D(samplers[index], vec2(coords.x + 4.0 * blurX, coords.y + 4.0 * blurY)) * 0.0162162162;
fragColor = color * vec4(sum.rgb, 1.0);
}
这是我渲染 FrameBuffer 的方式:
public void render(boolean fixed) {
model.setTextureID(Shader.getTextureID(texture));
model.buffer(vertices);
indices.put(0).put(1).put(2).put(2).put(3).put(0);
vertices.flip();
indices.flip();
shader.bind();
texture.bind();
shader.setUniform1iv("samplers", Shader.SAMPLERS);
shader.setUniform1f("radius", 10.0f);
shader.setUniform2f("resolution", width, height);
shader.setUniform2f("direction", horizontal, vertical);
if(fixed) {
shader.setUniformMatrix4f("camProjection", Camera.fixedProjection);
shader.setUniformMatrix4f("camTranslation", Camera.fixedTranslation);
} else {
shader.setUniformMatrix4f("camProjection", Camera.projection);
shader.setUniformMatrix4f("camTranslation", Camera.translation);
}
vao.bind();
vbo.bind();
vbo.uploadSubData(0, vertices);
ibo.bind();
ibo.uploadSubData(0, indices);
GL11.glDrawElements(GL11.GL_TRIANGLES, Model.INDICES, GL11.GL_UNSIGNED_INT, 0);
vao.unbind();
texture.unbind();
shader.unbind();
vertices.clear();
indices.clear();
}
虽然采样器制服工作得很好,但问题似乎只影响其他三个制服。 我对 OpenGL 和 GLSL 没有太多经验,我缺少什么?
您的着色器代码根本无法工作,因为
samplers[index]
samplers
是 sampler2D
的数组,index
是从顶点着色器输入设置的 samplerIndex
:
int index = int(samplerIndex);
请参阅您使用的 GLSL 版本 3.30(来自 OpenGL Shading Language 3.30 Specification - 4.1.7 Samplers):
Samplers aggregated into arrays within a shader (using square brackets [ ]) can only be indexed with integral constant expressions
查看 GLSL 版本 4.60(最新)(来自 OpenGL Shading Language 4.60 Specification - 4.1.7. Opaque Types):
(此规则适用于 GLSL 4.00 之后的所有版本)
When aggregated into arrays within a shader, these types can only be indexed with a dynamically uniform expression, or texture lookup will result in undefined values.
因此,无论是在您使用的 GLSL 版本中,还是在最新版本中,采样器数组都不能通过顶点着色器输入(属性)进行索引。
从 GLSL 4.00 开始,可以通过统一索引采样器数组,因为通过统一变量索引是 dynamically uniform expression.
我建议使用 sampler2DArray
(参见 Sampler)而不是 sampler2D
的数组。
当您使用 sampler2DArray
时,您根本不需要任何索引,因为 "index" 在纹理查找时被编码在纹理坐标的第三个分量中(参见 texture
)。