OpenGL ES 3.0 Hello Triangle — черный

avatar
Daskie
8 апреля 2018 в 08:02
859
1
1

Я впервые работаю с Android и OpenGL ES, но у меня достаточно опыта работы с OpenGL. Я просто пытаюсь нарисовать красный треугольник. Никаких униформ, только один атрибут вершины.

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

#version 300 es

in vec3 in_loc;

void main() {
    gl_Position.xyz = in_loc;
}

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

#version 300 es

precision mediump float;

out vec4 outColor;

void main() {
    outColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);
}

Результат:

enter image description here

Я проверяю и не получаю никаких ошибок во время создания, компиляции, присоединения и компоновки шейдера. Я пробовал изменить precision mediump float; на precision highp float; и precision lowp float;.

Обычно я ожидаю, что этот прямой черный вывод указывает на неработающий фрагментный шейдер, но я не получаю никаких ошибок, и, насколько я могу судить, это очень простой код, который идентичен различным примерам кода, найденным в Интернете.

Код создания шейдера:

public class Shader {

    public enum Type { VERTEX, FRAGMENT }

    static private int createShader(String src, Type type) {
        int shaderHandle = 0;
        switch (type) {
            case VERTEX:
                shaderHandle = GLES30.glCreateShader(GLES30.GL_VERTEX_SHADER);
                break;
            case FRAGMENT:
                shaderHandle = GLES30.glCreateShader(GLES30.GL_FRAGMENT_SHADER);
                break;
        }
        if (shaderHandle == 0) {
            Log.e("Shader", "Failed to create shader");
            return 0;
        }

        // Compile shader
        GLES30.glShaderSource(shaderHandle, src);
        GLES30.glCompileShader(shaderHandle);

        // Check for compile errors
        int status[] = { 0 };
        GLES30.glGetShaderiv(shaderHandle, GLES30.GL_COMPILE_STATUS, status, 0);
        if (status[0] == 0) {
            Log.e("Shader", "Failed to compile shader");
            Log.e("Shader", GLES30.glGetShaderInfoLog(shaderHandle));
            GLES30.glDeleteShader(shaderHandle);
            return 0;
        }

        // Check for OpenGL errors
        if (Util.isGLError()) {
            GLES30.glDeleteShader(shaderHandle);
            return 0;
        }

        return shaderHandle;
    }

    static private int createProgram(int vertShaderHandle, int fragShaderHandle) {
        int programHandle = GLES30.glCreateProgram();
        if (programHandle == 0) {
            Log.e("Shader", "Failed to create program");
            return 0;
        }

        // Attach and link shaders to form program
        GLES30.glAttachShader(programHandle, vertShaderHandle);
        GLES30.glAttachShader(programHandle, fragShaderHandle);
        GLES30.glLinkProgram(programHandle);

        // Check for linking errors
        int status[] = { 0 };
        GLES30.glGetProgramiv(programHandle, GLES30.GL_LINK_STATUS, status, 0);
        if (status[0] == 0) {
            Log.e("Shader", "Failed to link program");
            Log.e("Shader", GLES30.glGetProgramInfoLog(programHandle));
            GLES30.glDeleteProgram(programHandle);
            return 0;
        }

        // Check for OpenGL errors
        if (Util.isGLError()) {
            GLES30.glDeleteProgram(programHandle);
            return 0;
        }

        return programHandle;
    }

    private String name;
    private int programHandle;

    public Shader(String name) {
        this.name = name;
        this.programHandle = 0;
    }

    public boolean initFromSrc(String vertSrc, String fragSrc) {
        // Create shaders
        int vertShaderHandle = createShader(vertSrc, Type.VERTEX);
        if (vertShaderHandle == 0) {
            Log.e("Shader", "Failed to create vertex shader");
            return false;
        }
        int fragShaderHandle = createShader(fragSrc, Type.FRAGMENT);
        if (fragShaderHandle == 0) {
            Log.e("Shader", "Failed to create fragment shader");
            GLES30.glDeleteShader(vertShaderHandle);
            return false;
        }

        // Create shader program
        programHandle = createProgram(vertShaderHandle, fragShaderHandle);
        if (programHandle == 0) {
            Log.e("Shader", "Failed to create program");
            GLES30.glDeleteShader(vertShaderHandle);
            GLES30.glDeleteShader(fragShaderHandle);
            return false;
        }

        // Shaders can now be deleted
        GLES30.glDeleteShader(vertShaderHandle);
        GLES30.glDeleteShader(fragShaderHandle);

        return true;
    }

    public boolean initFromFile(String vertFile, String fragFile) {
        String vertSrc = Util.readTextFile(vertFile);
        if (vertSrc == null) {
            Log.e("Shader", "Failed to read shader file: " + vertFile);
            return false;
        }

        String fragSrc = Util.readTextFile(fragFile);
        if (fragSrc == null) {
            Log.e("Shader", "Failed to read shader file: " + fragFile);
            return false;
        }

        return initFromSrc(vertSrc, fragSrc);
    }

    public int getProgramHandle() { return programHandle; }

}

Все остальное:

@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
    GLES30.glClearColor(0.0f, 0.5f, 1.0f, 1.0f);

    shader = new Shader("basic");
    if (!shader.initFromFile("shaders/basic.vert", "shaders/basic.frag")) {
        Log.e("MainRenderer", "Failed to initialize basic shader");
    }

    float[] locs = {
            0.0f, 0.0f, 0.0f,
            1.0f, 0.0f, 0.0f,
            1.0f, 1.0f, 0.0f
    };
    ByteBuffer locsBB = ByteBuffer.allocateDirect(locs.length * 4);
    locsBB.order(ByteOrder.nativeOrder());
    FloatBuffer locsFB = locsBB.asFloatBuffer();
    locsFB.put(locs);
    int[] vboArr = { 0 };
    GLES30.glGenBuffers(1, vboArr, 0);
    int vboHandle = vboArr[0];
    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vboHandle);
    GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, locs.length * 4, locsBB, GLES30.GL_STATIC_DRAW);
    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);

    int[] indices = {
            0, 1, 2
    };
    ByteBuffer indicesBB = ByteBuffer.allocateDirect(indices.length * 4);
    indicesBB.order(ByteOrder.nativeOrder());
    IntBuffer indicesIB = indicesBB.asIntBuffer();
    indicesIB.put(indices);
    int[] iboArr = { 0 };
    GLES30.glGenBuffers(1, iboArr, 0);
    int iboHandle = iboArr[0];
    GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, iboHandle);
    GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER, indices.length * 4, indicesBB, GLES30.GL_STATIC_DRAW);
    GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0);

    int[] vaoArr = { 0 };
    GLES30.glGenVertexArrays(1, vaoArr, 0);
    vaoHandle = vaoArr[0];
    if (vaoHandle == 0) {
        Log.e("MainRenderer", "Failed to create vao");
    }

    GLES30.glBindVertexArray(vaoHandle);
    int locationAI = GLES30.glGetAttribLocation(shader.getProgramHandle(), "in_loc");
    GLES30.glEnableVertexAttribArray(locationAI);
    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vboHandle);
    GLES30.glVertexAttribPointer(locationAI, 3, GLES30.GL_FLOAT, false, 0, 0);
    GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, iboHandle);
    GLES30.glBindVertexArray(0);
    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);
    GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0);
}

@Override
public void onDrawFrame(GL10 unused) {
    // Redraw background color
    GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);

    // Draw triangle
    GLES30.glBindVertexArray(vaoHandle);
    GLES30.glDrawElements(GLES30.GL_TRIANGLES, 3, GLES30.GL_UNSIGNED_INT, 0);
    GLES30.glBindVertexArray(0);
}
Источник
Ville Krumlinde
8 апреля 2018 в 08:13
2

Я не вижу вызова glUseProgram, чтобы активировать шейдеры?

Daskie
8 апреля 2018 в 08:29
0

Это было так, спасибо. О, чувак, какая простая глупая ошибка

Ответы (1)

avatar
Daskie
8 апреля 2018 в 08:32
2

Как заметил Вилле, проблема была в том, что я не использовал программу в методе рисования.

Пересмотрено:

// Draw triangle

// Actually use the program
GLES30.glUseProgram(shader.getProgramHandle());

GLES30.glBindVertexArray(vaoHandle);
GLES30.glDrawElements(GLES30.GL_TRIANGLES, 3, GLES30.GL_UNSIGNED_INT, 0);
GLES30.glBindVertexArray(0);

GLES30.glUseProgram(0);