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

49 篇文章 15 订阅
本文详细介绍了OpenGL中的纹理概念,通过一个实例演示如何使用纹理坐标和顶点坐标来为旋转立方体添加纹理。涉及关键知识点包括纹理与渐变色的区别、纹理坐标的作用以及如何在MyRender类中实现纹理贴图的绘制。
摘要由CSDN通过智能技术生成

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);
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图王大胜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值