旁白:上集說到,爲了獲取黑龍寶藏,勇者集結,共闖
黑龍洞穴
通過一路艱辛,終於過了第四副本,前面還有什麼困難等待着他們?一塊兒收看java
龍之圖陣
畫一個矩形
NPC:隱藏任務,解謎:
GLES20.GL_TRIANGLE_STRIP
繪製方式
發現逆時針畫的點貌似連的方式有點問題,貌似是先繪製2->3->4
,在繪製1->2->3
由於2->3->4
的三角形被1->2->3
的等三角形遮住了,後來居上是編程的共識git
static float sCoo[] = { //以逆時針順序
-0.5f, 0.5f, 0.0f, // 左上
-0.5f, -0.5f, 0.0f, // 左下
0.5f, -0.5f, 0.0f, // 右下
0.5f, 0.5f, 0.0f, //右上
};
float colors[] = new float[]{
1f, 1f, 0.0f, 1.0f,//黃
0.05882353f, 0.09411765f, 0.9372549f, 1.0f,//藍
0.19607843f, 1.0f, 0.02745098f, 1.0f,//綠
1.0f, 0.0f, 1.0f, 1.0f,//紫色
};
---->[Rectangle#draw]---------
//繪製三角形
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
複製代碼
怎麼能讓
1->2->3
和2->3->4
不會重疊?--點調下順序就好了
1->2->4->3
github
static float sCoo[] = { //以逆時針順序
-0.5f, 0.5f, 0.0f, // 1.
-0.5f, -0.5f, 0.0f, // 2.
0.5f, 0.5f, 0.0f, //4.
0.5f, -0.5f, 0.0f, // 3.
};
複製代碼
畫五邊形
先按照
p1->p2->p3->p4->p5
的順序,看有什麼效果
意料以內,先把p1->p2->p3->p4
四點畫完,再畫第五點編程
怎麼調點呢?恩...好吧,哥要開始吹牛了
我這麼隨便一想,在知足正方形的條件下,動一下p5點,就好了,而後讓p5上漂數組
static float sCoo[] = { //以逆時針順序
-0.5f, 0.5f, 0.0f, // p1
0.0f, 0.8f, 0.0f, //p5
-0.5f, -0.5f, 0.0f, // p2
0.5f, 0.5f, 0.0f, //p4
0.5f, -0.5f, 0.0f, // p3
};
複製代碼
再多邊形也能夠用三角形拼出來,不過感受有點麻煩
解密:GL_TRIANGLE_STRIP
:相鄰三個頂點繪製一個三角形bash
glDrawElements
我就想來着,應該有控制三角形頂點的東西,否則調起來很麻煩微信
緩衝頂點數據的套路基本一致,封個方法在GLUtils裏吧,
暫時float(4字節)和short(2字節),其餘的遇到再說ide
/**
* float數組緩衝數據
* @param vertexs 頂點
* @return 獲取浮點形緩衝數據
*/
public static FloatBuffer getFloatBuffer(float[] vertexs) {
FloatBuffer buffer;
///每一個浮點數:座標個數* 4字節
ByteBuffer qbb = ByteBuffer.allocateDirect(vertexs.length * 4);
//使用本機硬件設備的字節順序
qbb.order(ByteOrder.nativeOrder());
// 從字節緩衝區建立浮點緩衝區
buffer = qbb.asFloatBuffer();
// 將座標添加到FloatBuffer
buffer.put(vertexs);
//設置緩衝區以讀取第一個座標
buffer.position(0);
return buffer;
}
/**
* short數組緩衝數據
* @param vertexs short 數組
* @return 獲取short緩衝數據
*/
public static ShortBuffer getShortBuffer(short[] vertexs) {
ShortBuffer buffer;
ByteBuffer qbb = ByteBuffer.allocateDirect(vertexs.length * 2);
qbb.order(ByteOrder.nativeOrder());
buffer = qbb.asShortBuffer();
buffer.put(vertexs);
buffer.position(0);
return buffer;
}
複製代碼
我們從0開始數數,怎麼控制點,看圖你應該能知道post
static float sCoo[] = { //以逆時針順序
-0.5f, 0.5f, 0.0f, // p0
-0.5f, -0.5f, 0.0f, // p1
0.5f, -0.5f, 0.0f, // p2
0.5f, 0.5f, 0.0f, //p3
0.0f, 0.8f, 0.0f, //p4
};
//索引數組
private short[] idx = {
0, 4, 3,
1, 3, 0,
1, 2, 3
};
//索引緩衝
idxBuffer = GLUtils.getShortBuffer(idx);
//繪製
GLES20.glDrawElements(GLES20.GL_TRIANGLES, idx.length,
GLES20.GL_UNSIGNED_SHORT, idxBuffer);
複製代碼
先轉六邊形應該沒有什麼大問題了測試
static float sCoo[] = { //以逆時針順序
-0.5f, 0.5f, 0.0f, // p0
-1.0f, 0.0f, 0.0f, // p1
-0.5f, -0.5f, 0.0f, // p2
0.5f, -0.5f, 0.0f, //p3
1.0f, 0.0f, 0.0f, //p4
0.5f, 0.5f, 0.0f, //p5
};
//索引數組
private short[] idx = {
0, 1, 5,
1, 5, 2,
2, 5, 4,
2, 3, 4
};
複製代碼
龍之空間
到這來,我們幾乎都是在平面,先轉要變立體了
守關boss要發大招了,勇士們,hold住
關於變換第一集講了一些,忘了的能夠回去看看
下面是轉一圈的效果,感受少了一半
//圍繞y軸旋轉
Matrix.setRotateM(mOpMatrix, 0, currDeg, 0, 1, 0);
複製代碼
我讓她一邊移動一邊旋轉,好像能夠看出一點東西
不過是轉起來了,等到轉講視野的時候再詳細論述吧
Matrix.setRotateM(mOpMatrix, 0, currDeg, 0, 1, 0);
Matrix.translateM(mOpMatrix, 0, currDeg/360.f, 0,0);
複製代碼
貌似一直z軸咱們都是0,動一下唄,紙上和ps上仍是各有優勢的
紙上畫起來有感受(但偏差很大),ps裏複用強,先看p0,p1,p2,p3
面
先從p0點(-0.5,0.5,0.5)入手,而後根據對稱關係,或目測肯定其餘點,
//點位數組
static float sCoo[] = {
-0.5f, 0.5f, 0.5f,//p0
-0.5f, -0.5f, 0.5f,//p1
-0.5f, -0.5f, -0.5f,//p2
-0.5f, 0.5f, -0.5f,//p3
}
//索引數組
private short[] idx = {
0, 1, 3,
1, 2, 3,
}
float colors[] = new float[]{
1f, 1f, 0.0f, 1.0f,//黃
0.05882353f, 0.09411765f, 0.9372549f, 1.0f,//藍
0.19607843f, 1.0f, 0.02745098f, 1.0f,//綠
1.0f, 0.0f, 1.0f, 1.0f,//紫色
}
複製代碼
一面完成了,第二面
p四、p五、p六、p7
就好辦了,能夠看出來p0,p1和p4,p5是同樣的
索引稍微畫畫也能看出規律,顏色再來那四個,就不貼了
能夠看出和咱們畫的有點出入,貌似是視口的問題,但不影響圖形自己
static float sCoo[] = {
-0.5f, 0.5f, 0.5f,//p0
-0.5f, -0.5f, 0.5f,//p1
-0.5f, -0.5f, -0.5f,//p2
-0.5f, 0.5f, -0.5f,//p3
-0.5f, 0.5f, 0.5f,//p4
-0.5f, -0.5f, 0.5f,//p5
0.5f, -0.5f, 0.5f,//p6
0.5f, 0.5f, 0.5f,//p7
//索引數組
private short[] idx = {
0, 1, 3,
1, 2, 3,
0+4, 1+4, 3+4,
1+4, 2+4, 3+4,
複製代碼
爲了方便表述,我給每一個面取了名字,分別是:
A、B、C、D、E、F
static float sCoo[] = {
//A面
-0.5f, 0.5f, 0.5f,//p0
-0.5f, -0.5f, 0.5f,//p1
-0.5f, -0.5f, -0.5f,//p2
-0.5f, 0.5f, -0.5f,//p3
//B面
-0.5f, 0.5f, 0.5f,//p4
-0.5f, -0.5f, 0.5f,//p5
0.5f, -0.5f, 0.5f,//p6
0.5f, 0.5f, 0.5f,//p7
//C面
0.5f, 0.5f, 0.5f,//p8
0.5f, -0.5f, 0.5f,//p9
0.5f, -0.5f, -0.5f,//p10
0.5f, 0.5f, -0.5f,//p11
//D面
-0.5f, 0.5f, 0.5f,//p12
0.5f, 0.5f, 0.5f,//p13
0.5f, 0.5f, -0.5f,//p14
-0.5f, 0.5f, -0.5f,//p15
//E面
-0.5f, -0.5f, 0.5f,//p16
0.5f, -0.5f, 0.5f,//p17
0.5f, -0.5f, -0.5f,//p18
-0.5f, -0.5f, -0.5f,//p19
//F面
-0.5f, 0.5f, -0.5f,//p20
-0.5f, -0.5f, -0.5f,//p21
0.5f, -0.5f, -0.5f,//p22
0.5f, 0.5f, -0.5f,//p23
};
//索引數組
private short[] idx = {
0, 1, 3,//A
1, 2, 3,
0 + 4, 1 + 4, 3 + 4,//B
1 + 4, 2 + 4, 3 + 4,
0 + 4 * 2, 1 + 4 * 2, 3 + 4 * 2,//C
1 + 4 * 2, 2 + 4 * 2, 3 + 4 * 2,
0 + 4 * 3, 1 + 4 * 3, 3 + 4 * 3,//D
1 + 4 * 3, 2 + 4 * 3, 3 + 4 * 3,
0 + 4 * 4, 1 + 4 * 4, 3 + 4 * 4,//E
1 + 4 * 4, 2 + 4 * 4, 3 + 4 * 4,
0 + 4 * 5, 1 + 4 * 5, 3 + 4 * 5,//F
1 + 4 * 5, 2 + 4 * 5, 3 + 4 * 5,
};
float colors[] = new float[]{
//A
1f, 1f, 0.0f, 1.0f,//黃
0.05882353f, 0.09411765f, 0.9372549f, 1.0f,//藍
0.19607843f, 1.0f, 0.02745098f, 1.0f,//綠
1.0f, 0.0f, 1.0f, 1.0f,//紫色
//B
1f, 1f, 0.0f, 1.0f,//黃
0.05882353f, 0.09411765f, 0.9372549f, 1.0f,//藍
0.19607843f, 1.0f, 0.02745098f, 1.0f,//綠
1.0f, 0.0f, 1.0f, 1.0f,//紫色
//C
1f, 1f, 0.0f, 1.0f,//黃
0.05882353f, 0.09411765f, 0.9372549f, 1.0f,//藍
0.19607843f, 1.0f, 0.02745098f, 1.0f,//綠
1.0f, 0.0f, 1.0f, 1.0f,//紫色
//D
1f, 1f, 0.0f, 1.0f,//黃
0.05882353f, 0.09411765f, 0.9372549f, 1.0f,//藍
0.19607843f, 1.0f, 0.02745098f, 1.0f,//綠
1.0f, 0.0f, 1.0f, 1.0f,//紫色
//E
1f, 1f, 0.0f, 1.0f,//黃
0.05882353f, 0.09411765f, 0.9372549f, 1.0f,//藍
0.19607843f, 1.0f, 0.02745098f, 1.0f,//綠
1.0f, 0.0f, 1.0f, 1.0f,//紫色
//F
1f, 1f, 0.0f, 1.0f,//黃
0.05882353f, 0.09411765f, 0.9372549f, 1.0f,//藍
0.19607843f, 1.0f, 0.02745098f, 1.0f,//綠
1.0f, 0.0f, 1.0f, 1.0f,//紫色
};
複製代碼
龍之逆鱗
第六副本中的立方體並不怎麼讓人滿意,視角不怎麼好,
這一副本就來再看看相機和投影以及矩陣
一開始眼睛在(0, 0, -3),看下圖你就知道爲何畫的時候面有問題了
由於相機在後面,並且很正,因此看着就很正...
// 設置相機位置(視圖矩陣)
Matrix.setLookAtM(mViewMatrix, 0,
0, 0, -3,
0f, 0f, 0f,
0f, 1.0f, 0.0f);
複製代碼
如今調到後上方(2,2,-5)
// 設置相機位置(視圖矩陣)
Matrix.setLookAtM(mViewMatrix, 0,
2f, 2f, -5.0f,
0f, 0f, 0f,
0f, 1.0f, 0.0f);
複製代碼
//初始化變換矩陣
Matrix.setRotateM(mOpMatrix, 0, 130, 0, 1, 0);
複製代碼
而後再來看繪製的流程,就和紙上的一致了,因此視口很重要
龍之盛裝 LEVEL1
顏色多沒勁,我們來貼圖,經歷了這麼多,回頭看看,感慨良多 這個副本將簡單認識貼圖,之後還會有高級的
龍之盛裝
百度了一個小時,愣是沒有把貼圖整明白,敘述的邏輯性欠佳,都是貼個代碼完事,
貼個完整的還好,但都是一段一段的代碼...
如今我來捋一遍,最簡單的三角形貼圖的流程,先把視野移到(0,0,-3) 否則確定變形
rect_texture.frag
precision mediump float;
varying vec2 aCoordinate;//貼圖座標系
uniform sampler2D vTexture;//貼圖
void main() {
gl_FragColor=texture2D(vTexture,aCoordinate);
}
複製代碼
rect_texture.vert
attribute vec3 vPosition;//頂點座標
uniform mat4 uMVPMatrix; //總變換矩陣
attribute vec2 vCoordinate;//貼圖頂點座標
varying vec2 aCoordinate;//貼圖頂點座標--片元變量
void main() {
gl_Position = uMVPMatrix*vec4(vPosition,1);
aCoordinate=vCoordinate;
}
複製代碼
TextureRectangle
就是把顏色句柄換成了貼圖句柄 再繪製的時候接受一個貼圖的id,
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId);
兩行代碼貼圖
其他的基本一致,下面最重要的是這個貼圖id如何獲取
/**
* 做者:張風捷特烈<br/>
* 時間:2019/1/9 0009:20:09<br/>
* 郵箱:1981462002@qq.com<br/>
* 說明:貼圖測試
*/
public class TextureRectangle {
private static final String TAG = "Triangle";
private Context mContext;
private int mProgram;//OpenGL ES 程序
private int mPositionHandle;//位置句柄
private int mColorHandle;//顏色句柄
private int muMVPMatrixHandle;//頂點變換矩陣句柄
private FloatBuffer vertexBuffer;//頂點緩衝
private final int vertexStride = COORDS_PER_VERTEX * 4; // 3*4=12
static final int COORDS_PER_VERTEX = 3;//數組中每一個頂點的座標數
static final int c = 1;//數組中每一個頂點的座標數
static float sCoo[] = { //以逆時針順序
-c, c, 0.0f, // p0
-c, -c, 0.0f, // p1
c, -c, 0.0f, // p2
};
private final float[] textureCoo = {
0.0f,0.0f,
0.0f,1.0f,
1.0f,0.0f,
};
static final int TEXTURE_PER_VERTEX = 2;//數組中每一個頂點的座標數
private final int vertexTextureStride = TEXTURE_PER_VERTEX * 4; // 4*4=16
private ShortBuffer idxBuffer;
//索引數組
private short[] idx = {
1, 2, 3,
};
private FloatBuffer mTextureCooBuffer;
public TextureRectangle(Context context) {
mContext = context;
//初始化頂點字節緩衝區
bufferData();//緩衝頂點數據
initProgram();//初始化OpenGL ES 程序
}
/**
* 緩衝數據
*/
private void bufferData() {
vertexBuffer = GLUtil.getFloatBuffer(sCoo);
mTextureCooBuffer = GLUtil.getFloatBuffer(textureCoo);
idxBuffer = GLUtil.getShortBuffer(idx);
}
/**
* 初始化OpenGL ES 程序
*/
private void initProgram() {
////頂點着色
int vertexShader = GLUtil.loadShaderAssets(mContext,
GLES20.GL_VERTEX_SHADER, "rect_texture.vert");
//片元着色
int fragmentShader = GLUtil.loadShaderAssets(mContext,
GLES20.GL_FRAGMENT_SHADER, "rect_texture.frag");
mProgram = GLES20.glCreateProgram();//建立空的OpenGL ES 程序
GLES20.glAttachShader(mProgram, vertexShader);//加入頂點着色器
GLES20.glAttachShader(mProgram, fragmentShader);//加入片元着色器
GLES20.glLinkProgram(mProgram);//建立可執行的OpenGL ES項目
//獲取頂點着色器的vPosition成員的句柄
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
//獲取片元着色器的vColor成員的句柄
mColorHandle = GLES20.glGetAttribLocation(mProgram, "vCoordinate");
//獲取程序中總變換矩陣uMVPMatrix成員的句柄
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
}
public void draw(float[] mvpMatrix, int texId ) {
// 將程序添加到OpenGL ES環境中
GLES20.glUseProgram(mProgram);
//啓用三角形頂點的句柄
GLES20.glEnableVertexAttribArray(mPositionHandle);
//啓用三角形頂點顏色的句柄
GLES20.glEnableVertexAttribArray(mColorHandle);
//頂點矩陣變換
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mvpMatrix, 0);
//準備三角頂點座標數據
GLES20.glVertexAttribPointer(
mPositionHandle,//int indx, 索引
COORDS_PER_VERTEX,//int size,大小
GLES20.GL_FLOAT,//int type,類型
false,//boolean normalized,//是否標準化
vertexStride,// int stride,//跨度
vertexBuffer);// java.nio.Buffer ptr//緩衝
//準備三角頂點顏色數據
GLES20.glVertexAttribPointer(
mColorHandle,
TEXTURE_PER_VERTEX,
GLES20.GL_FLOAT,
false,
vertexTextureStride,
mTextureCooBuffer);
//綁定紋理
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId);
//繪製
GLES20.glDrawElements(GLES20.GL_TRIANGLES, idx.length, GLES20.GL_UNSIGNED_SHORT, idxBuffer);
//禁用頂點數組:
//禁用index指定的通用頂點屬性數組。
// 默認狀況下,禁用全部客戶端功能,包括全部通用頂點屬性數組。
// 若是啓用,將訪問通用頂點屬性數組中的值,
// 並在調用頂點數組命令(如glDrawArrays或glDrawElements)時用於呈現
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
}
複製代碼
我在GLUtil中封裝了兩個方法
/**
* 資源id 加載紋理
* @param ctx 上下文
* @param resId 資源id
* @return 紋理id
*/
public static int loadTexture(Context ctx, int resId) {
Bitmap bitmap = BitmapFactory.decodeResource(ctx.getResources(), resId);
return loadTexture(ctx, bitmap);
}
/**
* bitmap 加載紋理
* @param ctx 上下文
* @param bitmap bitmap
* @return 紋理id
*/
public static int loadTexture(Context ctx, Bitmap bitmap) {
//生成紋理ID
int[] textures = new int[1];
//(產生的紋理id的數量,紋理id的數組,偏移量)
GLES20.glGenTextures(1, textures, 0);
int textureId = textures[0];
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
//實際加載紋理(紋理類型,紋理的層次,紋理圖像,紋理邊框尺寸)
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle(); //紋理加載成功後釋放圖片
return textureId;
}
複製代碼
GLRenderer.java
private int textureId;
---->[GLRenderer#onSurfaceCreated]------
textureId = GLUtil.loadTexture(mContext, R.mipmap.mian_a);//初始化紋理
---->[GLRenderer#onDrawFrame]------
mTextureRectangle.draw(mMVPMatrix,textureId);//繪製時使用紋理
複製代碼
這是一道送分題,沒別的,座標改改就好了
static float sCoo[] = { //以逆時針順序
-c, c, 0.0f, // p0
-c, -c, 0.0f, // p1
c, -c, 0.0f, // p2
c, c, 0.0f, //p3
};
private final float[] textureCoo = {
0.0f,0.0f,
0.0f,1.0f,
1.0f,0.0f,
1.0f,1.0f,
};
//索引數組
private short[] idx = {
1, 2, 3,
0, 1, 3,
};
複製代碼
有興趣的能夠動動貼圖座標系的點看一下,本身瞭解一下貼圖座標系
(出現一道門)NPC:恭喜勇者攻克第八副本,請使用您的立方開啓這道
黑龍之門
自此,您將正式踏入黑龍領地
,祝您征途順利
我將立方嵌入門中,大門打開,眼前竟是...
OK,本集結束,下一集:"聖火之光",敬請期待
項目源碼 | 日期 | 備註 |
---|---|---|
V0.1-github | 2018-1-11 | Android多媒體之GL-ES戰記第二集--謎團立方 |
筆名 | 微信 | 愛好 | |
---|---|---|---|
張風捷特烈 | 1981462002 | zdl1994328 | 語言 |
個人github | 個人簡書 | 個人掘金 | 我的網站 |