glDrawElements()只绘制前两个面

时间:2017-09-27 15:39:49

标签: android opengl-es opengl-es-2.0 google-cardboard

解决。解决问题的方法: attribStride未正确设置。

我正在编写一个小型Google Cardboard应用程序,可以加载和呈现任何Wavefront .obj文件及其链接.mtl文件中表面的材质属性。为了渲染我正在使用VBO和IBO。对于表面和闪电的材料特性,我正在使用phong着色。

我的问题是,glDrawElements()只会渲染一个立方体的前两个三角形,它由12个三角形组成。

  • 形成立方体的所有三角形都是逆时针设置的。
  • 通过解析.obj文件生成的顶点数组和索引数组数据有效。
  • 用于VBO的客户端FloatBuffer和IBO的客户端ShortBuffer的数据和长度均有效。
  • glBufferData()设置的VBO和IBO的长度有效。
  • 着色器已正确编译和附加。
  • 着色器为glGetAttribLocation()glGetUniformLocation()设置的所有属性和统一位置均有效。

我在Debugger和logcat中检查过这些点。 我意识到它的代码很多。但我无法在任何地方找到问题或解决我的问题。所以请帮助:D并首先感谢:)

此方法设置VBO,IBO,着色器程序,着色器程序位置,纹理和着色器程序统一值:

private void initializeGL() {
    Log.i(TAG, "initializeGL()");

    // Set camera matrix.
    Matrix.setLookAtM(camera, OFFSET, EYE_POINT_X, EYE_POINT_Y, EYE_POINT_Z, CENTER_OF_VIEW_X, CENTER_OF_VIEW_Y, CENTER_OF_VIEW_Z, UP_VECTOR_X, UP_VECTOR_Y, UP_VECTOR_Z);

    // Initialize shader program.
    shaderProgram.init();
    shaderProgramHandle = shaderProgram.getProgramHandle();

    // Initialize object information.
    objectInformation.init();

    vboHandle = objectInformation.getVbo().getVboHandle();
    vboLength = objectInformation.getVbo().getVboLength();

    iboHandle = objectInformation.getIbo().getIboHandle();
    iboLength = objectInformation.getIbo().getIboLength();

    uniforms = objectInformation.getUniformArray();
    numOfUniforms = objectInformation.getNumOfUniforms();
    Log.i(TAG, "initializeGL(): Number of uniforms = " + numOfUniforms);

    textures = objectInformation.getTextureArray();
    numOfTextures = objectInformation.getNumOfTextures();
    Log.i(TAG, "initializeGL(): Number of textures = " + numOfTextures);

    // Get vertex shader uniform locations.
    modelViewProjectionParam = GLES20.glGetUniformLocation(shaderProgramHandle, "u_ModelViewProjection");
    Log.i(TAG, "initializeGL(): modelViewProjectionParam = " + modelViewProjectionParam);

    modelViewParam = GLES20.glGetUniformLocation(shaderProgramHandle, "u_ModelView");
    Log.i(TAG, "initializeGL(): modelViewParam = " + modelViewParam);

    normalMatrixParam = GLES20.glGetUniformLocation(shaderProgramHandle, "u_NormalMatrix");
    Log.i(TAG, "initializeGL(): normalMatrixParam = " + normalMatrixParam);

    // Get vertex shader attribute locations.
    positionParam = GLES20.glGetAttribLocation(shaderProgramHandle, "a_Position");
    Log.i(TAG, "initializeGL(): positionParam = " + positionParam);
    if(boolTexCoords) {
        attribStride += 4 * BYTES_PER_FLOAT;
        texCoordParam = GLES20.glGetAttribLocation(shaderProgramHandle, "a_TexCoord");
        Log.i(TAG, "initializeGL(): texCoordParam = " + texCoordParam);
    }
    normalParam = GLES20.glGetAttribLocation(shaderProgramHandle, "a_Normal");
    Log.i(TAG, "initializeGL(): normalParam = " + normalParam);

    // Get fragment shader phong uniform locations.
    if(boolPhongLightning) {
        lightPosParam = GLES20.glGetUniformLocation(shaderProgramHandle, "lightPosition");
        Log.i(TAG, "initializeGL(): lightPosParam = " + lightPosParam);
        IaParam = GLES20.glGetUniformLocation(shaderProgramHandle, "Ia");
        Log.i(TAG, "initializeGL(): IaParam = " + IaParam);
        IpParam = GLES20.glGetUniformLocation(shaderProgramHandle, "Ip");
        Log.i(TAG, "initializeGL(): IpParam = " + IpParam);
    }

    // Set fragment shader material uniforms.
    GLES20.glUseProgram(shaderProgramHandle);

    for(int i = 0; i < numOfUniforms; i++) {
        String unifName = uniforms[i].getUnifName();
        location = GLES20.glGetUniformLocation(shaderProgramHandle, unifName);
        checkGLError(TAG, "initializeGL(): " + unifName + " shader location");

        vec = uniforms[i].getArray();
        if(vec != null) {
            GLES20.glUniform3fv(location, 1, vec, 0);
            Log.i(TAG, "initializeGL(): " + unifName + "_Param = " + location);
        } else {
            float value = uniforms[i].getValue();
            GLES20.glUniform1f(location, value);
            Log.i(TAG, "initializeGL(): " + unifName + "_Param = " + location);
        }
    }

    // Set fragment shader phong uniforms.
    if(boolPhongLightning) {
        GLES20.glUniform3fv(IaParam, 1, Ia, 0);
        GLES20.glUniform3fv(IpParam, 1, Ip, 0);
    }

    // Set fragment shader textures.
    for(int i = 0; i < numOfTextures; i++) {
        // Set active texture unit.
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i);

        // Bind texture to active texture unit.
        int texHandle = textures[i].getTextureHandle();
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texHandle);

        // Assign texture unit to uniform in fragment shader.
        String unifName = textures[i].getUnifName();
        location = GLES20.glGetUniformLocation(shaderProgramHandle, unifName);

        GLES20.glUniform1i(location, i);
        checkGLError(TAG, "initializeGL(): glUniform1i()");
        Log.i(TAG, "initializeGL(): " + unifName + "Param = " + location);
    }

    GLES20.glUseProgram(0);

    GLES20.glEnable(GLES20.GL_DEPTH_TEST);
    GLES20.glDepthFunc(GLES20.GL_LESS);

    GLES20.glEnable(GLES20.GL_CULL_FACE);
    GLES20.glFrontFace(GLES20.GL_CCW);
    GLES20.glCullFace(GLES20.GL_BACK);

    GLES20.glClearColor(0.3f, 0.3f, 0.3f, 0.1f);
}

public void onDrawEye():

@Override
public void onDrawEye(Eye eye) {
    Log.i(TAG, "onDrawEye()");

    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

    projection = eye.getPerspective(Z_NEAR, Z_FAR);
    Matrix.multiplyMM(view, 0, eye.getEyeView(), 0, camera, 0);
    Matrix.multiplyMM(modelView, 0, view, 0, modelMatrix, 0);
    Matrix.multiplyMM(modelViewProjection, 0, projection, 0, modelView, 0);
    Matrix.multiplyMV(lightPosInEyeSpace, 0, view, 0, lightPosInWorldSpace, 0);
    normalMatrix = RPMath.getNormalMatrix3x3(modelView);

    draw();
}

private void draw():

private void draw() {
    Log.i(TAG, "draw()");

    // Bind shader program, VBO and IBO.
    GLES20.glUseProgram(shaderProgramHandle);
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboHandle);
    GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, iboHandle);

    // Set vertex shader uniforms.
    GLES20.glUniformMatrix4fv(modelViewProjectionParam, 1, false, modelViewProjection, 0);
    GLES20.glUniformMatrix4fv(modelViewParam, 1, false, modelView, 0);
    GLES20.glUniformMatrix3fv(normalMatrixParam, 1, false, normalMatrix, 0);
    if(boolPhongLightning) { // fragment shader uniforms.
        vec = new float[3];
        vec[0] = lightPosInEyeSpace[0];
        vec[1] = lightPosInEyeSpace[1];
        vec[2] = lightPosInEyeSpace[2];
        GLES20.glUniform3fv(lightPosParam, 1, vec, 0);
    }

    // Set vertex attribute pointers.
    attribOffset = 0;
    GLES20.glVertexAttribPointer(positionParam, 4, GLES20.GL_FLOAT, false, attribStride, attribOffset);
    if(boolTexCoords) {
        attribOffset += 4 * BYTES_PER_FLOAT;
        GLES20.glVertexAttribPointer(texCoordParam, 4, GLES20.GL_FLOAT, false, attribStride, attribOffset);
    }
    attribOffset += 4 * BYTES_PER_FLOAT;
    GLES20.glVertexAttribPointer(normalParam, 4, GLES20.GL_FLOAT, false, attribStride, attribOffset);

    // Enable vertex attribute arrays.
    GLES20.glEnableVertexAttribArray(positionParam);
    if(boolTexCoords) {
        GLES20.glEnableVertexAttribArray(texCoordParam);
    }
    GLES20.glEnableVertexAttribArray(normalParam);

    // Draw.
    GLES20.glDrawElements(GLES20.GL_TRIANGLES, iboLength, GLES20.GL_UNSIGNED_SHORT, 0);

    // Disable vertex attribute arrays.
    GLES20.glDisableVertexAttribArray(positionParam);
    if(boolTexCoords) {
        GLES20.glDisableVertexAttribArray(texCoordParam);
    }
    GLES20.glDisableVertexAttribArray(normalParam);

    // Unbind shader program, VBO and IBO.
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
    GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
    GLES20.glUseProgram(0);
}

修改 RPVBO和RPIBO类。有趣的部分是init()方法:

public final class RPVBO {

    private static final String TAG = "RPVBO";
    private static final int BYTES_PER_FLOAT = 4;

    private int[] vboHandles;
    private Vector<Float> vertices;
    private int vboLength;


    public RPVBO() {
        Log.i(TAG, "Constructor()");
        vboHandles = null;
        vertices = new Vector();
        vboLength = 0;
    }


    public void init() {
        Log.i(TAG, "init()");

        if((vboHandles != null) && (vboHandles[0] != 0)) {
            return;
        }

        vboHandles = new int[1];
        GLES20.glGenBuffers(1, vboHandles, 0);

        if(vboHandles[0] != 0) {
            float[] vertexArray = getVertexArray();

            FloatBuffer clientSideBuffer = ByteBuffer.allocateDirect(vertexArray.length * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
            clientSideBuffer.position(0);
            clientSideBuffer.put(vertexArray);
            clientSideBuffer.position(0);

            if(clientSideBuffer.capacity() != vertexArray.length) {
                Log.e(TAG, "init(): Error creating client side Floatbuffer.");
                throw new RuntimeException("Error: " + TAG + "init(): Error creating client side Floatbuffer.");
            }

            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboHandles[0]);

            GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, clientSideBuffer.capacity() * BYTES_PER_FLOAT, clientSideBuffer, GLES20.GL_STATIC_DRAW);
            MainActivity.checkGLError(TAG, "init(): glBufferData()");

            int[] params = new int[2];
            GLES20.glGetBufferParameteriv(GLES20.GL_ARRAY_BUFFER, GLES20.GL_BUFFER_SIZE, params, 0);
            MainActivity.checkGLError(TAG, "init(): glGetBufferParameteriv()");
            GLES20.glGetBufferParameteriv(GLES20.GL_ARRAY_BUFFER, GLES20.GL_BUFFER_USAGE, params, 1);
            MainActivity.checkGLError(TAG, "init(): glGetBufferParameteriv()");

            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

            if(params[0] != (clientSideBuffer.capacity() * BYTES_PER_FLOAT)) {
                Log.e(TAG, "init(): Error setting OpenGL VBO data.");
                throw new RuntimeException("Error: " + TAG + ": init(): Error setting OpenGL VBO data.");
            }

            Log.i(TAG, "init(): OpenGL VBO handle: " + vboHandles[0]);
            Log.i(TAG, "init(): OpenGL VBO size in Bytes: " + params[0]);
            switch(params[1]) {
                case GLES20.GL_STREAM_DRAW:
                    Log.i(TAG, "init(): OpenGL VBO usage: GL_STREAM_DRAW.");
                    break;

                case GLES20.GL_STATIC_DRAW:
                    Log.i(TAG, "init(): OpenGL VBO usage: GL_STATIC_DRAW.");
                    break;

                case GLES20.GL_DYNAMIC_DRAW:
                    Log.i(TAG, "init(): OpenGL VBO usage: GL_DYNAMIC_DRAW.");
            }

            vertices.clear();
        }

        if(vboHandles[0] == 0) {
            Log.e(TAG, "init(): Error creating VBO in OpenGL.");
            throw new RuntimeException("Error: " + TAG + "init(): Error creating VBO in OpenGL.");
        }
    }


    public void addValue(final float value) {
        vertices.add(value);
        ++vboLength;
    }

    public void addValue(final Float value) {
        vertices.add(value);
        ++vboLength;
    }


    public void addArray(final float[] array) {
        final int arrayLength = array.length;
        for(int i = 0; i < arrayLength; i++) {
            vertices.add(array[i]);
            ++vboLength;
        }
    }

    public void addArray(final Float[] array) {
        final int arrayLength = array.length;
        for(int i = 0; i < arrayLength; i++) {
            vertices.add(array[i]);
            ++vboLength;
        }
    }


    public int getVboHandle() {
        if(vboHandles == null) {
            return 0;
        }
        return vboHandles[0];
    }
    @Nullable
    public float[] getVertexArray() {
        float[] array = new float[vertices.size()];
        for(int i = 0; i < vertices.size(); i++) {
            array[i] = vertices.get(i);
        }
        return array;
    }

    public int getVboLength() {
        return vboLength;
    }
}

public final class RPIBO {

    private static final String TAG = "RPIBO";
    private static final int BYTES_PER_SHORT = 2;

    private int[] iboHandles;
    private Vector<Short> indices;
    private int iboLength;


    public RPIBO() {
        Log.i(TAG, "Constructor()");
        iboHandles = null;
        indices = new Vector();
        iboLength = 0;
    }


    public void init() {
        Log.i(TAG, "init()");

        if((iboHandles != null) && (iboHandles[0] != 0)) {
            return;
        }

        iboHandles = new int[1];
        GLES20.glGenBuffers(1, iboHandles, 0);

        if(iboHandles[0] != 0) {
            short[] indexArray = getIndexArray();

            ShortBuffer clientSideBuffer = ByteBuffer.allocateDirect(indexArray.length * BYTES_PER_SHORT).order(ByteOrder.nativeOrder()).asShortBuffer();
            clientSideBuffer.position(0);
            clientSideBuffer.put(indexArray);
            clientSideBuffer.position(0);

            if(clientSideBuffer.capacity() != indexArray.length) {
                Log.e(TAG, "init(): Error creating client side Shortbuffer.");
                throw new RuntimeException("Error: " + TAG + "init(): Error creating client side Shortbuffer.");
            }

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

            GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, clientSideBuffer.capacity() * BYTES_PER_SHORT, clientSideBuffer, GLES20.GL_STATIC_DRAW);
            MainActivity.checkGLError(TAG, "init(): glBufferData()");

            int[] params = new int[2];
            GLES20.glGetBufferParameteriv(GLES20.GL_ELEMENT_ARRAY_BUFFER, GLES20.GL_BUFFER_SIZE, params, 0);
            MainActivity.checkGLError(TAG, "init(): glGetBufferParameteriv()");
            GLES20.glGetBufferParameteriv(GLES20.GL_ELEMENT_ARRAY_BUFFER, GLES20.GL_BUFFER_USAGE, params, 1);
            MainActivity.checkGLError(TAG, "init(): glGetBufferParameteriv()");

            GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);

            if(params[0] != (clientSideBuffer.capacity() * BYTES_PER_SHORT)) {
                Log.e(TAG, "init(): Error setting OpenGL IBO data.");
                throw new RuntimeException("Error: " + TAG + ": init(): Error setting OpenGL IBO data.");
            }

            Log.i(TAG, "init(): OpenGL IBO handle: " + iboHandles[0]);
            Log.i(TAG, "init(): OpenGL IBO size in Bytes: " + params[0]);
            switch(params[1]) {
                case GLES20.GL_STREAM_DRAW:
                    Log.i(TAG, "init(): OpenGL IBO usage: GL_STREAM_DRAW.");
                    break;

                case GLES20.GL_STATIC_DRAW:
                    Log.i(TAG, "init(): OpenGL IBO usage: GL_STATIC_DRAW.");
                    break;

                case GLES20.GL_DYNAMIC_DRAW:
                    Log.i(TAG, "init(): OpenGL IBO usage: GL_DYNAMIC_DRAW.");
            }

            indices.clear();
        }

        if(iboHandles[0] == 0) {
            Log.e(TAG, "init(): Error creating IBO in OpenGL.");
            throw new RuntimeException("Error: " + TAG + "init(): Error creating IBO in OpenGL.");
        }
    }


    public void addValue(final short value) {
        indices.add(value);
        ++iboLength;
    }

    public void addValue(final Short value) {
        indices.add(value);
        ++iboLength;
    }


    public void addArray(final short[] array) {
        final int arrayLength = array.length;
        for(int i = 0; i < arrayLength; i++) {
            indices.add(array[i]);
            ++iboLength;
        }
    }

    public void addArray(final Short[] array) {
        final int arrayLength = array.length;
        for(int i = 0; i < arrayLength; i++) {
            indices.add(array[i]);
            ++iboLength;
        }
    }


    public int getIboHandle() {
        if(iboHandles == null) {
            return 0;
        }
        return iboHandles[0];
    }
    @Nullable
    public short[] getIndexArray() {
        short[] array = new short[indices.size()];
        for(int i = 0; i < indices.size(); i++) {
            array[i] = indices.get(i);
        }
        return array;
    }

    public int getIboLength() {
        return iboLength;
    }
}

1 个答案:

答案 0 :(得分:0)

glVertexAttribPointerstride)的第4个参数,指定连续通用顶点属性之间的字节偏移量。

请参阅Khronos OpenGL specification - Chapter 10.3. VERTEX ARRAYS,其中包含:

  

从缓冲区对象获取顶点数据时,offset指定顶点缓冲区中第一个元素的基本机器单位的偏移量。指向数组的 i (i + 1) st元素的指针相差stride个基本机器单元,指向(i + 1) st元素的指针更大。


这意味着,如果您的顶点缓冲区包含顶点,纹理坐标和法线向量,格式为:

vx, vy, vz, 1.0,  s, t, 0.0, 1.0,  nx, ny, nz, 1.0

然后stride必须是(4+4+4)*BYTES_PER_FLOAT = 48,因为顶点的大小是4,纹理坐标的大小是4和法线向量的大小是4 纹理坐标的offset4*BYTES_PER_FLOAT = 16,法线向量的偏移为(4+4)*BYTES_PER_FLOAT = 32