安卓平台OpenGL ES的调用

安卓平台OpenGL ES的调用

  • 开发游戏如果直接使用OpenGL是比较痛苦的,最好的办法是使用封装好的引擎,但很有必要了解在安卓java代码直接调用OpenGL的渲染方法
  • 固定渲染管线只可通过配置实现不同的效果,而可编程渲染管线通过一般编程的方式实现,可以实现更加灵活的效果

OpenGL ES

  • OpenGL从3.0开始,而OpenGL ES从2.0开始,支持可编程管线
  • 下图中橙色两块儿即为可编程部分,而顶点和片段着色器要相互配合好才能发挥最大性能

Programmable Pipeline of OpenGL 2.0

  • 一般通用编程模式为写好两个shader的代码,每次运行程序时即时编译运行

代码框架

  • 在manifest中声明OpenGL ES <uses-feature android:glEsVersion="0x00020000" android:required="true" />
  • 在入口Acitvity中需要使用GLSurfaceView作为主视图
  • 在GLSurfaceView中可以扩展出一些其他函数,需要创建一个GLSurfaceView.Renderer的派生类对象负责显示
  • GLSurfaceView.Renderer需要关注三个函数:
    • onSurfaceCreated:仅调用一次
    • onDrawFrame:每次显示都调用
    • onSurfaceChanged:view大小变化时调用

3D坐标变换

  • 安卓同样有对应坐标变换的库Matrix
  • MVP变换的实际乘法顺序是PVM
  • V可以通过setLookAtM得到
  • P则是orthoM frustumM/perspectiveM生成,其中perspectiveM是对frustumM的封装,只是在API Level 14后才存在
  • M如果不是I的话,表明模型有位置偏移

使用shader画图

  • 需要创建一个顶点shader、一个片段shader,以及一个program
  • 通过glCreateShader可以创建一个shader,之后调用glShaderSourceglCompileShader分别设置shader代码和编译
  • progam则通过glCreateProgram创建,调用glAttachShader添加这两个shader,调用glLinkProgram进行“链接”生成可执行指令,使用时要glUseProgram

示例代码

  • OpenGLES20Activity.java

    package com.example.androiddeveloper;
    
    //import android.support.v7.app.ActionBarActivity;
    import android.os.Bundle;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.MotionEvent;
    
    import javax.microedition.khronos.opengles.GL10;
    
    import android.app.Activity;
    import android.content.Context;
    import android.opengl.*;
    
    public class OpenGLES20Activity extends Activity {
    
        private GLSurfaceView mGLView;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            // Create a GLSurfaceView instance and set it
            // as the ContentView for this Activity.
            mGLView = new MyGLSurfaceView(this);
            setContentView(mGLView);
        }
    }
    
    class MyGLSurfaceView extends GLSurfaceView {
    
        private final MyGLRenderer mRenderer;
    
        public MyGLSurfaceView(Context context){
            super(context);
    
            // Create an OpenGL ES 2.0 context
            setEGLContextClientVersion(2);
            //setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
    
            mRenderer = new MyGLRenderer();
    
            // Set the Renderer for drawing on the GLSurfaceView
            setRenderer(mRenderer);
        }
    
        private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
        private float mPreviousX;
        private float mPreviousY;
    
        @Override
        public boolean onTouchEvent(MotionEvent e) {
            // MotionEvent reports input details from the touch screen
            // and other input controls. In this case, you are only
            // interested in events where the touch position changed.
    
            float x = e.getX();
            float y = e.getY();
    
            switch (e.getAction()) {
                case MotionEvent.ACTION_MOVE:
    
                    float dx = x - mPreviousX;
                    float dy = y - mPreviousY;
    
                    // reverse direction of rotation above the mid-line
                    if (y > getHeight() / 2) {
                      dx = dx * -1 ;
                    }
    
                    // reverse direction of rotation to left of the mid-line
                    if (x < getWidth() / 2) {
                      dy = dy * -1 ;
                    }
    
                    mRenderer.setAngle(
                            mRenderer.getAngle() +
                            ((dx + dy) * TOUCH_SCALE_FACTOR));
                    requestRender();
            }
    
            mPreviousX = x;
            mPreviousY = y;
            return true;
        }
    }
    
  • MyGLRenderer.java

    package com.example.androiddeveloper;
    
    import javax.microedition.khronos.opengles.GL10;
    
    import android.opengl.GLES20;
    import android.opengl.GLSurfaceView;
    import android.opengl.Matrix;
    import android.os.SystemClock;
    
    public class MyGLRenderer implements GLSurfaceView.Renderer {
    
        private Triangle mTriangle;
    
        private final float[] mMVPMatrix = new float[16];
        private final float[] mProjectionMatrix = new float[16];
        private final float[] mViewMatrix = new float[16];
    
    
        public void onSurfaceCreated(GL10 unused, javax.microedition.khronos.egl.EGLConfig config) {
            // Set the background frame color
            GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    
            mTriangle = new Triangle();
        }
    
        private float[] mRotationMatrix = new float[16];
        public void onDrawFrame(GL10 unused) {
            float[] scratch = new float[16];
            long time = SystemClock.uptimeMillis() % 4000L;
            float angle = 0.090f * ((int) time);
            Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);
    
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    
            Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
            Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
    
    
            Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
    
            mTriangle.draw(scratch);
        }
    
        public void onSurfaceChanged(GL10 unused, int width, int height) {
            GLES20.glViewport(0, 0, width, height);
    
    
    
            float ratio = (float) width / height;
            Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
        }
    
        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 volatile float mAngle;
    
        public float getAngle() {
            return mAngle;
        }
    
        public void setAngle(float angle) {
            mAngle = angle;
        }
    }
    
  • Triangle.java

    package com.example.androiddeveloper;
    
    import java.nio.ByteBuffer;
    import java.nio.ByteOrder;
    import java.nio.FloatBuffer;
    
    import android.opengl.GLES20;
    
    public class Triangle {
    
        private FloatBuffer vertexBuffer;
    
        // number of coordinates per vertex in this array
        static final int COORDS_PER_VERTEX = 3;
        static float triangleCoords[] = {   // in counterclockwise order:
                 0.0f,  0.622008459f, 0.0f, // top
                -0.5f, -0.311004243f, 0.0f, // bottom left
                 0.5f, -0.311004243f, 0.0f  // bottom right
        };
    
        // Set color with red, green, blue and alpha (opacity) values
        float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
    
        private final int mProgram;
    
    
        public Triangle() {
            // initialize vertex byte buffer for shape coordinates
            ByteBuffer bb = ByteBuffer.allocateDirect(
                    // (number of coordinate values * 4 bytes per float)
                    triangleCoords.length * 4);
            // use the device hardware's native byte order
            bb.order(ByteOrder.nativeOrder());
    
            // create a floating point buffer from the ByteBuffer
            vertexBuffer = bb.asFloatBuffer();
            // add the coordinates to the FloatBuffer
            vertexBuffer.put(triangleCoords);
            // set the buffer to read the first coordinate
            vertexBuffer.position(0);
    
            int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
                    vertexShaderCode);
            int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
                            fragmentShaderCode);
    
            // create empty OpenGL ES Program
            mProgram = GLES20.glCreateProgram();
    
            // add the vertex shader to program
            GLES20.glAttachShader(mProgram, vertexShader);
    
            // add the fragment shader to program
            GLES20.glAttachShader(mProgram, fragmentShader);
    
            // creates OpenGL ES program executables
            GLES20.glLinkProgram(mProgram);
        }
    
        private final String vertexShaderCode =
            "uniform mat4 uMVPMatrix;" +
            "attribute vec4 vPosition;" +
            "void main() {" +
            "  gl_Position = uMVPMatrix * vPosition;" +
            "}";
    
        private final String fragmentShaderCode =
            "precision mediump float;" +
            "uniform vec4 vColor;" +
            "void main() {" +
            "  gl_FragColor = vColor;" +
            "}";
    
        private int mPositionHandle;
        private int mColorHandle;
    
        private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
        private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
    
        private int mMVPMatrixHandle;
    
        public void draw(float[] mvpMatrix) {
            // Add program to OpenGL ES environment
            GLES20.glUseProgram(mProgram);
    
            // get handle to vertex shader's vPosition member
            mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
    
            // Enable a handle to the triangle vertices
            GLES20.glEnableVertexAttribArray(mPositionHandle);
    
            // Prepare the triangle coordinate data
            GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                                         GLES20.GL_FLOAT, false,
                                         vertexStride, vertexBuffer);
    
            // get handle to fragment shader's vColor member
            mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
    
            // Set color for drawing the triangle
            GLES20.glUniform4fv(mColorHandle, 1, color, 0);
    
            mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
            GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
    
            // Draw the triangle
            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
    
            // Disable vertex array
            GLES20.glDisableVertexAttribArray(mPositionHandle);
        }
    }
    

作者Focustc,来自于 CSDN
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值