6

安卓开发者!我有麻烦了。我的 android 应用程序必须使用 OpenGL 绘制几条线。我以这个作为例子开始并重写了它。它抛出 IllegalArgumentException: must use a native order direct Buffer when调用 GLES20.glVertexAttribPointer。我不明白为什么,因为我将它设置为 nativeorder,就像我使用的示例一样。这是我完整的 OpenGLRenderer 类:(在创建此类的实例时,我使用带有 float[] 参数的第二个构造函数)

public class OpenGLRenderer implements GLSurfaceView.Renderer {

        final int COORDS_PER_VERTEX = 3;
        final int NR_OF_LINES; 
        final int NR_OF_VERTECES;
        final int VertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
        final int NR_OF_VERTECES_PER_LINE = 2;
        final int BYTES_PER_VERTEX = 4;


    private FloatBuffer bufferVertecesLines;
    private float[] arrayVertecesLines;
    //private FloatBuffer ColorBuffer;      
    // Set color with red, green, blue and alpha (opacity) values
    float color[] = { 0.3f, 0.7f, 0.2f, 1.0f };

    private int GlProgram;
    private int PositionHandle;
    private int ColorHandle;


    //SHADERS----------------------------------------------------------------------------------------------------------------------------
    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
        "  gl_Position = uMVPMatrix * vPosition;" +
        "}";

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


    //CONSTRUCTOR----------------------------------------------------------------------------------------------------------------------------
    public OpenGLRenderer(FloatBuffer thisLineVertexBuffer, int numberoflines)
    {

        bufferVertecesLines = thisLineVertexBuffer; 
        NR_OF_VERTECES = numberoflines * 2;
        NR_OF_LINES = numberoflines;
        Log.v("Leen","mijn eigen logje - OpenGLRenderer - Constructor");
    }

    public OpenGLRenderer(float[] thisLineVertexArray)
    {
        arrayVertecesLines = thisLineVertexArray;
        NR_OF_VERTECES = thisLineVertexArray.length / COORDS_PER_VERTEX;
        NR_OF_LINES = thisLineVertexArray.length / COORDS_PER_VERTEX / NR_OF_VERTECES_PER_LINE; 
    }

    private void convertArrayToBuffer()
    {
        int NrOfBytes = NR_OF_LINES * NR_OF_VERTECES_PER_LINE * COORDS_PER_VERTEX * BYTES_PER_VERTEX;
        // in voorbeeld:
        // NrOfBytes =          2   *           2           *           3           *       4       =   48                   

        ByteBuffer bb = ByteBuffer.allocate(NrOfBytes);
        bb.order(ByteOrder.nativeOrder());
        bufferVertecesLines = bb.asFloatBuffer();
        bufferVertecesLines.put(arrayVertecesLines);

    }

    //---------------------------------------------------------------------------------------------------------------------------------------
    @Override
    public void onSurfaceChanged(GL10 unused, int width, int height) 
    {
        // Adjust the viewport based on geometry changes,
        // such as screen rotation
        GLES20.glViewport(0, 0, width, height);
    }

    //---------------------------------------------------------------------------------------------------------------------------------------
    @Override
    public void onDrawFrame(GL10 arg0) 
    {
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, VertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, FragmentShaderCode);

        GlProgram = GLES20.glCreateProgram();             // create empty OpenGL ES Program
        GLES20.glAttachShader(GlProgram, vertexShader);   // add the vertex shader to program
        GLES20.glAttachShader(GlProgram, fragmentShader); // add the fragment shader to program
        GLES20.glLinkProgram(GlProgram);                  // creates OpenGL ES program executables

        this.drawAllLines();
    }

    //---------------------------------------------------------------------------------------------------------------------------------------
    @Override
    public void onSurfaceCreated(GL10 unused, EGLConfig config) 
    {
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    }


    //---------------------------------------------------------------------------------------------------------------------------------------   
    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 drawAllLines()
    {
        // Add program to OpenGL ES environment
        GLES20.glUseProgram(GlProgram);

        // get handle to vertex shader's vPosition member
        PositionHandle = GLES20.glGetAttribLocation(GlProgram, "vPosition");

        // Enable a handle to the triangle vertices
        GLES20.glEnableVertexAttribArray(PositionHandle);

        // Prepare the Line coordinate data
        // vertexstride = offset. 3 coordinaten per vertex * 4 bytes per vertex = 12

        this.convertArrayToBuffer();

        GLES20.glVertexAttribPointer(PositionHandle, COORDS_PER_VERTEX,
                                             GLES20.GL_FLOAT, false,
                                             VertexStride, bufferVertecesLines);

        // get handle to fragment shader's vColor member
        ColorHandle = GLES20.glGetUniformLocation(GlProgram, "vColor");

        // Set color for drawing the triangle
        GLES20.glUniform4fv(ColorHandle, 1, color, 0);

        // Draw the triangle
        GLES20.glDrawArrays(GLES20.GL_LINES, 0, NR_OF_VERTECES);

        // Disable vertex array
        GLES20.glDisableVertexAttribArray(PositionHandle);

    }

}
4

3 回答 3

22

好的,找到了。我没有使用ByteBuffer.allocate()方法,而是ByteBuffer.allocateDirect()-方法。这篇文章没有例外:

private void convertArrayToBuffer()
{
    int NrOfBytes = NR_OF_LINES * NR_OF_VERTECES_PER_LINE * COORDS_PER_VERTEX * BYTES_PER_VERTEX;
    // in voorbeeld:
    // NrOfBytes =          2   *           2           *           3           *       4       =   48                   

    ByteBuffer bb = ByteBuffer.allocateDirect(NrOfBytes);       //!!!!!!!!!!
    bb.order(ByteOrder.nativeOrder());
    bufferVertecesLines = bb.asFloatBuffer();
    bufferVertecesLines.put(arrayVertecesLines);
    bb.position(0);                 
    bufferVertecesLines.position(0);
}
于 2013-10-26T12:55:28.303 回答
1
private void convertArrayToBuffer()
{
    int NrOfBytes = NR_OF_LINES * NR_OF_VERTECES_PER_LINE * COORDS_PER_VERTEX * BYTES_PER_VERTEX;
    // in voorbeeld:
    // NrOfBytes =          2   *           2           *           3           *       4       =   48                   

    ByteBuffer bb = ByteBuffer.allocate(NrOfBytes);
    bb.order(ByteOrder.nativeOrder());
    bufferVertecesLines = bb.asFloatBuffer();
    bufferVertecesLines.put(arrayVertecesLines);
    bb.position(0);                 //!!!!!!!!!!!!!
    bufferVertecesLines.position(0);//!!!!!!!!!!!!!
}
于 2013-10-25T15:39:33.283 回答
1

我也遇到了同样的问题,我在enter link description here找到了答案。使用allocateDirect而不是allocate, bb 需要是直接的,因此它不会在内存中移动。

于 2019-02-27T03:23:05.873 回答