OpenGLES: mapa de textura única

I. Descripción general

He estado descuidando los blogs recientemente, por lo que actualizaré parte del proceso de desarrollo de OpenGLES durante este período.

Los dos primeros blogs de OpenGLES explicaron cómo usar OpenGLES para implementar la vista previa normal de la cámara y filtros de cuadrícula múltiple.

En el proceso de implementación de la cámara, aunque se usan texturas, solo se usan para crear una SurfaceTexture después de generar una textura, y luego usar SurfaceTexture para crear una Surface.La textura no se usa para la representación de imágenes, es decir, el mapeo de texturas.

En la publicación anterior del blog "OpenGL: Textura", se utilizó OpenGL para implementar el mapeo de textura del cuadro cuadrado, y también se presentaron en detalle la generación de textura, las coordenadas de textura, la configuración de filtrado, los métodos de ajuste, etc.

Este blog explicará el mapeo de texturas de OpenGLES. Los principios de los dos son en realidad los mismos, pero este blog se centra más en aplicaciones prácticas.

Lo siguiente es principalmente una demostración de código. Siga los comentarios del código para comprender el proceso de implementación.

2. Clase de renderizado:

public class ImgRender implements GLSurfaceView.Renderer {
    private final String TAG = ImgRender.class.getSimpleName();

    private final Context mContext;

    private float vertexData[] = {
            -1f, -1f,  //左下
            1f, -1f,   //右下
            -1f, 1f,   //左上
            1f, 1f,    //右上
    };

    //Android 纹理原点在左上角
    private float textureData[] = {
            0.0f, 1.0f,  //左上
            1.0f, 1.0f,  //右上
            0.0f, 0.0f,  //左下
            1.0f, 0.0f,  //右下
    };

    //shader程序/渲染器
    private int shaderProgram;
    //纹理id
    private int[] textureId = new int[1];
    //顶点坐标
    private int aPosition;
    //纹理坐标
    private int aTexCoord;
    //采样器
    private int sampler;
    //顶点数据缓存
    private FloatBuffer vertexBuffer;
    //纹理数据缓存
    private FloatBuffer textureBuffer;
    //一个顶点有几个数据
    private int VERTEX_POSITION_SIZE = 2;
    //一个纹理点有几个数据
    private int TEXTURE_POSITION_SIZE = 2;

    public ImgRender(Context context) {
        mContext = context;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        Log.v(TAG, "onSurfaceCreated()");
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        initGLES();
    }

    public void initGLES() {
        Log.v(TAG, "initGLES!");

        /************** 着色器程序/渲染器 **************/
        //创建并连接 着色器程序
        shaderProgram = ShaderUtils.createAndLinkProgram(mContext,
                "img_vertex_shader.glsl",
                "img_fragtment_shader.glsl");
        if (shaderProgram == 0) {
            Log.v(TAG, "create And Link ShaderProgram Fail!");
            return;
        }
        //使用着色器源程序
        glUseProgram(shaderProgram);

        /************** 着色器变量 **************/
        //从着色器程序中获取各个变量
        aPosition = glGetAttribLocation(shaderProgram, "aPosition");
        aTexCoord = glGetAttribLocation(shaderProgram, "aTexCoord");
        sampler = glGetUniformLocation(shaderProgram, "sampler");
        //将片段着色器的采样器(纹理属性:sampler)设置为0号单元
        glUniform1i(sampler, 0);

        vertexBuffer = ShaderUtils.getFloatBuffer(vertexData);
        textureBuffer = ShaderUtils.getFloatBuffer(textureData);

        //创建纹理对象
        glGenTextures(textureId.length, textureId, 0);

        TextureUtils.LoadTexture(mContext, textureId[0], R.drawable.bg2);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        Log.v(TAG, "onSurfaceChanged(): " + width + " x " + height);

        glViewport(0, 0, width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        //Log.v(TAG, "onDrawFrame()");
        glClear(GL_COLOR_BUFFER_BIT);

        /********* 顶点操作 **********/
        glEnableVertexAttribArray(aPosition);
        glEnableVertexAttribArray(aTexCoord);

        glVertexAttribPointer(aPosition, VERTEX_POSITION_SIZE, GL_FLOAT, false, 2 * 4, vertexBuffer);
        glVertexAttribPointer(aTexCoord, TEXTURE_POSITION_SIZE, GL_FLOAT, false, 2 * 4, textureBuffer);

        /********* 纹理操作:激活、绑定 **********/
        glActiveTexture(GL_TEXTURE);
        glBindTexture(GL_TEXTURE_2D, textureId[0]);

        /********* 绘制 **********/
        //绘制vertexData.length/2即4个点
        glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexData.length / 2);
        /********* 纹理操作:解除绑定 **********/
        glBindTexture(GL_TEXTURE_2D, 0);

        //关闭顶点数组的句柄
        glDisableVertexAttribArray(aPosition);
        glDisableVertexAttribArray(aTexCoord);
    }
}

3. Funciones relacionadas con ShaderUtils:

3.1 crearAndLinkProgram()

    /*
     * 创建和链接着色器程序
     * 参数:顶点着色器、片段着色器程序ResId
     * 返回:成功创建、链接了顶点和片段着色器的着色器程序Id
     */
    public static int createAndLinkProgram(Context context, String vertexShaderFN, String fragShaderFN) {
        //创建着色器程序
        int shaderProgram = glCreateProgram();
        if (shaderProgram == 0) {
            Log.e(TAG, "Failed to create shaderProgram ");
            return 0;
        }

        //获取顶点着色器对象
        int vertexShader = loadShader(GL_VERTEX_SHADER, loadShaderSource(context, vertexShaderFN));
        if (0 == vertexShader) {
            Log.e(TAG, "Failed to load vertexShader");
            return 0;
        }

        //获取片段着色器对象
        int fragmentShader = loadShader(GL_FRAGMENT_SHADER, loadShaderSource(context, fragShaderFN));
        if (0 == fragmentShader) {
            Log.e(TAG, "Failed to load fragmentShader");
            return 0;
        }

        //绑定顶点着色器到着色器程序
        glAttachShader(shaderProgram, vertexShader);
        //绑定片段着色器到着色器程序
        glAttachShader(shaderProgram, fragmentShader);

        //链接着色器程序
        glLinkProgram(shaderProgram);
        //检查着色器链接状态
        int[] linked = new int[1];
        glGetProgramiv(shaderProgram, GL_LINK_STATUS, linked, 0);
        if (linked[0] == 0) {
            glDeleteProgram(shaderProgram);
            Log.e(TAG, "Failed to link shaderProgram");
            return 0;
        }

        return shaderProgram;
    }

3.2 obtenerFloatBuffer()

    public static FloatBuffer getFloatBuffer(float[] array) {
        //将顶点数据拷贝映射到 native 内存中,以便opengl能够访问
        FloatBuffer buffer = ByteBuffer
                .allocateDirect(array.length * BYTES_PER_FLOAT)//直接分配 native 内存,不会被gc
                .order(ByteOrder.nativeOrder())//和本地平台保持一致的字节序(大/小头)
                .asFloatBuffer();//将底层字节映射到FloatBuffer实例,方便使用

        buffer.put(array)//将顶点拷贝到 native 内存中
                .position(0);//每次 put position 都会 + 1,需要在绘制前重置为0

        return buffer;
    }

4. Funciones relacionadas con TextureUtils

4.1 CargarTextura()

    //纹理Id由外部传入
    public static void LoadTexture(Context context, int textureId, int bitmapResId) {
        //绑定纹理:将纹理放到当前单元的 GL_TEXTURE_BINDING_EXTERNAL_OES 目标对象中
        glBindTexture(GL_TEXTURE_2D, textureId);
        //配置纹理:过滤方式
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        /************* bitmap **************/
        //获取图片的 bitmap
        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), bitmapResId);
        //绑定 bitmap 到textureIds[1]纹理
        GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
        bitmap.recycle();//用完及时回收

        //解绑纹理 指的是离开对 纹理的配置,进入下一个状态
        glBindTexture(GL_TEXTURE_2D, 0);
    }

5. Código de sombreado

5.1 img_vertex_shader.glsl

#version 300 es

layout (location = 0) in vec4 aPosition;         //把顶点坐标给这个变量, 确定要画画的形状
layout (location = 1) in vec4 aTexCoord;         //接收纹理坐标,接收采样器采样图片的坐标

//传给片元着色器 像素点
out vec2 vTexCoord;

void main()
{
    //内置变量 gl_Position ,我们把顶点数据赋值给这个变量 opengl就知道它要画什么形状了
    gl_Position = aPosition;
    vTexCoord = aTexCoord.xy;
}

5.2 img_fragment_shader.glsl

#version 300 es
#extension GL_OES_EGL_image_external_essl3 : require
precision mediump float;

in vec2 vTexCoord; //纹理坐标,图片当中的坐标点

uniform sampler2D sampler;  //图片,采样器

out vec4 outColor;

void main(){
    outColor = texture(sampler, vTexCoord);
}

6. Proceso de implementación de Render, GLSurfaceView, etc.

GLRender y su configuración en GLSurfaceView:

mGLSurfaceView = rootView.findViewById(R.id.gl_SurfaceView);
//设置GLES版本
mGLSurfaceView.setEGLContextClientVersion(3);
//创建Render对象,并将其设置到GLSurfaceView
mImgRender = new ImgRender(getActivity());
mGLSurfaceView.setRenderer(mImgRender);
mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);

También está la carga de GLSurfeaceView en Actividad o Fragmento. El código para estas operaciones regulares no se demostrará en detalle. Simplemente impleméntelo de acuerdo con su proceso de desarrollo real.

7. Puntos a tener en cuenta

1. Uso de muestreadores en sombreadores de fragmentos.

Una cosa a tener en cuenta es que en el código de sombreado de fragmentos anterior que implementó la vista previa de la cámara, la muestra utilizada fue:

muestreador uniformeExternalOES sCameraTexture;

La muestra utilizada al renderizar imágenes ahora es:

muestreador uniformemuestreador 2D; 

En el proceso de implementación del mapeo de texturas OpenGLES, inicialmente se utilizó directamente el sampler samplerExternalOES utilizado para implementar la vista previa de la cámara, pero la imagen nunca se pudo renderizar correctamente.

Esto se debe a que "sampler: samplerExternalOES" se usa especialmente para muestrear datos YUV en OpenGLES, por lo que debe usarse al implementar la vista previa de la cámara, pero al renderizar imágenes, se debe usar el "sampler Sampler2D" normal.

8. Efecto final

Se utiliza un mapa cósmico del cielo estrellado. Ignore el proceso de "abra la aplicación y haga clic en el botón" .

La presentación final del mapa del cielo estrellado cósmico es el efecto final del mapa de textura que se logrará en esta publicación del blog de OpenGLES :

Supongo que te gusta

Origin blog.csdn.net/geyichongchujianghu/article/details/132928008
Recomendado
Clasificación