Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.4k views
in Technique[技术] by (71.8m points)

java - Empty texture when using glTexImage2D with ByteBuffer in LWJGL

I just got a test texture working in my LWJGL code using an array of floats. Now, though, I need to load an image from a file and store it in the texture. I have gotten the image loaded and the data into a ByteBuffer object, but when I use glTexImage2D like so:

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

the texture is empty and will render as completely black. I've looked at how other people do this but nothing seems to be helping... The function call is also the same as with the float array, except for the type parameter, of course. And yes, my image is RGB and yes, it's 4x4. There's probably something really simple I'm not getting, so any help is appreciated.

Full working test program:

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
    }
}

This reproduced the problem for me. Usual LWJGL libs (lwjgl, opengl and glfw) are needed for this. As mentioned in the code comments, glGetError returns zero after each GL call.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

If you use

ByteBuffer buffer = ByteBuffer.wrap(data);

the the buffer is not "direct".

You have to use BufferUtils.createByteBuffer:

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

Explanation:

BufferUtils.createByteBuffer allocates a direct native-ordered bytebuffer with the specified capacity.

put(vboData) transfers the the data to the buffer, beginning at the current position (which is the start of the buffer in this case). The buffer position is incremented by the size of the data. So the new buffer position is at the end of the new data.

flip() sets the limit (length) of the buffer to the current position and then the position is set to zero.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...