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方向上的速度来改变立方体的旋转角度,这样就可以让该立方体随用户的手势而转动了。

  • 相关阅读:
    EV: There is no source code available for the current location.
    EV: 致新教育萤火虫父母们
    DEL: 2012年每月花销
    DEL: 博客分类规则
    java编程规范
    maven随笔
    JMS组成结构与特点
    activemq 的简单使用
    activeMQ安装与访问
    java8 stream
  • 原文地址:https://www.cnblogs.com/jiww/p/5628178.html
Copyright © 2011-2022 走看看