美文网首页Android OpenGL
OpenGL ES渲染图片纹理

OpenGL ES渲染图片纹理

作者: 张俊峰0613 | 来源:发表于2019-01-18 17:27 被阅读104次

    1、步骤:

    • 1、编写着色器(顶点着色器和片元着色器)

    • 2、设置顶点、纹理坐标

    • 3、加载着色器

    • 4、创建纹理

    • 5、渲染图片

    2、OpenGL ES坐标系

    首先介绍一下纹理映射时的坐标系,纹理映射的坐标系和顶点着色器的坐标系是不一样的。

    2.1、顶点坐标系

    控制窗口坐标

    顶点坐标系

    2.2、纹理坐标系

    控制纹理位置

    纹理坐标用浮点数来表示,范围一般从0.0到1.0,左上角坐标为(0.0,0.0),右上角坐标为(1.0,0.0),左下角坐标为(0.0,1.0),右下角坐标为(1.0,1.0),具体如下:


    纹理坐标系

    3、OpenGL ES绘制四边形

    将纹理映射到下边的两个三角形上(也就是一个矩形),需要将纹理坐标指定到正确的顶点上,才能使纹理正确的显示,否则显示出来的纹理会无法显示,或者出现旋转、翻转、错位等情况。规定:图形环绕方向必须一致!

    顶点坐标系

    1、GL_TRIANGLES:
    v1, v2, v3,
    v3, v2, v4,

    2、GL_TRIANGLE_STRIP:
    偶数:n-1, n-2, n
    奇数:n-2, n-1, n

    3.1、绘制坐标范围:

    float[] vertexData = {
        -1f, -1f,
        1f, -1f,
        -1f, 1f,
        1f, 1f};
    

    3.2、为坐标分配本地内存地址:

        FloatBuffer vertexBuffer;
        vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
                    .order(ByteOrder.nativeOrder())
                    .asFloatBuffer()
                    .put(vertexData);
        vertexBuffer.position(0);
    

    3.3、Shader编写

    3.3.1、顶点着色器:vertex_shader.glsl

    attribute vec4 v_Position;
    attribute vec2 f_Position;
    varying vec2 ft_Position;
    void main() {
        ft_Position = f_Position;
        gl_Position = v_Position;
    }
    

    注: attribute 只能在vertex中使用;varying 用于vertex和fragment之间传递值。

    3.3.2、片元着色器:fragment_shader.glsl

    precision mediump float;
    varying vec2 ft_Position;
    uniform sampler2D sTexture;
    void main() {
        gl_FragColor=texture2D(sTexture, ft_Position);
    }
    

    注: uniform 用于在application中向vertex和fragment中传递值。

    3.4、OpenGL ES加载Shader

    1、创建shader(着色器:顶点或片元)

    int shader = GLES20.glCreateShader(shaderType);
    

    2、加载shader源码并编译shader

    GLES20.glShaderSource(shader, source);
    GLES20.glCompileShader(shader);
    

    3、检查是否编译成功:

    GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
    

    4、创建一个渲染程序:

    int program = GLES20.glCreateProgram();
    

    5、将着色器程序添加到渲染程序中:

    GLES20.glAttachShader(program, vertexShader);
    

    6、链接源程序:

    GLES20.glLinkProgram(program);
    

    前面6个部分可以用一个工具类完成,步骤都是一样的

    7、检查链接源程序是否成功

    GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
    

    8、得到着色器中的属性:

    int vPosition  = GLES20.glGetAttribLocation(program, "v_Position");
    

    9、使用源程序:

    GLES20.glUseProgram(program);
    

    10、使顶点属性数组有效:

    GLES20.glEnableVertexAttribArray(vPosition);
    

    11、为顶点属性赋值:

    GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8,vertexBuffer);
    

    12、绘制图形:

    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
    

    3.5、OpenGL ES绘制纹理过程

    1、加载shader和生成program过程不变
    如3.4
    2、创建和绑定纹理:

    GLES20.glGenTextures(1, textureId, 0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureid);
    

    3、设置环绕和过滤方式
    环绕(超出纹理坐标范围):(s==x t==y GL_REPEAT 重复)

    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
    

    过滤(纹理像素映射到坐标点):(缩小、放大:GL_LINEAR线性)

    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
    

    4、设置图片(bitmap)

    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
    

    5、绑定顶点坐标和纹理坐标

    6、绘制图形

    4、实现

    4.1、加载shader、创建program(前6步)

    import android.content.Context;
    import android.opengl.GLES20;
    import android.util.Log;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    
    public class JfShaderUtil {
        /**
         * 得到shade代码
         * @param context
         * @param rawId
         * @return
         */
        public static String getRawResource(Context context,int rawId){
            InputStream inputStream = context.getResources().openRawResource(rawId);
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            StringBuffer sb = new StringBuffer();
            String line;
            try {
                while ((line = reader.readLine()) != null) {
                    sb.append(line).append("\n");
                }
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return sb.toString();
        }
    
    
        /**
         * 加载着色器源码
         * @param shadeType 顶点、片元
         * @param source
         * @return
         */
        public static int loadShader(int shadeType,String source){
            //1、创建shader(着色器:顶点或片元)
            int shader = GLES20.glCreateShader(shadeType);
            if (shader != 0) {
                //2、加载shader源码并编译shader
                GLES20.glShaderSource(shader, source);
                GLES20.glCompileShader(shader);
    
                //3、检查是否编译成功
                int[] compile = new int[1];
                GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS,compile,0);
    
                if (compile[0] != GLES20.GL_TRUE) {
                    Log.e("zjf","编译失败");
                    GLES20.glDeleteShader(shader);
                    shader = 0;
                }
                return shader;
            } else {
                return 0;
            }
        }
    
    
        /**
         * 创建渲染程序
         * @param vertexSource
         * @param fragmentSoruce
         * @return
         */
        public static int createProgram(String vertexSource, String fragmentSoruce){
            int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,vertexSource);
            int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentSoruce);
    
            if (vertexShader != 0 && fragmentShader != 0) {
                //4、创建一个渲染程序
                int program = GLES20.glCreateProgram();
                //5、将着色器程序添加到渲染程序中
                GLES20.glAttachShader(program,vertexShader);
                GLES20.glAttachShader(program,fragmentShader);
                //6、链接源程序
                GLES20.glLinkProgram(program);
                return program;
            }
            return 0;
        }
    }
    

    4.2、渲染纹理

    public class JfTextureRender implements JfEGLSurfaceView.JfGLRender {
        private Context context;
    
        //顶点坐标
        private float[] vertexData = {
                -1f,-1f,
                1f,-1f,
                -1f,1f,
                1f,1f
        };
        private FloatBuffer vertexBuffer;
    
        //纹理坐标
        private float[] fragmentData = {
                0f,1f,
                1f,1f,
                0f,0f,
                1f,0f
        };
        private FloatBuffer fragmentBuffer;
    
    
        private int program;//程序
        private int vPosition;//顶点着色器属性
        private int fPosition;//片元着色器属性
        private int textureId;
        private int sampler;
    
        public JfTextureRender(Context context){
            this.context = context;
            vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
                    .order(ByteOrder.nativeOrder())
                    .asFloatBuffer()
                    .put(vertexData);
            vertexBuffer.position(0);
    
            fragmentBuffer = ByteBuffer.allocateDirect(fragmentData.length * 4)
                    .order(ByteOrder.nativeOrder())
                    .asFloatBuffer()
                    .put(fragmentData);
            fragmentBuffer.position(0);
        }
        @Override
        public void onSurfaceCreated() {
            //获取源码
            String vertexSource = JfShaderUtil.getRawResource(context,R.raw.vertex_shader);
            String fragmentSource = JfShaderUtil.getRawResource(context,R.raw.fragment_shader);
            //前6步完成
            program = JfShaderUtil.createProgram(vertexSource,fragmentSource);
    
            //得到着色器中的属性
            vPosition = GLES20.glGetAttribLocation(program,"v_Position");
            fPosition = GLES20.glGetAttribLocation(program,"f_Position");
            sampler = GLES20.glGetUniformLocation(program,"sTexture");
            //开始绘制纹理,只绘制一个图片纹理
            int[] textureIds = new int[1];
    
            GLES20.glGenTextures(1,textureIds,0);//创建纹理
            textureId = textureIds[0];
    
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textureId);//绑定纹理
    
            GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
            GLES20.glUniform1i(sampler,0);
    
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
    
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
    
            Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),R.mipmap.fengjing);
            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D,0,bitmap,0);
            bitmap.recycle();
            bitmap = null;
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,0);//解绑纹理
        }
    
        @Override
        public void onSurfaceChanged(int width, int height) {
            GLES20.glViewport(0,0,width,height);
        }
    
        @Override
        public void onDrawFrame() {
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
            GLES20.glClearColor(1f,0f,0f,1f);
    
            //使用源程序
            GLES20.glUseProgram(program);
    
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textureId);//再次绑定纹理
    
            //使顶点属性数组有效
            GLES20.glEnableVertexAttribArray(vPosition);
            //为顶点属性赋值
            GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8,
                    vertexBuffer);
            GLES20.glEnableVertexAttribArray(fPosition);
            GLES20.glVertexAttribPointer(fPosition, 2, GLES20.GL_FLOAT, false, 8,
                    fragmentBuffer);
    
            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,0);//再次解绑纹理
        }
    }
    

    相关文章

      网友评论

        本文标题:OpenGL ES渲染图片纹理

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