之前的文章:
《OpenGL從入門到放棄01 》一些基本概念
《OpenGL從入門到放棄02 》GLSurfaceView和Renderer
《OpenGL從入門到放棄03 》相機(jī)和視圖
《OpenGL從入門到放棄04 》畫一個(gè)長方形
《OpenGL從入門到放棄05》著色器語言
這一節(jié)我們來學(xué)習(xí)一下如何用OpenGL顯示一張圖片柑肴,先上圖
在OpenGL中顯示一張圖片蛔添,需要使用到紋理采樣函數(shù) texture2D,整個(gè)步驟大概如下
我們?cè)?a href="http://www.reibang.com/p/e75e03ab135b" target="_blank">《OpenGL從入門到放棄04 》畫一個(gè)長方形的基礎(chǔ)上修改
1角雷、修改著色器
// 頂點(diǎn)著色器的腳本
String vertexShaderCode =
"uniform mat4 uMVPMatrix;" + //接收傳入的轉(zhuǎn)換矩陣
"attribute vec4 vPosition;" + //接收傳入的頂點(diǎn)
"attribute vec2 aTexCoord;" + //接收傳入的頂點(diǎn)紋理位置
"varying vec2 vTextureCoord;" + //增加用于傳遞給片元著色器的紋理位置變量
"void main() {" +
"gl_Position = uMVPMatrix * vPosition;" + //矩陣變換計(jì)算之后的位置
"vTextureCoord = aTexCoord;" +
" }";
// 片元著色器的腳本
String fragmentShaderCode =
" precision mediump float;" + // 聲明float類型的精度為中等(精度越高越耗資源)
"varying vec2 vTextureCoord;" + //紋理坐標(biāo)
"uniform sampler2D sTexture;" + //紋理采樣器,代表一副紋理
" void main() {" +
"gl_FragColor = texture2D(sTexture,vTextureCoord);" +//進(jìn)行紋理采樣
" }";
片元的顏色不再是簡單的單色咆课,而是通過texture2D進(jìn)行紋理采樣燃领,得到的顏色。
紋理采樣器 sampler2D sTexture某饰,變量名sTexture是我們自己取的,我們不用為sTexture賦值,著色器會(huì)自動(dòng)處理sTexture黔漂,指向我們待會(huì)兒要傳過去的紋理圖片诫尽,紋理坐標(biāo)由頂點(diǎn)著色器傳過來。
2炬守、準(zhǔn)備紋理坐標(biāo)數(shù)據(jù)
先說一下紋理坐標(biāo)系
紋理貼圖:把一個(gè)紋理(對(duì)于2D貼圖牧嫉,可以簡單的理解為圖片),按照所期望的方式顯示在圖形的表面减途。
如果想把一幅紋理映射到相應(yīng)的幾何圖元酣藻,就必須告訴GPU如何進(jìn)行紋理映射,也就是為圖元的頂點(diǎn)指定恰當(dāng)?shù)募y理坐標(biāo)鳍置。紋理坐標(biāo)用浮點(diǎn)數(shù)來表示臊恋,范圍一般從0.0到1.0,左上角坐標(biāo)為(0.0墓捻,0.0)抖仅,右上角坐標(biāo)為(1.0,0.0)砖第,左下角坐標(biāo)為(0.0撤卢,1.0),右下角坐標(biāo)為(1.0梧兼,1.0)
看上面兩張圖就明白了放吩,假如長方形的頂點(diǎn)順序是V1、v2羽杰、v4渡紫、v3,那么紋理坐標(biāo)對(duì)應(yīng)V1考赛、v2惕澎、v4、v3颜骤,才能正常顯示
了解了紋理坐標(biāo)之后唧喉,開始寫代碼了~
根據(jù)長方形的頂點(diǎn)坐標(biāo),定義對(duì)應(yīng)的紋理坐標(biāo)
private void initVertext() {
float vertices[] = new float[]{
-1, 1, 0,
-1, -1, 0,
1, 1, 0,
1, -1, 0,
};//頂點(diǎn)位置
float[] colors = new float[]{
0, 0,
0, 1,
1, 0,
1, 1,
};//紋理頂點(diǎn)數(shù)組
//轉(zhuǎn)換成 FloatBuffer
mVertexBuffer = GLUtil.floatArray2FloatBuffer(vertices);
mTexCoordBuffer = GLUtil.floatArray2FloatBuffer(colors);
}
這一步非常簡單了忍抽,頂點(diǎn)坐標(biāo)跟紋理坐標(biāo)一一對(duì)應(yīng)八孝,比如頂點(diǎn)在左上角[-1,1],紋理坐標(biāo)對(duì)應(yīng)[0,0]鸠项,此處忽略z軸干跛。不明白再看看上面兩張圖
3、獲取紋理坐標(biāo)句柄
頂點(diǎn)著色器中增加了紋理坐標(biāo)變量 vTextureCoord祟绊,
需要給他賦值楼入,所以先獲取句柄哥捕,然后在draw方法進(jìn)行設(shè)置數(shù)據(jù)
//紋理位置句柄
maTexCoordHandle = GLES20.glGetAttribLocation(mProgram,"aTexCoord");
光有紋理坐標(biāo),沒有紋理數(shù)據(jù)也不行浅辙,所以下一步是設(shè)置紋理數(shù)據(jù)
4扭弧、設(shè)置紋理數(shù)據(jù)
先上代碼
private void initTexture(){
int textures[] = new int[1]; //生成紋理id
GLES20.glGenTextures( //創(chuàng)建紋理對(duì)象
1, //產(chǎn)生紋理id的數(shù)量
textures, //紋理id的數(shù)組
0 //偏移量
);
mTextureId = textures[0];
//綁定紋理id阎姥,將對(duì)象綁定到環(huán)境的紋理單元
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);//設(shè)置MIN 采樣方式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);//設(shè)置MAG采樣方式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);//設(shè)置S軸拉伸方式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);//設(shè)置T軸拉伸方式
if (mBitmap == null){
Log.e("lxb", "initTexture: mBitmap == null");
return;
}
//加載圖片
GLUtils.texImage2D( //實(shí)際加載紋理進(jìn)顯存
GLES20.GL_TEXTURE_2D, //紋理類型
0, //紋理的層次记舆,0表示基本圖像層,可以理解為直接貼圖
mBitmap, //紋理圖像
0 //紋理邊框尺寸
);
}
設(shè)置紋理數(shù)據(jù)有幾個(gè)步驟
- 創(chuàng)建紋理對(duì)象 GLES20.glGenTextures呼巴,可以拿到紋理id
- 綁定紋理id GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId);
- 設(shè)置采樣方法 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST) - 實(shí)際加載紋理進(jìn)顯存 GLUtils.texImage2D泽腮,需要先準(zhǔn)備Bitmap
4、紋理坐標(biāo)賦值再繪制
紋理數(shù)據(jù)設(shè)置好了衣赶,紋理句柄有了诊赊,只差最后一步,把紋理坐標(biāo)傳給著色器
//把紋理坐標(biāo)傳給著色器
GLES20.glEnableVertexAttribArray(maTexCoordHandle);
GLES20.glVertexAttribPointer(maTexCoordHandle, 2,
GLES20.GL_FLOAT, false,
2*4, mTexCoordBuffer);
主要修改以上幾點(diǎn)府瞄,其它的保存不變碧磅,整理后的代碼如下
/**
*
* 增加紋理
*/
public class Square02 {
// 頂點(diǎn)著色器的腳本
String vertexShaderCode =
"uniform mat4 uMVPMatrix;" + //接收傳入的轉(zhuǎn)換矩陣
"attribute vec4 vPosition;" + //接收傳入的頂點(diǎn)
"attribute vec2 aTexCoord;" + //接收傳入的頂點(diǎn)紋理位置
"varying vec2 vTextureCoord;" + //增加用于傳遞給片元著色器的紋理位置變量
"void main() {" +
"gl_Position = uMVPMatrix * vPosition;" + //矩陣變換計(jì)算之后的位置
"vTextureCoord = aTexCoord;" +
" }";
// 片元著色器的腳本
String fragmentShaderCode =
" precision mediump float;" + // 聲明float類型的精度為中等(精度越高越耗資源)
"varying vec2 vTextureCoord;" +
"uniform sampler2D sTexture;" + //紋理采樣器,代表一副紋理
" void main() {" +
"gl_FragColor = texture2D(sTexture,vTextureCoord);" +//進(jìn)行紋理采樣
" }";
private FloatBuffer mVertexBuffer; //頂點(diǎn)坐標(biāo)數(shù)據(jù)要轉(zhuǎn)化成FloatBuffer格式
private FloatBuffer mTexCoordBuffer;//頂點(diǎn)紋理坐標(biāo)緩存
// 數(shù)組中每3個(gè)值作為一個(gè)坐標(biāo)點(diǎn)
static final int COORDS_PER_VERTEX = 3;
//一個(gè)頂點(diǎn)有3個(gè)float遵馆,一個(gè)float是4個(gè)字節(jié)鲸郊,所以一個(gè)頂點(diǎn)要12字節(jié)
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per mVertex
//當(dāng)前繪制的頂點(diǎn)位置句柄
private int vPositionHandle;
//變換矩陣句柄
private int mMVPMatrixHandle;
//這個(gè)可以理解為一個(gè)OpenGL程序句柄
private int mProgram;
//紋理坐標(biāo)句柄
private int maTexCoordHandle;
//變換矩陣,提供set方法
private float[] mvpMatrix = new float[16];
private int mTextureId;
public void setMvpMatrix(float[] mvpMatrix) {
this.mvpMatrix = mvpMatrix;
}
private Bitmap mBitmap;
public Square02(Bitmap bitmap) {
this.mBitmap = bitmap;
initVertext();
initShder();
initTexture();
}
private void initVertext() {
float vertices[] = new float[]{
-1, 1, 0,
-1, -1, 0,
1, 1, 0,
1, -1, 0,
};//頂點(diǎn)位置
float[] colors = new float[]{
0, 0,
0, 1,
1, 0,
1, 1,
};//紋理頂點(diǎn)數(shù)組
mVertexBuffer = GLUtil.floatArray2FloatBuffer(vertices);
mTexCoordBuffer = GLUtil.floatArray2FloatBuffer(colors);
}
private void initShder() {
//獲取程序货邓,封裝了加載秆撮、鏈接等操作
mProgram = GLUtil.createProgram(vertexShaderCode,fragmentShaderCode);
/***1.獲取句柄*/
// 獲取頂點(diǎn)著色器的位置的句柄(這里可以理解為當(dāng)前繪制的頂點(diǎn)位置)
vPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// 獲取變換矩陣的句柄
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
//紋理位置句柄
maTexCoordHandle = GLES20.glGetAttribLocation(mProgram,"aTexCoord");
}
private void initTexture(){
int textures[] = new int[1]; //生成紋理id
GLES20.glGenTextures( //創(chuàng)建紋理對(duì)象
1, //產(chǎn)生紋理id的數(shù)量
textures, //紋理id的數(shù)組
0 //偏移量
);
mTextureId = textures[0];
//綁定紋理id,將對(duì)象綁定到環(huán)境的紋理單元
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);//設(shè)置MIN 采樣方式
// GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
// GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);//設(shè)置MAG采樣方式
// GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
// GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);//設(shè)置S軸拉伸方式
// GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
// GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);//設(shè)置T軸拉伸方式
if (mBitmap == null){
Log.e("lxb", "initTexture: mBitmap == null");
return;
}
//加載圖片
GLUtils.texImage2D( //實(shí)際加載紋理進(jìn)顯存
GLES20.GL_TEXTURE_2D, //紋理類型
0, //紋理的層次换况,0表示基本圖像層职辨,可以理解為直接貼圖
mBitmap, //紋理圖像
0 //紋理邊框尺寸
);
}
public void draw() {
// 將程序添加到OpenGL ES環(huán)境
GLES20.glUseProgram(mProgram);
/**設(shè)置數(shù)據(jù)*/
// 啟用頂點(diǎn)屬性,最后對(duì)應(yīng)禁用
GLES20.glEnableVertexAttribArray(vPositionHandle);
GLES20.glEnableVertexAttribArray(maTexCoordHandle);
//設(shè)置三角形坐標(biāo)數(shù)據(jù)(一個(gè)頂點(diǎn)三個(gè)坐標(biāo))
GLES20.glVertexAttribPointer(vPositionHandle, 3,
GLES20.GL_FLOAT, false,
3 * 4, mVertexBuffer);
//設(shè)置紋理坐標(biāo)數(shù)據(jù)
GLES20.glVertexAttribPointer(maTexCoordHandle, 2,
GLES20.GL_FLOAT, false,
2*4, mTexCoordBuffer);
// 將投影和視圖轉(zhuǎn)換傳遞給著色器戈二,可以理解為給uMVPMatrix這個(gè)變量賦值為mvpMatrix
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
// //設(shè)置使用的紋理編號(hào)
// GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
/** 繪制三角形舒裤,三個(gè)頂點(diǎn)*/
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
// 禁用頂點(diǎn)數(shù)組(好像不禁用也沒啥問題)
GLES20.glDisableVertexAttribArray(vPositionHandle);
GLES20.glDisableVertexAttribArray(maTexCoordHandle);
}
}
源碼已經(jīng)給出,大家可以先動(dòng)手試試觉吭,有問題歡迎留言惭每。
下一篇文章比較有意思了,關(guān)于濾鏡的亏栈,實(shí)現(xiàn)黑白圖片台腥、冷暖色調(diào)、四分鏡等等绒北,敬請(qǐng)期待黎侈。