在 LWJGL 中使用带有 ByteBuffer 的 glTexImage2D 时的空纹理

Empty texture when using glTexImage2D with ByteBuffer in LWJGL

我刚刚使用 float 数组在我的 LWJGL 代码中获得了一个测试纹理。不过,现在我需要从文件中加载图像并将其存储在纹理中。我已经将图像和数据加载到 ByteBuffer 对象中,但是当我像这样使用 glTexImage2D 时:

GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB,
    4, 4, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, buffer);

纹理为空,将呈现为全黑。我看过其他人是如何做到这一点的,但似乎没有任何帮助......函数调用也与 float 数组相同,除了 type参数,当然。是的,我的图像是 RGB,是的,它是 4x4。可能有些东西 真的 很简单我没有得到,所以任何帮助都将不胜感激。

完整的工作测试程序:

static org.lwjgl.system.MemoryUtil.NULL;

import java.nio.ByteBuffer;

import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;

public class Example {

    public static void main(String[] args) {
        if (!GLFW.glfwInit()) {
            throw new IllegalStateException("Unable to initialize GLFW");
        }

        // Create a window as the GL context
        long window = GLFW.glfwCreateWindow(100, 100, "", NULL, NULL);

        if (window == NULL) {
            GLFW.glfwTerminate();
            throw new RuntimeException("Failed to create the GLFW window");
        }

        GLFW.glfwMakeContextCurrent(window);

        GL.createCapabilities();

        // Generate the texture and set parameters
        int textureID = GL11.glGenTextures();
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);

        // A byte array of 4x4 RBG values
        byte[] data = new byte[] {
                127, 127, 0, 127, 127, 0, 127, 127, 0, 127, 127, 0,
                127, 127, 0, 127, 127, 0, 127, 127, 0, 127, 127, 0,
                127, 127, 0, 127, 127, 0, 127, 127, 0, 127, 127, 0,
                127, 127, 0, 127, 127, 0, 127, 127, 0, 127, 127, 0,
        };
        ByteBuffer buffer = ByteBuffer.wrap(data);

        // Load the data to the texture
        GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, 4, 4, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, buffer);
        // glGetError returns 0.

        // Test if the buffer data is correctly stored in the texture.
        // I have unrelated problems while getting the data using a
        // ByteBuffer, so it's a float array for debug purposes.
        float[] floats = new float[data.length];
        GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, GL11.GL_FLOAT, floats);
        // glGetError returns 0.

        for (float f : floats) {
            System.out.println(f);
        }
        // Expected output is 16 times the following:
        //   0.5
        //   0.5
        //   0.0
        // Actual output: Random (garbage?) values
        // Examples:
        //   0.003921569
        //   0.87843144
        //   1.0
    }
}

这为我重现了这个问题。为此需要常用的 LWJGL 库(lwjgl、opengl 和 glfw)。如代码注释中所述,每次 GL 调用后 glGetError returns 为零。

如果你使用

ByteBuffer buffer = ByteBuffer.wrap(data);

缓冲区不是 "direct"

你必须使用 BufferUtils.createByteBuffer:

ByteBuffer buffer = BufferUtils.createByteBuffer(data.length);
buffer.put(data);
buffer.flip();

解释:

BufferUtils.createByteBuffer 分配具有指定容量的直接本机排序字节缓冲区。

put(vboData) 将数据传输到缓冲区,从当前位置开始(在本例中是缓冲区的开头)。缓冲区位置按数据大小递增。所以新的缓冲区位置在新数据的末尾。

flip() 将缓冲区的限制(长度)设置为当前位置,然后将位置设置为零。

您应该阅读此 wiki,然后使用 "Stack Allocation" 或 MemoryUtil class。

实际上还有一个更快的方法。当您知道您永远不会超过每帧的给定数量时,您可以只分配一次,然后用于所有短暂的分配,例如纹理所需的分配。然后在每一帧之后,您将清除整个缓冲区。

我在我的 project

中应用了这个概念