使用 GLES30 的 VAO 渲染:偏移量 / len 错误!!!!!!错误

问题描述

在 Android 上尝试在 GLES30 中使用 VAO 渲染立方体时,我收到以下错误消息:

D/emuglGLESv2_enc: sendVertexAttributes: bad offset / len!!!!!

有人知道这是什么意思以及如何解决吗?我在任何地方都找不到它的任何文档,并且函数的行为不像它们在普通 java 中的 lwjgl 中所做的那样。这是我的渲染类:

/**
   * renders an object
   * @param object - the mesh object to be rendered
   */
  public void renderMesh(MeshObject object) {

      // bind the vertex array
      GLES30.glBindVertexArray(object.getMesh().getVAO()[0]);

      // get the attrib pointers
      int pAttrib = GLES30.glGetAttribLocation(shaderProgramID,"vPosition");
      int nAttrib = GLES30.glGetAttribLocation(shaderProgramID,"vnormal");
      int tAttrib = GLES30.glGetAttribLocation(shaderProgramID,"vTextureCoords");

      // enable the attributes
      GLES30.glEnabLevertexAttribArray(pAttrib); // position attribute
      GLES30.glEnabLevertexAttribArray(nAttrib); // normal attribute
      GLES30.glEnabLevertexAttribArray(tAttrib); // texture attribute

      // send empty data
      GLES30.glVertexAttribPointer(pAttrib,3,GLES30.GL_FLOAT,false,3 * 4,0);
      GLES30.glVertexAttribPointer(nAttrib,0);
      GLES30.glVertexAttribPointer(tAttrib,2,2 * 4,0);

      // bind the index buffer
      GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,object.getMesh().getIBO()[0]);

      // bind the shader
      GLES30.gluseProgram(shaderProgramID);

      // bind the texture
      GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D,object.getMesh().getTextureID());

      // get pointers to the uniform locations
      int viewPositionHandle = GLES30.glGetUniformlocation(shaderProgramID,"viewPos");
      int mHandle = GLES30.glGetUniformlocation(shaderProgramID,"vModel");
      int vHandle = GLES30.glGetUniformlocation(shaderProgramID,"vView");
      int pHandle = GLES30.glGetUniformlocation(shaderProgramID,"vProjection");

      // set the uniforms
      GLES30.gluniform3fv(viewPositionHandle,1,camera.getPosition().toFloatArray(),0);
      GLES30.gluniformMatrix4fv(mHandle,object.getModelMatrix(),0);
      GLES30.gluniformMatrix4fv(vHandle,camera.getViewMatrix(),0);
      GLES30.gluniformMatrix4fv(pHandle,surfaceRenderer.getProjectionMatrix(),0);

      // draw the triangles specified by the index buffer
      GLES30.glDrawElements(GLES30.GL_TRIANGLES,object.getMesh().getIndices().length,GLES30.GL_UNSIGNED_INT,0);

      // unbind the shader
      GLES30.gluseProgram(0);

      // unbind the index buffer
      GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,0);

      // disable the vertex attributes
      GLES30.gldisabLevertexAttribArray(pAttrib); // position attribute
      GLES30.gldisabLevertexAttribArray(nAttrib); // normal attribute
      GLES30.gldisabLevertexAttribArray(tAttrib); // texture attribute

      // unbind the vertex array
      GLES30.glBindVertexArray(0);
  }

这是我的网格类:

package com.bramerlabs.productivitree.graphics_engine.graphics;

import android.opengl.GLES30;

import com.bramerlabs.productivitree.graphics_engine.math.Vertex;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;

public class Mesh {

    // the vertex array object
    private final int[] vao = new int[1];

    // the buffer objects
    private final int[] pbo = new int[1]; // position buffer object
    private final int[] nbo = new int[1]; // normal buffer object
    private final int[] tbo = new int[1]; // texture buffer object
    private final int[] ibo = new int[1]; // index buffer object

    private final Vertex[] vertices;
    private final int[] indices;
    private final int textureID;

    /**
     * default constructor
     *
     * @param vertices - a list of vertices in the mesh
     * @param indices - the order in which the vertices should be drawn
     */
    public Mesh(Vertex[] vertices,int[] indices,int textureID) {
        this.vertices = vertices;
        this.indices = indices;
        this.textureID = textureID;
    }

    /**
     * creates the mesh
     */
    public void create() {
        // generate and bind the vertex array
        GLES30.glGenVertexArrays(1,vao,0);
        GLES30.glBindVertexArray(vao[0]);

        // generate the data arrays
        // generate the position buffer object
        float[] positionData = new float[vertices.length * 3];
        for (int i = 0; i < vertices.length; i++) {
            positionData[3 * i] = vertices[i].getPosition().getX();
            positionData[3 * i + 1] = vertices[i].getPosition().getY();
            positionData[3 * i + 2] = vertices[i].getPosition().getZ();
        }
        FloatBuffer positionBuffer = createFloatBuffer(positionData,3);

        // generate the normal buffer object
        float[] normalData = new float[vertices.length * 3];
        for (int i = 0; i < vertices.length; i++) {
            positionData[3 * i] = vertices[i].getnormal().getX();
            positionData[3 * i + 1] = vertices[i].getnormal().getY();
            positionData[3 * i + 2] = vertices[i].getnormal().getZ();
        }
        FloatBuffer normalBuffer = createFloatBuffer(normalData,3);

        // generate the texture buffer object
        float[] textureData = new float[vertices.length * 2];
        for (int i = 0; i < vertices.length; i++) {
            textureData[2 * i] = vertices[i].getTextureCoord().getX();
            textureData[2 * i + 1] = vertices[i].getTextureCoord().getY();
        }
        FloatBuffer textureBuffer = createFloatBuffer(textureData,2);

        // generate the index buffer object
        ByteBuffer bb = ByteBuffer.allocateDirect(indices.length * 4);
        bb.order(ByteOrder.nativeOrder());
        IntBuffer indexBuffer = bb.asIntBuffer();
        indexBuffer.put(indices).flip();
        indexBuffer.position(0);

        // store the data
        storeData(pbo,positionBuffer,3);
        storeData(nbo,normalBuffer,3);
        storeData(tbo,textureBuffer,2);

        // create the index buffer
        GLES30.glGenBuffers(1,ibo,0);
        GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,ibo[0]);
        GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER,indexBuffer.capacity(),indexBuffer,GLES30.GL_STATIC_DRAW);
        GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,0);
    }

    /**
     * stores buffer data in an index
     */
    private void storeData(int[] location,FloatBuffer buffer,int index,int size) {
        // generate a buffer at the location
        GLES30.glGenBuffers(1,location,0);

        // bind the buffer
        GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,location[0]);

        // add the data to the buffer
        GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER,buffer.capacity(),buffer,GLES30.GL_STATIC_DRAW);

        // set the data type attribute
        GLES30.glVertexAttribPointer(index,size,0);

        // unbind the buffer
        GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,0);
    }

    /**
     * creates a buffer
     * @param data - a float array of data
     * @param stride - the stride of the data
     * @return - a float buffer containing the data
     */
    private FloatBuffer createFloatBuffer(float[] data,int stride) {
        // initialize empty float buffer
        ByteBuffer bb = ByteBuffer.allocateDirect(data.length * stride * 4);
        bb.order(ByteOrder.nativeOrder());
        FloatBuffer dataBuffer = bb.asFloatBuffer();

        // add the data to the float buffer and flip it
        dataBuffer.put(data).flip();

        // seek to the first position
        dataBuffer.position(0);
        return dataBuffer;
    }

    /**
     * getter method
     * @return - the position buffer object
     */
    public int[] getPBO() {
        return this.pbo;
    }

    /**
     * getter method
     * @return - the normal buffer object
     */
    public int[] getNBO() {
        return this.nbo;
    }

    /**
     * getter method
     * @return - the texture buffer object
     */
    public int[] getTBO() {
        return this.tbo;
    }

    /**
     * getter method
     * @return - the index buffer object
     */
    public int[] getIBO() {
        return this.ibo;
    }

    /**
     * getter method
     * @return - the vertex array object
     */
    public int[] getVAO() {
        return this.vao;
    }

    /**
     * getter method
     * @return - the draw order
     */
    public int[] getIndices() {
        return this.indices;
    }

    /**
     * getter method
     * @return - the vertices
     */
    public Vertex[] getVertices() {
        return this.vertices;
    }

    public int getTextureID() {
        return this.textureID;
    }
}

解决方法

glBufferData 的第二个参数是缓冲区的大小以字节为单位,但不是数组中元素的数量。
FloatBufferIntBuffer 中元素的字节大小为 4:

GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER,buffer.capacity(),buffer,GLES30.GL_STATIC_DRAW);

GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER,buffer.capacity() * 4,GLES30.GL_STATIC_DRAW);

GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER,indexBuffer.capacity(),indexBuffer,indexBuffer.capacity() * 4,GLES30.GL_STATIC_DRAW);