内容简介:旁白:上集说到:勇者....张风捷特烈(抢话筒):废话不多说,观看此篇,先把拿出草稿纸,自己画一画,抛开书本(发现那本书的画法思路不怎么样,不优雅)
旁白:上集说到:勇者....
张风捷特烈(抢话筒):废话不多说,观看此篇,先把 笔和草稿纸
拿出来,这非常重要!
第九副本: 擎天之柱
:
拿出草稿纸,自己画一画,抛开书本(发现那本书的画法思路不怎么样,不优雅)
咱们来自己算,自己画,该副本的代码在 shape/part
,琐碎的小点就省去了
一路走到这里,套路基本上都一样,本文研究的只是图形画法,基本用法不会的就前补吧
1.第一关卡: GL_TRIANGLES画圆
1.1:顶点的计算
/** * 初始化顶点坐标数据的方法 * * @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; } } 复制代码
1.2:贴图坐标的计算
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θ); } 复制代码
2.第二关卡:圆柱侧面
/** * 圆柱侧面 * @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°
3.第三关卡:圆柱的拼接
3.1:移动和旋转的辅助方法 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); } 复制代码
3.2:三块拼型: 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
来做一些通用的事 它的孩子只需在意:三角形坐标、贴图坐标、法向量坐标三个数组即可
1.第一关卡: 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θ); } } 复制代码
2.第二关卡: 圆锥侧面方式一: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; } } 复制代码
3.第三关卡: 圆锥侧面方式二:GL_TRIANGLE_FAN
省顶点,而且写起来简单
/** * 初始化顶点 * * @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; } } 复制代码
4.第三关卡: 拼接圆锥
/** * 作者:张风捷特烈<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); } } 复制代码
第十一副本: 立方之魔
封装立方,拼合魔方
1.第一关卡:面封装
/** * 作者:张风捷特烈<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); } } 复制代码
2.第二关卡:封装立方
/** * 作者:张风捷特烈<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; } } 复制代码
3.第三关卡:拼合魔方
---->[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的世界有了简单的认识,如果你和我一路走来
相信你的运算能力和代码控制力以及学习能力都会有一定的提高,之后的路还要自己去走
第一季到此结束: 九层之台,起于累土;千里之行,始于足下
,切莫眼高手低
下一季(如果有的话)我们再见,临走,丢几个图...自己实现去。
接下来继续原来的多媒体路线。
后记:捷文规范
1.本文成长记录及勘误表
项目源码 | 日期 | 备注 |
---|---|---|
V0.1-github | 2018-1-17 | Android多媒体之GLES2战记第六集--九层之台 |
2.更多关于我
笔名 | 微信 | 爱好 | |
---|---|---|---|
张风捷特烈 | 1981462002 | zdl1994328 | 语言 |
我的github | 我的简书 | 我的掘金 | 个人网站 |
3.声明
1----本文由张风捷特烈原创,转载请注明
2----欢迎广大编程爱好者共同交流
3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
4----看到这里,我在此感谢你的喜欢与支持
以上所述就是小编给大家介绍的《Android多媒体之GLES2战记第六集--九层之台》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Java播放多媒体
- Java处理多媒体文件
- 07.Android之多媒体问题
- 音视频基础之多媒体封装格式
- FFmpeg 3.3.4 发布,多媒体处理工具
- FFmpeg 3.4 发布,多媒体处理工具合集
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。