无法在 lwjgl 中使用 vbos opengl 绘制基本三角形

Cannot draw basic triangle with vbos opengl in lwjgl

我尝试使用 lwjgl 绘制一个简单的三角形

这是我的 3D 对象 class:

public class ThreeDObject {
    
    float[] vertices;
    float[] color;
    
    int vao;
    int vvbo; //vertex vbo
    int cvbo; //color vbo
    int vtexNumber;
    boolean isSetUp = false;
    
    String fragmentShader;
    String vertexShader;
    int frag;
    int vert;
    int program;
    
    public ThreeDObject( float[] vertices, float[] color) {
        this.vertices = vertices;
        this.color = color;
        this.vtexNumber = this.vertices.length / 3;
        setupVAO();
        this.vertexShader = defaultVert;
        this.fragmentShader = defaultFrag;
        setupShaders();
        System.out.println(Arrays.toString(this.vertices));
    }

    public void setupVAO() {
        
        FloatBuffer vb = BufferUtils.createFloatBuffer(vertices.length);
        vb.put(vertices).flip();
        
        FloatBuffer cb = BufferUtils.createFloatBuffer(color.length);
        cb.put(color).flip();
        
        if(hasEBO()) {
            IntBuffer ob = BufferUtils.createIntBuffer(order.length);
            ob.put(order).flip();
        }
        
        vao = GL30.glGenVertexArrays();
        
        GL30.glBindVertexArray(vao);
        
        vvbo = GL15.glGenBuffers();
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vvbo);
        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vb, GL15.GL_STATIC_DRAW);
        GL30.glVertexAttribPointer(0, 3, GL30.GL_FLOAT, false, 0, 0);
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
        
        GL20.glEnableVertexAttribArray(0);
        GL30.glVertexAttribPointer(0, 3, GL30.GL_FLOAT, false, 0, 0);
        
        cvbo = GL15.glGenBuffers();
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, cvbo);
        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, cb, GL15.GL_STATIC_DRAW);
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
        
        GL20.glEnableVertexAttribArray(1);
        GL30.glVertexAttribPointer(1, 3, GL30.GL_FLOAT, false, 0, 0);
        
        GL30.glBindVertexArray(0);
        
        isSetUp = true;
    }
    
    public void setupShaders() {
        
        GL30.glBindVertexArray(vao);
        
        program = GL20.glCreateProgram();
        vert = GL20.glCreateShader(GL20.GL_VERTEX_SHADER);
        GL20.glShaderSource(vert, vertexShader);
        frag = GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER);
        GL20.glShaderSource(frag, fragmentShader);
        GL20.glCompileShader(vert);
        if(GL20.glGetShaderi(vert, GL20.GL_COMPILE_STATUS) == GL20.GL_FALSE) {
            System.out.println("Couldn't comile vertex shader");
            System.out.println(GL30.glGetShaderInfoLog(vert));
        }
        GL20.glCompileShader(frag);
        if(GL20.glGetShaderi(frag, GL20.GL_COMPILE_STATUS) == GL20.GL_FALSE) {
            System.out.println("Couldn't comile fragment shader");
            System.out.println(GL30.glGetShaderInfoLog(frag));
        }
        
        GL20.glAttachShader(program, vert);
        GL20.glAttachShader(program, frag);;
        
        GL20.glValidateProgram(program);
        if(GL20.glGetProgrami(program, GL20.GL_VALIDATE_STATUS) != GL20.GL_TRUE) {
            System.out.println("Can't validate shader");
            System.out.println(GL20.glGetProgramInfoLog(program));
        }
        
        GL30.glBindVertexArray(0);
        
    }

    public void draw() {
        
        GL20.glUseProgram(program);
        GL30.glBindVertexArray(vao);
        
            GL15.glDrawArrays(GL15.GL_TRIANGLES, 0, vtexNumber);
        
        GL30.glBindVertexArray(0);
        
    }
    
}

我的构造函数是:

t = new ThreeDObject(new float[] {
                0.0f, 0.0f, 0.0f,
                0.0f, 0.0f, 0.0f,
                -1.0f, -1.0f, 0.0f
        }, new float[] {
                1.0f, 0.0f, 0.0f,
                0.0f, 1.0f, 0.0f,
                0.0f, 0.0f, 1.0f
        });

(构造函数是故意错的)

我删除了一些未使用的代码,如果您找不到错误请告诉我

我得到的只是一个白色三角形被绘制到屏幕上。

我尝试了我能找到的所有解决方案,如果你能帮助我,我将不胜感激。

编辑:我更改了一些代码但仍然得到相同的结果。

在控制台上我得到这个:

Can't validate shader

[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, -1.0, 0.0]

这是顶点着色器:

#version 330
out vec4 outColor;

layout (location = 0) in vec3 inPosition;
layout (location = 1) in vec3 inColor;

void main() {

    gl_Position = vec4(inPosition,1.0);
    outColor = vec4(inColor, 1.0);

}

这是片段着色器:

  
#version 330

in vec3 outColor;

out vec4 finalColor;

void main() {

    finalColor = vec4(1.0,0.0,0.0,1.0);

}

结果是这个三角形:

Image

当我 link 着色器时的结果:

Result

编辑 2:

我改了密码

我正在 link 着色器:

        GL20.glAttachShader(program, frag);
        
        GL20.glLinkProgram(program);
        if(GL20.glGetProgrami(program, GL20.GL_LINK_STATUS) != GL20.GL_TRUE) {
            System.out.println("Can't link shader");
            System.out.println(GL20.glGetProgramInfoLog(program));
        }
        
        GL20.glValidateProgram(program);

我也更改了这一行:

GL15.glDrawArrays(GL15.GL_TRIANGLES, 0, vtexNumber);
        
        GL30.glBindVertexArray(0);
        GL20.glUseProgram(0);

并更改了顶点和片段着色器:

Vertex:

#version 330
out vec3 vertColor;

layout (location = 0) in vec3 inPosition;
layout (location = 1) in vec3 inColor;

void main() {

    gl_Position = vec4(inPosition,1.0);
    vertColor = inColor;

}

Fragment:

#version 330

in vec3 vertColor;

out vec4 FragColor;

void main() {

    FragColor = vec4(vertColor,1.0);

}

但我仍然得到奇怪的结果:

我得到一个黑色三角形覆盖了一半 window,我尝试移动相机但没有任何变化。

Black triangle

首先,在调用GL20.glEnableVertexAttribArray(1);之前调用GL30.glVertexAttribPointer(1, 3, GL30.GL_FLOAT, false, 0, 0);(用于颜色缓冲区)(您应该在启用属性数组之前分配您的属性)。

其次,你的绘制函数不正确:

渲染时,

  1. 绑定你的着色器(GL20.glUseProgram(program)

  2. 绑定您的 VAO (GL30.glBindVertexArray(VAO))

  3. 设置着色器制服(我猜你还没有完成这一步,所以暂时不要担心)

  4. 启用顶点属性数组 (GL30.glEnableVertexAttribArray(number)) - 为分配的每个缓冲区槽和每次渲染调用此方法(不仅仅是在设置缓冲区时)。

  5. 渲染/调用绘制函数

  6. 禁用顶点属性数组 (GL30.glDisableVertexAttribArray(number)) - 为分配的每个缓冲区槽调用此方法,并在每次渲染时再次调用此方法

  7. 解除绑定 VAO (GL30.glBindVertexArray(0))

  8. 取消绑定着色器(GL20.glUseProgram(0))

好的,我测试了你的代码,发现了 2 个错误,

1. 因为我怀疑你的三角形顶点数据排列不正确, 当我测试你的顶点数据时,我得到一个空白屏幕(我知道你是如何设法得到一个三角形的)。

t = new ThreeDObject(new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, -1.0f, 0.0f }, // Your vertex data

结果

A blank screen (grey is the clear colour)

如果你看到,你的顶点数据没有按逆时针顺序(CCW)排列; OpenGL 更喜欢 CCW 顺序的数据。应该是这样的:

Sorry for the link, cannot embed photo's yet, btw look at triangle 2, for counter-clockwise vertex order

所以,我将订单更改为:

t = new ThreeDObject(new float[] { -1.0f, 1.0f, 0f, -1.0f, -1.0f, 0f, 1.0f, -1.0f, 0f } //V1 --> V3 --> V2

导致:

The triangle you hopefully wanted (with the colours)

Here's another one (with a every coordinate halved)

2. 还有这个代码:

    cvbo = GL15.glGenBuffers();
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, cvbo);
    GL15.glBufferData(GL15.GL_ARRAY_BUFFER, cb, GL15.GL_STATIC_DRAW);
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
    GL20.glEnableVertexAttribArray(1);
    GL30.glVertexAttribPointer(1, 3, GL30.GL_FLOAT, false, 0, 0);

应该是这样的:

    cvbo = GL15.glGenBuffers();
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, cvbo);
    GL15.glBufferData(GL15.GL_ARRAY_BUFFER, cb, GL15.GL_STATIC_DRAW);
    GL30.glVertexAttribPointer(1, 3, GL30.GL_FLOAT, false, 0, 0);
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
    GL20.glEnableVertexAttribArray(1);

始终在绑定缓冲区时分配您的属性槽,因此出现错位错误的可能性很小(这是您可能得到黑色三角形的原因,因为您的数据混淆了)。

如果您需要更多帮助或需要查看我的代码,请发表评论!

致其他人:这不是问题的答案,而是作者在另一个答案中的评论。

ViewMatrix:

定义相机时,从技术上讲/需要定义视图 space(因此称为 viewMatrix or lookAtMatrix)。这很重要,因为此矩阵将您的对象从世界 space 转换为视图 space(相机 space),其中所有对象都是根据相机定义的。

(想一想...如果您的 worldMatrix / modelMatrix 根据世界原点变换所有对象,那么您的 viewMatrix 根据相机变换所有对象(相机现在是原点的地方,相机没有看到的任何东西都会被自动丢弃)。

这就是我在我的程序中定义相机 class 的方式(一直滚动到最后以进行完整细分):

public class Camera {

private Vector3f position;
private Vector3f cameraDirection;

private float pitch = 0f;
private float yaw = -90.0f;
private float roll = 0f;

private float lastMX = 0f;
private float lastMY = 0f;
private float mouseSensitivity = 0.1f;

private Vector3f front = new Vector3f(0, 0 ,-1);
private Vector3f up = new Vector3f(0, 1, 0);

private Matrix4f lookAt;

public Camera(Vector3f position) {
    this.position = position;
    lookAt = new Matrix4f().lookAt(position, position.add(front), up);
}


public void input() {
    
    float xOffSet = (float) (Input.getMouseX()) - lastMX;
    float yOffSet = (float) (-Input.getMouseY()) + lastMY;
    
    lastMX = (float) Input.getMouseX();
    lastMY = (float) Input.getMouseY();
    
    yaw += (xOffSet *= mouseSensitivity);
    pitch += (yOffSet *= mouseSensitivity);
    
    if(pitch > 89.0f) pitch = 89.0f;
    if(pitch < -89.0f) pitch = -89.0f;
    
    float cameraSpeed = 2.5f * Window.getDeltaTime();
    
    if(Input.isKeyDown(GLFW.GLFW_KEY_W)) position.add(front.mul(cameraSpeed));
    if(Input.isKeyDown(GLFW.GLFW_KEY_S)) position.sub(front.mul(cameraSpeed));
    if(Input.isKeyDown(GLFW.GLFW_KEY_A)) position.sub(new Vector3f(front.cross(up)).normalize().mul(cameraSpeed));
    if(Input.isKeyDown(GLFW.GLFW_KEY_D)) position.add(new Vector3f(front.cross(up)).normalize().mul(cameraSpeed));
    
    position.y = 0.0f;
}


public void update() {
    
    input();
    
    setCameraDirection(new Vector3f((float) Math.cos(Math.toRadians(yaw)), 
                                    (float) Math.sin(Math.toRadians(pitch)), 
                                    (float) Math.sin(Math.toRadians(yaw))));
    
    front = getCameraDirection().normalize();
    lookAt.identity().lookAt(position, new Vector3f(position).add(front), up); 
}

public Vector3f getPosition() {
    return position;
}

public float getPitch() {
    return pitch;
}

public float getYaw() {
    return yaw;
}

public float getRoll() {
    return roll;
}

public Vector3f getCameraDirection() {
    return cameraDirection;
}

public void setCameraDirection(Vector3f cameraDirection) {
    this.cameraDirection = cameraDirection;
}

public Matrix4f getLookAtMatrix() {
    return lookAt;
}


}

因此,如果您已经看到 lookAt 矩阵是使用 JOML 由三个向量定义的:

一个Camera Position; A Center (Front Vector + Camera Position); 和一个 Up 向量;

Camera Position 简单地定义了相机在世界中的位置(显然它会如何存在)。

Center 有点难以理解,但它所做的一切都定义了 相机应该注视的点

  • 如果你的中心不变,那么你就得到了所谓的Third Person Camera,其中相机以可变半径旋转大约一个center点。

  • 但是如果你想要First Person Camera,你的center不能保持不变,因此必须每帧重新计算能够创造出流畅的第一人称效果。 如果见上文,在 update() 方法中,front 向量使用 cameraDirection(相机面对的方向)在每一帧重新计算。

  • cameraDirection 本身必须计算每一帧才能使上述过程正常工作。

  • 俯仰、偏航、滚转: What are they

它们只是围绕三个轴的旋转 (x = Pitch, y = Yaw, z = Roll)(见图)。使用这些和一些三角函数,我们可以计算出相机的朝向 (cameraDirection):

    public void update() {
    
    input();
    
    setCameraDirection(new Vector3f((float) Math.cos(Math.toRadians(yaw)), 
                                    (float) Math.sin(Math.toRadians(pitch)), 
                                    (float) Math.sin(Math.toRadians(yaw))));
    
    front = getCameraDirection().normalize();
    lookAt.identity().lookAt(position, new Vector3f(position).add(front), up); 
    }

We can calculate x and z components of the direction vector, using the y rotation (YAW) and some trigonometry

We also need the y direction, which can be calculate through the (PITCH)

确保将方向向量(与任何方向向量一样)归一化为单位向量,否则中心将被弄乱

所以现在我们有一个 direction / frontposition 向量。

UP向量:

要像 view spaceworld spacetangent space 一样定义 "space",您需要三个向量来定义 space 的三个轴 - -> x轴、y轴和z轴

我对此了解不深(我可能是错的): UP向量定义视图space的y轴x轴是方向向量,z轴(右向量)是x轴和y轴的叉积)。

UP 向量只是 (0, 1, 0) 并且永远不会改变,因为 1 表示它是直线向上(正 y 方向)。

还有 lookAt 矩阵函数:

                                //camPos     //center       //up
lookAt = new Matrix4f().lookAt(position, position.add(front), up);

制作人员:https://learnopengl.com/Getting-started/Camera

绝对推荐查看本教程以获得深入的教程。