OpenGL высылает мне сообщение об ошибке Stack Underflow, когда я пытаюсь использовать шейдеры (Java) - PullRequest
0 голосов
/ 05 апреля 2020

Я разрабатываю игру с lwjgl 3 в java, и она работала нормально, но когда я хочу использовать шейдеры, OpenGL отправляет ошибку STACK_UNDERFLOW (1284).

Я использую 3 буфера: вершина буфер, цветной буфер, индексный буфер;

Мой старый код:

private int vbo;
private int cbo;
private int ibo;
private FloatBuffer buffer;
private FloatBuffer colorBuffer;
private IntBuffer indexBuffer;

private IcoSphere sphere;
int radius = 200;

@Override
public void init() {
    sphere = new IcoSphere(9, radius);
    sphere.generate();
    generateBuffer();
}

private void generateBuffer() {
    buffer = BufferUtils.createFloatBuffer(sphere.getVertexCount() * 3);
    colorBuffer = BufferUtils.createFloatBuffer(sphere.getFacesCount() * 4 * 4);
    indexBuffer = BufferUtils.createIntBuffer(sphere.getFacesCount());

    Random r = new Random();
    OpenSimplexNoise noise = new OpenSimplexNoise();

    ArrayList<Vector3f> vertex = sphere.getVertex();
    float[] v = new float[vertex.size() * 3];
    for (int i = 0; i < vertex.size(); i++) {
        vertex.get(i).normalize();
        vertex.get(i).mul(sphere.getRadius() + (float) noise.eval(
                vertex.get(i).x * 8,
                vertex.get(i).y * 8,
                vertex.get(i).z * 8
            ) * 12);
        v[i * 3 + 0] = vertex.get(i).x;
        v[i * 3 + 1] = vertex.get(i).y;
        v[i * 3 + 2] = vertex.get(i).z;
    }
    buffer.put(sphere.getVertexArray());

    indexBuffer.put(sphere.getIndexArray());

    for (int i = 0; i < sphere.getFacesCount(); i++) {
        colorBuffer.put(new float[] {
                r.nextFloat(), r.nextFloat(), r.nextFloat(), 1,
                r.nextFloat(), r.nextFloat(), r.nextFloat(), 1,
                r.nextFloat(), r.nextFloat(), r.nextFloat(), 1
        });
    }

    buffer.flip();
    colorBuffer.flip();
    indexBuffer.flip();

    createBuffer();
}

private void createBuffer() {
    vbo = glGenBuffers();
    cbo = glGenBuffers();
    ibo = glGenBuffers();

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, cbo);
    glBufferData(GL_ARRAY_BUFFER, colorBuffer, GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

@Override
public void update() {

}

@Override
public void render() {
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glVertexPointer(3, GL_FLOAT, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER, cbo);
    glColorPointer(4, GL_FLOAT, 0, 0);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);

    glDrawElements(GL_TRIANGLES, sphere.getFacesCount() * 3, GL_UNSIGNED_INT, 0);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);
}

Мой новый код после добавления шейдеров:

GlUtils.glCall(() -> ..); предназначен для отлова ошибок opengl.

private int vbo;
private int cbo;
private int ibo;
private FloatBuffer buffer;
private FloatBuffer colorBuffer;
private IntBuffer indexBuffer;

private IcoSphere sphere;
int radius = 200;

@Override
public void init() {
    sphere = new IcoSphere(9, radius);
    sphere.generate();
    generateBuffer();
}

private void generateBuffer() {
    buffer = BufferUtils.createFloatBuffer(sphere.getVertexCount() * 3);
    colorBuffer = BufferUtils.createFloatBuffer(sphere.getFacesCount() * 4 * 4);
    indexBuffer = BufferUtils.createIntBuffer(sphere.getFacesCount());

    Random r = new Random();
    OpenSimplexNoise noise = new OpenSimplexNoise();

    ArrayList<Vector3f> vertex = sphere.getVertex();
    float[] v = new float[vertex.size() * 3];
    for (int i = 0; i < vertex.size(); i++) {
        vertex.get(i).normalize();
        vertex.get(i).mul(sphere.getRadius() + (float) noise.eval(
                vertex.get(i).x * 8,
                vertex.get(i).y * 8,
                vertex.get(i).z * 8
            ) * 12);
        v[i * 3 + 0] = vertex.get(i).x;
        v[i * 3 + 1] = vertex.get(i).y;
        v[i * 3 + 2] = vertex.get(i).z;
    }
    buffer.put(sphere.getVertexArray());

    indexBuffer.put(sphere.getIndexArray());

    for (int i = 0; i < sphere.getFacesCount(); i++) {
        colorBuffer.put(new float[] {
                r.nextFloat(), r.nextFloat(), r.nextFloat(), 1,
                r.nextFloat(), r.nextFloat(), r.nextFloat(), 1,
                r.nextFloat(), r.nextFloat(), r.nextFloat(), 1
        });
    }

    buffer.flip();
    colorBuffer.flip();
    indexBuffer.flip();

    createBuffer();
}

private void createBuffer() {

    vbo = glGenBuffers();
    cbo = glGenBuffers();
    ibo = glGenBuffers();

    GlUtils.glCall(() -> glBindBuffer(GL_ARRAY_BUFFER, vbo));
    GlUtils.glCall(() -> glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW));
    GlUtils.glCall(() -> glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0));

    GlUtils.glCall(() -> glBindBuffer(GL_ARRAY_BUFFER, cbo));
    GlUtils.glCall(() -> glBufferData(GL_ARRAY_BUFFER, colorBuffer, GL_STATIC_DRAW));
    GlUtils.glCall(() -> glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, 0));

    GlUtils.glCall(() -> glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo));
    GlUtils.glCall(() -> glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL_STATIC_DRAW));

    GlUtils.glCall(() -> glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
    GlUtils.glCall(() -> glBindBuffer(GL_ARRAY_BUFFER, 0));

}

@Override
public void update() {

}

@Override
public void render() {
    Shader.MAIN.bind();

    GlUtils.glCall(() -> glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0));

    GlUtils.glCall(() -> glEnableVertexAttribArray(0));
    GlUtils.glCall(() -> glEnableVertexAttribArray(1));


    GlUtils.glCall(() -> glDrawElements(GL_TRIANGLES, indexBuffer));

    GlUtils.glCall(() -> glDisableVertexAttribArray(0));
    GlUtils.glCall(() -> glDisableVertexAttribArray(1));

    Shader.MAIN.unbind();
}

Мои шейдеры:

Frag

#version 410

out vec4 vertColor;

void main(){
    gl_FragColor = vertColor;
}

Vert

#version 410

layout (location=0) in vec3 position;

void main()
{
    gl_Position = vec4(position, 1.0);
}

1 Ответ

0 голосов
/ 05 апреля 2020

Когда вы используете шейдерную программу, вы можете нарисовать me sh так же, как вы делали это раньше, используя возможности на стороне клиента.
Все, что вам нужно сделать, это использовать glEnableVertexAttribArray и glVertexAttribPointer вместо glEnableClientState, glVertexPointer и glColorPointer:

Создайте буферы:

vbo = glGenBuffers();
cbo = glGenBuffers();
ibo = glGenBuffers();

glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, cbo);
glBufferData(GL_ARRAY_BUFFER, colorBuffer, GL_STATIC_DRAW);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL_STATIC_DRAW);

Нарисуйте меня sh

glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, cbo);
glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, 0);

glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glDrawElements(GL_TRIANGLES, sphere.getFacesCount() * 3, GL_UNSIGNED_INT, 0);

glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);

Что вы на самом деле делаете, так это используете по умолчанию Vertex Array Object (0) для спецификации. Обратите внимание, что VAO (0) по умолчанию просто допустимо в профиле совместимости Контекст OpenGL .


Это можно улучшить с помощью именованного Vertex Array Object, Обратите внимание, что вы должны использовать именованный VAO в профиле ядра Контекст OpenGL :

private int vao;
vao = glGenVertexArrays();
vbo = glGenBuffers();
cbo = glGenBuffers();
ibo = glGenBuffers();

glBindVertexArray(vao);

glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);

glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, cbo);
glBufferData(GL_ARRAY_BUFFER, colorBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, 0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL_STATIC_DRAW);

glBindVertexArray(0);

Спецификация массива вершин указана в объекте массива вершин. Таким образом, glDisableVertexAttribArray.
не требуется. Более того, индексные буферы (GL_ELEMENT_ARRAY_BUFFER) также указаны в VAO. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); нарушит привязку.

Теперь достаточно привязать VAO, когда рисуется me sh:

glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, sphere.getFacesCount() * 3, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);

У вас есть 2 цветовых атрибута, координата вершины и цвет. Эти 2 атрибута являются входными данными для Vertex Shader . Координата вершины используется для установки gl_Position. Цвет должен быть передан в Фрагментный шейдер . Это выход вершинного шейдера и вход для фрагментного шейдера. В фрагментном шейдере цвет записывается на вывод fragColor. Вывод фрагмента шейдера записывается во фрамбуфер:

Вершинный шейдер:

layout (location=0) in vec3 position;
layout (location=1) in vec4 color;

out vec4 vertColor;

void main()
{
    vertColor = color;
    gl_Position = vec4(position, 1.0);
}

Фрагмент шейдера:

#version 410

in vec4 vertColor;
out vec4 fragColor;

void main()
{
    fragColor = vertColor;
}
...