九層之臺,起於累土;千里之行,始於足下
旁白:上集說到:勇者....
張風捷特烈(搶話筒):廢話很少說,觀看此篇,先把筆和草稿紙
拿出來,這很是重要!java
擎天之柱
:拿出草稿紙,本身畫一畫,拋開書本(發現那本書的畫法思路不怎麼樣,不優雅)
我們來本身算,本身畫,該副本的代碼在shape/part
,瑣碎的小點就省去了
一路走到這裏,套路基本上都同樣,本文研究的只是圖形畫法,基本用法不會的就前補吧git
GL_TRIANGLES畫圓
/**
* 初始化頂點座標數據的方法
*
* @param r 半徑
* @param splitCount 切分的份數
*/
public void initVertex(float r, int splitCount) {
float dθ = 360.0f / splitCount;//頂角的度數
vertexCount = 3 * splitCount;//頂點個數,共有n個三角形,每一個三角形都有三個頂點
float[] vertices = new float[vertexCount * 3];//座標數據
for (int v = 0, t = 0; v < vertexCount; v += 3, t += 3) {
int n = v / 3;
vertices[3 * v] = 0;//頂點座標:p0
vertices[3 * v + 1] = 0;
vertices[3 * v + 2] = 0;
vertices[3 * v + 3] = r * cos(n * dθ);//頂點座標:p1
vertices[3 * v + 4] = r * sin(n * dθ);
vertices[3 * v + 5] = 0;
vertices[3 * v + 6] = r * cos((n + 1) * dθ);//頂點座標:p2
vertices[3 * v + 7] = r * sin((n + 1) * dθ);
vertices[3 * v + 8] = 0;
}
}
複製代碼
for (int v = 0, t = 0; v < vertexCount; v += 3, t += 3) {
int n = v / 3;
//頂點座標計算同上, 略 ....
textures[2 * t] = 0.5f;//貼圖:p0
textures[2 * t + 1] = 0.5f;
textures[2 * t + 2] = 0.5f + 0.5f * r * cos(n * dθ);//貼圖:p1
textures[2 * t + 3] = 0.5f - 0.5f * r * sin(n * dθ);
textures[2 * t + 4] = 0.5f + 0.5f * r * cos((n + 1) * dθ);//貼圖:p2
textures[2 * t + 5] = 0.5f - 0.5f * r * sin((n + 1) * dθ);
}
複製代碼
/**
* 圓柱側面
* @param r 半徑
* @param h 高度
* @param splitCount 切分的份數
*/
public void initVertex(float r, float h, int splitCount) {
float dθ = 360.0f / splitCount;
vertexCount = splitCount * 4 * 3;//頂點個數,共有3*splitCount*4個三角形,每一個三角形都有三個頂點
//座標數據初始化
float[] vertices = new float[vertexCount * 3];
float[] textures = new float[vertexCount * 2];//頂點紋理S、T座標值數組
for (int v = 0, t = 0; v < vertexCount; v += 6, t += 6) {
int n = v / 6;
float x = r * cos(n * dθ);
float xNext = r * cos(n * dθ + dθ);
float z = -r * sin(n * dθ);
float zNext = -r * sin(n * dθ + dθ);
vertices[3 * v + 0] = x;//底部p0
vertices[3 * v + 1] = 0;
vertices[3 * v + 2] = z;
vertices[3 * v + 3] = xNext;//頂部p2
vertices[3 * v + 4] = h;
vertices[3 * v + 5] = zNext;
vertices[3 * v + 6] = x;//頂部p1
vertices[3 * v + 7] = h;//y
vertices[3 * v + 8] = z;//z
vertices[3 * v + 9] = x;//底部p0
vertices[3 * v + 10] = 0;
vertices[3 * v + 11] = z;
vertices[3 * v + 12] = xNext;//底部p3
vertices[3 * v + 13] = 0;//y
vertices[3 * v + 14] = zNext;//z
vertices[3 * v + 15] = xNext;//頂部p2
vertices[3 * v + 16] = h;//y
vertices[3 * v + 17] = zNext;//z
float s = n * dθ / 360.f;
float sNext = (n + 1) * dθ / 360.f;
textures[2 * t + 0] = s;//貼圖:p0
textures[2 * t + 1] = 1;
textures[2 * t + 2] = sNext;//貼圖:p2
textures[2 * t + 3] = 0;
textures[2 * t + 4] = s;//貼圖:p1
textures[2 * t + 5] = 0;
textures[2 * t + 6] = s;//貼圖:p0
textures[2 * t + 7] = 1;
textures[2 * t + 8] = sNext;//貼圖:p3
textures[2 * t + 9] = 1;
textures[2 * t + 10] = sNext;//貼圖:p2
textures[2 * t + 11] = 0;
}
//法向量數據初始化
float[] normals = new float[vertices.length];
for (int i = 0; i < vertices.length; i++) {
if (i % 3 == 1) {
normals[i] = 0;
} else {
normals[i] = vertices[i];
}
}
vertexBuffer = GLUtil.getFloatBuffer(vertices);
mNormalBuffer = GLUtil.getFloatBuffer(normals);
mTexCoorBuffer = GLUtil.getFloatBuffer(textures);
}
複製代碼
側面旋轉90°github
MatrixStack
將MatrixStack在保存狀態下重置,再進行變換操做,最後restore,感受用着蠻不錯的編程
/**
* 設置沿xyz軸移動 注意:本方法和restore聯合使用
*
* @param x 移動的 x 份量
* @param y 移動的 y 份量
* @param z 移動的 z 份量
*/
public static void reTranslate(float[] target, float x, float y, float z) {
save();
reset();
Matrix.translateM(MatrixStack.getOpMatrix(), 0, target, 0,
x, y, z);
}
/**
* 設置沿(x,y,z)點旋轉 注意:本方法和restore聯合使用
*
* @param deg 角度
* @param x 旋轉點的 x 份量
* @param y 旋轉點的 y 份量
* @param z 旋轉點的 z 份量
*/
public static void reRotate(float[] target, float deg, float x, float y, float z) {
save();
reset();
Matrix.rotateM(MatrixStack.getOpMatrix(), 0, target, 0,
deg, x, y, z);
}
複製代碼
Cylinder.java
這個比較簡單,圓和側面都有了,拼起來就好了數組
/**
* 做者:張風捷特烈<br/>
* 時間:2019/1/16/016:19:22<br/>
* 郵箱:1981462002@qq.com<br/>
* 說明:圓柱類
*/
public class Cylinder extends RendererAble {
private final Circle mBottomCircle;//底圓
private final Circle mTopCircle;//頂圓
private final CylinderSide mCylinderSide;
private float mH;
/**
* @param context 上下文
* @param h 高
* @param r 底面半徑
* @param splitCount 切割數
* @param textureIdX3 貼圖id 上、下、周圍貼圖
*/
public Cylinder(Context context, float r, float h, int splitCount, int[] textureIdX3) {
super(context);
if (textureIdX3.length != 3) {
throw new IllegalArgumentException("the length of textureIdX3 must be 3");
}
mH = h;
mBottomCircle = new Circle(context, r, splitCount, textureIdX3[0]);
mTopCircle = new Circle(context, r, splitCount, textureIdX3[1]);
mCylinderSide = new CylinderSide(mContext, r, h, splitCount, textureIdX3[2]);
}
@Override
public void draw(float[] mvpMatrix) {
MatrixStack.reTranslate(mvpMatrix, 0, 0, mH);
mTopCircle.draw(MatrixStack.getOpMatrix());
MatrixStack.restore();
MatrixStack.reRotate(mvpMatrix, 90, 1, 0, 0);
mCylinderSide.draw(MatrixStack.getOpMatrix());
MatrixStack.restore();
mBottomCircle.draw(mvpMatrix);
}
}
複製代碼
鑽天之錐
:其餘立體圖形的思路基本一致,就是尋找三角形座標、貼圖座標、法向量座標
其中法向量座標是和光照相關的,這裏暫時不討論,後面光照會詳細討論
寫了這麼多感受重複的代碼不少,抽取了一個父類EvnRender
來作一些通用的事 它的孩子只需在乎:三角形座標、貼圖座標、法向量座標三個數組便可bash
GL_TRIANGLE_FAN繪製 三角形,拼合圓形
好處:頂點少 之前是:
3*splitCount
,如今是splitCount+2
微信
/**
* 初始化頂點座標數據的方法
*
* @param r 半徑
* @param splitCount 切分的份數
*/
public void initVertex(float r, int splitCount) {
float dθ = 360.0f / splitCount;//頂角的度數
int vertexCount = splitCount + 2;//頂點個數,共有n個三角形,每一個三角形都有三個頂點
float[] vertices = new float[vertexCount * 3];//座標數據
float[] textures = new float[vertexCount * 2];//頂點紋理S、T座標值數組
vertices[0] = 0;
vertices[1] = 0;
vertices[2] = 0;
textures[0] = 0.5f;
textures[1] = 0.5f;
for (int n = 1; n < vertexCount; n++) {
//頂點座標
vertices[n * 3 + 0] = r * cos((n - 1) * dθ);//x
vertices[n * 3 + 1] = r * sin((n - 1) * dθ);//y
vertices[n * 3 + 2] = 0;//z
//紋理座標
textures[2 * n] = 0.5f + 0.5f * cos((n - 1) * dθ);
textures[2 * n + 1] = 0.5f - 0.5f * sin((n - 1) * dθ);
}
}
複製代碼
圓錐側面方式一:GL_TRIANGLES
/**
* 初始化頂點
* @param r 半徑
* @param h 高度
* @param splitCount 切分的份數
*/
public void initVertexData(float r, float h, int splitCount) {
float dθ = 360.0f / splitCount;
int vCount = splitCount * 3;//頂點個數,共有3*splitCount*4個三角形,每一個三角形都有三個頂點
//座標數據初始化
float[] vertices = new float[vCount * 3];
float[] textures = new float[vCount * 2];//頂點紋理S、T座標值數組
float[] normals = new float[vertices.length];//法向量數組
for (int v = 0, t = 0; v < vCount; v += 3, t += 3) {
int n = v / 3;
float x = r * cos(n * dθ);
float xNext = r * cos(n * dθ + dθ);
float z = r * sin(n * dθ);
float zNext = r * sin(n * dθ + dθ);
//頂點座標
vertices[3 * v + 0] = 0;//p0
vertices[3 * v + 1] = h;
vertices[3 * v + 2] = 0;
vertices[3 * v + 3] = x;//p1
vertices[3 * v + 4] = 0;
vertices[3 * v + 5] = z;
vertices[3 * v + 6] = xNext;//p2
vertices[3 * v + 7] = 0;
vertices[3 * v + 8] = zNext;
//紋理座標
float s = n * dθ / 360.f;
float sNext = (n + 1) * dθ / 360.f;
textures[2 * t + 0] = 0.5f;//p0
textures[2 * t + 1] = 0f;
textures[2 * t + 2] = s;//p1
textures[2 * t + 3] = 1f;
textures[2 * t + 4] = sNext;//p2
textures[2 * t + 5] = 1f;
}
}
複製代碼
圓錐側面方式二:GL_TRIANGLE_FAN
省頂點,並且寫起來簡單ide
/**
* 初始化頂點
*
* @param r 半徑
* @param h 高度
* @param splitCount 切分的份數
*/
public void initVertexData(float r, float h, int splitCount) {
float dθ = 360.0f / splitCount;
int vCount = splitCount + 2;//頂點個數,共有3*splitCount*4個三角形,每一個三角形都有三個頂點
//座標數據初始化
float[] vertices = new float[vCount * 3];
float[] textures = new float[vCount * 2];//頂點紋理S、T座標值數組
float[] normals = new float[vertices.length];//法向量數組
//頂點座標
vertices[0] = 0;//p0
vertices[1] = h;
vertices[2] = 0;
textures[0] = 0.5f;//p0
textures[1] = 0f;
for (int n = 1; n < vCount; n++) {
float x = r * cos(n * dθ);
float z = r * sin(n * dθ);
//頂點座標
vertices[3 * n + 0] = x;//p1
vertices[3 * n + 1] = 0;
vertices[3 * n + 2] = z;
//紋理座標
float s = n * dθ / 360.f;
textures[2 * n + 0] = s;//p1
textures[2 * n + 1] = 1f;
}
}
複製代碼
拼接圓錐
/**
* 做者:張風捷特烈<br/>
* 時間:2019/1/16/016:19:22<br/>
* 郵箱:1981462002@qq.com<br/>
* 說明:圓錐類
*/
public class Cone extends RenderAble {
private CircleFanEvn mBottomCircleTris;//底圓
private ConeSideFanEvn mConeSide;//側面
private float mH;
/**
* @param context 上下文
* @param h 高
* @param r 底面半徑
* @param splitCount 切割數
* @param textureIdX2 貼圖id 下、周圍貼圖
*/
public Cone(Context context, float r, float h, int splitCount, int[] textureIdX2) {
super(context);
if (textureIdX2.length != 2) {
throw new IllegalArgumentException("the length of textureIdX3 must be 2");
}
mH = h;
mBottomCircleTris = new CircleFanEvn(context, textureIdX2[0], r, splitCount);
mConeSide = new ConeSideFanEvn(context, textureIdX2[1], r, h,splitCount);
}
@Override
public void draw(float[] mvpMatrix) {
MatrixStack.reRotate(mvpMatrix, 90, 1, 0, 0);
mConeSide.draw(MatrixStack.getOpMatrix());
MatrixStack.restore();
mBottomCircleTris.draw(mvpMatrix);
}
}
複製代碼
立方之魔
封裝立方,拼合魔方post
/**
* 做者:張風捷特烈<br/>
* 時間:2019/1/17/017:11:28<br/>
* 郵箱:1981462002@qq.com<br/>
* 說明:與Y軸組成的面
*/
public class RectangleEvn extends EvnRender {
public RectangleEvn(Context context, int tId, float x, float y, float z) {
super(context, tId, GLES20.GL_TRIANGLE_STRIP);
initVertex(x, y, z);
}
private void initVertex(float x, float y, float z) {
int vertexCount = 4;//頂點個數,共有n個三角形,每一個三角形都有三個頂點
float[] vertices = new float[vertexCount * 3];//座標數據
float[] textures = new float[vertexCount * 2];//頂點紋理S、T座標值數組
float[] normals = new float[vertices.length];
//頂點座標
vertices[0] = 0;//p0
vertices[1] = 0;
vertices[2] = 0;
vertices[3] = 0;//p1
vertices[4] = y;
vertices[5] = 0;
vertices[6] = x;//p3
vertices[7] = 0;
vertices[8] = z;
vertices[9] = x;//p2
vertices[10] = y;
vertices[11] = z;
//貼圖座標
textures[0] = 0;//p0
textures[1] = 1;
textures[2] = 0;//p1
textures[3] = 0;
textures[4] = 1;//p3
textures[5] = 1;
textures[6] = 1;//p2
textures[7] = 0;
init(vertices, textures, normals);
}
}
複製代碼
/**
* 做者:張風捷特烈<br/>
* 時間:2019/1/9 0009:20:09<br/>
* 郵箱:1981462002@qq.com<br/>
* 說明:貼圖立方
*/
public class Cube3d extends RenderAble {
private final RectangleEvn mRectA;
private final RectangleEvn mRectB;
private final RectangleEvn mRectD;
private final RectangleEvn mRectC;
private final RectangleEvn mRectE;
private final RectangleEvn mRectF;
private float rate;
private float mX;
private float mY;
private float mZ;
public Cube3d(Context context, float x, float y, float z, int[] textureIdX6) {
super(context);
if (textureIdX6.length != 6) {
throw new IllegalArgumentException("the length of textureIdX3 must be 6");
}
mX = x;
mY = y;
mZ = z;
mRectA = new RectangleEvn(mContext, textureIdX6[0], 0, y, z);
mRectB = new RectangleEvn(mContext, textureIdX6[1], 0, y, z);
mRectC = new RectangleEvn(mContext, textureIdX6[2], 0, y, z);
mRectD = new RectangleEvn(mContext, textureIdX6[3], 0, y, z);
mRectE = new RectangleEvn(mContext, textureIdX6[4], 0, y, z);
mRectF = new RectangleEvn(mContext, textureIdX6[5], 0, y, z);
}
@Override
public void draw(float[] mvpMatrix) {
mRectA.draw(mvpMatrix);
MatrixStack.reTranslate(mvpMatrix, 0, 0, mZ);
MatrixStack.rotate(90, 0, 1, 0);
mRectB.draw(MatrixStack.getOpMatrix());
MatrixStack.restore();
MatrixStack.reTranslate(mvpMatrix, mX, 0, 0);
MatrixStack.rotate(90, 0, -1, 0);
mRectD.draw(MatrixStack.getOpMatrix());
MatrixStack.restore();
MatrixStack.reTranslate(mvpMatrix, 0, 0, 0);
MatrixStack.rotate(-90, 0, 0, 1);
MatrixStack.translate(0, 0, mZ);
MatrixStack.rotate(180, 0, 1, 0);
mRectF.draw(MatrixStack.getOpMatrix());
MatrixStack.restore();
MatrixStack.reTranslate(mvpMatrix, 0, mY, 0);
MatrixStack.rotate(-90, 0, 0, 1);
mRectE.draw(MatrixStack.getOpMatrix());
MatrixStack.restore();
MatrixStack.reTranslate(mvpMatrix, mX, 0, mZ);
MatrixStack.rotate(-180, 0, 1, 0);
mRectC.draw(MatrixStack.getOpMatrix());
MatrixStack.restore();
}
public void setRate(float rate) {
this.rate = rate;
}
}
複製代碼
---->[WorldShape#draw]----------
//立方的偏移數組
mTrans = new float[]{
0, 0, 0,
0, 0, 0.5f,
0, 0, -0.5f,
0, 0.5f, 0,
0, 0.5f, 0.5f,
0, 0.5f, -0.5f,
0.5f, 0.5f, 0,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, -0.5f,
0.5f, 0f, 0,
0.5f, 0f, 0.5f,
0.5f, 0f, -0.5f,
0.5f, -0.5f, 0,
0.5f, -0.5f, 0.5f,
0.5f, -0.5f, -0.5f,
0f, -0.5f, 0,
0f, -0.5f, 0.5f,
0f, -0.5f, -0.5f,
-0.5f, -0.5f, 0,
-0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, 0f, 0,
-0.5f, 0f, 0.5f,
-0.5f, 0f, -0.5f,
-0.5f, 0.5f, 0,
-0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
};
---->[WorldShape#draw]----------
for (int i = 0; i < mTrans.length / 3; i++) {
MatrixStack.reTranslate(mvpMatrix, mTrans[3 * i], mTrans[3 * i + 1], mTrans[3 * i + 2]);
mCube3d.draw(MatrixStack.getOpMatrix());
MatrixStack.restore();
}
複製代碼
GLES2戰記下季預告
到此,咱們已經能夠對OpenGL的世界有了簡單的認識,若是你和我一路走來
相信你的運算能力和代碼控制力以及學習能力都會有必定的提升,以後的路還要本身去走
第一季到此結束:九層之臺,起於累土;千里之行,始於足下
,切莫眼高手低
下一季(若是有的話)咱們再見,臨走,丟幾個圖...本身實現去。
接下來繼續原來的多媒體路線。學習
項目源碼 | 日期 | 備註 |
---|---|---|
V0.1-github | 2018-1-17 | Android多媒體之GLES2戰記第六集--九層之臺 |
筆名 | 微信 | 愛好 | |
---|---|---|---|
張風捷特烈 | 1981462002 | zdl1994328 | 語言 |
個人github | 個人簡書 | 個人掘金 | 我的網站 |
1----本文由張風捷特烈原創,轉載請註明
2----歡迎廣大編程愛好者共同交流
3----我的能力有限,若有不正之處歡迎你們批評指證,一定虛心改正
4----看到這裏,我在此感謝你的喜歡與支持