【问题标题】:LWJGL Textures and StringsLWJGL 纹理和字符串
【发布时间】:2012-06-03 18:53:09
【问题描述】:

是否可以在不使用 Slick 框架的情况下加载 PNG 纹理并在 LWJGL 中绘制字符串?

每次我谷歌“如何在 lwjgl 中加载 png 图像” 我都会得到这样的答案 -> “嘿,只需使用 slick 框架中的纹理加载器”
“如何在 lwjgl 中绘制字符串” -> “只需使用 slick 框架中的 TTFFont 类”

但我不想使用这种中途跨框架设计。因为我不认为这是最好的方法。

LWJGL 是否有任何仅用于纹理或字符串的库或扩展?

【问题讨论】:

    标签: java image lwjgl


    【解决方案1】:

    基本上,你取一个BufferedImage,用getRGB()获取每个像素的RGB,取那个数据并把它放入一个ByteBuffer(用于将图像数据输入OpenGL的数据类型),设置一些纹理数据,并创建GL_TEXTURE_2D

    Krythic 的这段代码做到了:

    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.nio.ByteBuffer;
    
    import javax.imageio.ImageIO;
    
    import org.lwjgl.BufferUtils;
    import org.lwjgl.opengl.GL12;
    
    import static org.lwjgl.opengl.GL11.*;
    
    public class TextureLoader {
        private static final int BYTES_PER_PIXEL = 4;//3 for RGB, 4 for RGBA
           public static int loadTexture(BufferedImage image){
    
              int[] pixels = new int[image.getWidth() * image.getHeight()];
                image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
    
                ByteBuffer buffer = BufferUtils.createByteBuffer(image.getWidth() * image.getHeight() * BYTES_PER_PIXEL); //4 for RGBA, 3 for RGB
    
                for(int y = 0; y < image.getHeight(); y++){
                    for(int x = 0; x < image.getWidth(); x++){
                        int pixel = pixels[y * image.getWidth() + x];
                        buffer.put((byte) ((pixel >> 16) & 0xFF));     // Red component
                        buffer.put((byte) ((pixel >> 8) & 0xFF));      // Green component
                        buffer.put((byte) (pixel & 0xFF));               // Blue component
                        buffer.put((byte) ((pixel >> 24) & 0xFF));    // Alpha component. Only for RGBA
                    }
                }
    
                buffer.flip(); //FOR THE LOVE OF GOD DO NOT FORGET THIS
    
                // You now have a ByteBuffer filled with the color data of each pixel.
                // Now just create a texture ID and bind it. Then you can load it using 
                // whatever OpenGL method you want, for example:
    
              int textureID = glGenTextures(); //Generate texture ID
                glBindTexture(GL_TEXTURE_2D, textureID); //Bind texture ID
    
                //Setup wrap mode
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
    
                //Setup texture scaling filtering
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    
                //Send texel data to OpenGL
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
    
                //Return the texture ID so we can bind it later again
              return textureID;
           }
    
           public static BufferedImage loadImage(String loc)
           {
                try {
                   return ImageIO.read(MainClass.class.getResource(loc));
                } catch (IOException e) {
                    //Error Handling Here
                }
               return null;
           }
    }
    

    要使用此代码,请执行以下操作:

    BufferedImage image = TextureLoader.loadImage("/res/test.png");//The path is inside the jar file
    int textureID = TextureLoader.loadTexture(image);
    

    您可以将 textureID 保存为 final 变量(如果纹理从不改变),或者在每次渲染后使用 GL11.glDeleteTextures(textureID); 卸载纹理

    要做文本,只需手动创建一个BufferedImage,然后使用createGraphics() 获取图像的graphics2D() 实例。然后,使用drawString()BufferedImage上绘制,加载到TextureLoader中,渲染到屏幕上,然后按照上面的方法卸载纹理。

    【讨论】:

    • 以上代码是我的,前段时间写的。想象一下我在 Stack Overflow 上随机找到它的惊喜!知道它一直在互联网上流行,让我感到温暖和模糊! =P
    • 还应该注意的是,我将相同的 sn-p 提供给了 Dinnerbone,以帮助他在 Minecraft 中创建 Tinted Glass。
    • 有趣的是我没有在原始的 sn-p 中添加“为了上帝的爱,不要忘记这个”。我想我说过类似的话:“确保你不要忘记这个”或类似的话。自从我制作它以来,它显然经过了几手。
    • "//3 for RGB, 4 for RGBA" 是相同的,未捕获的图像加载是相同的,也是内部图像加载,这正是我第一次构建的方式。 (这是快速拼凑起来的东西,以帮助阐明如何通过呼叫列表完成,而无需 Slick for Dinnerbone)
    • @T_01 你会使用glBindTexture(GL_TEXTURE_2D, textureID);
    【解决方案2】:

    LWJGL 现在包括 STB 绑定,这是加载图像和字体的首选方式,无需使用 Slick 甚至 AWT。

    要加载 PNG:

    import static org.lwjgl.opengl.GL11.GL_REPEAT;
    import static org.lwjgl.opengl.GL11.GL_LINEAR;
    import static org.lwjgl.opengl.GL11.GL_RGBA;
    import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
    import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER;
    import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER;
    import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S;
    import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T;
    import static org.lwjgl.opengl.GL11.GL_UNPACK_ALIGNMENT;
    import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
    import static org.lwjgl.opengl.GL11.glBindTexture;
    import static org.lwjgl.opengl.GL11.glGenTextures;
    import static org.lwjgl.opengl.GL11.glPixelStorei;
    import static org.lwjgl.opengl.GL11.glTexImage2D;
    import static org.lwjgl.opengl.GL11.glTexParameteri;
    import static org.lwjgl.opengl.GL30.glGenerateMipmap;
    import static org.lwjgl.stb.STBImage.stbi_load_from_memory;
    import static org.lwjgl.system.MemoryStack.stackPush;
    import static org.lwjgl.demo.util.IOUtils.ioResourceToByteBuffer;
      
    import java.nio.ByteBuffer;
    import java.nio.IntBuffer;
    
    import org.lwjgl.system.MemoryStack;
    
    public class Texture{
        private int width;
        private int height;
        private int id;
    
        public Texture(String imagePath) {
            ByteBuffer imageData = ioResourceToByteBuffer(imagePath, 1024);
        
            try (MemoryStack stack = stackPush()) {
                IntBuffer w = stack.mallocInt(1);
                IntBuffer h = stack.mallocInt(1);
                IntBuffer components = stack.mallocInt(1);
    
                // Decode texture image into a byte buffer
                ByteBuffer decodedImage = stbi_load_from_memory(imageData, w, h, components, 4);
            
                this.width = w.get();
                this.height = h.get();
            
                // Create a new OpenGL texture 
                this.id = glGenTextures();
            
                // Bind the texture
                glBindTexture(GL_TEXTURE_2D, this.id);
    
                // Tell OpenGL how to unpack the RGBA bytes. Each component is 1 byte size
                glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
            
                // Upload the texture data
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this.width, this.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, decodedImage);
            
                // Generate Mip Map
                glGenerateMipmap(GL_TEXTURE_2D);
            }
        }
    }
    

    更完整的图片加载、文字打印示例见LWJGL源码:

    org.lwjgl.demo.stb

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-12
      • 2014-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-04
      相关资源
      最近更新 更多