使用LWJGL3发现glDrawElements渲染图片会直接黑屏?

graphics.Shader:

package com.blank.Flappy.graphics;

import com.blank.Flappy.maths.Matrix4f;
import com.blank.Flappy.maths.Vector3f;
import com.blank.Flappy.utils.ShaderUtils;

import java.util.Map;
import java.util.HashMap;

import static org.lwjgl.opengl.GL20.*;

public class Shader {

    public static final int VERTEX_ATTRIB = 0;
    public static final int TCOORD_ATTRIB = 1;

    public static Shader BG, BIRD, PIPE;

    private final int ID;
    private Map<String, Integer> locationCache = new HashMap<String, Integer>();  //缓存路径 不会实时更新

    private boolean enabled = false;  //创建一个布尔变量用来检测着色器的启用和禁用

    public Shader(String vertex, String fragment){  //加载顶点和片元着色器
        ID = ShaderUtils.load(vertex, fragment);
    }

    public static void loadAll(){  //读取着色器文件
        BG = new Shader("shaders/bg.vert","shaders/bg.frag");
    }

    public int getUniform(String name){  //创建方法用于获取uniform变量
        if (locationCache.containsKey(name)){
            return locationCache.get(name);
        }
        int result = glGetUniformLocation(ID, name);
        if (result == -1)
            System.err.println("Could not find uniform variable '" + name + "'!");
        else
            locationCache.put(name, result);
        return result;
    }

    //设置不同类型的uniform变量(用于顶点和片元着色器中表示变换矩阵,材质,光照参数和颜色等信息。
    public void setUniform1i(String name, int value){
        if(!enabled) enable();
        glUniform1i(getUniform(name), value);
    }

    public void setUniform1f(String name, float value){
        if(!enabled) enable();
        glUniform1f(getUniform(name), value);
    }

    public void setUniform2f(String name, float x, float y){
        if(!enabled) enable();
        glUniform2f(getUniform(name), x, y);
    }

    public void setUniform3f(String name, Vector3f vector){
        if(!enabled) enable();
        glUniform3f(getUniform(name), vector.x, vector.y, vector.z);
    }

    public void setUniformMat4f(String name, Matrix4f matrix){
        if(!enabled) enable();
        glUniformMatrix4fv(getUniform(name), false, matrix.toFloatBuffer());  //因为OpenGL需要列优先读取,所以矩阵不需要转置
    }

    public void enable(){  //启用着色器
        glUseProgram(ID);
        enabled = true;
    }

    public void disable(){  //禁用着色器 用完之后一定要禁用以避免系统资源的浪费
        glUseProgram(0);
        enabled = false;
    }

}

graphics.Texture:

package com.blank.Flappy.graphics;

import com.blank.Flappy.utils.BufferUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.IOException;

import static org.lwjgl.opengl.GL11.*;

public class Texture {

    private int width, height, texture;

    public Texture(String path){
        texture = load(path);
    }

    private int load(String path){  //从图片中读取材纹理信息
        int[] pixels = null;
        try{
            BufferedImage image = ImageIO.read(new FileInputStream(path));  //读取图片文件
            width = image.getWidth();  //获取图片宽
            height = image.getHeight();  //获取图片高
            pixels = new int[width * height];  //创建数组获取图片像素
            image.getRGB(0, 0, width, height, pixels, 0, width);  //获取图片颜色
        }catch (IOException e){
            e.printStackTrace();
        }

        int[] data = new int[width * height];  //创建数组存储图片颜色信息
        for(int i = 0; i < width * height; i++){  //根据OpenGL的读取方式获取颜色信息
            int a = (pixels[i] & 0xff000000) >> 24;
            int r = (pixels[i] & 0xff0000) >> 16;
            int g = (pixels[i] & 0xff00) >> 8;
            int b = (pixels[i] & 0xff);

            data[i] = a << 24 | b << 16 | g << 8 | r;  //OpenGL的颜色读取顺序
        }

        int result = glGenTextures();  //创建int变量存储纹理
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  //设置纹理参数(二维纹理,缩小纹理,临近采样)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);  //(二维纹理,放大纹理,临近采样)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, BufferUtils.createIntBuffer(data));  //指定二维纹理图片 将之前获取的参数传入
        return result;
    }

    public void bind(){
        glBindTexture(GL_TEXTURE_2D, texture);  //将二维纹理绑定至texture变量上
    }

    public void unbind(){
        glBindTexture(GL_TEXTURE_2D, 0);  //取消绑定
    }

}

graphics.VertexArray:

package com.blank.Flappy.graphics;

import com.blank.Flappy.utils.BufferUtils;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL30.*;

public class VertexArray {

    private int vao, vbo, ibo, tbo;  //顶点数组对象,顶点缓冲对象,索引(index)缓冲对象,纹理缓冲对象
    private int count;  //需要渲染的顶点数量

    public VertexArray(float[] vertices, byte[] indices, float[] textureCoordinates){
        count = indices.length;  //用索引数组长度表示顶点数量

        vao = glGenVertexArrays();  //生成顶点数组
        glBindVertexArray(vao);  //绑定顶点数组

        vbo = glGenBuffers();  //生成缓冲对象
        glBindBuffer(GL_ARRAY_BUFFER, vbo);  //绑定缓冲对象
        glBufferData(GL_ARRAY_BUFFER, BufferUtils.createFloatBuffer(vertices), GL_STATIC_DRAW);  //创建并初始化缓冲对象的数据
        glVertexAttribPointer(Shader.VERTEX_ATTRIB, 3, GL_FLOAT, false, 0, 0);  //定义通用顶点属性数据的数组 (size为3是因为vertex中有x,y,z三种参数)
        glEnableVertexAttribArray(Shader.VERTEX_ATTRIB);

        tbo = glGenBuffers();  //纹理对象
        glBindBuffer(GL_ARRAY_BUFFER, tbo);
        glBufferData(GL_ARRAY_BUFFER, BufferUtils.createFloatBuffer(textureCoordinates), GL_STATIC_DRAW);
        glVertexAttribPointer(Shader.TCOORD_ATTRIB, 2, GL_FLOAT, false, 0, 0);  //(size为2是因为texture中只有x,y两种参数)
        glEnableVertexAttribArray(Shader.TCOORD_ATTRIB);

        ibo = glGenBuffers();  //索引缓冲对象
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, BufferUtils.createByteBuffer(indices), GL_STATIC_DRAW);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);  //解绑索引缓冲
        glBindBuffer(GL_ARRAY_BUFFER, 0);  //解绑数组缓冲
        glBindVertexArray(0);  //解绑顶点数组

    }

    public void bind(){
        glBindVertexArray(vao);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    }

    public void unbind(){
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
    }

    public void draw(){
        glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_BYTE, 0);  //从数组数据三角化渲染图元
    }

    public void render(){
        bind();
        draw();
    }

}

input.Input:

package com.blank.Flappy.input;

import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWKeyCallback;

public class Input extends GLFWKeyCallback {  //反馈用户按键

    public static boolean[] keys = new boolean[65536];

    public void invoke(long window, int key, int scancode, int action, int mods) {
        keys[key] = action != GLFW.GLFW_RELEASE;
    }
}

level.Level:

package com.blank.Flappy.level;

import com.blank.Flappy.graphics.Shader;
import com.blank.Flappy.graphics.Texture;
import com.blank.Flappy.graphics.VertexArray;

public class Level {

    private VertexArray background;
    private Texture bgTexture;

    public Level(){
        float[] vertices = new float[]{  //与16:9的矩阵对应
                -10.0f, -10.0f * 9.0f / 16.0f, 0.0f,
                -10.0f,  10.0f * 9.0f / 16.0f, 0.0f,
                 0.0f ,  10.0f * 9.0f / 16.0f, 0.0f,
                 0.0f , -10.0f * 9.0f / 16.0f, 0.0f
        };

        byte[] indices = new byte[]{  //重复使用相同的顶点来防止创建多余的顶点
                0, 1, 2,  //第一个三角形
                2, 3, 0  //第二个三角形
        };

        float[] tcs = new float[]{
                0, 1,
                0, 0,
                1, 0,
                1, 1
        };

        background = new VertexArray(vertices, indices, tcs);
        bgTexture = new Texture("res/bg.jpeg");
    }

    public void render(){
        bgTexture.bind();
        Shader.BG.enable();
        background.render();
        Shader.BG.disable();
        bgTexture.unbind();
    }

}

maths.Matrix4f:

package com.blank.Flappy.maths;

import java.nio.FloatBuffer;
import com.blank.Flappy.utils.BufferUtils;


public class Matrix4f {  //定义矩阵类


    public static final int SIZE = 4 * 4;
    public float[] elements = new float[SIZE];

    public Matrix4f(){

    }

    public static Matrix4f identity(){  //初始化矩阵
        Matrix4f result = new Matrix4f();
        for (int i = 0; i < SIZE; i++){
            result.elements[i] = 0.0f;
        }
        result.elements[0 + 0 * 4] = 1.0f;
        result.elements[1 + 1 * 4] = 1.0f;
        result.elements[2 + 2 * 4] = 1.0f;
        result.elements[3 + 3 * 4] = 1.0f;

        return result;
    }

    public static Matrix4f orthographic(float left, float right, float bottom, float top, float near, float far){ //创建正交矩阵数组
        Matrix4f result = identity();

        result.elements[0 + 0 * 4] = 2.0f / (right - left);
        result.elements[1 + 1 * 4] = 2.0f / (top - bottom);
        result.elements[2 + 2 * 4] = 2.0f / (near - far);

        result.elements[0 + 3 * 4] = (left + right) / (left - right);
        result.elements[1 + 3 * 4] = (bottom + top) / (bottom - top);
        result.elements[2 + 3 * 4] = (far + near) / (far - near);

        return result;
    }

    public static Matrix4f translate(Vector3f vector){  //平移矩阵
        Matrix4f result = identity();
        result.elements[0 + 3 * 4] = vector.x;
        result.elements[1 + 3 * 4] = vector.y;
        result.elements[2 + 3 * 4] = vector.z;
        return result;
    }

    public static Matrix4f rotate(float angle){  //旋转矩阵
        Matrix4f result = identity();
        float r = (float) Math.toRadians(angle);
        float cos = (float) Math.cos(r);
        float sin = (float) Math.sin(r);

        result.elements[0 + 0 * 4] = cos;
        result.elements[1 + 0 * 4] = sin;

        result.elements[0 + 1 * 4] = -sin;
        result.elements[1 + 1 * 4] = cos;

        return result;
    }

    public Matrix4f multiply(Matrix4f matrix){  //矩阵乘法
        Matrix4f result = new Matrix4f();
        for(int y = 0; y < 4; y++){
            for(int x = 0; x < 4; x++){
                float sum = 0.0f;
                for(int e = 0; e < 4; e++){
                    sum += this.elements[x + e * 4] * matrix.elements[e + y * 4];
                }
                result.elements[x + y *4] = sum;
            }
        }
        return result;
    }

    public FloatBuffer toFloatBuffer(){  //返回缓存数据
        return BufferUtils.createFloatBuffer(elements);
    }

}

maths.Vector3f:

package com.blank.Flappy.maths;

public class Vector3f {  //定义向量类并初始化

    public float x, y, z;

    public Vector3f(){
        x = 0.0f;
        y = 0.0f;
        z = 0.0f;
    }

    public Vector3f(float x, float y, float z){
        this.x = x;
        this.y = y;
        this.z = z;
    }

}

utils.BufferUtils:

package com.blank.Flappy.utils;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

public class BufferUtils {  //创建三种缓存 用来存放不同的数据类型数组的信息

    private BufferUtils(){

    }

    public static ByteBuffer createByteBuffer(byte[] array){
        ByteBuffer result = ByteBuffer.allocateDirect(array.length).order(ByteOrder.nativeOrder());
        result.put(array).flip();
        return result;
    }

    public static FloatBuffer createFloatBuffer(float[] array){
        FloatBuffer result = ByteBuffer.allocateDirect(array.length << 2).order(ByteOrder.nativeOrder()).asFloatBuffer();
        result.put(array).flip();
        return result;
    }

    public static IntBuffer createIntBuffer(int[] array){
        IntBuffer result = ByteBuffer.allocateDirect(array.length << 2).order(ByteOrder.nativeOrder()).asIntBuffer();
        result.put(array).flip();
        return result;
    }

}

utils.FileUtils:

package com.blank.Flappy.utils;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class FileUtils {

    private FileUtils(){

    }

    public static String loadAsString(String file){  //以数组形式读取文件 便于将图片转换为矩阵和向量
        StringBuilder result = new StringBuilder();
        try{
            BufferedReader reader = new BufferedReader(new FileReader(file));
            String buffer = "";
            while((buffer = reader.readLine()) != null){
                result.append(buffer + '\n');
            }
            reader.close();
        }catch (IOException e){
            e.printStackTrace();
        }
        return result.toString();
    }

}

utils.ShaderUtils:

package com.blank.Flappy.utils;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL20.*;

public class ShaderUtils {

    private ShaderUtils(){

    }

    public static int load(String vertPath, String fragPath){  //读取顶点和片元着色器文件(由于是2D的 所以并没有用到几何着色器)
        String vert = FileUtils.loadAsString(vertPath);
        String frag = FileUtils.loadAsString(fragPath);
        return create(vert,frag);
    }

    public static int create(String vert, String frag){
        int program = glCreateProgram();  //创建一个program对象用于附加着色器对象
        int vertID = glCreateShader(GL_VERTEX_SHADER);  //创建着色器对象
        int fragID = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(vertID, vert);  //修改着色器对象中的源代码
        glShaderSource(fragID, frag);

        glCompileShader(vertID);  //编译着色器
        if (glGetShaderi(vertID,GL_COMPILE_STATUS) == GL_FALSE){
            System.err.println("Failed to compile vertex shader!");
            System.err.println(glGetShaderInfoLog(vertID));
            return -1;
        }
        glCompileShader(fragID);
        if (glGetShaderi(fragID,GL_COMPILE_STATUS) == GL_FALSE){
            System.err.println("Failed to compile fragment shader!");
            System.err.println(glGetShaderInfoLog(fragID));
            return -1;
        }

        glAttachShader(program, vertID);  //将着色器对象附着到program对象上
        glAttachShader(program, fragID);
        glLinkProgram(program);  //链接program对象,将两种着色器对象用于创建可执行文件
        glValidateProgram(program);  //验证program对象已经链接

        glDeleteShader(vertID);  //删除已经附着好的着色器对象 释放内存
        glDeleteShader(fragID);

        return program;
    }

}

Main:

package com.blank.Flappy;

import com.blank.Flappy.graphics.Shader;
import com.blank.Flappy.input.Input;
import com.blank.Flappy.level.Level;
import com.blank.Flappy.maths.Matrix4f;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.opengl.GL;

import static org.lwjgl.glfw.GLFW.*;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.system.MemoryUtil.*;

public class Main implements Runnable{

    private int width = 1280;
    private int height = 720;

    private Thread thread;
    private boolean running = false;

    private long window;

    private Level level;

    public void start(){
        running = true;
        thread = new Thread(this,"Game");  //创建名为Game的线程
        thread.start();
    }

    private void init(){  //初始化
       if(!glfwInit()){  //初始化失败
           System.err.println("Could not initialize GLFW!");
           return;
       }

        glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);  //配置上下文环境
        window = glfwCreateWindow(width, height, "Flappy Blank", NULL, NULL);  //创建窗口

        if(window == NULL){  //创建窗口失败
            System.err.println("Could not create GLFW window!");
            return;
        }

        GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());  //获取默认显示屏
        glfwSetWindowPos(window, (vidmode.width() - width) / 2, (vidmode.height() - height) / 2);  //将窗口位置设置为默认显示屏中央

        glfwSetKeyCallback(window, new Input());  //获取用户输入按键信息

        glfwMakeContextCurrent(window);  //设置上下文
        glfwShowWindow(window);  //显示窗口
        GL.createCapabilities();  //初始化上下文

        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);  //设置背景颜色
        glEnable(GL_DEPTH_TEST);
        glActiveTexture(GL_TEXTURE1);  //与setUniform1i中的value=1对应
        System.out.println("OPENGL: " + glGetString(GL_VERSION));  //显示OpenGL版本
        Shader.loadAll();

        Matrix4f pr_matrix = Matrix4f.orthographic(-10.0f, 10.0f, -10.0f * 9.0f / 16.0f, 10.0f * 9.0f / 16.0f, -1.0f, 1.0f);  //16:9的背景比例
        Shader.BG.setUniformMat4f("pr_matrix", pr_matrix);
        Shader.BG.setUniform1i("tex", 1);

        level = new Level();
    }

    public void run(){
        init();
        while(running){
            update();
            render();

            //检测窗口是否关闭
            if(glfwWindowShouldClose(window)){
                running = false;
            }
        }
    }

    private void update(){
        glfwPollEvents();

    }

    private void render(){
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        level.render();
        int error = glGetError();  //检查错误
        if (error != GL_NO_ERROR){
            System.out.println(error);
        }
        glfwSwapBuffers(window);
    }


    public static void main(String[] args){
        new Main().start();
    }

}

bg.frag:

#version 330 core

layout (location = 0) out vec4 color;

in DATA
{
    vec2 tc;
} fs_in;

uniform sampler2D tex;

void main()
{
    color = texture(tex, fs_in.tc);
}

bg.vert:

#version 330 core

layout (location = 0) in vec4 position;
layout (location = 1) in vec2 tc;

uniform mat4 pr_matrix;

out DATA
{
    vec2 tc;
} vs_out;

void main()
{
    gl_Position = pr_matrix * position;
    vs_out.tc = tc;
}

求大佬帮忙看看,所有代码都在这里了,运行出来结果如下:

但期望中应该左边显示图片

你好,我是有问必答小助手,非常抱歉,本次您提出的有问必答问题,目前超出我们的服务范围,暂时无法为您解答。

首次提问人员可免费体验一次有问必答服务。目前首次提问的问题服务范围为:编程语言、Java开发、python、数据库、前端开发 领域专业技术问题,为您提供问题的解决思路和指导。不提供源码代写、项目文档代写、论文代写、安装包资源发送或安装、软件使用指导等服务。

我们后续会持续优化,扩大我们的服务范围,为您带来更好地服务。