opengles之展翅飞翔的雄鹰

效果图:




核心看 顶点 shader的实现

uniform mat4 uMVPMatrix; //总变换矩阵
attribute vec3 aPosition;  //顶点位置 来自1号关键帧
attribute vec3 bPosition;  //顶点位置 来自2号关键帧
attribute vec3 cPosition;  //顶点位置 来自3号关键帧
attribute vec2 aTexCoor;    //顶点纹理坐标
uniform float uBfb;//融合比例
varying vec2 vTextureCoord;

void main()
{
 	vec3 tv;
   if(uBfb<=1.0)//若融合比例小于1,则需要执行的是1,2号关键帧的融合
   {
   		tv=mix(aPosition,bPosition,uBfb);//mix(x,y,z) x,y的线性混叠,x(1-a)+y*a;
   }
   else //若融合比例大于1,则需要执行的是2,3号关键帧的融合
   {
   		tv=mix(bPosition,cPosition,uBfb-1.0);
   }
   gl_Position = uMVPMatrix * vec4(tv,1);
   vTextureCoord = aTexCoor;//将接收的纹理坐标传递给片元着色器
}

package test.com.opengles_zcfxdxy;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import android.opengl.GLES20;
/**
 * Created by hbin on 2016/11/3.
 * //加载后的物体——仅携带顶点信息,颜色随机
 */

public class GledeForDraw {
    int mProgram;//自定义渲染管线着色器程序id
    int muMVPMatrixHandle;//总变换矩阵引用
    int maPositionHandle1; //顶点位置属性引用
    int maPositionHandle2; //顶点位置属性引用
    int maPositionHandle3; //顶点位置属性引用
    int maTexCoorHandle; //顶点纹理坐标属性引用
    int muBfbHandle;//变化百分比引用
    String mVertexShader;//顶点着色器代码脚本
    String mFragmentShader;//片元着色器代码脚本

    FloatBuffer   mVertexBuffer1;//顶点坐标数据缓冲
    FloatBuffer   mVertexBuffer2;//顶点坐标数据缓冲
    FloatBuffer   mVertexBuffer3;//顶点坐标数据缓冲
    FloatBuffer   mTexCoorBuffer;//顶点纹理坐标数据缓冲

    float[][] glede_one;
    float[] glede_two;
    float[] glede_three;

    int vCount=0;

    int operator=1;
    float span=0.15f;
    float bfbCurr=0f;

    public GledeForDraw(MySurfaceView mv)
    {
        //初始化顶点坐标与着色数据
        initVertexData(mv);
        //初始化shader
        intShader(mv);
        new Thread()
        {
            @Override
            public void run()
            {
                while(true)
                {
                    bfbCurr=bfbCurr+operator*span;
                    if(bfbCurr>2.0f)
                    {
                        bfbCurr=2.0f;
                        operator=-operator;
                    }
                    else if(bfbCurr<0)
                    {
                        bfbCurr=0;
                        operator=-operator;
                    }
                    try
                    {
                        Thread.sleep(50);
                    }
                    catch(Exception e)
                    {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

    //初始化顶点坐标与着色数据的方法
    public void initVertexData(MySurfaceView mv)
    {
        glede_one=LoadUtil.loadFromFileVertexOnly("laoying01.obj",mv);
        glede_two=LoadUtil.loadFromFileVertexOnly("laoying02.obj",mv)[0];
        glede_three=LoadUtil.loadFromFileVertexOnly("laoying03.obj",mv)[0];

        //========================1=========================================
        vCount=glede_one.length/3;
        //创建顶点坐标数据缓冲
        //vertices.length*4是因为一个整数四个字节
        ByteBuffer vbb = ByteBuffer.allocateDirect(glede_one[0].length*4);
        vbb.order(ByteOrder.nativeOrder());//设置字节顺序
        mVertexBuffer1 = vbb.asFloatBuffer();//转换为Float型缓冲
        mVertexBuffer1.put(glede_one[0]);//向缓冲区中放入顶点坐标数据
        mVertexBuffer1.position(0);//设置缓冲区起始位置
        //====================2==========================
        vCount=glede_two.length/3;
        //创建顶点坐标数据缓冲
        //vertices.length*4是因为一个整数四个字节
        vbb = ByteBuffer.allocateDirect(glede_two.length*4);
        vbb.order(ByteOrder.nativeOrder());//设置字节顺序
        mVertexBuffer2 = vbb.asFloatBuffer();//转换为Float型缓冲
        mVertexBuffer2.put(glede_two);//向缓冲区中放入顶点坐标数据
        mVertexBuffer2.position(0);//设置缓冲区起始位置
        //---------------------------------3-----------------------------
        vCount=glede_three.length/3;
        //创建顶点坐标数据缓冲
        //vertices.length*4是因为一个整数四个字节
        vbb = ByteBuffer.allocateDirect(glede_three.length*4);
        vbb.order(ByteOrder.nativeOrder());//设置字节顺序
        mVertexBuffer3 = vbb.asFloatBuffer();//转换为Float型缓冲
        mVertexBuffer3.put(glede_three);//向缓冲区中放入顶点坐标数据
        mVertexBuffer3.position(0);//设置缓冲区起始位置

        //------------------纹理-----------------------------------------
        ByteBuffer tbb = ByteBuffer.allocateDirect(glede_one[1].length*4);
        tbb.order(ByteOrder.nativeOrder());//设置字节顺序
        mTexCoorBuffer = tbb.asFloatBuffer();//转换为Float型缓冲
        mTexCoorBuffer.put(glede_one[1]);//向缓冲区中放入顶点纹理坐标数据
        mTexCoorBuffer.position(0);//设置缓冲区起始位置
        //特别提示:由于不同平台字节顺序不同数据单元不是字节的一定要经过ByteBuffer
        //转换,关键是要通过ByteOrder设置nativeOrder(),否则有可能会出问题
        //顶点纹理坐标数据的初始化================end============================
    }
    //初始化shader
    public void intShader(MySurfaceView mv)
    {
        //加载顶点着色器的脚本内容
        mVertexShader=ShaderUtil.loadFromAssetsFile("vertex.sh", mv.getResources());
        //加载片元着色器的脚本内容
        mFragmentShader=ShaderUtil.loadFromAssetsFile("frag.sh", mv.getResources());
        //基于顶点着色器与片元着色器创建程序
        mProgram = ShaderUtil.createProgram(mVertexShader, mFragmentShader);
        //获取程序中顶点位置属性引用
        maPositionHandle1 = GLES20.glGetAttribLocation(mProgram, "aPosition");
        maPositionHandle2 = GLES20.glGetAttribLocation(mProgram, "bPosition");
        maPositionHandle3 = GLES20.glGetAttribLocation(mProgram, "cPosition");
        //获取程序中总变换矩阵引用
        muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
        //获取程序中顶点纹理坐标属性引用
        maTexCoorHandle= GLES20.glGetAttribLocation(mProgram, "aTexCoor");
        //变化百分比引用
        muBfbHandle= GLES20.glGetUniformLocation(mProgram, "uBfb");
    }

    public void drawSelf(int texId)
    {
        //制定使用某套shader程序
        GLES20.glUseProgram(mProgram);
        //将最终变换矩阵传入shader程序
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0);
        //将变化百分比传入shader程序
        GLES20.glUniform1f(muBfbHandle, bfbCurr);
        System.out.println(bfbCurr);
        //将顶点位置数据
        GLES20.glVertexAttribPointer
                (
                        maPositionHandle1,
                        3,
                        GLES20.GL_FLOAT,
                        false,
                        3*4,
                        mVertexBuffer1
                );
        //将顶点位置数据
        GLES20.glVertexAttribPointer
                (
                        maPositionHandle2,
                        3,
                        GLES20.GL_FLOAT,
                        false,
                        3*4,
                        mVertexBuffer2
                );
        //将顶点位置数据传入渲染管线
        GLES20.glVertexAttribPointer
                (
                        maPositionHandle3,
                        3,
                        GLES20.GL_FLOAT,
                        false,
                        3*4,
                        mVertexBuffer3
                );
        //将顶点纹理坐标数据传入渲染管线
        GLES20.glVertexAttribPointer
                (
                        maTexCoorHandle,
                        2,
                        GLES20.GL_FLOAT,
                        false,
                        2*4,
                        mTexCoorBuffer
                );
        //启用顶点位置、法向量、纹理坐标数据
        GLES20.glEnableVertexAttribArray(maPositionHandle1);
        GLES20.glEnableVertexAttribArray(maPositionHandle2);
        GLES20.glEnableVertexAttribArray(maPositionHandle3);
        GLES20.glEnableVertexAttribArray(maTexCoorHandle);
        //绑定纹理
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId);
        //绘制加载的物体
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
    }
}

package test.com.opengles_zcfxdxy;
import java.io.IOException;
import java.io.InputStream;

import android.opengl.GLSurfaceView;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.view.MotionEvent;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
/**
 * Created by hbin on 2016/11/3.
 */

public class MySurfaceView extends GLSurfaceView{
    private final float TOUCH_SCALE_FACTOR = 180.0f/320;//角度缩放比例
    private SceneRenderer mRenderer;//场景渲染器

    private float mPreviousY;//上次的触控位置Y坐标
    private float mPreviousX;//上次的触控位置X坐标

    int textureId;//系统分配的纹理id
    public MySurfaceView(Context context) {
        super(context);
        this.setEGLContextClientVersion(2); //设置使用OPENGL ES2.0
        mRenderer = new SceneRenderer();	//创建场景渲染器
        setRenderer(mRenderer);				//设置渲染器
        setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);//设置渲染模式为主动渲染
        this.setKeepScreenOn(true);
    }

    //触摸事件回调方法
    @Override
    public boolean onTouchEvent(MotionEvent e){
        float y=e.getY();
        float x=e.getX();
        switch (e.getAction()){
            case MotionEvent.ACTION_MOVE:
                float dy=y-mPreviousY;
                float dx=x-mPreviousX;
                mRenderer.yAngle+=dy*TOUCH_SCALE_FACTOR;
                mRenderer.zAngle+=dx*TOUCH_SCALE_FACTOR;
                requestRender();
        }
        mPreviousX=x;
        mPreviousY=y;
        return  true;
    }


    private class SceneRenderer implements  GLSurfaceView.Renderer{

        float yAngle;//绕Y轴旋转的角度
        float zAngle; //绕Z轴旋转的角度
        //从指定的obj文件中加载对象
        GledeForDraw glede1;

        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            //设置屏幕背景色RGBA
            GLES20.glClearColor(1.0f,1.0f,1.0f,1.0f);
            //打开深度检测
            GLES20.glEnable(GLES20.GL_DEPTH_TEST);
            //关闭背面剪裁
            GLES20.glDisable(GLES20.GL_CULL_FACE);
            //初始化变换矩阵
            MatrixState.setInitStack();

            glede1=new GledeForDraw(MySurfaceView.this);//创建雄鹰
            //加载纹理
            textureId=initTexture(R.mipmap.ttt);

        }

        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            //设置视窗大小及位置
            GLES20.glViewport(0, 0, width, height);
            //计算GLSurfaceView的宽高比
            float ratio = (float) width / height;
            //调用此方法计算产生透视投影矩阵
            MatrixState.setProjectFrustum(-ratio, ratio, -1, 1, 2, 100);
            //调用此方法产生摄像机9参数位置矩阵
            MatrixState.setCamera(0,0,0,0f,0f,-1f,0f,1.0f,0.0f);
        }

        @Override
        public void onDrawFrame(GL10 gl) {
            //清除深度缓冲与颜色缓冲
            GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);

            //坐标系推远
            MatrixState.pushMatrix();
            MatrixState.translate(0, -5f, -40f);
            //绕Y轴、Z轴旋转
            MatrixState.rotate(yAngle, 0, 1, 0);
            MatrixState.rotate(zAngle, 1, 0, 0);

            //若加载的物体部位空则绘制物体
            if(glede1!=null)
            {
                glede1.drawSelf(textureId);
            }
            MatrixState.popMatrix();
        }
    }

    public int initTexture(int drawableId)//textureId
    {
        //生成纹理ID
        int[] textures = new int[1];
        GLES20.glGenTextures
                (
                        1,          //产生的纹理id的数量
                        textures,   //纹理id的数组
                        0           //偏移量
                );
        int textureId=textures[0];
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_REPEAT);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_REPEAT);

        //通过输入流加载图片===============begin===================
        InputStream is = this.getResources().openRawResource(drawableId);
        Bitmap bitmapTmp;
        try
        {
            bitmapTmp = BitmapFactory.decodeStream(is);
        }
        finally
        {
            try
            {
                is.close();
            }
            catch(IOException e)
            {
                e.printStackTrace();
            }
        }
        //通过输入流加载图片===============end=====================

        //实际加载纹理
        GLUtils.texImage2D
                (
                        GLES20.GL_TEXTURE_2D,   //纹理类型,在OpenGL ES中必须为GL10.GL_TEXTURE_2D
                        0, 					  //纹理的层次,0表示基本图像层,可以理解为直接贴图
                        bitmapTmp, 			  //纹理图像
                        0					  //纹理边框尺寸
                );
        bitmapTmp.recycle(); 		  //纹理加载成功后释放图片
        return textureId;
    }
}
完整代码下载地址:

http://download.csdn.net/detail/hb707934728/9672038

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值