OpenGL ES рисует квадрат на Android

#java #android #opengl-es #opengl-es-2.0 #gpu

#java #Android #opengl-es #opengl-es-2.0 #графический процессор

Вопрос:

Я пытался нарисовать квадрат в OpenGL ES для Android, но по какой-то причине мой код выходит из строя или показывает только чистый цвет. Я уверен, что настройка проекта с помощью средства визуализации и класса GLSurfaceView верна, и что функция для импорта вершины и шейдера фрагмента из файла работает. Это код для рисования квадрата (конструктор вызывается в onSurfaceCreated в методе рисования в методе onDrawFrame моего класса визуализации):

 import android.content.Context;
import android.opengl.GLES20;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

public class Square {
    int ShaderProgramID;
    private FloatBuffer vertexBuffer;
    private int vertexBufferID;
    private int vertexCount;
    private int vertexStride;
    static final int COORDS_PER_VERTEX = 3;
    static final int COLORS_PER_VERTEX = 4;
    static final int SIZE_OF_FLOAT = 4;
    static final float coords[] = {
          //x:    y:     z:            r:    g:    b:    a:
            -0.5f, 0.5f, 0.0f,         1.0f, 0.0f, 0.0f, 1.0f,
            -0.5f,-0.5f, 0.0f,         0.0f, 1.0f, 0.0f, 1.0f,
             0.5f,-0.5f, 0.0f,         0.0f, 0.0f, 1.0f, 1.0f,
            -0.5f, 0.5f, 0.0f,         1.0f, 0.0f, 0.0f, 1.0f,
             0.5f,-0.5f, 0.0f,         0.0f, 0.0f, 1.0f, 1.0f,
             0.5f, 0.5f, 0.0f,         1.0f, 1.0f, 1.0f, 1.0f,

    };
    public Square(Context context)  {
        String vertexShaderSrc = ReadFromfile("defaultVertexShader.glsl", context);
        String fragmentShaderSrc = ReadFromfile("defaultFragmentShader.glsl", context);

        int vertexID = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
        GLES20.glShaderSource(vertexID, vertexShaderSrc);
        GLES20.glCompileShader(vertexID);

        int fragmetID = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
        GLES20.glShaderSource(fragmetID, fragmentShaderSrc);
        GLES20.glCompileShader(fragmetID);

        ShaderProgramID = GLES20.glCreateProgram();
        GLES20.glAttachShader(ShaderProgramID, vertexID);
        GLES20.glAttachShader(ShaderProgramID, fragmetID);
        GLES20.glBindAttribLocation(ShaderProgramID, 0, "aPos");
        GLES20.glBindAttribLocation(ShaderProgramID, 1, "aColor");
        GLES20.glLinkProgram(ShaderProgramID);

        positionHandle = GLES20.glGetAttribLocation(ShaderProgramID, "a_Position");
        colorHandle = GLES20.glGetAttribLocation(ShaderProgramID, "a_Color");

        vertexBuffer = FloatBuffer.allocate(coords.length);
        vertexBuffer.put(coords);
        vertexBuffer.position(0);
        IntBuffer buffer = IntBuffer.allocate(1);
        GLES20.glGenBuffers(1, buffer);
        vertexBufferID = buffer.get(0);
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferID);
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, coords.length * 4, vertexBuffer, GLES20.GL_STATIC_DRAW);

        vertexCount = coords.length / (COORDS_PER_VERTEX   COLORS_PER_VERTEX);
        vertexStride = (COORDS_PER_VERTEX   COLORS_PER_VERTEX) * 4;
    }
    private int positionHandle;
    private int colorHandle;
    public void draw() {
        GLES20.glUseProgram(ShaderProgramID);


        vertexBuffer.position(0);
        GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
        GLES20.glEnableVertexAttribArray(positionHandle);


        vertexBuffer.position(3);
        GLES20.glVertexAttribPointer(colorHandle, COLORS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
        GLES20.glEnableVertexAttribArray(colorHandle);


        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
        GLES20.glDisableVertexAttribArray(positionHandle);
        GLES20.glDisableVertexAttribArray(colorHandle);

    }

    public String ReadFromfile(String fileName, Context context) {
        StringBuilder ReturnString = new StringBuilder();
        InputStream fIn = null;
        InputStreamReader isr = null;
        BufferedReader input = null;
        try {
            fIn = context.getResources().getAssets()
                    .open(fileName);
            isr = new InputStreamReader(fIn);
            input = new BufferedReader(isr);
            String line = "";
            while ((line = input.readLine()) != null) {
                ReturnString.append(line   "n");
            }
        } catch (Exception e) {
            e.getMessage();
        } finally {
            try {
                if (isr != null)
                    isr.close();
                if (fIn != null)
                    fIn.close();
                if (input != null)
                    input.close();
            } catch (Exception e2) {
                e2.getMessage();
            }
        }
        return ReturnString.toString();
    }
}
 

это код VertexShaderCode:

 attribute vec4 aPos;
attribute vec4 aColor;

varying vec4 v_Color;

void main()
{
    v_Color = a_Color;
    gl_Position = a_Position;
}
 

и это FragmentShaderCode

 precision mediump float;
varying vec4 v_Color;
void main()
{
    gl_FragColor = v_Color;
}
 

Ответ №1:

В вершинном шейдере:

 attribute vec4 aPos;
 

позиция — это 4-компонентный вектор, но в «VertexBuffer» позиция записывается как 3-компонентный вектор. Так что попробуйте улучшить шейдер:

 attribute vec3 aPos;
 

Также используется «a_Position», но нигде не объявлено, сделайте это:

 gl_Position = vec4(a_Pos,1.0);
 

и улучшайте здесь:

 positionHandle = GLES20.glGetAttribLocation(ShaderProgramID, "a_Pos");
 

Этот код может показать, скомпилирован шейдер или нет, и ошибку.

 int[] compiled = new int[1];
        GLES31.glGetShaderiv(shader, GLES31.GL_COMPILE_STATUS, compiled, 0);
        if (compiled[0] == 0) {
            GLES31.glDeleteShader(shader);
            throw new RuntimeException("Could not compile program: "
                      GLES31.glGetShaderInfoLog(shader)   " | ");
        }
 

Это правильный способ подготовки буфера с плавающей запятой:

 ByteBuffer bb = ByteBuffer.allocateDirect(coords.length*4);
bb.order(ByteOrder.nativeOrder());

FloatBuffer vertexBuffer = bb.asFloatBuffer();
 

Комментарии:

1. вершина теперь выглядит так: атрибут vec3 aPos; атрибут vec4 aColor; изменение vec4 vColor; void main() { v_Color = aColor; gl_Position = aPos; } но он все еще падает. также я убедился, что нужно использовать только aPos и aColor, а не a_Pos или a_Color где-либо в коде

2. gl_Position = vec4(a_Pos,1.0);

3. я исправил все ошибки, теперь шейдеры успешно скомпилированы, но приложение по-прежнему работает с ошибками

4. Какая строка вылетает?

5. строка 76: GLES20.glVertexAttribPointer(positionHandle, COORD_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, VertexBuffer);

Ответ №2:

Это текущий код:

 import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLES31;
import android.util.Log;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;


public class Square {
int ShaderProgramID;
private FloatBuffer vertexBuffer;
private int vertexBufferID;
private int vertexCount;
private int vertexStride;
static final int COORDS_PER_VERTEX = 3;
static final int COLORS_PER_VERTEX = 4;
static final int SIZE_OF_FLOAT = 4;
static final float coords[] = {
        //x:    y:     z:            r:    g:    b:    a:
        -0.5f, 0.5f, 0.0f,         1.0f, 0.0f, 0.0f, 1.0f,
        -0.5f,-0.5f, 0.0f,         0.0f, 1.0f, 0.0f, 1.0f,
         0.5f,-0.5f, 0.0f,         0.0f, 0.0f, 1.0f, 1.0f,
        -0.5f, 0.5f, 0.0f,         1.0f, 0.0f, 0.0f, 1.0f,
         0.5f,-0.5f, 0.0f,         0.0f, 0.0f, 1.0f, 1.0f,
         0.5f, 0.5f, 0.0f,         1.0f, 1.0f, 1.0f, 1.0f,

};
public Square(Context context)  {
    String vertexShaderSrc = ReadFromfile("defaultVertexShader.glsl", context);
    String fragmentShaderSrc = ReadFromfile("defaultFragmentShader.glsl", context);

    int vertexID = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
    GLES20.glShaderSource(vertexID, vertexShaderSrc);
    GLES20.glCompileShader(vertexID);

    int fragmetID = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
    GLES20.glShaderSource(fragmetID, fragmentShaderSrc);
    GLES20.glCompileShader(fragmetID);

    ShaderProgramID = GLES20.glCreateProgram();
    GLES20.glAttachShader(ShaderProgramID, vertexID);
    GLES20.glAttachShader(ShaderProgramID, fragmetID);
    GLES20.glBindAttribLocation(ShaderProgramID, 0, "aPos");
    GLES20.glBindAttribLocation(ShaderProgramID, 1, "aColor");
    GLES20.glLinkProgram(ShaderProgramID);

    positionHandle = GLES20.glGetAttribLocation(ShaderProgramID, "aPos");
    colorHandle = GLES20.glGetAttribLocation(ShaderProgramID, "aColor");

    vertexBuffer = FloatBuffer.allocate(coords.length);
    vertexBuffer.put(coords);
    vertexBuffer.position(0);
    IntBuffer buffer = IntBuffer.allocate(1);
    GLES20.glGenBuffers(1, buffer);
    vertexBufferID = buffer.get(0);
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferID);
    GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, coords.length * 4, vertexBuffer, GLES20.GL_STATIC_DRAW);

    vertexCount = coords.length / (COORDS_PER_VERTEX   COLORS_PER_VERTEX);
    vertexStride = (COORDS_PER_VERTEX   COLORS_PER_VERTEX) * 4;
}
private int positionHandle;
private int colorHandle;
public void draw() {
    GLES20.glUseProgram(ShaderProgramID);

    vertexBuffer.position(0);
    GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, 0);
    GLES20.glEnableVertexAttribArray(positionHandle);


    vertexBuffer.position(3);
    GLES20.glVertexAttribPointer(colorHandle, COLORS_PER_VERTEX, GLES20.GL_FLOAT,        false, vertexStride, 3);
    GLES20.glEnableVertexAttribArray(colorHandle);


    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
    GLES20.glDisableVertexAttribArray(positionHandle);
    GLES20.glDisableVertexAttribArray(colorHandle);

}

public String ReadFromfile(String fileName, Context context) {
    StringBuilder ReturnString = new StringBuilder();
    InputStream fIn = null;
    InputStreamReader isr = null;
    BufferedReader input = null;
    try {
        fIn = context.getResources().getAssets()
                .open(fileName);
        isr = new InputStreamReader(fIn);
        input = new BufferedReader(isr);
        String line = "";
        while ((line = input.readLine()) != null) {
            ReturnString.append(line   "n");
        }
    } catch (Exception e) {
        e.getMessage();
    } finally {
        try {
            if (isr != null)
                isr.close();
            if (fIn != null)
                fIn.close();
            if (input != null)
                input.close();
        } catch (Exception e2) {
            e2.getMessage();
        }
    }
    return ReturnString.toString();
}
}
 

Фрагмент:

 #version 310 es
precision mediump float;
in vec4 vColor;
void main()
{
gl_FragColor = vColor;
}
 

Вершина:

 #version 310 es
attribute vec3 aPos;
attribute vec4 aColor;
out vec4 vColor;

void main()
{
vColor = aColor;
gl_Position = vec4(aPos,1.0);
}