美文网首页
4.带纹理的正方形

4.带纹理的正方形

作者: WorldOpenGLES | 来源:发表于2019-04-08 21:40 被阅读0次

    案例下载 提取码:4zm9

    这一篇我将会详细的讲纹理(Texture),本节课讲的是2D纹理,后续教程还有3D纹理立体纹理

    纹理不仅能用来显示在几何体上,还可以纹理传输数据给着色器,例如法线贴图等

    纹理映射

    如果想给三角形线上纹理,我们得让他们都顶点位置纹理坐标对应。可能我这一篇没有讲清楚,可以看看这篇

    图片的纹理坐标

    上图是一个图片的纹理坐标,左上角为原点(0,0),纹理坐标取值为[0-1]

    上一篇说过,一个正方形由两个直角三角形组成 正方形 两个直角三角形对应纹理坐标 纹理坐标

    使用纹理之前,我们需要把之前的着色器换成带纹理的TextureShader着色器

        //带纹理坐标的着色器
        private TextureShader shader;
        
    

    我们先画正方形左边的直角三角形,声明它的顶点数组

    float vertex[]={
                -2,2,0,
                -2,-2,0,
                2,-2,0,
                
            };
    

    再声明一个对应顶点数组纹理数组,因为纹理是二维的所以不需要z轴

    float texcoor[]={
                0,0,
                0,1,
                1,1
            };
    

    现在我们有了顶点数组纹理坐标我们把他保存在Mesh类中

            mesh=new Mesh();
            //设置顶点数组
            mesh.setVertex(vertex);
            //设置纹理坐标数组
            mesh.setTextureCoord(texcoor);
    

    Bitmap类无法直接使用,需要转换成Texture2D类,使用Texture2D中的静态方法Texture2D.create来创建一个纹理

            //获取Bitmap图片
            Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
            Texture2D texture=Texture2D.create(bitmap);
            //记得释放Bitmap
            bitmap.recycle();
    

    Bitmap如果不需要可以释放,释放不影响纹理,纹理照样可以使用

    有了纹理,现在我们可以把纹理传给着色器,并且初始化几何体

            //初始化带纹理着色器
            shader=new TextureShader();
            shader.setTexture(texture);
    
            geometry=new Geometry(mesh);
            //设置着色器
            geometry.setShader(shader);
            //初始化位置
            geometry.genMatrix();
            geometry.translate(0,0,0);
    

    做好一切准备后,把几何体加入到渲染列表

        //绘画函数
        @Override
        public void draw(Rendering rendering)
        {
            //获取视图类
            ViewPort viewport=rendering.getViewport();
            //设置摄像机
            viewport.setCameraPosition(0,0,10);
            viewport.setCameraLook(0,0,0);
            viewport.setCameraUp(0,1,0);
            
            //把几何体加入到渲染列表
            rendering.addGeometry(geometry);
            
        }
    
    

    运行一下试试?

    运行效果

    纹理成功显示出来了,现在我们把正方形顶点数组完整的写入

            //顶点数组
            float vertex[]={
                -2,2,0,
                -2,-2,0,
                2,-2,0,
                
                -2,2,0,
                2,-2,0,
                2,2,0,
            };
            
            //纹理坐标数组
            float texcoor[]={
                0,0,
                0,1,
                1,1,
                
                0,0,
                1,1,
                1,0
            };
    

    运行效果

    运行效果

    不使用记得调用texture.delete()删除纹理

    注意!本库如果一个类中有delete方法,说明这个类如果不需要了记得调用delete方法!释放内存,否则可能会内存溢出

    纹理过滤

    简单的说,一个就是像素化(大名鼎鼎的Mc就是用的这个),一个是抗锯齿比较模糊的(这个比上面那个速度慢)

    NEAREST过滤

            texture.setMinFilter(Texture2D.Filter.NEAREST);
            texture.setMagFilter(Texture2D.Filter.NEAREST);
    
    运行效果

    LINEAR过滤

            texture.setMinFilter(Texture2D.Filter.LINEAR);
            texture.setMagFilter(Texture2D.Filter.LINEAR);
    
    运行效果

    Mipmap

    简单的来说就是,远距离用小图,近距离用大图,目前只支持自动生成Mipmap(自行设置懒得弄,等后面版本更新)

    程序会自动生成比纹理图尺寸小的纹理,增加内存,但是会提高绘画效率,牺牲这一点内存也值得 Mipmap

    如何生成Mipmap纹理? 很简单只需要把过滤方式修改为以下几种,程序会自动生成Mipmap

    LINEAR_MIPMAP_LINEAR:远近都使用LINEAR过滤

    NEAREST_MIPMAP_NEAREST:远近都使用NEAREST过滤

    LINEAR_MIPMAP_NEAREST:近处使用LINEAR过滤,远处使用NEAREST过滤

    NEARST_MIPMAP_LINEAR:近处使用NEARST过滤,远处使用LINEAR```过滤

            texture.setMagFilter(Texture2D.Filter.LINEAR_MIPMAP_LINEAR);
            texture.setMinFilter(Texture2D.Filter.LINEAR_MIPMAP_LINEAR);
    

    纹理采样

    我们之前的纹理坐标是[0, 0][1, 1],那如果我们把纹理坐标设置在范围之外会发生什么?默认是循环采样纹理,如下图

            //纹理坐标数组
            float texcoor[]={
                0,0,
                0,4,
                4,4,
                
                0,0,
                4,4,
                4,0
            };
    
    运行效果

    默认是重复采样纹理,我们可以用Texture2D类中的两个方法设置不同的采样模式

    setStretchS:超过S(X轴)该如何采样
    setStretchT:超过T(Y轴)该如何采样

    REPEAT(默认)
    重复采样纹理

            texture.setStretchS(Texture2D.Stretch.REPEAT);
            texture.setStretchT(Texture2D.Stretch.REPEAT);
    
    REPEAT模式(默认)

    MIRRORED_REPEAT
    REPEAT效果差不多,只不过是镜像采样,因为这个纹理机器人左右对称,所以看起来好像只有上下镜像.

            texture.setStretchS(Texture2D.Stretch.MIRRORED_REPEAT);
            texture.setStretchT(Texture2D.Stretch.MIRRORED_REPEAT);
    
    MIRRORED_REPEAT

    CLAMP_TO_EDGE
    如果纹理坐标超过1则超过的坐标按1采样纹理,如果坐标低于0则按照0坐标采样纹理。

    CLAMP_TO_EDGE

    借用一下别人的图,OpenGL ES不支持最后一种采样模式图片原文链接

    采样模式

    纹理透明

    实际上这个纹理是透明的,但是显示并不是透明的。我们只需要把普通渲染队列修改到透明渲染队列就可以实现透明

            //把几何体加入到透明渲染列表
            rendering.addAlphaGeometry(geometry);
    
    
    透明渲染队列

    案例代码

    public class MainActivity extends Activity implements DrawRenderer
    {
        //渲染控件类
        private GameView gameview;
        //网格
        private Mesh mesh;
        //带纹理坐标的着色器
        private TextureShader shader;
        //几何体
        private Geometry geometry;
        
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            gameview=new GameView(this);
            gameview.setDrawRenderer(this);
            setContentView(gameview);
            
        }
        
        //初始化
        @Override
        public void SurfaceCreated(Rendering rendering)
        {
            //设置背景颜色为白色
            rendering.setColor(new ColorRGBA(1,1,1,1));
        
            //顶点数组
            float vertex[]={
                -2,2,0,
                -2,-2,0,
                2,-2,0,
                
                -2,2,0,
                2,-2,0,
                2,2,0,
            };
            
            //纹理坐标数组
            float texcoor[]={
                0,0,
                0,1,
                1,1,
                
                0,0,
                1,1,
                1,0
            };
            
            mesh=new Mesh();
            //设置顶点数组
            mesh.setVertex(vertex);
            //设置纹理坐标数组
            mesh.setTextureCoord(texcoor);
            
            //获取Bitmap图片
            Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
            Texture2D texture=Texture2D.create(bitmap);
            //设置过滤模式
            texture.setMagFilter(Texture2D.Filter.LINEAR);
            texture.setMinFilter(Texture2D.Filter.LINEAR);
            //如果Texture不使用了
            //记得删除释放空间
            //texture.delete();
            
            //记得释放Bitmap
            bitmap.recycle();
            
            //初始化带纹理着色器
            shader=new TextureShader();
            //把纹理传给着色器
            shader.setTexture(texture);
            
            geometry=new Geometry(mesh);
            //设置着色器
            geometry.setShader(shader);
            //初始化位置
            geometry.genMatrix();
            geometry.translate(0,0,0);
        }
    
        //绘画函数
        @Override
        public void draw(Rendering rendering)
        {
            //获取视图类
            ViewPort viewport=rendering.getViewport();
            //设置摄像机
            viewport.setCameraPosition(0,0,10);
            viewport.setCameraLook(0,0,0);
            viewport.setCameraUp(0,1,0);
            
            //把几何体加入到渲染列表
            rendering.addGeometry(geometry);
            
        }
    
        //改变宽高调用
        @Override
        public void SurfaceChanged(Rendering rendering, int width, int heigth)
        {
            
        }
        
        
    }
    

    相关文章

      网友评论

          本文标题:4.带纹理的正方形

          本文链接:https://www.haomeiwen.com/subject/xvjmiqtx.html