栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android APP OpenGL ES应用(02)GLSurfaceView 纹理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android APP OpenGL ES应用(02)GLSurfaceView 纹理

1 纹理解读

关于OpenGL基础内容以及更多了解可关注 系列文章:专题分纲目录 OpenGL教程。

@1 纹理概念:纹理是一种图形数据,用于包装不同的物体,就像衣服一样,衣服的各种展示样式就是我们所说的纹理。

@2 纹理与渐变色:

渐变色:光栅化过程中,计算出颜色值,然后在fragment shader中赋值。纹理:光栅化过程中,计算出当前片段在纹理上的坐标,然后在fragment shader中根据纹理坐标获取相应的颜色值。

@3 纹理坐标(也叫ST纹理坐标 或 UV坐标)与顶点坐标的对比:

顶点坐标 & 纹理坐标 草图

@4 顶点坐标 & 立方体面数组 & 面纹理坐标

他们的关系可以参照文章:Android OpenGL ES顶点坐标、纹理贴图坐标设置

2 纹理实战 带纹理的旋转立方体

实现功能:效果如下所示(绕(1,1)向量轴旋转):

关于该程序,自定义MyRender的代码实现如下所示:

class MyRender implements GLSurfaceView.Renderer {
    private static final float OFFSET = 0.5f;
    // 立方体的顶点坐标(一共是24个顶点,组成12个三角形)
    private float[] cubeVertices = {
            -OFFSET, -OFFSET, OFFSET, OFFSET, -OFFSET, OFFSET, OFFSET, OFFSET, OFFSET, -OFFSET, OFFSET, OFFSET,    //2103,前
            -OFFSET, -OFFSET, -OFFSET, -OFFSET, OFFSET, -OFFSET, OFFSET, OFFSET, -OFFSET, OFFSET, -OFFSET, -OFFSET,//6745,后
            -OFFSET, OFFSET, OFFSET, OFFSET, OFFSET, OFFSET, OFFSET, OFFSET, -OFFSET, -OFFSET, OFFSET, -OFFSET,    //3047,上
            -OFFSET, -OFFSET, OFFSET, -OFFSET, -OFFSET, -OFFSET, OFFSET, -OFFSET, -OFFSET,OFFSET, -OFFSET,OFFSET,  //2651,下  
            -OFFSET, -OFFSET, -OFFSET, -OFFSET, -OFFSET, OFFSET, -OFFSET, OFFSET, OFFSET, -OFFSET, OFFSET, -OFFSET,//6237,左
            OFFSET, -OFFSET, -OFFSET, OFFSET, OFFSET, -OFFSET, OFFSET, OFFSET, OFFSET, OFFSET, -OFFSET, OFFSET,   //5401,右
    };

    // 立方体6个面 位置
    private byte[] cubeFacets = {
            0, 1, 3, 2,     //前
            4, 5, 7, 6,     //后
            8, 9, 11, 10,   //上
            15, 12,14,13,   //下
            16, 17, 19, 18, //左
            20, 21, 23, 22, //右
    };

    // 纹理贴图坐标 6组,每组4个坐标(uv)
    private float[] cubeTextures = {
            0.0000f, 1.0000f, 1.0000f, 1.0000f, 1.0000f, 0.0000f, 0.0000f, 0.0000f,//前
            0.0000f, 1.0000f, 0.0000f, 0.0000f, 1.0000f, 0.0000f, 1.0000f, 1.0000f,//后
            0.0000f, 1.0000f, 1.0000f, 1.0000f, 1.0000f, 0.0000f, 0.0000f, 0.0000f,//上
            0.0000f, 0.0000f, 1.0000f, 0.0000f, 1.0000f, 1.0000f, 0.0000f, 1.0000f,//下
            0.0000f, 1.0000f, 1.0000f, 1.0000f, 1.0000f, 0.0000f, 0.0000f, 0.0000f,//左
            1.0000f, 1.0000f, 1.0000f, 0.0000f, 0.0000f, 0.0000f, 0.0000f, 1.0000f,//右
    };

    // 定义Open GL ES绘制所需要的Buffer对象
    FloatBuffer cubeVerticesBuffer;
    ByteBuffer cubeFacetsBuffer;
    private FloatBuffer cubeTexturesBuffer;
    private float rotate = 0.0f;
    private Context mContext;

    public MyRender(Context context){
        cubeVerticesBuffer = BufferUtil.floatBufferUtil(cubeVertices);
        cubeFacetsBuffer = ByteBuffer.wrap(cubeFacets);
        cubeTexturesBuffer = BufferUtil.floatBufferUtil(cubeTextures);
        mContext = context;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        gl.glDisable(GL10.GL_DITHER);//关闭防抖
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_FASTEST);//设置透视修正
        gl.glClearColor(0, 0, 0, 0);
        gl.glShadeModel(GL10.GL_SMOOTH);//设置为阴影平滑模式
        gl.glEnable(GL10.GL_DEPTH_TEST);//启用深度测试
        gl.glDepthFunc(GL10.GL_LEQUAL); //设置深度测试的类型
        gl.glEnable(GL10.GL_TEXTURE_2D);//启用2D纹理贴图
        BufferUtil.loadTexture(mContext,gl);//装载纹理
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        gl.glViewport(0, 0, width, height); //设置3D视窗的大小及位置
        gl.glMatrixMode(GL10.GL_PROJECTION); //设置矩阵模式设为投影矩阵
        gl.glLoadIdentity(); //初始化单位矩阵
        float ratio = (float) width / height; //计算视窗宽高比
        gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);//设置视窗空间大小
    }

    @Override
    public void onDrawframe(GL10 gl) {
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);//启用vertex shader 数据
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); //启用贴图坐标数组数据
        gl.glMatrixMode(GL10.GL_MODELVIEW);//设置当前矩阵堆栈为模型堆栈

        gl.glLoadIdentity();
        gl.glTranslatef(0.0f, 0.0f, -4f);
        gl.glRotatef(rotate, 1.0f, 1.0f, 0.0f); //沿着(1,1)向量为轴的方向旋转
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, cubeVerticesBuffer);//设置顶点的位置数据
        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, cubeTexturesBuffer);//设置贴图的坐标数据
        // 按cubeFacetsBuffer指定的面绘制三角形gl.glDrawElements(GL10.GL_TRIANGLE_STRIP,cubeFacetsBuffer.remaining(),GL10.GL_UNSIGNED_BYTE, cubeFacetsBuffer);

        gl.glFinish();//绘制结束
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        rotate+=1;
    }
}

代码中涉及到的工具类 BufferUtil 代码实现如下:

public class BufferUtil {
    //将int[]数组转换为OpenGLES所需的IntBuffer
    public static IntBuffer intBufferUtil(int[] arr)
    {
        IntBuffer buffer;
        // 初始化ByteBuffer,长度为arr数组的长度*4,因为一个int占4字节
        ByteBuffer bb = ByteBuffer.allocateDirect(arr.length * 4);
        bb.order(ByteOrder.nativeOrder()); //数组排列用nativeOrder
        buffer = bb.asIntBuffer();
        buffer.put(arr);
        buffer.position(0);
        return buffer;
    }

    //将float[]数组转换为OpenGLES所需的FloatBuffer
    public static FloatBuffer floatBufferUtil(float[] arr)
    {
        FloatBuffer buffer;
        //初始化ByteBuffer,长度为arr数组的长度*4,因为一个float占4字节
        ByteBuffer bb = ByteBuffer.allocateDirect(arr.length * 4);
        bb.order(ByteOrder.nativeOrder());
        buffer = bb.asFloatBuffer();
        buffer.put(arr);
        buffer.position(0);
        return buffer;
    }

    public static int loadTexture(Context context, GL10 gl)
    {
        Bitmap bitmap = null;
        int texture = 0;
        try
        {
            // 加载位图
            InputStream isImage = null;
            try {
                isImage = context.getAssets().open("sand.png");
            } catch (IOException e) {
                e.printStackTrace();
            }
            bitmap = BitmapFactory.decodeStream(isImage);

            int[] textures = new int[1];
            // 指定生成N个纹理(第一个参数指定生成一个纹理),这里textures数组将负责存储所有纹理的代号
            gl.glGenTextures(1, textures, 0);
            // 获取textures纹理数组中的第一个纹理
            texture = textures[0];
            // 绑定纹理到GL10.GL_TEXTURE_2D目标中
            gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);
            gl.glTexParameterf(GL10.GL_TEXTURE_2D,
                    GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
            gl.glTexParameterf(GL10.GL_TEXTURE_2D,
                    GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
            // 设置横向/纵向为平铺纹理
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
                    GL10.GL_REPEAT);
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
                    GL10.GL_REPEAT);
            // 生成纹理
            GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
        }finally {
            if (bitmap != null) //生成纹理之后,回收位图
                bitmap.recycle();
        }
        return texture;
    }
}

注意:这里的资源是放在asset文件夹下的,可以根据自己的需要更改bitmap和对应的纹理图片。在MainActivity中实现代码为:

public class MainActivity extends AppCompatActivity  {
    private static String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        GLSurfaceView glSurfaceView = new GLSurfaceView(this);
        MyRender myRender = new MyRender();
        glSurfaceView.setRenderer(myRender);
        setContentView(glSurfaceView);
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/735368.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号