問:學OpenGL能幹嗎? 答: 隨心所欲。
編程
提及
OpenGLES
,你們可能都敬而遠之,其實它並無想象中的那麼可怕
,固然也並無那麼容易
都0202年了,本系列使用OpenGLES3.0
,這是一次有預謀的計劃:數組
這是正文的第二篇,在上一篇講述了OpenGLES的基本使用
如今你已經可以操做着色器繪製點線了,若是你還不會,請先看第一集緩存
三角形是OpenGL中最重要的一種圖形,能夠說全部的體和麪都是由三角形拼組而成
全部這一節是很是重要的。bash
GL_TRIANGLES
目前的座標系以下: 三個點從右上角開始逆時針,白、紅、綠微信
//頂點數組
private final float vertexes[] = {//以逆時針順序
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
};
// 顏色數組
private final float colors[] = new float[]{
1.0f, 1.0f, 1.0f, 1.0f,//白色
1.0f, 0.0f, 0.0f, 1.0f,//紅色
0.0f, 1.0f, 0.0f, 1.0f,//綠色
};
複製代碼
由三點進行繪製三角形,繪製時使用
GLES30.GL_TRIANGLES
便可函數
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vertexes.length / VERTEX_DIMENSION);
複製代碼
繪製三角形有三種模式,另外兩個是:
GL_TRIANGLE_STRIP
和GL_TRIANGLE_STRIP
下面經過四個點進行對比演示工具
//頂點數組
private final float vertexes[] = { //以逆時針順序
1.0f, 1.0f, 0.0f,//原點
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
};
// 顏色數組
private final float colors[] = new float[]{
1.0f, 1.0f, 1.0f, 1.0f,//白色
1.0f, 0.0f, 0.0f, 1.0f,//紅色
0.0f, 1.0f, 0.0f, 1.0f,//綠色
0.0f, 0.0f, 1.0f, 1.0f,//藍色
};
複製代碼
glDrawArrays:
---->[繪製點線]-------
GLES20.GL_POINTS 繪製點
GLES20.GL_LINES 兩點一線
GLES20.GL_LINE_STRIP 相鄰兩點一線(不連首尾)
GLES20.GL_LINE_LOOP 相鄰兩點一線(連首尾)
---->[繪製三角形]-------
GLES20.GL_TRIANGLES 三點一個(不夠三個,被忽略)
GLES20.GL_TRIANGLE_STRIP 相鄰三點一個
GLES20.GL_TRIANGLE_FAN 第一點中心,散射到其餘點
複製代碼
矩形也就是兩個三角形拼成的,因此如今繪製面的技能你已經get了。post
如今你應該有所體會,OpenGL中最重要的是處理頂點和顏色的數據
圓形的繪製無非就是找到那些頂點在哪裏,根據三角函數很容易求得測試
下面的圖很好的體現了這些點的座標是如何肯定的ui
private void initData() {
//頂點座標數據的初始化
int verticeCount = splitCount + 2;
vertexes = new float[verticeCount * 3];//座標數據
colors = new float[verticeCount * 4];//顏色數據
float thta = 360.f / splitCount;
vertexes[0] = 0;
vertexes[1] = 0;
vertexes[2] = 0;
colors[0] = 1;
colors[1] = 1;
colors[2] = 1;
colors[3] = 1;
for (int n = 1; n <= verticeCount - 1; n++) {
vertexes[n * 3] = r * cos((n - 1) * thta);//x
vertexes[n * 3 + 1] = r * sin((n - 1) * thta);//y
vertexes[n * 3 + 2] = 0;//z
colors[4 * n] = 1;
colors[4 * n + 1] = 0;
colors[4 * n + 2] = 0;
colors[4 * n + 3] = 1.0f;
}
}
複製代碼
沒有貼圖,就像肉包裏沒有肉餡。以前咱們都是自定義顏色去給頂點着色
而貼圖就是使用圖形象的像素信息來給頂點着色,get貼圖技能以後,
你就能夠用OpenGLES 對圖片進行處理和展現,甚至保存。這也是支線1的基礎
要注意,貼圖的紋理座標系是一個二維繫,原點在左上角,注意和頂點系區分
下面是頂點系xoy面
和紋理系
的示意圖,咱們須要給出紋理座標,就能夠把圖片貼起來:
//頂點數組
private final float vertexes[] = { //以逆時針順序
1.0f, 1.0f, 0.0f,//原點
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
};
// 貼圖座標
private final float textureCoo[] = new float[]{
1.0f,0.0f,
0.0f,0.0f,
0.0f,1.0f,
1.0f,1.0f,
};
private static final int VERTEX_DIMENSION = 3;
private static final int TEXTURE_DIMENSION = 2;
複製代碼
這裏給出一個圖片加載成貼圖的工具類
//貼圖工具類
public class GLTexture {
/**
* 資源id 加載紋理,默認重複方式:RepeatType.REPEAT
*
* @param ctx 上下文
* @param resId 資源id
* @return 紋理id
*/
public static int loadTexture(Context ctx, int resId) {
return loadTexture(ctx, resId, RepeatType.REPEAT);
}
/**
* 圖片加載紋理,默認重複方式:RepeatType.REPEAT
* @param bitmap 圖片
* @return 紋理id
*/
public static int loadTexture(Bitmap bitmap) {
return loadTexture(bitmap, RepeatType.REPEAT);
}
/**
* 資源id 加載紋理
*
* @param ctx 上下文
* @param resId 資源id
* @param repeatType 重複方式 {@link RepeatType}
* @return 紋理id
*/
public static int loadTexture(Context ctx, int resId, RepeatType repeatType) {
Bitmap bitmap = BitmapFactory.decodeResource(ctx.getResources(), resId);
return loadTexture(bitmap, repeatType);
}
/**
* bitmap 加載紋理
*
* @param bitmap bitmap
* @param repeatType 重複方式 {@link RepeatType}
* @return 紋理id
*/
public static int loadTexture(Bitmap bitmap, RepeatType repeatType) {
//生成紋理ID
int[] textures = new int[1];
//(產生的紋理id的數量,紋理id的數組,偏移量)
GLES30.glGenTextures(1, textures, 0);
int textureId = textures[0];
//綁定紋理id
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId);
//採樣方式MIN
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
int wrapS = 0;
int wrapT = 0;
switch (repeatType) {
case NONE:
wrapS = GLES30.GL_CLAMP_TO_EDGE;
wrapT = GLES30.GL_CLAMP_TO_EDGE;
break;
case REPEAT_X:
wrapS = GLES30.GL_REPEAT;
wrapT = GLES30.GL_CLAMP_TO_EDGE;
break;
case REPEAT_Y:
wrapS = GLES30.GL_CLAMP_TO_EDGE;
wrapT = GLES30.GL_REPEAT;
break;
case REPEAT:
wrapS = GLES30.GL_REPEAT;
wrapT = GLES30.GL_REPEAT;
break;
}
//設置s軸拉伸方式---重複
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, wrapS);
//設置t軸拉伸方式---重複
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, wrapT);
//實際加載紋理(紋理類型,紋理的層次,紋理圖像,紋理邊框尺寸)
GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle(); //紋理加載成功後釋放圖片
return textureId;
}
}
enum RepeatType {
NONE,//不重複
REPEAT_X,//僅x軸重複
REPEAT_Y,//僅y軸重複
REPEAT//x,y重複
}
複製代碼
主要將vsh中顏色的輸入變量緩存座標變量,在fsh中經過texture函數獲取色值
---->[texture.vsh]----
#version 300 es
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec2 aTexCoord;
uniform mat4 uMVPMatrix;
out vec2 vTexCoord;
void main(){
gl_Position = uMVPMatrix*vec4(aPosition.x, aPosition.y, aPosition.z, 1.0);
vTexCoord = aTexCoord;
}
---->[texture.fsh]----
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main(){
outColor = texture(sTexture, vTexCoord);
}
複製代碼
主體和前面同樣,這裏用GLTextureTriangle類進行貼圖測試
public class GLTextureTriangle {
//頂點數組
private final float vertexes[] = { //以逆時針順序
1.0f, 1.0f, 0.0f,//原點
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
};
// 貼圖座標
private final float textureCoo[] = new float[]{
1.0f,0.0f,
0.0f,0.0f,
0.0f,1.0f,
1.0f,1.0f,
};
private int program;
private static final int VERTEX_DIMENSION = 3;
private static final int TEXTURE_DIMENSION = 2;
private FloatBuffer vertBuffer;
private FloatBuffer textureCooBuffer;
private int aPosition = 0;//位置的句柄
private int aTexCoord = 1;//顏色的句柄
private int uMVPMatrix;//頂點變換矩陣句柄
private int textureId;//貼圖id
public GLTextureTriangle(Context context) {
textureId= GLTexture.loadTexture(context, R.mipmap.chaos);
program = GLLoader.initProgramByAssets(context, "texture.vsh", "texture.fsh");
vertBuffer = GLBuffer.getFloatBuffer(vertexes);
textureCooBuffer = GLBuffer.getFloatBuffer(textureCoo);
uMVPMatrix = GLES30.glGetUniformLocation(program, "uMVPMatrix");
}
public void draw(float[] mvpMatrix) {
//清除顏色緩存和深度緩存
GLES30.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// 將程序添加到OpenGL ES環境中
GLES30.glUseProgram(program);
GLES30.glUniformMatrix4fv(uMVPMatrix, 1, false, mvpMatrix, 0);
//啓用三角形頂點的句柄
GLES30.glEnableVertexAttribArray(aPosition);
//啓用三角形頂點顏色的句柄
GLES30.glEnableVertexAttribArray(aTexCoord);
//準備三角座標數據
GLES30.glVertexAttribPointer(
aPosition, VERTEX_DIMENSION,
GLES30.GL_FLOAT, false,
VERTEX_DIMENSION * 4, vertBuffer);
//準備頂點顏色數據
GLES30.glVertexAttribPointer(
aTexCoord, TEXTURE_DIMENSION,
GLES30.GL_FLOAT, false,
TEXTURE_DIMENSION * 4, textureCooBuffer);
//綁定紋理
GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId);
//繪製點
GLES30.glLineWidth(10);
GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, vertexes.length / VERTEX_DIMENSION);
//禁用頂點數組
GLES30.glDisableVertexAttribArray(aPosition);
GLES30.glDisableVertexAttribArray(aTexCoord);
}
}
複製代碼
也許你會以爲,廢了這麼大半天的勁就展現了一個圖片,有什麼意義?
這就像你給一個不懂編程的人用計算機算出10+10=20同樣,他也會以爲沒什麼意義
但當你演示34564*9894=341976216他就會以爲很厲害。其實本質並無什麼區別
經過着色器的編寫,你就能夠完成你須要的特效,好比OpenGLES3.0 接入視頻實現特效 - 引言
理論上你能夠經過shader完成一切圖片特效。下一篇將會詳細介紹着色器代碼的使用,你將會了解如何經過着色器的代碼控制像素值以及像素的位置。本片就這樣,相信你已經能夠完成貼圖了。
@張風捷特烈 2020.01.11 未允禁轉
個人公衆號:編程之王
聯繫我--郵箱:1981462002@qq.com --微信:zdl1994328
~ END ~