博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android多媒体之GLES2战记第三集--圣火之光
阅读量:6843 次
发布时间:2019-06-26

本文共 14672 字,大约阅读时间需要 48 分钟。

前情回顾

旁边: 勇者们为求黑龙宝藏,集结起来共闯黑龙副本,经历重重艰辛,

终于获得立方开启了黑龙之门,这也只是新征程的起点,后面将有更大的挑战等着他们
张风捷特烈打开了门之后,看到了什么?让我们继续收看


副本九:黑暗之渊

在打开门后,光芒全部消失,眼中一团黑暗,张风捷特烈踏出一步

便立刻下坠,仿佛是无尽的深渊,地面?地面在那里?我还要下坠多久?


1.第一关卡:创造世界

NPC:This is the world without anything,you must create everything by yourself.

我:好吧,总结一下流程吧,顺便该封的封一下

1.1.常量:
public class Cons {    //维度:独立参数的数目    public static final int DIMENSION_2 = 2;//2维度    public static final int DIMENSION_3 = 3;//3维度    public static final int DIMENSION_4 = 4;//4维度}复制代码

1.2.显示的世界:World.java
/** * 作者:张风捷特烈
* 时间:2019/1/13/013:10:46
* 邮箱:1981462002@qq.com
* 说明:GL的世界 */public class World extends GLSurfaceView { private WorldRenderer mRenderer; public World(Context context) { this(context,null); } public World(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { setEGLContextClientVersion(2);//设置OpenGL ES 2.0 context mRenderer = new WorldRenderer(getContext()); setRenderer(mRenderer);//设置渲染器 setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); }}复制代码

1.3.世界的渲染器WorldRenderer
/** * 作者:张风捷特烈
* 时间:2019/1/9 0009:18:56
* 邮箱:1981462002@qq.com
* 说明:GL世界渲染类 */public class WorldRenderer implements GLSurfaceView.Renderer { private static final String TAG = "GLRenderer"; //Model View Projection Matrix--模型视图投影矩阵 private static float[] mMVPMatrix = new float[16]; //投影矩阵 mProjectionMatrix private static final float[] mProjectionMatrix = new float[16]; //视图矩阵 mViewMatrix private static final float[] mViewMatrix = new float[16]; //变换矩阵 private float[] mOpMatrix = new float[16]; private Context mContext; private RendererAble mWorldShape; public WorldRenderer(Context context) { mContext = context; } private int currDeg = 0; @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { GLES20.glClearColor(0.0f,0.0f,0.0f,1.0f);//rgba mWorldShape = new WorldShape(mContext); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { GLES20.glViewport(0, 0, width, height);//GL视口 float ratio = (float) width / height; //透视投影矩阵--截锥 Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 9); // 设置相机位置(视图矩阵) Matrix.setLookAtM(mViewMatrix, 0, 2f, 2f, -6.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f); } /** * 此方法会不断执行 {@link GLSurfaceView.RENDERMODE_CONTINUOUSLY} * 此方法执行一次 {@link GLSurfaceView.RENDERMODE_WHEN_DIRTY} * * @param gl */ @Override public void onDrawFrame(GL10 gl) { //清除颜色缓存和深度缓存 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); //初始化变换矩阵 Matrix.setRotateM(mOpMatrix, 0, currDeg, 0, 1, 0); Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mOpMatrix, 0); Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0); mWorldShape.draw(mMVPMatrix); //打开深度检测 GLES20.glEnable(GLES20.GL_DEPTH_TEST); }}复制代码

2.第二关卡:打开圣火之光(画点)

黑暗中应该先出现一个点,代表希望之光


2.1--片元着色代码:world.frag
precision mediump float; varying vec4 vColor;  void main() {   gl_FragColor = vColor; }复制代码

2.2--顶点着色代码:world.frag

注意这里要设置点的大小,否则默认为0

attribute vec3 vPosition;//顶点坐标uniform mat4 uMVPMatrix; //总变换矩阵attribute vec4 aColor;//顶点颜色varying  vec4 vColor;//片元颜色void main() {  gl_Position = uMVPMatrix*vec4(vPosition,1);  vColor = aColor;//将顶点颜色传给片元  gl_PointSize=10.0;//设置点的大小,默认为0}复制代码

2.3--点形状绘制
/** * 作者:张风捷特烈
* 时间:2019/1/13/013:8:39
* 邮箱:1981462002@qq.com
* 说明:世界的形状 */public class WorldShape extends RendererAble { private int mProgram;//OpenGL ES 程序 private int mPositionHandle;//位置句柄 private int mColorHandle;//颜色句柄 private int muMVPMatrixHandle;//顶点变换矩阵句柄 private FloatBuffer mColorBuffer;//颜色缓冲 private final int vertexColorStride = Cons.DIMENSION_4 * 4; // 4*4=16 private FloatBuffer mVertexBuffer;//顶点缓冲 private final int vertexStride = Cons.DIMENSION_3 * 4; // 3*4=12 private float[] mVertex = new float[]{ 0.0f,0.0f,0.0f }; private float[] mColor = new float[]{ 1.0f, 1.0f, 1.0f, 1.0f, }; public WorldShape(Context context) { super(context); mColorBuffer = GLUtil.getFloatBuffer(mColor); mVertexBuffer = GLUtil.getFloatBuffer(mVertex); initProgram(); } private void initProgram() { //顶点着色 int vertexShader = GLUtil.loadShaderAssets(mContext, GLES20.GL_VERTEX_SHADER, "world.vert"); //片元着色 int fragmentShader = GLUtil.loadShaderAssets(mContext, GLES20.GL_FRAGMENT_SHADER, "world.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, "aColor"); //获取程序中总变换矩阵uMVPMatrix成员的句柄 muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); } @Override public void draw(float[] mvpMatrix) { // 将程序添加到OpenGL ES环境中 GLES20.glUseProgram(mProgram); //启用顶点的句柄 GLES20.glEnableVertexAttribArray(mPositionHandle); //启用顶点颜色的句柄 GLES20.glEnableVertexAttribArray(mColorHandle); //顶点矩阵变换 GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mvpMatrix, 0); //准备顶点坐标数据 GLES20.glVertexAttribPointer( mPositionHandle,//int indx, 索引 Cons.DIMENSION_3,//int size,大小 GLES20.GL_FLOAT,//int type,类型 false,//boolean normalized,//是否标准化 vertexStride,// int stride,//跨度 mVertexBuffer);// java.nio.Buffer ptr//缓冲 //准备顶点颜色数据 GLES20.glVertexAttribPointer( mColorHandle, Cons.DIMENSION_4, GLES20.GL_FLOAT, false, vertexColorStride, mColorBuffer); int count = mVertex.length / Cons.DIMENSION_3; GLES20.glDrawArrays(GLES20.GL_POINTS, 0, count); }}复制代码

NPC:很好,获取技能GLES20.GL_POINTS,勇者,继续展现你的创造力吧!


3.第三关卡:绘制四点

private float[] mVertex = new float[]{        -1.0f, 0.0f, -1.0f,        -1.0f, 0.0f, 1.0f,        1.0f, 0.0f, 1.0f,        1.0f, 0.0f, -1.0f,};private float[] mColor = new float[]{        1.0f, 1.0f, 1.0f, 1.0f,        1.0f, 1.0f, 1.0f, 1.0f,        1.0f, 1.0f, 1.0f, 1.0f,        1.0f, 1.0f, 1.0f, 1.0f,};复制代码

张风捷特烈黑暗之渊中踩在四个点上,停止了下落,经过测量,发现点的单位是px


副本十:萦龙之丝

1.第一关卡:坐标系体系

接下来我们将使用以下视角进行世界的构建

现在将D点变色:可见视角和坐标系不一致

private float[] mVertex = new float[]{        -1.0f, 0.0f, -1.0f,//A        -1.0f, 0.0f, 1.0f,//B        1.0f, 0.0f, 1.0f,//C        1.0f, 0.0f, -1.0f,//D};private float[] mColor = new float[]{        1.0f, 1.0f, 1.0f, 1.0f,        1.0f, 1.0f, 1.0f, 1.0f,        1.0f, 1.0f, 1.0f, 1.0f,        0.21960784f,0.56078434f,0.92156863f,1.0f,};复制代码

2.第二关卡:调整视角,符合ps画的坐标系

为了视觉上好些,也为了ps里画图方便,这里讲视角逆时针旋转130°

Matrix.setRotateM(mOpMatrix, 0, currDeg+130, 0, 1, 0);复制代码


3.第三关卡:画线

直接把画点改成画线就行了,看一下GLES20几个常量的区别

GLES20.glLineWidth(10);//设置线的宽度int count = mVertex.length / Cons.DIMENSION_3;//GLES20.glDrawArrays(GLES20.GL_POINTS, 0, count);//GLES20.glDrawArrays(GLES20.GL_LINES, 0, count);//GLES20.glDrawArrays(GLES20.GL_LINE_STRIP, 0, count);GLES20.glDrawArrays(GLES20.GL_LINE_LOOP, 0, count);复制代码


为了使用方便,封装一下绘制简单图形的代码,就是把变量抽取一下

虽然只能画些简单的东西,但画画辅助线还是蛮方便的,一个SimpleShape

/** * 作者:张风捷特烈
* 时间:2019/1/13/013:17:37
* 邮箱:1981462002@qq.com
* 说明:形状类 */public class Shape { private float[] mVertex;//顶点 private float[] mColor;//颜色 private int mDrawType;//绘制类型复制代码
/** * 作者:张风捷特烈
* 时间:2019/1/13/013:8:39
* 邮箱:1981462002@qq.com
* 说明:简单的形状 */public class SimpleShape extends RendererAble { //略... private Shape mShape; public SimpleShape(Context context, Shape shape) { super(context); mShape = shape; mColorBuffer = GLUtil.getFloatBuffer(mShape.getColor()); mVertexBuffer = GLUtil.getFloatBuffer(mShape.getVertex()); initProgram(); } //略...复制代码

副本十一:The World

目的,形象地认识这个世界


1.第一关卡:坐标系的绘制
1.1:确定坐标和颜色(由于不怎么变动,所以放在常量类Cons里了)

记住三个轴的颜色(Z轴:蓝色,X轴:黄色,Y轴:绿色)

public static final float[] VERTEX_COO = {//坐标轴        0.0f, 0.0f, 0.0f,//Z轴        0.0f, 0.0f, 1.0f,        0.0f, 0.0f, 0.0f,//X轴        1.0f, 0.0f, 0.0f,        0.0f, 0.0f, 0.0f,//Y轴        0.0f, 1.0f, 0.0f,};public static final float[] COLOR_COO = {//坐标轴颜色        0.0f, 0.0f, 1.0f, 1.0f,//Z轴:蓝色        0.0f, 0.0f, 1.0f, 1.0f,        1.0f, 1.0f, 0.0f, 1.0f,//X轴:黄色        1.0f, 1.0f, 0.0f, 1.0f,        0.0f, 1.0f, 0.0f, 1.0f,//Y轴:绿色        0.0f, 1.0f, 0.0f, 1.0f,};复制代码

1.2:使用SimpleShape
---->[WorldRenderer#onSurfaceCreated]--------Shape shape = new Shape(Cons.VERTEX_COO, Cons.COLOR_COO, GLES20.GL_LINES);mCoo = new SimpleShape(mContext, shape);---->[WorldRenderer#onDrawFrame]--------mCoo.draw(mMVPMatrix);复制代码


2.第二关卡:简单封装

如果图形创建在WorldRenderer中,感觉很不舒服,毕竟会有很多形状,

WorldRenderer的本意只是为了渲染以及视角的控制,并不希望图形掺杂其中
WorldShape可以专门绘制形状,由它统一向WorldRenderer输出形状
既然WorldShape总管图形,那么操作图形,在所难免,建一个OP接口,目前只放两个方法


2.1:操作接口
/** * 作者:张风捷特烈
* 时间:2019/1/13/013:19:27
* 邮箱:1981462002@qq.com
* 说明:操作接口 */public interface OP
{ /** * 添加 * @param ts 若干对象 */ void add(T... ts); /** * 根据id移除元素 * @param id 索引 */ void remove(int id);}复制代码

2.2:世界的形状:WorldShape
/** * 作者:张风捷特烈
* 时间:2019/1/13/013:8:39
* 邮箱:1981462002@qq.com
* 说明:世界的形状 */public class WorldShape extends RendererAble implements OP
{ List
mRendererAbles; private float[] mVertex = new float[]{ -1.0f, 0.0f, -1.0f,//A -1.0f, 0.0f, 1.0f,//B 1.0f, 0.0f, 1.0f,//C 1.0f, 0.0f, -1.0f,//D }; private float[] mColor = new float[]{ 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.21960784f, 0.56078434f, 0.92156863f, 1.0f, }; public WorldShape(Context ctx) { super(ctx); mRendererAbles = new ArrayList<>(); Shape coo = new Shape(Cons.VERTEX_COO, Cons.COLOR_COO, GLES20.GL_LINES); Shape ground = new Shape(mVertex, mColor, GLES20.GL_LINE_LOOP); add( new SimpleShape(mContext,coo), new SimpleShape(mContext,ground), } @Override public void draw(float[] mvpMatrix) { for (RendererAble rendererAble : mRendererAbles) { rendererAble.draw(mvpMatrix); } } @Override public void add(RendererAble... rendererAbles) { for (RendererAble rendererAble : rendererAbles) { mRendererAbles.add(rendererAble); } } @Override public void remove(int id) { if (id>=mRendererAbles.size()) { return; } mRendererAbles.remove(id); }}复制代码

2.3:使用WorldShape

现在工作重心移入WorldShape,避免对WorldRenderer造成负担

---->[WorldRenderer#onSurfaceCreated]--------mWorldShape = new WorldShape(mContext);---->[WorldRenderer#onDrawFrame]-------- mWorldShape.draw(mMVPMatrix);复制代码

3.Shape的强化,移动与移动创建

关于深拷贝和浅拷贝我就不废话了,移动创建中需要深拷贝(成员变量有引用数据类型)

Shape implements Cloneable

3.1:深拷贝
/** * 深拷贝 * @return 形状副本 */public Shape clone() {    Shape clone = null;    try {        clone = (Shape) super.clone();        float[] vertex = new float[mVertex.length];        float[] color = new float[mColor.length];        System.arraycopy(mVertex, 0, vertex, 0, mVertex.length);        System.arraycopy(mColor, 0, color, 0, mColor.length);        clone.mVertex = vertex;        clone.mColor = color;    } catch (CloneNotSupportedException e) {        e.printStackTrace();    }    return clone;}复制代码

3.2:移动与移动拷贝
/** * 移动并创建新图形 * @param x * @param y * @param z * @return */public Shape moveAndCreate(float x, float y, float z) {    Shape clone = clone();    clone.move(x, y, z);    return clone;}/** * 仅移动图形 * @param x * @param y * @param z */public void move(float x, float y, float z) {    for (int i = 0; i < mVertex.length; i++) {        if (i % 3 == 0) {//x            mVertex[i] += x;        }        if (i % 3 == 1) {//y            mVertex[i] += y;        }        if (i % 3 == 2) {//y            mVertex[i] += z;        }    }}复制代码

3.3:移动创建图形

两行代码搞定,我都佩服我自己,感觉可以用矩阵变换,现在还不是进击矩阵的时候

---->[WorldShape#WorldShape]------------ Shape coo = new Shape(Cons.VERTEX_COO, Cons.COLOR_COO, GLES20.GL_LINES); Shape ground = new Shape(mVertex, mColor, GLES20.GL_LINE_LOOP); Shape top = ground.moveAndCreate(0, 1, 0); Shape bottom = ground.moveAndCreate(0, -1, 0); add(         new SimpleShape(mContext,coo),         new SimpleShape(mContext,top),         new SimpleShape(mContext,bottom),         new SimpleShape(mContext,ground));复制代码

3.4:再加四根线(感觉有点low...)
private float[] mVertex2 = new float[]{        1.0f, 1.0f, 1.0f,        1.0f, -1.0f, 1.0f,        -1.0f, 1.0f, 1.0f,        -1.0f, -1.0f, 1.0f,        -1.0f, 1.0f, -1.0f,        -1.0f, -1.0f, -1.0f,        1.0f, 1.0f, -1.0f,        1.0f, -1.0f, -1.0f,};private float[] mColor2 = new float[]{        1.0f, 0.0f, 0.0f, 1.0f,        1.0f, 0.0f, 0.0f, 1.0f,        1.0f, 1.0f, 1.0f, 1.0f,        1.0f, 1.0f, 1.0f, 1.0f,        1.0f, 1.0f, 1.0f, 1.0f,        1.0f, 1.0f, 1.0f, 1.0f,        1.0f, 1.0f, 1.0f, 1.0f,        1.0f, 1.0f, 1.0f, 1.0f,};Shape side = new Shape(mVertex2, mColor2, GLES20.GL_LINES);复制代码

世界的坐标已经映入眼帘,yes!


副本十二:黑龙之瞳LEVEL 2

在明确世界坐标之后,现在可以再来看一下视线了

相信你会觉得恍然大悟,原来如此,just so so
在此之前再说一遍:Z轴:蓝色,X轴:黄色,Y轴:绿色,正对红线


1.第一关卡:移动相机 Z轴

注意:现在将视角转回(0,0,-6),旋转角度归0为了不遮挡视线,将ground四条线隐藏

看红线在后面,说明我们是从后面开始看的,Z轴:蓝色无法看到,说明视点在Z轴
即:现在视点在Z轴上,值为-6,绝对值的大小即离物体的远近,近大远小没毛病
but,移到-8时,可见后面已经消失了,说明视野是有限制的

// 设置相机位置(视图矩阵)    Matrix.setLookAtM(mViewMatrix, 0,        0f, 0f, -6.0f,        0f, 0f, 0f,        0f, 1.0f, 0.0f);复制代码

2.第二关卡:移动相机 X轴

将X每次向x负方向移动0.3f,想一下你拿着相机站在后面,看你的X轴方向

或者直接看黄线,黄线所指方向为X轴正方向,你应该可以感觉相机是怎么移动的吧!

// 设置相机位置(视图矩阵)Matrix.setLookAtM(mViewMatrix, 0,        -1.5f, 0f, -6,        0f, 0f, 0f,        0f, 1.0f, 0.0f);复制代码

3.第三关卡:移动相机 Y轴

将Y每次向Y负方向移动0.3f,想一下你拿着相机站在后面,看你的X轴方向

或者直接看黄线,黄线所指方向为X轴正方向,你应该可以感觉相机是怎么移动的吧!

// 设置相机位置(视图矩阵)Matrix.setLookAtM(mViewMatrix, 0,        -1.5f, 1.5f, -6,        0f, 0f, 0f,        0f, 1.0f, 0.0f);复制代码

GLSurfaceView再怎么牛,也是个View,我们便可以添加事件

下面一个小练习,相信上面的理解了,对你来说不会太难


NPC:恭喜完成十二个新手副本,下面将进入普通副本,祝君顺利

本集结束,下集--移形换影,敬请期待

后记:捷文规范

1.本文成长记录及勘误表
日期 备注
2018-1-14
2.更多关于我
笔名 QQ 微信 爱好
张风捷特烈 1981462002 zdl1994328 语言
3.声明

1----本文由张风捷特烈原创,转载请注明

2----欢迎广大编程爱好者共同交流
3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
4----看到这里,我在此感谢你的喜欢与支持


你可能感兴趣的文章
Android 发布可穿戴设备 SDK 的开发者预览版
查看>>
ajax跨域请求
查看>>
记录自己面试遇到的难题及分析
查看>>
使用java+TestNG进行接口回归测试
查看>>
Linaria 1.0正式发布:一个零运行时CSS-in-JS库
查看>>
元数据驱动设计 —— 设计一套用于API数据检索的灵活引擎
查看>>
《The Manager’s Path》 作者 Camille Fournier 访谈
查看>>
Python 3.5正式发布,支持async/await异步编程
查看>>
ARKit奠定了Apple平台上实现AR的基石
查看>>
为什么说我们需要软件架构图?
查看>>
非泄露,NSA官方开源反汇编工具GHIDRA
查看>>
Rust核心团队前成员Brian Anderson加入PingCAP
查看>>
年终总结,程序员票选最喜欢的编程语言花落谁家?
查看>>
Suave 1.0发布,一个面向F#的Web服务器和开发库
查看>>
使用实体框架、Dapper和Chain的仓储模式实现策略
查看>>
V神推荐99%容错共识新算法
查看>>
直击微信公开课:2019年小程序将会有哪些改变?
查看>>
GitHub Draft Pull请求支持新的协作流程
查看>>
摩根大通发行稳定币,其创始人预言每家银行都将推出一种币
查看>>
Oracle将NetBeans交给了Apache基金会
查看>>