内容简介:旁白:上集说到,为了获取黑龙宝藏,勇者集结,共闯第五副本:1.第一关卡:
旁白:上集说到,为了获取黑龙宝藏,勇者集结,共闯 黑龙洞穴
经过一路艰辛,终于过了第四副本,前面还有什么困难等待着他们?一起收看
第五副本: 龙之图阵
1.第一关卡: 画一个矩形
NPC:隐藏任务,解谜: GLES20.GL_TRIANGLE_STRIP
绘制方式
2->3->4
,在绘制
1->2->3
因为 2->3->4
的三角形被 1->2->3
的等三角形遮住了,后来居上是编程的共识
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
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. }; 复制代码
2.第二关卡: 画五边形
先按照 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
:相邻三个顶点绘制一个三角形
3.第三关卡:索引五边形-- glDrawElements
我就想来着,应该有控制三角形顶点的东西,不然调起来很麻烦
3.1.缓冲的简单封装
缓冲顶点数据的套路基本一致,封个方法在GLUtils里吧,
暂时float(4字节)和short(2字节),其他的遇到再说
/** * 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; } 复制代码
3.2:自己控制三角形的形成
咱们从0开始数数,怎么控制点,看图你应该能知道
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); 复制代码
4.第四关卡:六边形
先转六边形应该没有什么大问题了
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住
1.第一关卡:沿着y轴旋转起来
关于变换第一集讲了一些,忘了的可以回去看看
下面是转一圈的效果,感觉少了一半
//围绕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); 复制代码
1.第二关卡:空间面
貌似一直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,//紫色 } 复制代码
2.第二关卡:第二面
一面完成了,第二面 p4、p5、p6、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, 复制代码
3.第三关卡:其他面
为了方便表述,我给每个面取了名字,分别是: 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,//紫色 }; 复制代码
第七副本: 龙之逆鳞
第六副本中的立方体并不怎么让人满意,视角不怎么好,
这一副本就来再看看相机和投影以及矩阵
1.第一关卡:调整相机
一开始眼睛在(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); 复制代码
2.第二关卡:旋转试图,按纸上的视口绘制
//初始化变换矩阵 Matrix.setRotateM(mOpMatrix, 0, 130, 0, 1, 0); 复制代码
然后再来看绘制的流程,就和纸上的一致了,所以视口很重要
第八副本: 龙之盛装 LEVEL1
颜色多没劲,咱们来贴图,经历了这么多,回头看看,感慨良多 这个副本将简单认识贴图,以后还会有高级的 龙之盛装
1.第一关卡:三角形贴图
百度了一个小时,愣是没有把贴图整明白,叙述的逻辑性欠佳,都是贴个代码完事,
贴个完整的还好,但都是一段一段的代码...
现在我来捋一遍,最简单的三角形贴图的流程,先把视野移到(0,0,-3) 不然肯定变形
1.1:片元代码 rect_texture.frag
precision mediump float; varying vec2 aCoordinate;//贴图坐标系 uniform sampler2D vTexture;//贴图 void main() { gl_FragColor=texture2D(vTexture,aCoordinate); } 复制代码
1.2:顶点代码: 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; } 复制代码
1.3:贴图三角形: TextureRectangle
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); } } 复制代码
1.4:加载纹理
我在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; } 复制代码
1.5:使用纹理 GLRenderer.java
private int textureId; ---->[GLRenderer#onSurfaceCreated]------ textureId = GLUtil.loadTexture(mContext, R.mipmap.mian_a);//初始化纹理 ---->[GLRenderer#onDrawFrame]------ mTextureRectangle.draw(mMVPMatrix,textureId);//绘制时使用纹理 复制代码
2.第二关卡:矩形纹理
这是一道送分题,没别的,坐标改改就行了
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, }; 复制代码
有兴趣的可以动动贴图坐标系的点看一下,自己了解一下贴图坐标系
以上所述就是小编给大家介绍的《Android多媒体之GL-ES战记第二集--谜团立方》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Java播放多媒体
- Java处理多媒体文件
- 07.Android之多媒体问题
- 音视频基础之多媒体封装格式
- FFmpeg 3.3.4 发布,多媒体处理工具
- FFmpeg 3.4 发布,多媒体处理工具合集
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。