【问题标题】:OpenGL array textures not rendering at allOpenGL阵列纹理根本不渲染
【发布时间】:2016-03-23 01:14:27
【问题描述】:

我目前正在努力将一个项目从使用纹理图集转换为数组纹理,但对于我来说,我无法让它工作。

关于我的环境的一些说明:

  • 我在 GLSL 3.30 版中使用 OpenGL 3.3 核心上下文
  • 纹理都是 128x128 并且在使用图集时渲染得非常好(除非边缘伪影说服我切换)

我认为我已经排除的问题:

  • 分辨率问题 - 128x128,是 2 的幂,应该没问题
  • 纹理加载(和以前一样完美)
  • 纹理不完整(mipmap 问题) - 我已经了解了有关 mipmap 的常见问题,但我认为 OpenGL 不应该期待它们

这是我创建数组纹理的代码:

public void createTextureArray() {
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    int handle = glGenTextures();
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D_ARRAY, handle);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, Texture.SIZE);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, Texture.SIZE, Texture.SIZE, textures.size());

    try {
        int layer = 0;
        for (Texture tex : textures.values()) {
            // Next few lines are just for loading the texture. They've been ruled out as the issue.
            PNGDecoder decoder = new PNGDecoder(ImageHelper.asInputStream(tex.getImage()));
            ByteBuffer buffer = BufferUtils.createByteBuffer(decoder.getWidth() * decoder.getHeight() * 4);
            decoder.decode(buffer, decoder.getWidth() * 4, PNGDecoder.Format.RGBA);
            buffer.flip();

            glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, layer, decoder.getWidth(), decoder.getHeight(), 1,
                    GL_RGBA, GL_UNSIGNED_BYTE, buffer);

            tex.setLayer(layer);

            layer++;
        }
    } catch (IOException ex) {
        ex.printStackTrace();
        System.err.println("Failed to create/load texture array");
        System.exit(-1);
    }
}

创建VAO/VBO的代码:

private static int prepareVbo(int handle, FloatBuffer vbo) {
    IntBuffer vaoHandle = BufferUtils.createIntBuffer(1);
    glGenVertexArrays(vaoHandle);
    glBindVertexArray(vaoHandle.get());
    glBindBuffer(GL_ARRAY_BUFFER, handle);

    glBufferData(GL_ARRAY_BUFFER, vbo, GL_STATIC_DRAW);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D_ARRAY, GraphicsMain.TEXTURE_REGISTRY.atlasHandle);

    glEnableVertexAttribArray(positionAttrIndex);
    glEnableVertexAttribArray(texCoordAttrIndex);

    glVertexAttribPointer(positionAttrIndex, 3, GL_FLOAT, false, 24, 0);
    glVertexAttribPointer(texCoordAttrIndex, 3, GL_FLOAT, false, 24, 12);

    glBindVertexArray(0);

    vaoHandle.rewind();
    return vaoHandle.get();
}

片段着色器:

#version 330 core

uniform sampler2DArray texArray;

varying vec3 texCoord;

void main() {
    gl_FragColor = texture(texArray, texCoord);
}

texCoord 工作正常;它从顶点着色器正确传递。)

我几乎没有想法了,所以对于现代 OpenGL 来说还是有点陌生​​,我想知道我的代码是否有什么明显的错误。

【问题讨论】:

  • 你的纹理坐标是多少?确保图层索引是整数,而不是标准化的0-1 值。
  • "texture2DArray" 这不是合法的 GLSL 3.30 函数。用于从纹理数组中采样的函数称为texture,就像用于从各种纹理中采样的函数一样。
  • @ColonelThirtyTwo xy 坐标为 0 或 1,具体取决于正在渲染的顶点。该层存储为int,并直接从访问器传递到作为VBO 提供的FloatBuffer
  • @NicolBolas 奇怪,它编译得很好。无论如何,我已将其替换为 texture,我将立即更新 OP 以反映这一点。
  • @caseif:“图层存储为int 并直接从访问器传递给FloatBuffer”是什么意思?确保在其中传递了正确的浮点值。

标签: opengl textures lwjgl


【解决方案1】:

一些注意事项:

  • 你不再需要拥有两种纹理的力量
  • 确保每一层都有相同数量的级别/mipmaps,就像 wiki says
  • 前四个glTexParameteri 会影响绑定到GL_TEXTURE_2D_ARRAY 的内容在那一刻,所以最好在glBindTexture 之后移动它们
  • 如何指定要使用glGenTextures() 创建的纹理数量?如果您有可能使用更具体的方法,请使用它
  • GL_UNPACK_ROW_LENGTH 如果大于 0,则定义一行中的像素数。我想Texture.SIZE 并不是真正的纹理大小,而是一侧的尺寸(在您的情况下为 128)。反正你不需要设置,你可以跳过它
  • 仅当您的行长度是它的倍数时,才将GL_UNPACK_ALIGNMENT 设置为 4。大多数情况下,人们在加载纹理之前将其设置为 1 以避免任何麻烦,然后在完成后将其设置回 4
  • glTexStorage3D 的最后一个参数预计是层数,我希望textures.size() 更好地返回它而不是大小(128x128)
  • glActiveTextureglBindTexture 里面的 prepareVbo 没用,它们不是 vao 的一部分
  • 不要在 glsl 中使用varying,它已被弃用,切换到简单的in out
  • 您可能想从this sample 获得灵感
  • 使用采样器,它们为您提供更大的灵活性
  • 如果可用,请使用Debug Output,否则使用glGetError(),渲染输出可能无法明确看到一些静默错误
  • 你称它为 prepareVbo 但你确实在其中初始化了 vao 和 vbo

【讨论】:

  • 我已经验证了所有这些并更新了 OP,但纹理仍然不起作用。几个注意事项:glGenTextures()(不带参数)意味着要生成 1 个纹理。 textures.size() 返回纹理List 中单个纹理的数量,这也是正确的层数。
  • 已解决 - 我忘记从 prepareVbo 中删除 glBindTexture 调用。省略它会导致纹理完美地工作。出于好奇,为什么调用这个函数会破坏程序?
  • 很高兴你解决了。我能想到的唯一合乎逻辑的原因是,在prepareVbo 之后的某个地方,您正在调用一些函数,该函数将修改绑定到GL_TEXTURE_2D_ARRAY 的纹理参数,即GraphicsMain.TEXTURE_REGISTRY.atlasHandle。 Ps:我添加了另外几个提示;)
  • 谢谢,我会研究实现采样器。
猜你喜欢
  • 2014-08-09
  • 2013-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
相关资源
最近更新 更多