1. 程式人生 > 其它 >最通俗的安卓OpenGL教學05——繪製圖片紋理

最通俗的安卓OpenGL教學05——繪製圖片紋理

技術標籤:OpenGL ES

OpenGL繪製圖片紋理可以應用在安卓圖片顯示、播放控制元件背景設定、新增圖片水印、新增文字水印等等,其主要需要學習的就是紋理的建立與繫結。

OpenGL繪製圖片紋理的步驟一般如下:

  1. 編寫著色器(頂點著色器和片元著色器)
  2. 設定頂點、 紋理座標
  3. 載入著色器 (shader)
  4. 建立紋理
  5. 設定環繞和過濾方式
  6. 設定圖片(bitmap)
  7. 繫結頂點座標和紋理座標
  8. 繪製圖片

上一節我們已經知道OpenGL如何繪製不同形狀,也就是前3步基本不變,這一節重點是紋理的建立、配置與繫結。

先看效果:

1.OpenGL建立紋理

在onSurfaceCreated時建立紋理


        //建立 1個紋理,放入到 int [] textureIds, 一共有 30多個 紋理
textureIds = new int[1]; GLES20.glGenTextures(1, textureIds, 0);//第三個引數是指從哪兒開始取 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[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); //解綁紋理 指的是離開對 紋理的配置,進入下一個狀態
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);

2.OpenGL 繪製紋理

在onDrawFrame時建立紋理

        //要開始繪製紋理了,啟用紋理 0號, 之所以啟用 0號,是因為在沒設定點的情況下預設是 0號
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        //繫結 textureIds[0] 到已啟用的 2D紋理 GL_TEXTURE0上
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]);
        //獲取圖片的 bitmap
        Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.nobb);
        //繫結 bitmap 到textureIds[0]紋理
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
        bitmap.recycle();//用完及時回收
        //繪製圖形
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        //解綁 2D紋理
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);

3. 整體程式碼

package com.york.media.opengl.demo.bitmap;

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

import com.york.media.opengl.R;
import com.york.media.opengl.egl.YGLSurfaceView;
import com.york.media.opengl.egl.YShaderUtil;

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

/**
 * author : York
 * date   : 2020/12/20 0:55
 * desc   : 繪製圖片紋理的 Render
 */
public class YBitmapRender implements YGLSurfaceView.YGLRender {

    private final Context mContext;
    private final FloatBuffer vertexBuffer;
    private final FloatBuffer fragmentBuffer;
    private int program;
    private int vPosition;
    private int fPosition;
    private int []textureIds;


    public YBitmapRender(Context context) {
        this.mContext = context;

        //頂點座標
        float[] vertexData = {
                -1f, -1f,
                1f, -1f,
                -1f, 1f,
                1f, 1f
        };
        //讀取頂點座標
        vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(vertexData);
        vertexBuffer.position(0);

        //紋理座標
        float[] fragmentData = {
                0f, 1f,
                1f, 1f,
                0f, 0f,
                1f, 0f
        };
        //讀取紋理座標
        fragmentBuffer = ByteBuffer.allocateDirect(fragmentData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(fragmentData);
        fragmentBuffer.position(0);

    }

    @Override
    public void onSurfaceCreated() {
        //載入頂點著色器 shader
        String vertexSource = YShaderUtil.getRawResource(mContext, R.raw.screen_vert);
        //載入片元著色器 shader
        String fragmentSource = YShaderUtil.getRawResource(mContext, R.raw.screen_frag);
        //獲取源程式
        program = YShaderUtil.createProgram(vertexSource, fragmentSource);
        //從渲染程式中得到著頂點色器中的屬性
        vPosition = GLES20.glGetAttribLocation(program, "vPosition");
        //從渲染程式中得到片元著色器中的屬性
        fPosition = GLES20.glGetAttribLocation(program, "fPosition");

        //建立 1個紋理,放入到 int [] textureIds, 一共有 30多個 紋理
        textureIds = new int[1];
        GLES20.glGenTextures(1, textureIds, 0);//第三個引數是指從哪兒開始取
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[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);
        //解綁紋理 指的是離開對 紋理的配置,進入下一個狀態
        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.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);

        //要開始繪製紋理了,啟用紋理 0號, 之所以啟用 0號,是因為在沒設定點的情況下預設是 0號
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        //繫結 textureIds[0] 到已啟用的 2D紋理 GL_TEXTURE0上
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]);
        //獲取圖片的 bitmap
        Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.nobb);
        //繫結 bitmap 到textureIds[0]紋理
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
        bitmap.recycle();//用完及時回收
        //繪製圖形
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        //解綁 2D紋理
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);


    }
}