open glHelloWorld之旋转的三角形(android)

来源:互联网 发布:淘宝图库 编辑:程序博客网 时间:2024/06/07 23:52

       这两天在看open GL相关的东西,很多人都感觉有点高深莫测,包括自己对他也有些敬畏了。准备花一点时间,好好研究下。

       就当是Hello World,上代码,大家来看看,其实有很多自己目前也不是太懂,先上代码分享下,如果大家有什么意见和建议,也记得给我评论和分享下哈...


      下面代码是基于android的,不是Unity,也不是C++,笔者技术比较偏于android,故,希望大家不要介意哈,其实应该都差不多吧~


运行后效果描述:

                              

                          这是动态图,沿z轴正方向旋转。



代码一(FirstGLActivity):

public class FirstGLActivity extends Activity {    MyTDView mView;    public void onCreate(Bundle savedInstanceState){        super.onCreate(savedInstanceState);        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);        mView = new MyTDView(this);        mView.requestFocus();        mView.setFocusableInTouchMode(true);        setContentView(mView);    }    public void onResume(){        super.onResume();        mView.onResume();    }    public void onPause(){        super.onPause();        mView.onPause();    }}


代码二(MyTDView):

package com.clark.gldemo;import android.content.Context;import android.opengl.GLES20;import android.opengl.GLSurfaceView;import android.opengl.Matrix;import com.clark.matrix.Triangle;import javax.microedition.khronos.egl.EGLConfig;import javax.microedition.khronos.opengles.GL10;public class MyTDView extends GLSurfaceView {    //每次三角形旋转的角度    final float ANGLE_SPAN = 0.375f;    //自定义线程类RotateThread的引用    RotateThread rotateThread;    //自定义渲染器的引用    SceneRenderer mRenderer;    private class SceneRenderer implements  GLSurfaceView.Renderer{        Triangle tie;//声明Triangle的引用        @Override        public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {            GLES20.glClearColor(0,0,0,1.0f);//设置屏幕背景色            tie = new Triangle(MyTDView.this);//创建Triangle类的对象            GLES20.glEnable(GLES20.GL_DEPTH_TEST);            rotateThread = new RotateThread();//创建RotateThread对象            rotateThread.start();//开启线程        }        @Override        public void onSurfaceChanged(GL10 gl10, int width, int height) {            GLES20.glViewport(0,0,width,height);//设置视口            float ratio = (float) width/height;//计算屏幕的宽度和高度比例            Matrix.frustumM(Triangle.mProjMatrix,0,-ratio,ratio,-1,1,1,10);//设置透视投影            Matrix.setLookAtM(Triangle.mVMatrix,0,0,0,3,0f,0f,0f,0f,1.0f,0.0f);//设置摄像机        }        @Override        public void onDrawFrame(GL10 gl10) {            GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT| GLES20.GL_COLOR_BUFFER_BIT);            tie.drawSelf();//通过Triangle的对象调用drawSelf绘制三角形        }    }    public MyTDView(Context context) {        super(context);        this.setEGLContextClientVersion(2);//使用open GL ES2.0需要该设置该值为2        mRenderer = new SceneRenderer();//创建SceneRenderer类的对象        this.setRenderer(mRenderer);//设置渲染器        this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);    }    /**     * 自定义内部类线程     */    public class RotateThread extends Thread{        public boolean flag = true;//设置循环标志位        public void run(){            while(flag){                mRenderer.tie.xAngle = mRenderer.tie.xAngle + ANGLE_SPAN;                try {                    Thread.sleep(20);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }}


代码三(Triangle):

package com.clark.matrix;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;import android.opengl.GLES20;import android.opengl.Matrix;import com.clark.gldemo.MyTDView;import com.clark.utils.ShadeUtil;//三角形public class Triangle{    public static float[] mProjMatrix = new float[16];//4x4矩阵 投影用    public static float[] mVMatrix = new float[16];//摄像机位置朝向9参数矩阵    public static float[] mMVPMatrix;//最后起作用的总变换矩阵    int mProgram;//自定义渲染管线程序id    int muMVPMatrixHandle;//总变换矩阵引用id    int maPositionHandle; //顶点位置属性引用id    int maColorHandle; //顶点颜色属性引用id    String mVertexShader;//顶点着色器    String mFragmentShader;//片元着色器    static float[] mMMatrix = new float[16];//具体物体的移动旋转矩阵,旋转、平移    FloatBuffer   mVertexBuffer;//顶点坐标数据缓冲    FloatBuffer   mColorBuffer;//顶点着色数据缓冲    int vCount=0;    public float xAngle=0;//绕x轴旋转的角度    public Triangle(MyTDView mv)    {        //初始化顶点坐标与着色数据        initVertexData();        //初始化shader        initShader(mv);    }    public void initVertexData() {        //顶点坐标数据的初始化        vCount=3;        final float UNIT_SIZE=0.2f;        float vertices[]=new float[]                {                        -4*UNIT_SIZE,0,                        0,0,-4*UNIT_SIZE,                        0,4*UNIT_SIZE,0,0                };        ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);        vbb.order(ByteOrder.nativeOrder());        mVertexBuffer = vbb.asFloatBuffer();        mVertexBuffer.put(vertices);        mVertexBuffer.position(0);        float colors[]=new float[]{                        1,1,1,0,                        0,0,1,0,                        0,1,0,0                };        ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4);        cbb.order(ByteOrder.nativeOrder());        mColorBuffer = cbb.asFloatBuffer();        mColorBuffer.put(colors);        mColorBuffer.position(0);    }    //初始化shader    public void initShader(MyTDView mv){        //加载顶点着色器的脚本内容        mVertexShader=ShadeUtil.loadFromAssetsFile("vertex.sh", mv.getResources());        //加载片元着色器的脚本内容        mFragmentShader= ShadeUtil.loadFromAssetsFile("frag.sh", mv.getResources());        //基于顶点着色器与片元着色器创建程序        mProgram = ShadeUtil.createProgram(mVertexShader, mFragmentShader);        //获取程序中顶点位置属性引用id        maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");        //获取程序中顶点颜色属性引用id        maColorHandle= GLES20.glGetAttribLocation(mProgram, "aColor");        //获取程序中总变换矩阵引用id        muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");    }    public void drawSelf()    {        //制定使用某套shader程序        GLES20.glUseProgram(mProgram);        //初始化变换矩阵        Matrix.setRotateM(mMMatrix,0,0,0,1,0);        //设置沿Z轴正向位移1        Matrix.translateM(mMMatrix,0,0,0,1);        //设置绕x轴旋转        Matrix.rotateM(mMMatrix,0,xAngle,1,0,0);        //        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, Triangle.getFinalMatrix(mMMatrix), 0);        //为画笔指定顶点位置数据        GLES20.glVertexAttribPointer(                maPositionHandle,                3,                GLES20.GL_FLOAT,                false,                3*4,                mVertexBuffer        );        GLES20.glVertexAttribPointer                (                        maColorHandle,                        4,                        GLES20.GL_FLOAT,                        false,                        4*4,                        mColorBuffer                );        //允许顶点位置数据数组        GLES20.glEnableVertexAttribArray(maPositionHandle);        GLES20.glEnableVertexAttribArray(maColorHandle);        //绘制三角形        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);    }    public static float[] getFinalMatrix(float[] spec)    {        mMVPMatrix=new float[16];        Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, spec, 0);        Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);        return mMVPMatrix;    }}

代码四(ShadeUtil):

package com.clark.utils;import android.content.res.Resources;import android.opengl.GLES20;import android.util.Log;import java.io.ByteArrayOutputStream;import java.io.InputStream;/** * 加载顶点和片元着色器的类 */public class ShadeUtil {    private static final String GLES_ERROR = "ES_20_ERROR";    /**     * 加载着色器方法     * @param shaderType 着色器类型     * @param source 着色器的脚本字符串     * @return 着色器id -- 0 错误   其他 成功     */    public static int loadShader(int shaderType,String source){        //创建着色器        int shader = GLES20.glCreateShader(shaderType);        //创建成功        if(shader != 0){            GLES20.glShaderSource(shader,source);            GLES20.glCompileShader(shader);            int[] compiled = new int[1];            //编译着色器            GLES20.glGetShaderiv(shader,GLES20.GL_COMPILE_STATUS,compiled,0);            //编译失败            if(compiled[0] == 0){                Log.e(GLES_ERROR,"Could not compile shader " + shaderType + ";");                Log.e(GLES_ERROR,GLES20.glGetShaderInfoLog(shader));                GLES20.glDeleteShader(shader);                shader = 0;            }        }        return shader;    }    /**     * 创建着色器程序的方法     * @param vertexSource 顶点着色器资源     * @param frgmentSource 片元着色器资源     * @return 着色器程序结果 0-失败  其他-成功     */    public static int createProgram(String vertexSource,String frgmentSource){        //加载顶点着色器        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,vertexSource);        if(vertexShader == 0){            return 0;        }        //加载片元着色器        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER,frgmentSource);        if(pixelShader == 0){            return 0;        }        //GPU 加载完毕        //创建着色器程序        int program = GLES20.glCreateProgram();        //程序创建成功,则向程序中加入顶点着色器和片元着色器        if(program != 0){            //加入顶点着色器            GLES20.glAttachShader(program,vertexShader);            checkGLError("glAttachShader");            //加入片元着色器            GLES20.glAttachShader(program,pixelShader);            checkGLError("glAtaachShader");            //链接程序            GLES20.glLinkProgram(program);            int [] linkStatus = new int [1];            GLES20.glGetProgramiv(program,GLES20.GL_LINK_STATUS,linkStatus,0);            //链接失败,删除程序            if(linkStatus[0] != GLES20.GL_TRUE){                Log.e(GLES_ERROR,"Could not link program:");                Log.e(GLES_ERROR,GLES20.glGetProgramInfoLog(program));                GLES20.glDeleteProgram(program);                program = 0;            }        }        return program;    }    /**     * 检查每一步操作是否有错误方法     * @param op 错误原因     */    public static void checkGLError(String op){        int error;        while((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR){            Log.e(GLES_ERROR,op+": glError:" + error);            throw new RuntimeException(op+": glError:" + error);        }    }    /**     * 从sh脚本加载着色器内容的方法     * @param fname assets下文件的名字     * @param r 资源     * @return 着色器内容文本     */    public static String loadFromAssetsFile(String fname,Resources r){        String result = null;        try{            InputStream in = r.getAssets().open(fname);            int ch = 0;            ByteArrayOutputStream baos = new ByteArrayOutputStream();            while((ch = in.read()) != -1){                baos.write(ch);            }            byte[] buff = baos.toByteArray();            baos.close();            in.close();            result = new String(buff,"UTF-8");            result = result.replaceAll("\\r\\n","\n");        }catch(Exception e){            e.printStackTrace();        }        return result;    }}

在assets/vetex.sh中添加顶点着色器代码:

uniform mat4 uMVPMatrix;//总变换矩阵attribute vec3 aPosition;//顶点位置attribute vec4 aColor;//顶点颜色varying  vec4 vColor;//用于传给片元着色器的易变变量void main()     {   gl_Position = uMVPMatrix * vec4(aPosition,1);//根据总变换矩阵计算此次绘制此顶点的位置   vColor = aColor;//接收的顶点颜色传递给片元着色器}                      


在assets/frag.sh中添加颜色着色器代码:

precision mediump float;varying  vec4 vColor;//接收从顶点着色器过来的易变变量void main(){   gl_FragColor = vColor;}


今天时间已晚,仅上代码。大家先看代码,看不懂可以根据我写的注释看下。后面会解析。当然也非常希望高手评论分享下自己学习的心得哈。





ps,记得打赏哦~~~

                                        



0 0
原创粉丝点击