2016-07-21 6 views
1

Grüße meine Kolleginnen und Programmierer zu verwenden,Failing VBOs in OpenGl/Android

ich das Web durchsucht habe, geprüft Beispiele online, aber immer noch nicht herausfinden können,. Es tut mir leid, wenn das vorher gefragt wurde, ich bin müde nach einer Woche Debuggen von diesem. Ich hoffe ihr könnt mir helfen.

Grundsätzlich ist das Problem, dass ich versuche, einige Quads (mit Dreiecken) zu zeichnen, aber nichts wird gezeichnet. Zuvor zeichnete ich ohne VBOs wie in "Triangle example" auf der offiziellen Android-Website beschrieben. Alles funktionierte gut, aber ich entschied, dass Eckpunkte/Indizes Puffer in Renderer.OnDrawFrame Aktualisierung() nicht effizient :)

So, hier ist mein Code:

public class FloorPlanRenderer implements GLSurfaceView.Renderer { 

public volatile float mAngle; 

// mMVPMatrix is an abbreviation for "Model View Projection Matrix" 
private final float[] mMVPMatrix = new float[16]; 
private final float[] mProjectionMatrix = new float[16]; 
private final float[] mViewMatrix = new float[16]; 
private final float[] mRotationMatrix = new float[16]; 

private GLSurfaceView mGlView; 
private GlEngine mGlEngine; 
private boolean dataSet = false; 

@Override 
public void onSurfaceCreated(GL10 gl, EGLConfig config) { 
    // Set the background frame color 
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 

    // Initialize the accumulated rotation matrix 
    Matrix.setIdentityM(mRotationMatrix, 0); 

    // Position the eye in front of the origin. 
    final float eyeX = 0.0f; 
    final float eyeY = 0.0f; 
    final float eyeZ = -3.0f; 

    // We are looking toward the distance 
    final float lookX = 0.0f; 
    final float lookY = 0.0f; 
    final float lookZ = 0.0f; //-5.0f; 

    // Set our up vector. This is where our head would be pointing were we holding the camera. 
    final float upX = 0.0f; 
    final float upY = 1.0f; 
    final float upZ = 0.0f; 

    // Set the view matrix. This matrix can be said to represent the camera position. 
    Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ); 
    mGlEngine = new GlEngine(10); 
    mGlEngine.registerQuad(new Wall(-0.5f, 0.4f, -0.2f, 0.4f)); 
    mGlEngine.registerQuad(new Wall(0.5f, 0.4f, 0.2f, 0.4f)); 
    mGlEngine.registerQuad(new Wall(0.0f, 0.0f, 0.0f, 0.3f, 0.02f)); 
} 

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

    // Create a new perspective projection matrix. The height will stay the same 
    // while the width will vary as per aspect ratio. 
    final float ratio = (float) width/height; 
    final float left = -ratio; 
    final float right = ratio; 
    final float bottom = -1.0f; 
    final float top = 1.0f; 
    final float near = 3.0f; 
    final float far = 7.0f; 

    // this projection matrix is applied to object coordinates 
    // in the onDrawFrame() method 
    Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far); 
} 

@Override 
public void onDrawFrame(GL10 gl) { 
    float[] scratch = new float[16]; 

    // Calculate the projection and view transformation 
    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0); 

    Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, 1.0f); 

    // Combine the rotation matrix with the projection and camera view 
    // Note that the mMVPMatrix factor *must be first* in order 
    // for the matrix multiplication product to be correct. 
    Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0); 

    mGlEngine.render(scratch); 
} 

}

GlEngine Klasse:

public class GlEngine { 
public static final int COORDS_PER_VERTEX = 3; 
public static final int ORDER_INDICES_PER_QUAD = 6; 
public static final int VERTICES_PER_QUAD = 4; 
public static final int SIZE_OF_FLOAT = Float.SIZE/Byte.SIZE; 
public static final int SIZE_OF_SHORT = Short.SIZE/Byte.SIZE; 

private int mQuadsNum = 0; 
private int mLastCoordsIndex = 0; 
private int mLastOrderIndex = 0; 

private final FloatBuffer vertexBuffer; 
private final ShortBuffer indexBuffer; 

private final String vertexShaderCode = 
     // This matrix member variable provides a hook to manipulate 
     // the coordinates of the objects that use this vertex shader 
     "uniform mat4 uMVPMatrix;" + 
       "attribute vec4 vPosition;" + 
       "void main() {" + 
       // the matrix must be included as a modifier of gl_Position 
       // Note that the uMVPMatrix factor *must be first* in order 
       // for the matrix multiplication product to be correct. 
       " gl_Position = uMVPMatrix * vPosition;" + 
       "}"; 

// Use to access and set the view transformation 
private int mMVPMatrixHandle; 

private final String fragmentShaderCode = 
     "precision mediump float;" + 
       "uniform vec4 vColor;" + 
       "void main() {" + 
       " gl_FragColor = vColor;" + 
       "}"; 

private final int mProgram; 

private int mPositionHandle; 
private int mColorHandle; 

private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex 
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 0.0f }; 
private boolean mDataInitNeeded = true; 

public GlEngine(int quadsNum) { 
    ByteBuffer bb = ByteBuffer.allocateDirect(quadsNum * VERTICES_PER_QUAD * 
      COORDS_PER_VERTEX * SIZE_OF_FLOAT); 
    bb.order(ByteOrder.nativeOrder()); // device hardware's native byte order 
    vertexBuffer = bb.asFloatBuffer(); 

    ByteBuffer bb2 = ByteBuffer.allocateDirect(quadsNum * 
      ORDER_INDICES_PER_QUAD * SIZE_OF_SHORT); 
    bb2.order(ByteOrder.nativeOrder()); 
    indexBuffer = bb2.asShortBuffer(); 

    int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, 
      vertexShaderCode); 
    int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, 
      fragmentShaderCode); 

    mProgram = GLES20.glCreateProgram(); 
    GLES20.glAttachShader(mProgram, vertexShader); 
    GLES20.glAttachShader(mProgram, fragmentShader); 
    GLES20.glLinkProgram(mProgram); 
} 

public static int loadShader(int type, String shaderCode){ 

    // create a vertex shader type (GLES20.GL_VERTEX_SHADER) 
    // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER) 
    int shader = GLES20.glCreateShader(type); 

    // add the source code to the shader and compile it 
    GLES20.glShaderSource(shader, shaderCode); 
    GLES20.glCompileShader(shader); 

    return shader; 
} 

public void registerQuad(Wall quad) { 
    quad.putCoords(vertexBuffer); 
    quad.putIndices(indexBuffer); 
    mQuadsNum++; 
} 

// This code is dealing with VBO side of things 
private final int[] mVerticesBufferId = new int[BUFFERS_COUNT]; 
private final int[] mIndicesBufferId = new int[BUFFERS_COUNT]; 
private static final int BUFFERS_COUNT = 1; 

public void copyToGpu(FloatBuffer vertices) { 
    GLES20.glGenBuffers(BUFFERS_COUNT, mVerticesBufferId, 0); 

    // Copy vertices data into GPU memory 
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVerticesBufferId[0]); 
    GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertices.capacity() * SIZE_OF_FLOAT, vertices, GLES20.GL_STATIC_DRAW); 

    // Cleanup buffer 
    vertices.limit(0); 
    vertices = null; 
} 

public void copyToGpu(ShortBuffer indices) { 
    GLES20.glGenBuffers(BUFFERS_COUNT, mIndicesBufferId, 0); 

    // Copy vertices data into GPU memory 
    GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesBufferId[0]); 
    GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, indices.capacity() * SIZE_OF_SHORT, indices, GLES20.GL_STATIC_DRAW); 

    // Cleanup buffer 
    indices.limit(0); 
    indices = null; 
} 

public void render(float[] mvpMatrix) { 
    setData(); 

    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVerticesBufferId[0]); 
    GLES20.glUseProgram(mProgram); 

    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition"); 
    GLES20.glEnableVertexAttribArray(mPositionHandle); 
    GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, 0); 

    mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor"); 
    GLES20.glUniform4fv(mColorHandle, 1, color, 0); 

    // get handle to shape's transformation matrix 
    mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); 
    // Pass the projection and view transformation to the shader 
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0); 

    GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesBufferId[0]); 

    // Draw quads 
    GLES20.glDrawElements(
      GLES20.GL_TRIANGLES, mQuadsNum * ORDER_INDICES_PER_QUAD, 
      GLES20.GL_UNSIGNED_SHORT, 0); 

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); 
    GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0); 
} 

// This method is called on gl thread GlSurfaceView.queueEvent(...) 
public void setData() { 
    if (mDataInitNeeded) { 
     // Reset positions of buffers for consuming in GL 
     vertexBuffer.position(0); 
     indexBuffer.position(0); 

     copyToGpu(vertexBuffer); 
     copyToGpu(indexBuffer); 

     mDataInitNeeded = false; 
    } 
} 

public void deallocateGlBuffers() { 
    if (mVerticesBufferId[0] > 0) { 
     GLES20.glDeleteBuffers(mVerticesBufferId.length, mVerticesBufferId, 0); 
     mVerticesBufferId[0] = 0; 
    } 
    if (mIndicesBufferId[0] > 0) { 
     GLES20.glDeleteBuffers(mIndicesBufferId.length, mIndicesBufferId, 0); 
     mIndicesBufferId[0] = 0; 
    } 
} 
} 

The Wall Klasse, die Rechteck steht für:

public class Wall { 
// number of coordinates per vertex in this array 
private static final int COORDS_PER_VERTEX = 3; 
private static final int VERTICES_NUM = 4; // it's a rect after all 
private static final float DEFAULT_WIDTH = 0.05f; 
private static final float DEFAULT_COORDS_SOURCE = 0.5f; 

private final float mCoords[] = new float[COORDS_PER_VERTEX * VERTICES_NUM]; 

private final short mDrawOrder[] = { 0, 1, 2, // first triangle 
            1, 2, 3 }; // second triangle 

private int mVertexBufferPosition; 
private int mIndexBufferPosition; 

private final PointF mA = new PointF(0, 0); 
private final PointF mB = new PointF(0, 0); 
private float mWidth; 

public Wall() { 
    init(-DEFAULT_COORDS_SOURCE, DEFAULT_COORDS_SOURCE, DEFAULT_COORDS_SOURCE, 
      -DEFAULT_COORDS_SOURCE, DEFAULT_WIDTH); 
} 

public Wall(float x1, float y1, float x2, float y2) 
{ 
    init(x1, y1, x2, y2, DEFAULT_WIDTH); 
} 

public Wall(float x1, float y1, float x2, float y2, float width) { 
    init(x1, y1, x2, y2, width); 
} 

private void init(float x1, float y1, float x2, float y2, float width) { 
    mA.x = x1; 
    mA.y = y1; 
    mB.x = x2; 
    mB.y = y2; 
    mWidth = width; 
    calcCoords(); 
} 

private void calcCoords() { 
    float[] vector = {mA.x - mB.x, mA.y - mB.y}; 
    float magnitude = (float) Math.sqrt(vector[0]*vector[0] + vector[1]*vector[1]); 
    float[] identityVector = {vector[0]/magnitude, vector[1]/magnitude}; 
    float[] orthogonalIdentityVector = {identityVector[1], -identityVector[0]}; 

    mCoords[0] = mA.x + mWidth * orthogonalIdentityVector[0]; 
    mCoords[1] = mA.y + mWidth * orthogonalIdentityVector[1]; 

    mCoords[3] = mA.x - mWidth * orthogonalIdentityVector[0]; 
    mCoords[4] = mA.y - mWidth * orthogonalIdentityVector[1]; 

    mCoords[6] = mB.x + mWidth * orthogonalIdentityVector[0]; 
    mCoords[7] = mB.y + mWidth * orthogonalIdentityVector[1]; 

    mCoords[9] = mB.x - mWidth * orthogonalIdentityVector[0]; 
    mCoords[10] = mB.y - mWidth * orthogonalIdentityVector[1]; 
} 

public void putCoords(FloatBuffer vertexBuffer) { 
    mVertexBufferPosition = vertexBuffer.position(); 
    for (int i = 0; i < mDrawOrder.length; i++) { 
     mDrawOrder[i] += mVertexBufferPosition/GlEngine.COORDS_PER_VERTEX; 
    } 
    vertexBuffer.put(mCoords); 
} 

public void putIndices(ShortBuffer indexBuffer) { 
    mIndexBufferPosition = indexBuffer.position(); 
    indexBuffer.put(mDrawOrder); 
} 

public float getWidth() { 
    return mWidth; 
} 

public void setWidth(float mWidth) { 
    this.mWidth = mWidth; 
} 

public PointF getA() { 
    return mA; 
} 

public void setA(float x, float y) { 
    this.mA.x = x; 
    this.mA.y = y; 
} 

public PointF getB() { 
    return mB; 
} 

public void setB(float x, float y) { 
    this.mB.x = x; 
    this.mB.y = y; 
} 
} 

In der Wall-Klasse speichere ich Offset, wo es seine Eckpunkte und Indizes platziert, weil diese Klasse sich in der Zukunft ändern wird und ihre Eckpunkte im Hauptpuffer aktualisieren soll (der Puffer wird nicht für jeden OnDrawFrame neu kompiliert).

Vielen Dank. Ich hoffe mit deiner Hilfe werde ich dieses (andere) Hindernis auf meinem Weg zu OpenGl ES irgendwie überwinden.

+0

Ich würde versuchen, den "nahe" -Wert ein wenig kleiner zu setzen. Im Moment befindet sich Ihre Geometrie genau in der Nähe der Clip-Ebene. –

+0

Könnten Sie bitte mich auf die genaue Zeile im Code hinweisen? –

+0

'final float near = 3.0f;' –

Antwort

1

Schande über mich! Ich habe übrigens Indizes in falsche Reihen gebracht. Statt dessen:

// Copy vertices data into GPU memory 
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesBufferId[0]); 
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, indices.capacity() * SIZE_OF_SHORT, indices, GLES20.GL_STATIC_DRAW); 

sollte es sein:

// Copy vertices data into GPU memory 
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesBufferId[0]); 
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, indices.capacity() * SIZE_OF_SHORT, indices, GLES20.GL_STATIC_DRAW); 

Warum Scham? weil im Protokoll sah ich:

07-23 16: 20: 05.442 5170-5264/com.example.neutrino.maze W/Adreno-ES20: GL_INVALID_OPERATION

Kurz nach dem zweiten Aufruf von glBufferData wo Ich setze GL_ARRAY_BUFFER anstelle von GL_ELEMENT_ARRAY_BUFFER. Dies wurde sicherlich durch Kopieren-Einfügen verursacht, wie in vielen Fällen.