zoukankan      html  css  js  c++  java
  • 应用纹理贴图

    为了在OpenGL  ES中启用纹理贴图功能,可以在Renderer实现类的onSurfaceCreated(GL10  gl  ,  EGLConfig   config)方法中启动纹理贴图,例如如下代码:

    //启用2D纹理贴图
    gl.glEnable(GL10.GL_TEXTURE_2D);

    接下来就需要准备一张图片来作为纹理贴图了,建议改图片的长宽是2的N次方,把这张准备贴图的位图放在Android项目的/res/drawable-mdpi目录下,方便应用程序加载该图片资源。

    接下来程序开始加载该图片并生成对应的纹理贴图,例如如下方法:

    //加载位图
    bitmap = BitmapFactory.decodeResource(
    context.getResources(), R.drawable.sand);
    int[] textures = new int[1];
    //指定生成N个纹理(第一个参数指定生成1个纹理)
    //textures数组将负责存储所有纹理的代号
    gl.glGenTextures(1, textures , 0);
    //获取textures纹理数组中的第一个纹理
    texture = textures[0];
    //通知OpenGL将texture纹理绑定到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);

    上面的程序中用到了GL10的如下方法:

    glGenTextures(int  n , int[]  textures , int  offset):该方法指定一次性生成n个纹理,该方法所生成的纹理的代号放入其中textures数组中,offset指定从第几个数组元素开始存放纹理代号。

    glBindTexture(int  target , int  texture):该方法用于将texture纹理绑定到target目标上。

    glTeXParameterf(int  target  ,int  pname  , float  param):该方法用于为target纹理目标设置属性,其中第二个参数是属性名,第三个参数是属性值。程序设置了当纹理被放大时使用GL10.GL_LINEAR滤波方式;当纹理被缩小时使用GL10.GL_NEAREST滤波方式;一般来说,使用GL10.GL_LINEAR滤波方式有较好的效果,但系统开小略微大一些,具体采用哪种滤波方式则取决于目标机器本身的性能。

    上面代码的最后一行调用了GLUtils工具类的方法来加载指定位图,并根据位图来生成纹理,通过上面的代码即可得到一个用于贴图的纹理了。

    在3D绘制中进行纹理贴图与设置顶点颜色的步骤相似,只要三步:

    1、设置启用贴图坐标数组。

    2、设置贴图坐标的数组信息。

    3、调用GL10的glBindTexture(int  target , int  texture)方法执行贴图。

    下面的程序示范了如何为一个立方体进行贴图,而且这个程序提供了手势检测器,语允许用户通过手势来改变该立方体的角度。

    import java.nio.ByteBuffer;
    import java.nio.FloatBuffer;

    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.opengles.GL10;

    import android.opengl.GLSurfaceView;
    import android.opengl.GLSurfaceView.Renderer;
    import android.opengl.GLUtils;
    import android.os.Bundle;
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.view.GestureDetector;
    import android.view.GestureDetector.OnGestureListener;
    import android.view.Menu;
    import android.view.MotionEvent;

    public class Texture3D extends Activity implements OnGestureListener{
      //定义旋转角度
      private float anglex = 0f;
      private float angley = 0f;
      static final float ROTATE_FACTOR = 60;
      //定义手势检测器实例
      GestureDetector detector;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //创建一个GLSurfaceView,用于显示OpenGL绘制的图形
        GLSurfaceView glView = new GLSurfaceView(this);
        //创建GLSurfaceView的内容绘制器
        MyRenderer myRender = new MyRenderer(this);
        //为GLSurfaceView设置绘制器
        glView.setRenderer(myRender);
        setContentView(glView);
        //创建手势检测器
        detector = new GestureDetector(getApplicationContext(), this);
      }

      @Override
      public boolean onTouchEvent(MotionEvent event) {
        // 将该Activity上的触碰事件交给GestureDetector
        return detector.onTouchEvent(event);
      }

      @Override
      public boolean onDown(MotionEvent e) {
        return false;
      }

      @Override
      public void onShowPress(MotionEvent e) {
      }

      @Override
      public boolean onSingleTapUp(MotionEvent e) {
        return false;
      }

      @Override
      public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
                                    float distanceY) {
        return false;
      }

      @Override
      public void onLongPress(MotionEvent e) {
      }

      @Override
      public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                                              float velocityY) {
        velocityX = velocityX > 4000 ? 4000 : velocityX;
        velocityX = velocityX < -4000 ? -4000 : velocityX;
        velocityY = velocityX > 4000 ? 4000 : velocityY;
        velocityY = velocityX < -4000 ? -4000 : velocityY;
        //根据横向上的速度计算沿Y轴旋转的角度
        angley += velocityX * ROTATE_FACTOR / 4000;
        //根据纵向上的速度计算沿X轴旋转的角度
        anglex += velocityY * ROTATE_FACTOR / 4000;
        return true;
      }

      public class MyRenderer implements Renderer{
        //立方体的顶点坐标(一共是36个顶点,组成12个三角形)
        private float[] cubeVetices = {-0.6f,-0.6f,-0.6f,-0.6f,0.6f,
            -0.6f,0.6f,0.6f,-0.6f,0.6f,0.6f,-0.6f,0.6f,-0.6f,-0.6f,
            -0.6f,-0.6f,-0.6f,-0.6f,-0.6f,0.6f,0.6f,-0.6f,0.6f,0.6f,
            0.6f,0.6f,0.6f,0.6f,0.6f,-0.6f,0.6f,0.6f,-0.6f,-0.6f,
            0.6f,-0.6f,-0.6f,-0.6f,0.6f,-0.6f,-0.6f,0.6f,-0.6f,0.6f,
            0.6f,-0.6f,0.6f,-0.6f,-0.6f,0.6f,-0.6f,-0.6f,-0.6f,0.6f,
            -0.6f,-0.6f,0.6f,0.6f,-0.6f,0.6f,0.6f,0.6f,0.6f,0.6f,
            0.6f,0.6f,-0.6f,0.6f,0.6f,-0.6f,-0.6f,0.6f,0.6f,-0.6f,
            -0.6f,0.6f,-0.6f,-0.6f,0.6f,0.6f,-0.6f,0.6f,0.6f,0.6f,
            0.6f,0.6f,0.6f,0.6f,-0.6f,-0.6f,0.6f,-0.6f,-0.6f,-0.6f,
            -0.6f,-0.6f,-0.6f,0.6f,-0.6f,-0.6f,0.6f,-0.6f,0.6f,0.6f,
            0.6f,0.6f,0.6f};
        //定义立方体所需要的6个面(一共是12个三角形所需的顶点)
        private byte[] cubeFacets = {0,1,2,3,4,5,6,7,8,9,10,11,12,
            13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,
            30,31,32,33,34,35};
        //定义纹理贴图的坐标数据
        private float[] cubeTextures = {1.0000f,1.0000f,1.0000f,0.0000f,
            0.0000f,0.0000f,0.0000f,0.0000f,0.0000f,1.0000f,1.0000f,
            1.0000f,0.0000f,1.0000f,1.0000f,1.0000f,1.0000f,0.0000f,
            1.0000f,0.0000f,0.0000f,0.0000f,0.0000f,1.0000f,0.0000f,
            1.0000f,1.0000f,1.0000f,1.0000f,0.0000f,1.0000f,0.0000f,
            0.0000f,0.0000f,0.0000f,1.0000f,0.0000f,1.0000f,1.0000f,
            1.0000f,1.0000f,0.0000f,1.0000f,0.0000f,0.0000f,0.0000f,
            0.0000f,1.0000f,0.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
            0.0000f,1.0000f,0.0000f,0.0000f,0.0000f,0.0000f,1.0000f,
            0.0000f,1.0000f,1.0000f,1.0000f,1.0000f,0.0000f,1.0000f,
            0.0000f,0.0000f,0.0000f,0.0000f,1.0000f};
        private Context context;
        private FloatBuffer cubeVerticesBuffer;
        private ByteBuffer cubeFacetsBuffer;
        private FloatBuffer cubeTexturesBuffer;
        //定义本程序所使用的纹理
        private int texture;
        public MyRenderer(Context main){
          this.context = main;
          //将立方体的顶点位置数据数组包装成FloatBuffer
          cubeVerticesBuffer = FloatBuffer.wrap(cubeVetices);
          //将立方体的6个面(12个三角形)的数组包装成ByteBuffer
          cubeFacetsBuffer = ByteBuffer.wrap(cubeFacets);
          //将立方体的纹理贴图的坐标数据包装成FloatBuffer
          cubeTexturesBuffer = FloatBuffer.wrap(cubeTextures);
        }

        @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);
          //启用2D纹理贴图
          gl.glEnable(GL10.GL_TEXTURE_2D);
          //装载纹理
          loadTexture(gl);
        }

        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
          // 设置3D视窗的大小及位置
          gl.glViewport(0, 0, width, height);
          //将当前矩阵模式设为投影矩阵
          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);
          //启用贴图坐标数组数据
          gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
          //设置当前矩阵模式为模型视图
          gl.glMatrixMode(GL10.GL_MODELVIEW);
          //----------绘制第一个图形----------
          gl.glLoadIdentity();
          //把绘图中心移入屏幕2个单位
          gl.glTranslatef(0f, 0.0f, -2.0f);
          //旋转图形
          gl.glRotatef(angley, 0, 1, 0);
          gl.glRotatef(anglex, 1, 0, 0);
          //设置顶点的位置数据
          gl.glVertexPointer(3, GL10.GL_FLOAT, 0, cubeVerticesBuffer);
          //设置贴图的坐标数据
          gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, cubeTexturesBuffer);
          //执行纹理贴图
          gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);
          //按cubeFacetsBuffer指定的面绘制三角形
          gl.glDrawElements(GL10.GL_TRIANGLES,
          cubeFacetsBuffer.remaining(),
          GL10.GL_UNSIGNED_BYTE, cubeFacetsBuffer);
          //绘制结束
          gl.glFinish();
          //禁用顶点、纹理做标数组
          gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
          gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
          //递增角度值以便每次以不同角度绘制
        }
        private void loadTexture(GL10 gl){
          Bitmap bitmap = null;
          try {
            //加载位图
            bitmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.sand);
            int[] textures = new int[1];
            //指定生成N个纹理(第一个参数指定生成1个纹理)
            //textures数组将负责存储所有纹理的代号
            gl.glGenTextures(1, textures, 0);
            //获取textures纹理数组中的第一个纹理
            texture = textures[0];
            //通知OpenGL将texture纹理绑定到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);
          } catch (Exception e) {
          }finally{
            //生成纹理之后,回收位图
            if(bitmap != null){
              bitmap.recycle();
            }
          }

        }


      }


    }

    程序中粗体字代码用于计算用户手势在X方向、Y方向上速度,并根据X方向、Y方向上的速度来改变立方体的旋转角度,这样就可以让该立方体随用户的手势而转动了。

  • 相关阅读:
    Linux 下的类似Windows下Everything的搜索工具
    windows和linux环境下制作U盘启动盘
    程序调试手段之gdb, vxworks shell
    LeetCode 1021. Remove Outermost Parentheses (删除最外层的括号)
    LeetCode 1047. Remove All Adjacent Duplicates In String (删除字符串中的所有相邻重复项)
    LeetCode 844. Backspace String Compare (比较含退格的字符串)
    LeetCode 860. Lemonade Change (柠檬水找零)
    LeetCode 1221. Split a String in Balanced Strings (分割平衡字符串)
    LeetCode 1046. Last Stone Weight (最后一块石头的重量 )
    LeetCode 746. Min Cost Climbing Stairs (使用最小花费爬楼梯)
  • 原文地址:https://www.cnblogs.com/jiww/p/5628178.html
Copyright © 2011-2022 走看看