0

我正在开发一个使用 OpenGL ES 2.0 的 Android 应用程序

因为这是我第一次使用 OpenGL(我曾经使用 WebGL),所以我制作了一个自定义且非常简单的 API,例如 THREE.js,它由 aObject3DGeometry对象组成。

基本上,我所做的是:将形状存储在对象中,并使用其中的几何实例Geometry创建对象。Mesh另外,在里面Mesh,我有:Vector3object for: position, scale, rotation.

我创建了一个圈子来测试,这就是正在发生的事情

如果我不改变任何东西,圆圈在屏幕上是完美的。如果我在创建圆时更改顶点位置,圆仍然可以。

但是,当我进行一些变换(更改属性位置、缩放或旋转)或 Object3D(在本例中为网格)时,圆变成了“拉伸”。

所以,我认为projectionMatrix有问题,但是不变换圆就可以了。

我的矩阵代码有问题吗?我应该将旋转、平移和缩放矩阵发送到 GPU 吗?

也许我把事情复杂化了,但由于这是我在阅读大量信息后第一次使用 OpenGL,这是可以接受的......

这是 Object3D 代码:

public class Object3D {
    public Vector3 position = new Vector3();
    public Vector3 rotation = new Vector3();
    public Vector3 scale = new Vector3();

    public Color color = new Color();

    public float[] getMVMatrix(){
        // Initialize matrix with Identity
        float[] mvMatrix = new float[16];
        Matrix.setIdentityM(mvMatrix, 0);

        // apply scale
        Matrix.scaleM(mvMatrix, 0, scale.x, scale.y, scale.z);

        // set rotation
        Matrix.setRotateM(mvMatrix, 0, rotation.x, 1f, 0, 0);
        Matrix.setRotateM(mvMatrix, 0, rotation.y, 0, 1f, 0);
        Matrix.setRotateM(mvMatrix, 0, rotation.z, 0, 0, 1f);

        // apply translation
        Matrix.translateM(mvMatrix, 0, position.x, position.y, position.z);

        return mvMatrix;
    }
}

这是几何类,它简化了三角形的使用:

public class Geometry {

    // Public, to allow modifications
    public ArrayList<Vector3> vertices;
    public ArrayList<Face3> faces;

    // Type of Geometry
    public int triangleType = GLES20.GL_TRIANGLES;

    [...]

    public FloatBuffer getVerticesBuffer(){

        if(verticesBuffer == null || verticesBufferNeedsUpdate){

            /*
             *  Cache faces
             */

            int size = vertices.size();

            // (size of Vector3 list) * (3 for each object) * (4 bytes per float)
            ByteBuffer bb = ByteBuffer.allocateDirect( size * 3 * 4 );

            // use the device hardware's native byte order
            bb.order(ByteOrder.nativeOrder());

            // Get the ByteBuffer as a floatBuffer
            verticesBuffer = bb.asFloatBuffer();

            for(int i = 0; i < size; i++)
                verticesBuffer.put(vertices.get(i).toArray());

            verticesBufferNeedsUpdate = false;
        }

        verticesBuffer.position(0);
        return verticesBuffer;
    }

    public ShortBuffer getFacesBuffer(){

        if(facesBuffer == null || facesBufferNeedsUpdate){

            /*
             *  Cache faces
             */

            int size = faces.size();
//          Log.i(TAG, "FACES Size:    "+size);

            // (size of Vector3 list) * (3 for each object) * (2 bytes per short)
            ByteBuffer bb = ByteBuffer.allocateDirect( size * 3 * 2 );

            // use the device hardware's native byte order
            bb.order(ByteOrder.nativeOrder());

            // Get the ByteBuffer as a floatBuffer
            facesBuffer = bb.asShortBuffer();

            for(int i = 0; i < size; i++)
                facesBuffer.put(faces.get(i).toArray());

            facesBufferNeedsUpdate = false;
        }

        facesBuffer.position(0);
        return facesBuffer;
    }
}

此外,Mesh 类,负责重新渲染Geometry对象:

public class Mesh extends Object3D{
    [...]
    public void draw(float[] projectionMatrix, int shaderProgram){
        float[] MVMatrix = getMVMatrix();
        Matrix.multiplyMM(projectionMatrix, 0, projectionMatrix, 0, MVMatrix, 0);

        // Check if geometry is set
        if(geometry == null){
            Log.i(TAG, "Geometry is null. skiping");
            return;
        }

        // Add program to OpenGL environment
        GLES20.glUseProgram(shaderProgram);

        // Get, enable and Set the position attribute
        positionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition");
        GLES20.glEnableVertexAttribArray(positionHandle);

        // Prepare the triangles coordinate data
        Buffer vertexBuffer = geometry.getVerticesBuffer();

        GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX,
                                     GLES20.GL_FLOAT, false,
                                     COORDS_PER_VERTEX*4,
                                     vertexBuffer);

        // get handle to fragment shader's vColor member
        int mColorHandle = GLES20.glGetUniformLocation(shaderProgram, "vColor");
        // Set color for drawing the triangle
        GLES20.glUniform4fv(mColorHandle, 1, color.toArray(), 0);

        // get handle to shape's transformation matrix
        int mMVPMatrixHandle = GLES20.glGetUniformLocation(shaderProgram, "uMVPMatrix");
        ChwaziSurfaceView.checkGlError("glGetUniformLocation");

        // Apply the projection and view transformation
        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, projectionMatrix, 0);
        ChwaziSurfaceView.checkGlError("glUniformMatrix4fv");

        // Draw the triangles
        if(geometry.triangleType == GLES20.GL_TRIANGLES){

            Buffer indexesBuffer = geometry.getFacesBuffer();

            GLES20.glDrawElements(
                    GLES20.GL_TRIANGLES,
                    geometry.faces.size()*3,
                    GL10.GL_UNSIGNED_SHORT,
                    indexesBuffer);
        }else{
            GLES20.glDrawArrays(geometry.triangleType, 0, geometry.vertices.size());
            ChwaziSurfaceView.checkGlError("glDrawArrays");
        }

        // Disable vertex array
        GLES20.glDisableVertexAttribArray(positionHandle);
    }
}

这是我为测试它是否正常工作而制作的示例代码(只是翻译)

// Inside my Renderer...
 @Override
    public void onDrawFrame(GL10 unused) {

        // Draw background color
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        GLES20.glCullFace(GLES20.GL_FRONT_AND_BACK);

        // Set the camera position (View matrix)
        Matrix.setLookAtM(mVMatrix, 0,
                0, 0, -3,
                0f, 0f, 0f,
                0f, 1.0f, 0.0f);

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


        // Create a rotation for the triangle
        long time = SystemClock.uptimeMillis();// % 4000L;
        myMesh.position.x = (time%4000)/4000f;
        myMesh.draw(mMVPMatrix, shaderProgram.getProgram());
    }

    @Override
    public void onSurfaceChanged(GL10 unused, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
        float ratio = (float) width / height;
        // this projection matrix is applied to object coordinates
        Matrix.orthoM(mProjMatrix, 0, -1, 1, -1, 1, 0, 10);
    }

编辑

着色器代码:

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

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

0 回答 0