OpenGL 纹理呈现黑色,即使它的数据不为空
OpenGL Texture Renders black eventhough its data is not null
我已经在 LWJGL OpenGL 中编写了一个可以处理颜色的工作 2D 批处理渲染器。当我向它添加纹理支持时,渲染的四边形始终是黑色的。 STBImage 读取数据就好了。但它仍然呈现黑色。
这是着色器:顶点:
片段:
#version 450 core
in vec4 v_Colour;
in vec2 v_TexCoord;
in float v_TexIndex;
uniform sampler2D u_TextureSlots[16];
void main() {
int index = int(v_TexIndex);
gl_FragColor = texture(u_TextureSlots[index], v_TexCoord) * v_Colour;
}
渲染器的提交方法
public static void Submit(Texture texture, Rect drawRect, Rect uvRect, Vector4f colour) {
if (hasRoom) {
texture.BindSlot(textureIndex + 1);
int index = spriteCount++;
int offset = index * 6 * VERTEX_COUNT;
StoreData(offset, textureIndex++, drawRect, uvRect, colour);
if (textureIndex >= 16) hasRoom = false;
if (spriteCount >= maxBatchSize) hasRoom = false;
}
}
private static void StoreData(int offset, int textureIndex, Rect drawRect, Rect uvRect, Vector4f colour) {
float x1 = drawRect.x;
float y1 = drawRect.y;
float x2 = drawRect.x + drawRect.width;
float y2 = drawRect.y + drawRect.height;
float u1 = uvRect.x;
float v1 = uvRect.y;
float u2 = uvRect.x + uvRect.width;
float v2 = uvRect.y + uvRect.height;
for (int vertex = 0; vertex < 6; vertex++) {
int currentIndex = offset + vertex * VERTEX_COUNT;
float x = vertex == 0 || vertex == 3 || vertex == 5 ? x1 : x2;
float y = vertex == 0 || vertex == 3 || vertex == 1 ? y1 : y2;
float u = x == x1 ? u1 : u2;
float v = y == y1 ? v1 : v2;
vertices[currentIndex] = x;
vertices[currentIndex + 1] = y;
vertices[currentIndex + 2] = u;
vertices[currentIndex + 3] = v;
vertices[currentIndex + 4] = colour.x;
vertices[currentIndex + 5] = colour.y;
vertices[currentIndex + 6] = colour.z;
vertices[currentIndex + 7] = colour.w;
vertices[currentIndex + 8] = textureIndex;
}
}
纹理:
public Texture(String filepath) {
IntBuffer width = BufferUtils.createIntBuffer(1);
IntBuffer height = BufferUtils.createIntBuffer(1);
IntBuffer channels = BufferUtils.createIntBuffer(1);
ByteBuffer data = STBImage.stbi_load(filepath, width, height, channels, 0);
m_Width = width.get();
m_Height = height.get();
m_Channels = channels.get();
m_RendererID = glCreateTextures(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_RendererID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_Width, m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
assert data != null : "Image " + filepath + " doesn't exist";
STBImage.stbi_image_free(data);
}
片段着色器的行为未定义,因为:
int index = int(v_TexIndex);
... u_TextureSlots[index]...;
u_TextureSlots
是采样器数组,v_TexIndex
是片段着色器输入,因此 index
不是 Dynamically uniform expression.
请注意,未定义的行为意味着它可能会起作用,但规范不保证它会起作用。该行为在各种硬件上会有所不同。
查看 GLSL 4.60 版(最新)(来自 OpenGL Shading Language 4.60 Specification - 4.1.7. Opaque Types):
(当然这条规则也适用于GLSL 4.50版)
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.
我建议使用 sampler2DArray
(参见 Sampler)而不是 sampler2D
的数组。
当您使用 sampler2DArray
时,您根本不需要任何索引,因为 "index" 在纹理查找时被编码在纹理坐标的第三个分量中(参见 Texture)。
此外,指定纹理目标并使用glTexParameter
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
或纹理对象并使用glTextureParameteri
glTextureParameteri(m_RendererID, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTextureParameteri(m_RendererID, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
我已经在 LWJGL OpenGL 中编写了一个可以处理颜色的工作 2D 批处理渲染器。当我向它添加纹理支持时,渲染的四边形始终是黑色的。 STBImage 读取数据就好了。但它仍然呈现黑色。 这是着色器:顶点: 片段:
#version 450 core
in vec4 v_Colour;
in vec2 v_TexCoord;
in float v_TexIndex;
uniform sampler2D u_TextureSlots[16];
void main() {
int index = int(v_TexIndex);
gl_FragColor = texture(u_TextureSlots[index], v_TexCoord) * v_Colour;
}
渲染器的提交方法
public static void Submit(Texture texture, Rect drawRect, Rect uvRect, Vector4f colour) {
if (hasRoom) {
texture.BindSlot(textureIndex + 1);
int index = spriteCount++;
int offset = index * 6 * VERTEX_COUNT;
StoreData(offset, textureIndex++, drawRect, uvRect, colour);
if (textureIndex >= 16) hasRoom = false;
if (spriteCount >= maxBatchSize) hasRoom = false;
}
}
private static void StoreData(int offset, int textureIndex, Rect drawRect, Rect uvRect, Vector4f colour) {
float x1 = drawRect.x;
float y1 = drawRect.y;
float x2 = drawRect.x + drawRect.width;
float y2 = drawRect.y + drawRect.height;
float u1 = uvRect.x;
float v1 = uvRect.y;
float u2 = uvRect.x + uvRect.width;
float v2 = uvRect.y + uvRect.height;
for (int vertex = 0; vertex < 6; vertex++) {
int currentIndex = offset + vertex * VERTEX_COUNT;
float x = vertex == 0 || vertex == 3 || vertex == 5 ? x1 : x2;
float y = vertex == 0 || vertex == 3 || vertex == 1 ? y1 : y2;
float u = x == x1 ? u1 : u2;
float v = y == y1 ? v1 : v2;
vertices[currentIndex] = x;
vertices[currentIndex + 1] = y;
vertices[currentIndex + 2] = u;
vertices[currentIndex + 3] = v;
vertices[currentIndex + 4] = colour.x;
vertices[currentIndex + 5] = colour.y;
vertices[currentIndex + 6] = colour.z;
vertices[currentIndex + 7] = colour.w;
vertices[currentIndex + 8] = textureIndex;
}
}
纹理:
public Texture(String filepath) {
IntBuffer width = BufferUtils.createIntBuffer(1);
IntBuffer height = BufferUtils.createIntBuffer(1);
IntBuffer channels = BufferUtils.createIntBuffer(1);
ByteBuffer data = STBImage.stbi_load(filepath, width, height, channels, 0);
m_Width = width.get();
m_Height = height.get();
m_Channels = channels.get();
m_RendererID = glCreateTextures(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_RendererID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_Width, m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
assert data != null : "Image " + filepath + " doesn't exist";
STBImage.stbi_image_free(data);
}
片段着色器的行为未定义,因为:
int index = int(v_TexIndex);
... u_TextureSlots[index]...;
u_TextureSlots
是采样器数组,v_TexIndex
是片段着色器输入,因此 index
不是 Dynamically uniform expression.
请注意,未定义的行为意味着它可能会起作用,但规范不保证它会起作用。该行为在各种硬件上会有所不同。
查看 GLSL 4.60 版(最新)(来自 OpenGL Shading Language 4.60 Specification - 4.1.7. Opaque Types):
(当然这条规则也适用于GLSL 4.50版)
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.
我建议使用 sampler2DArray
(参见 Sampler)而不是 sampler2D
的数组。
当您使用 sampler2DArray
时,您根本不需要任何索引,因为 "index" 在纹理查找时被编码在纹理坐标的第三个分量中(参见 Texture)。
此外,指定纹理目标并使用glTexParameter
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
或纹理对象并使用glTextureParameteri
glTextureParameteri(m_RendererID, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTextureParameteri(m_RendererID, GL_TEXTURE_MAG_FILTER, GL_NEAREST);