【问题标题】:Cannot draw basic triangle with vbos opengl in lwjgl无法在lwjgl中使用vbos opengl绘制基本三角形
【发布时间】:2021-07-25 03:53:37
【问题描述】:

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

这是我的 3D 对象类:

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

链接着色器时的结果:

Result

编辑 2:

我改了代码

我现在正在链接着色器:

        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);

}

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

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

Black triangle

【问题讨论】:

  • 你为什么glEnableClientState?如果您使用的是着色器程序,则不需要固定的函数属性。
  • @Rabbid76 我编辑了帖子和代码以添加更多细节,但我仍然得到相同的结果。
  • 你在哪里链接着色器程序? (glLinkProgram)。此外,第一个和第二个顶点坐标是相同的。
  • @Rabbid76 当我链接着色器时,我得到了一个更奇怪的结果:屏幕全是红色,我编程让屏幕在我按下一个键时改变颜色,当我按下那个键时没有任何反应,第一个和第二个故意相同,即使使用了错误的三角形,它仍然显示相同的东西
  • 当我使用这个链接着色器时:GL20.glAttachShader(program, frag); GL20.glLinkProgram(program); if(GL20.GL_LINK_STATUS != GL20.GL_TRUE) { System.out.println("Can't link shader"); System.out.println(GL20.glGetProgramInfoLog(program)); } GL20.glValidateProgram(program); 我在控制台中得到相同的结果并在窗口中得到这个结果:结果在帖子中

标签: java opengl glsl lwjgl


【解决方案1】:

好的,我测试了你的代码,发现了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);

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

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

【讨论】:

  • 感谢您的回复,它确实有效,我不知道我怎么没有意识到这一点。
  • 我还有另一个问题,相机没有移动,我正在使用 JOML:我使用 lookAt 函数创建一个矩阵(类似于 glut)并使用 glLoadMatrix 设置为投影矩阵,当我使用它可以工作但不使用 vaos 的固定功能管道。
  • 抱歉回复晚了...检查以确保您的矩阵没有任何错误;我倾向于自己创建矩阵,因此它们比使用 OpenGL 的内置函数更容易调试。稍后,我将尝试上传另一个关于如何正确创建外观和投影矩阵的答案。 :)
【解决方案2】:

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

视图矩阵

当您定义相机时,您在技术上/需要已经定义了一个视图空间(因此称为viewMatrix or lookAtMatrix)。这很重要,因为此矩阵将您的对象从世界空间转换到视图空间(相机空间),其中所有对象都根据相机定义。

(想一想...如果您的worldMatrix / modelMatrix 根据世界原点转换所有对象,那么您的viewMatrix 根据您的相机(相机现在的位置)转换所有对象原点和相机看不到的东西会被自动丢弃)。

这就是我在我的程序中定义我的相机类的方式(一直滚动到最后才能完全分解):

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; 一个Center (Front Vector + Camera Position); 还有一个Up向量;

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

Center 有点难以理解,但它定义了相机应该朝向的点

  • 如果你的中心没有改变,那么你就有了所谓的Third Person Camera,相机以可变半径围绕center点旋转.

  • 但是如果你想要一个First Person Camera,你的center 不能保持不变,因此必须在每一帧都重新计算才能创建流畅的第一人称效果。 如上所示,在update() 方法中,每帧都会使用cameraDirection(相机朝向的方向)重新计算front 向量。

  • 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",您需要三个向量来定义该空间的三个轴 --> x 轴、y 轴和 z 轴

我对此不太了解(我可能错了): UP 向量定义了视图空间的 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

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

【讨论】:

    【解决方案3】:

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

    其次,你的draw函数不正确:

    渲染时,

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

    【讨论】:

    • 实际上,我在这里必须同意@Rabbid76,即使您的第一个和第二个顶点故意相同,这只会影响您的四边形的第一个三角形,您的第二个三角形仍在正确渲染,因为前两个顶点不影响它。 (这就是为什么您有 1 个彩色三角形和 1 个黑色三角形(在您的图像中),因为第一个三角形不存在且无法着色)。
    • @SnipingPoodle 只有一个三角形,第二个数组是颜色数组
    • 另外我已经在做你在遮阳篷里说的事情了
    • 等一下,我很快就要用你的顶点数据创建一个测试程序。
    猜你喜欢
    • 2017-08-07
    • 1970-01-01
    • 2013-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多