从零开始OpenGL ES(四) 绘制纹理 图片

理论

文章目录

  • 理论
    • 顶点Shader
    • 片元Shader
    • 绘制纹理过程
  • 代码

首先是两个坐标系

假如现在有一张图片,是通过纹理坐标系绘制出来的,图片的左上角(0,0),左下角(0,1),
那么我需要把纹理坐标系和顶点坐标系对齐, 那么要把纹理坐标系中(0,0)这个点,放到顶点坐标系中的(-1,0)这个点.
相应的要把纹理坐标系的(0,1)这个点,放到顶点坐标系中(-1,-1)这个点. 后面以此类推

具体做法: 先把OpenGL 需要展示的区域画出来(就是整个屏幕),再按照上面的做法 把纹理坐标系贴到顶点坐标系中.

顶点Shader

vertex_shader.glsl

attribute vec4 av_Position;
attribute vec2 af_Position;
varying vec2 v_texPo;
void main() {
    v_texPo = af_Position;
    gl_Position = av_Position;
}


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

  1. attribute vec4 av_Position; 这个是之前写过的 顶点坐标系
  2. attribute vec2 af_Position; 这个是纹理坐标系 vec2 图片是2d的 就用两个向量x,y
  3. varying vec2 v_texPo; 在顶点坐标和片元坐标之间传递数据 v_texPo 这个值需要在顶点坐标和片源坐标的文件中定义一直.

片元Shader

fragment_shader.glsl

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

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

  1. precision mediump float; 精度
  2. varying vec2 v_texPo; 从顶点Shader 获取到的值
  3. uniform sampler2D sTexture; 纹理的属性 因为是在片元里面 所以用uniform修饰 传值
  4. texture2D 把颜色取出来的方法 这里实际上就是做的两个坐标的转换

绘制纹理过程

1、加载shader和生成program过程不变

2、创建和绑定纹理:

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

glGenTextures 就是创建纹理 参数.1 是创建多少个纹理 texturId 是个整形的数组. 0 是从0开始
glBindTexture 绑定纹理 把生成的textrueId 生成的纹理绑定到GL_TEXTURE_2D 上

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、绘制图形

代码

按照前面文章

https://blog.csdn.net/liudao7994/article/details/84136584

绘制四边形 实际上的点 按照 v1 v2 v3 v4 绘制

在顶点坐标系中就是

//顶点坐标
    private final  float[] vertexData={
            -1f,-1f,
            1f,-1f,
            -1f,1f,
            1f,1f
    };


但是纹理坐标系和顶点坐标系不一样 需要对应起来所以纹理坐标系是

  //纹理坐标
    private final float[] textureData={
            0f,1f,
            1f,1f,
            0f,0f,
            0f,1f
    };

其他代码:

package com.xyyy.www.opengldemo;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;

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

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

/**
 * @author liuml
 * @explain  渲染图片
 * @time 2018/11/15 11:19
 */
public class XYRenderImage implements GLSurfaceView.Renderer {

    private Context context;
    //顶点坐标
    private final  float[] vertexData={
            -1f,-1f,
            1f,-1f,
            -1f,1f,
            1f,1f
    };

    //纹理坐标  正常
//    private final float[] textureData={
//            0f,1f,
//            1f,1f,
//            0f,0f,
//            1f,0f
//    };
    //纹理坐标 倒立
    private final float[] textureData={
            1f,0f,
            0f,0f,
            1f, 1f,
            0f, 1f
    };


    private FloatBuffer vertexBuffer;//顶点buffer
    private FloatBuffer textureBuffer;//纹理buffer
    private int program;
    private int avPosition;//顶点坐标
    private int afPosition;//纹理坐标
    private int textureId;//纹理id保存
//    private int afColor;


    public XYRenderImage(Context context){
        this.context = context;
        vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(vertexData);
        vertexBuffer.position(0);


        textureBuffer = ByteBuffer.allocateDirect(textureData.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(textureData);
        textureBuffer.position(0);
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        String vertexSource = XYShaderUtil.readRawText(context, R.raw.img_vertex_shader);
        String fragmentSource = XYShaderUtil.readRawText(context, R.raw.img_fragment_shader);
        program = XYShaderUtil.createProgram(vertexSource, fragmentSource);
        if (program > 0) {
            avPosition = GLES20.glGetAttribLocation(program, "av_Position");
            afPosition = GLES20.glGetAttribLocation(program, "af_Position");

            //创建纹理
            int[] textureIds = new int[1];
            GLES20.glGenTextures(1, textureIds, 0);
            if (textureIds[0] == 0) {
                return;
            }

            textureId = textureIds[0];

            //绑定
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);

            //设置参数 环绕(超出纹理坐标范围):
            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);

//            BitmapFactory.Options options = new BitmapFactory.Options();
//            options.inScaled = false;
            Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.test);
            if (bitmap == null) {
                return;
            }
            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
            bitmap.recycle();
            bitmap = null;
        }

    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width,int height) {
        //绘制区域
        GLES20.glViewport(0,0,width,height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        //清屏缓冲区
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        //利用颜色清屏
        GLES20.glClearColor(1.0f,1.0f,1.0f,1.0f);


        //让program可用
        GLES20.glUseProgram(program);
        //顶点坐标
        GLES20.glEnableVertexAttribArray(avPosition);
        GLES20.glVertexAttribPointer(avPosition, 2, GLES20.GL_FLOAT, false, 8, vertexBuffer);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        //纹理坐标
        GLES20.glEnableVertexAttribArray(afPosition);
        GLES20.glVertexAttribPointer(afPosition, 2, GLES20.GL_FLOAT, false, 8, textureBuffer);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
    }
}

效果:

引用: https://blog.csdn.net/ywl5320/article/details/81161147

你可能感兴趣的:(OpenGL)