未纹理的Quad无法在OpenGL ES 3.0中呈现

时间:2019-07-19 09:42:46

标签: java android opengl-es glsles opengl-es-3.0

我最近使用javax.swing框架编写了一个简单的游戏,并希望将其作为android应用程序发布。我进行了一些研究,发现大多数应用程序都使用Java和OpenGL ES。我在OpenGL方面有一些经验,但熟悉OpenGL ES。但是,每当我尝试仅渲染一个简单的四边形(使用GLES30顶点数组)时,我只会看到我的红色背景(已使用GL10.glClearColor()指定)。我很可能会遗漏一些非常明显的东西,但是我花了很多时间进行研究,却没有找到具体的结果。

这是我的MainActivity代码:

public class MainActivity extends Activity {

    private Screen screen;
    private Sketcher s;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        screen = findViewById(R.id.surface_view);
        screen.setEGLContextClientVersion(3);

        s = new Sketcher(getAssets());

        screen.setRenderer(s);
        screen.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
    }

    @Override
    public void onPause() {
        super.onPause();
        screen.onPause();
    }

    @Override
    public void onResume() {
        super.onResume();
        screen.onResume();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        s.free();
    }
} 

请记住,Screen类仅复制GLSurfaceView的构造函数,并公开onPause()和onResume()方法。

Sketcher类:

public class Sketcher implements GLSurfaceView.Renderer {

    private Player p;

    private Shader pShader;

    private AssetManager am;

    Sketcher(AssetManager am) {
        this.am = am;
    }

    @Override
    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        p = new Player();
        //pShader = new Shader(am, "playerVertexShader.txt", "playerFragmentShader.txt");
        //pShader.setUniforms();

        GLES10.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
    }

    @Override
    public void onDrawFrame(GL10 unused) {
        GLES10.glClear(GLES10.GL_COLOR_BUFFER_BIT);

        //pShader.activate();

        GLES30.glBindVertexArray(p.getVaoID());
        GLES20.glEnableVertexAttribArray(0);

        GLES20.glDrawElements(GLES20.GL_TRIANGLES, p.getVertexCount(), GLES20.GL_UNSIGNED_INT, 0);

        GLES20.glDisableVertexAttribArray(0);
        GLES30.glBindVertexArray(0);

        //pShader.deactivate();
    }

    @Override
    public void onSurfaceChanged(GL10 unused, int width, int height) {
        GLES10.glViewport(0, 0, width, height);
    }

    void free() {
        p.free();
        //pShader.free();
    }
}

播放器类:

public class Player {

    public static final float RADIUS = 0.5f;

    private static final float ACC = 0.02f;
    private static final float MAX_SPEED = 2.0f;

    private static final int PRECISION = 10;

    private float x, y;
    private float vx, vy;

    private int vaoID;
    private int vBufferID;
    private int iBufferID;

    public Player() {
        int[] vao = new int[1];
        int[] buffers = new int[2];

        GLES30.glGenVertexArrays(1, vao, 0);
        vaoID = vao[0];

        GLES30.glGenBuffers(2, buffers, 0);
        vBufferID = buffers[0];
        iBufferID = buffers[1];

        ByteBuffer vBuffer = ByteBuffer.allocateDirect(Float.BYTES * 8).order(ByteOrder.nativeOrder());
        vBuffer.putFloat(-RADIUS);
        vBuffer.putFloat(-RADIUS);
        vBuffer.putFloat( RADIUS);
        vBuffer.putFloat(-RADIUS);
        vBuffer.putFloat( RADIUS);
        vBuffer.putFloat( RADIUS);
        vBuffer.putFloat(-RADIUS);
        vBuffer.putFloat( RADIUS);
        vBuffer.flip();

        /*
        vBuffer.put(0.0f);
        vBuffer.put(0.0f);

        for (int i = 0; i < PRECISION; i++) {
            double angle = Math.PI / PRECISION * i;

            vBuffer.put((float)(Math.sin(angle) * RADIUS));
            vBuffer.put((float)(Math.cos(angle) * RADIUS));
        }
        */

        ByteBuffer iBuffer = ByteBuffer.allocateDirect(Integer.BYTES * 6).order(ByteOrder.nativeOrder());
        iBuffer.putInt(0);
        iBuffer.putInt(1);
        iBuffer.putInt(2);
        iBuffer.putInt(0);
        iBuffer.putInt(2);
        iBuffer.putInt(3);
        iBuffer.flip();
        /*
        for (int i = 1; i < PRECISION - 1; i++) {
            iBuffer.put(0);
            iBuffer.put(i + 1);
            iBuffer.put(i);
        }

        iBuffer.put(0);
        iBuffer.put(1);
        iBuffer.put(PRECISION - 1);
        */

        GLES30.glBindVertexArray(vaoID);

        GLES20.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vBufferID);
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vBuffer.capacity(), vBuffer, GLES20.GL_STATIC_DRAW);
        GLES20.glVertexAttribPointer(0, 2, GLES20.GL_FLOAT, false, 0, 0);

        GLES20.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, iBufferID);
        GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, iBuffer.capacity(), iBuffer, GLES20.GL_STATIC_DRAW);

        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
        GLES30.glBindVertexArray(0);
    }

    public float getX() {
        return x;
    }

    public float getY() {
        return y;
    }

    public int getVaoID() {
        return vaoID;
    }

    public int getVertexCount() {
        return 6;
    }

    public void free() {
        GLES30.glDeleteVertexArrays(1, new int[] {vaoID}, 0);
        GLES30.glDeleteBuffers(2, new int[] {vBufferID, iBufferID}, 0);
    }
}

我注释掉了许多与游戏相关的代码,因为我不得不简化,直到碰到底部(绘制一个简单的无纹理四边形)。

以下是着色器代码:

#version 300 es

layout(location = 0) in vec2 vertex;

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


#version 300 es

out vec4 fragment;

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

1 个答案:

答案 0 :(得分:0)

创建Index buffers时,将创建一个“字节”缓冲区。这意味着每个索引都存储在一个字节中:

  
ByteBuffer iBuffer = ByteBuffer.allocateDirect(Integer.BYTES*6).order(ByteOrder.nativeOrder());
       iBuffer.putInt(0);
       iBuffer.putInt(1);
     
GLES20.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, iBufferID);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, iBuffer.capacity(), iBuffer, GLES20.GL_STATIC_DRAW);

因此,在绘制网格(glDrawElements)时,指定的索引类型必须为GL_UNSIGNED_BYTE

GLES20.glDrawElements(GLES20.GL_TRIANGLES, p.getVertexCount(), GLES20.GL_UNSIGNED_BYTE, 0);

而不是GL_UNSIGNED_INT

GLES20.glDrawElements(GLES20.GL_TRIANGLES, p.getVertexCount(), GLES20.GL_UNSIGNED_INT, 0);


或者,也可以使用与元素类型GL_UNSIGNED_INT相对应的IntBuffer
或者将ShortBufferGL_UNSIGNED_SHORT结合使用。


在片段着色器中确实缺少Precision qualifiers,它们不是可选的(OpenGL ES)。例如,添加默认的精度限定符:

precision medium float;