OpenGL ES 在 android 上绘制一个正方形

OpenGL ES draw a square on android

我尝试在 OpenGL ES 中为 android 绘制一个正方形,但由于某种原因我的代码崩溃了,或者只显示了 clearColor。我敢肯定,使用渲染器和 GLSurfaceView class 的项目设置是正确的,并且从文件导入顶点和片段着色器的功能有效。这是绘制正方形的代码(在我的渲染器 class 的 onDrawFrame 方法中的绘制方法 onSurfaceCreated 中调用了构造函数 class):

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

在顶点着色器中:

attribute vec4 aPos;

position 是 4 分量向量,但在“vertexBuffer”中 position 被写为 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();

这是当前代码:

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