安卓学习笔记37:利用OpenGL ES绘制平面图形
文章目录
- 零、学习目标
- 一、OpenGL概述
- 二、了解三维直角坐标系
- 三、案例演示 - 绘制三角形
- (一)运行效果
- (二)实现步骤
- 1、创建安卓应用【DrawTriangle】
- 2、建模:创建三角形类 - Triangle
- 3、渲染:创建三角形表面视图 - TriangleSurfaceView
- 4、展示:主界面类 - MainActivity
- 5、运行程序,查看效果
- (三)小结
- 1、建模
- 2、渲染
- 3、展示
- (四)课堂练习:绘制嵌套三角形
- 四、案例演示 - 采用拼合法绘制正方形
- (一)运行效果
- (二)实现步骤
- 1、创建安装应用【DrawSquareBySyntheticMethod】
- 2、创建正方形模型类 - Square
- 3、创建正方形表面视图类 - SquareSurfaceView
- 4、主界面类MainActivity展示正方形
- 5、启动应用,查看效果
- 6、让正方形动起来
- (三) 课堂练习:让全部正方形旋转起来
- 五、案例演示 - 采用顶点法绘制正方形
- (一)运行效果
- (二)实现步骤
- 1、创建安卓应用【DrawSquareByVertexMethod】
- 2、建模:创建正方形类 - Square
- (1)采用FAN模式
- (2)采用STRIP模式
- 3、渲染:创建正方形表面视图 - SquareSurfaceView
- 4、展示:主界面类 - MainActivity
- 5、启动应用,查看效果
- (三)课堂作业 - 采用顶点法绘制变色旋转正方形
- 六、案例演示 - 采用索引法绘制正方形
- (一)运行效果
- (二)实现步骤
- 1、创建安卓应用【DrawSquareByIndexMethod】
- 2、建模:正方形类 - Square
- 3、渲染:正方形表面视图 - SquareSurfaceView
- 4、展示:主界面类 - MainActivity
- 5、启动应用,查看效果
- (三)课堂练习:采用索引法绘制嵌套实心六边形
- 七、案例演示 - 采用索引法绘制空心正方形
- (一)运行效果
- (二)实现步骤
- 1、创建安卓应用【DrawHollowedSquare】
- 2、建模:正方形类 - Square
- 3、渲染:正方形表面视图 - SquareSurfaceView
- 4、展示:主界面类 - MainActivity
- 5、启动应用,查看效果
- (三)课堂练习:采用索引法绘制嵌套空心六边形
零、学习目标
- 会利用OpenGL ES绘制三角形
- 会利用OpenGL ES绘制正方形
- 会利用OpenGL ES绘制六边形
一、OpenGL概述
OpenGL™ 是行业领域中最为广泛接纳的 2D/3D 图形 API,其自诞生至今已催生了各种计算机平台及设备上的数千优秀应用程序。OpenGL™ 是独立于视窗操作系统或其它操作系统的,亦是网络透明的。在包含CAD、内容创作、能源、娱乐、游戏开发、制造业、制药业及虚拟现实等行业领域中,OpenGL™ 帮助程序员实现在 PC、工作站、超级计算机等硬件设备上的高性能、极具冲击力的高视觉表现力图形处理软件的开发 。
OpenGL的前身是SGI公司为其图形工作站开发的IRIS GL。IRIS GL是一个工业标准的3D图形软件接口,功能虽然强大但是移植性不好,于是SGI公司便在IRIS GL的基础上开发了OpenGL。OpenGL的英文全称是“Open Graphics Library”,顾名思义,OpenGL便是“开放的图形程序接口”。虽然DirectX在家用市场全面领先,但在专业高端绘图领域,OpenGL是不能被取代的主角。
OpenGL ES (OpenGL for Embedded Systems) 是 OpenGL 三维图形 API 的子集,针对手机、PDA和游戏主机等嵌入式设备而设计。该API由Khronos集团定义推广。
OpenGL 规范被广泛用于 PC 和移动设备。在SIGGRAPH 2012大会上,OpenGL 背后公益性组织科纳斯组织(Khronos Group)公布了新版本:
- 面对移动领域的 OpenGL ES 版本更新到 3.0
- 面对桌面领域的 OpenGL 版本更新到 4.3
- 可运用在增强现实领域的图形接口 OpenVL
三者中,OpenGL ES 3.0 成为主角,因为它是 Android、iOS 等主流移动平台上的图形接口标准。
二、了解三维直角坐标系
- 三维空间上点的位置由三个坐标值确定:
P(x, y, z)
——横坐标、纵坐标、竖坐标 - 三维直角坐标系有三个坐标面:
xoy
坐标面、yoz
坐标面、zox
坐标面,三个坐标面把空间划分为八个部分,称为八卦限。(23=82^3 = 823=8)
三、案例演示 - 绘制三角形
(一)运行效果
(二)实现步骤
1、创建安卓应用【DrawTriangle】
2、建模:创建三角形类 - Triangle
- 在当前状态下绘制三角形,主要是设置并保存三角形的顶点坐标值
- 声明变量
- 注意:ΔP1P2P3\Delta P_1P_2P_3ΔP1P2P3在xoyxoyxoy平面。
- 构造方法:将三角形整型坐标值放到整型缓冲区对象里
- 在自绘方法里绘制三角形
- 查看三角形类完整源代码
package net.hw.draw_triangle;import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;import javax.microedition.khronos.opengles.GL10;/*** 功能:三角形类* 作者:华卫* 日期:2020年12月30日*/
public class Triangle {private int one = 0x10000; // 定义单位长度(OpenGL ES只使用int类型值高16位作为坐标值)private IntBuffer triangleBuffer; // 三角形整型缓冲区对象(用于存放三角形顶点坐标值)private int[] triangleVertices = new int[] {0, one, 0, // 第一个顶点-one, -one, 0, // 第二个顶点one, -one, 0 // 第三个顶点}; // 三角形定点数组/*** 构造方法:将三角形整型坐标值放到整型缓冲区对象里*/public Triangle() {// 创建字节数组,分配内存空间,因为Java中int是4个字节,所以要乘以4ByteBuffer byteBuffer = ByteBuffer.allocateDirect(triangleVertices.length * 4);// 按本地字节顺序来使用字节数据byteBuffer.order(ByteOrder.nativeOrder());// 将字节缓冲区转换成整型缓冲区triangleBuffer = byteBuffer.asIntBuffer();// 将三角形顶点坐标数据存放到整型缓冲区triangleBuffer.put(triangleVertices);// 整型缓冲区对象的内部指针定位到第一个字节triangleBuffer.position(0);}/*** 自绘方法** @param gl*/public void drawSelf(GL10 gl) {// 将三角形顶点坐标数据通过整型缓冲区加载到内存gl.glVertexPointer(3, // 参数1:指定每个顶点对应的坐标个数,只能是2、3、4GL10.GL_FIXED, // 参数2:指定每个顶点坐标的数据类型,可以取GL_BYTE, GL_SHORT, GL_FIXED, GL_FLOAT0, // 参数3:指定连续顶点间的字节排列方式,0表明采用紧凑方式triangleBuffer // 参数4:指定数组中第一个顶点的首地址,默认值为0);// 绘制三角形gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, // 参数1:模式0, // 参数2:起点3 // 参数3:顶点数);}
}
3、渲染:创建三角形表面视图 - TriangleSurfaceView
- 在onDrawFrame方法里,对模型进行平移和旋转等操作
- 实现渲染器接口 - Renderer
- 声明变量
- 编写表面创建回调方法
- 编写表面变化回调方法
- 说明:调用glLoadIdentity()之后,实际上将当前点移到了屏幕中心,X坐标轴从左至右,Y坐标轴从下至上,Z坐标轴从里至外。OpenGL屏幕中心的坐标值是X和Y轴上的0.0f点。中心左面的坐标值是负值,右面是正值。移向屏幕顶端是正值,移向屏幕底端是负值。移入屏幕深处是负值,移出屏幕则是正值。
- 编写绘制帧回调方法
- 查看三角形表面视图完整源代码
package net.hw.draw_triangle;import android.opengl.GLSurfaceView;import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;/*** 功能:三角形表面视图* 作者:华卫* 日期:2020年12月30日*/
public class TriangleSurfaceView implements GLSurfaceView.Renderer {private Triangle triangle; // 声明三角形变量/*** 表面创建回调方法** @param gl* @param config*/@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {// 实例化三角形对象triangle = new Triangle();}/*** 表面变化回调方法** @param gl* @param width* @param height*/@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {// 计算视口宽高比float ratio = (float) width / height;// 设置视口大小(整个手机屏幕)gl.glViewport(0, 0, width, height);// 设置当前矩阵模式为投影矩阵gl.glMatrixMode(GL10.GL_PROJECTION);// 将当前点移到屏幕中心gl.glLoadIdentity();// 设置透视投影的刻度范围gl.glFrustumf(-ratio * 2, ratio * 2, -2, 2, 1, 10);// 设置当前矩阵模式为模型视图矩阵gl.glMatrixMode(GL10.GL_MODELVIEW);}/*** 绘制帧回调方法** @param gl*/@Overridepublic void onDrawFrame(GL10 gl) {// 清除屏幕,否则上次绘制的图形不会自动消失gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);// 允许使用顶点绘制图形gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);// 将当前点移到屏幕中心gl.glLoadIdentity();// 沿x轴正向移动一个单位,沿z轴负向移动两个单位gl.glTranslatef(1.0f, 0.0f, -2.0f);// 画笔设置为红色gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);// 绘制第一个三角形triangle.drawSelf(gl);// 将当前点移到屏幕中心gl.glLoadIdentity();// 沿x轴正向移动一个单位,沿y轴负向移动两个单位,沿z轴负向移动两个单位gl.glTranslatef(1.0f, -2.0f, -2.0f);// 绕z轴旋转180度gl.glRotatef(180, 0.0f, 0.0f, 1.0f);// 画笔设置为绿色gl.glColor4f(0.0f, 1.0f, 0.0f, 1.0f);// 绘制第二个三角形triangle.drawSelf(gl);// 将当前点移到屏幕中心gl.glLoadIdentity();// 沿x轴负向移动三个单位,沿y轴正向移动两个单位,沿z轴负向移动五个单位gl.glTranslatef(-3.0f, 2.0f, -5.0f);// 画笔设置为黄色gl.glColor4f(1.0f, 1.0f, 0.0f, 1.0f);// 绘制第三个三角形triangle.drawSelf(gl);// 将当前点移到屏幕中心gl.glLoadIdentity();// 沿x轴负向移动三个单位,沿y轴正向移动三个单位,沿z轴负向移动五个单位gl.glTranslatef(-3.0f, 4.0f, -5.0f);// 绕z轴旋转180度gl.glRotatef(180, 0.0f, 0.0f, 1.0f);// 画笔设置为紫色gl.glColor4f(1.0f, 0.0f, 1.0f, 1.0f);// 绘制第四个三角形triangle.drawSelf(gl);// 禁止使用顶点绘制图形gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);}
}
4、展示:主界面类 - MainActivity
5、运行程序,查看效果
(三)小结
1、建模
- 创建三角形类Triangle
- 构造方法:存放三角形顶点坐标值到整型缓冲区对象里
- 自绘方法:加载顶点坐标数据到内存;绘制三角形
2、渲染
- 创建三角形表面视图TriangleSurfaceView
- 实现Renderer接口(渲染器接口:GLSurfaceView的子接口)
- 改写三个方法:onSurfaceCreated、onSurfaceChanged、onDrawFrame
- 设置视口大小、设置透视投影的可视范围、设置矩阵模式、设置颜色、平移旋转变换、调用三角形自绘方法
- 手机三维坐标系:x轴——水平向右为正向;y轴——竖直向上为正向;z轴——垂直向外为正向
- 平移方法glTranslatef(x, y, z):第一个参数管左右移动,第二个参数管上下移动,第三个参数管远近
3、展示
- 实例化表面视图
- 设置表面视图的渲染器
- 将表面视图设置为用户界面
(四)课堂练习:绘制嵌套三角形
- 利用OpenGL ES绘制嵌套三角形。大小是通过透视原理来实现的,在z轴方向距离观者越远越小。
四、案例演示 - 采用拼合法绘制正方形
(一)运行效果
- 所有正方形静止不动
- 中央正方形饶z轴逆时针旋转
- 中央正方形绕z轴逆时针旋转,外围正方形绕z轴顺时针旋转
- 中央正方形绕y轴逆时针旋转,外围正方形绕z轴顺时针旋转
(二)实现步骤
1、创建安装应用【DrawSquareBySyntheticMethod】
2、创建正方形模型类 - Square
package net.hw.draw_square_synthetic;import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;import javax.microedition.khronos.opengles.GL10;/*** 功能:正方形类* 作者:华卫* 日期:2020年12月30日*/
public class Square {/*** 定义单位长度*/private int one = 0x10000;/*** 字节缓冲区*/private ByteBuffer byteBuffer;/*** 三角形整型缓冲区*/private IntBuffer triangleBuffer;/*** 三角形顶点坐标数组*/private int[] triangleVertices = new int[]{0, one, 0, // 上顶点坐标-one, 0, 0, // 左顶点坐标one, 0, 0 // 右顶点坐标};/*** 构造方法:把三角形顶点坐标值保存到整型缓冲区对象里*/public Square(){// 分配内存空间byteBuffer = ByteBuffer.allocateDirect(triangleVertices.length * 4);// 设置字节数据的使用顺序byteBuffer.order(ByteOrder.nativeOrder());// 把字节缓冲区转换成整型缓冲区triangleBuffer = byteBuffer.asIntBuffer();// 把三角形顶点坐标存入整型缓冲区triangleBuffer.put(triangleVertices);// 将整型缓冲区内部指针移到第一个数据(否则指针指向最后一个数据的下一个位置)triangleBuffer.position(0);}/*** 自绘方法:采用拼合法来绘制正方形* @param gl*/public void drawSelf(GL10 gl){// 将三角形顶点坐标加载到内存gl.glVertexPointer(3, GL10.GL_FIXED, 0, triangleBuffer);// 绘制上三角形gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);// 绕x轴旋转180度gl.glRotatef(180, 1.0f, 0.0f, 0.0f);// 绘制下三角形gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);}
}
3、创建正方形表面视图类 - SquareSurfaceView
package net.hw.draw_square_synthetic;import android.opengl.GLSurfaceView;import javax.microedition.khronos.opengles.GL10;/*** 功能:正方形表面视图类* 作者:华卫* 日期:2020年12月31日*/
public class SquareSurfaceView implements GLSurfaceView.Renderer {private Square square; // 声明正方形变量/*** 表面创建回调方法*/@Overridepublic void onSurfaceCreated(GL10 gl, javax.microedition.khronos.egl.EGLConfig config) {// 实例化正方形square = new Square();}/*** 表面变化回调方法*/@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {// 保存手机屏幕宽高比float ratio = (float) width / height;// 设置视口大小,整个手机屏幕gl.glViewport(0, 0, width, height);// 设置矩阵模式为投影模式gl.glMatrixMode(GL10.GL_PROJECTION);// 加载单位矩阵,将当前点移到屏幕中心gl.glLoadIdentity();// 设置透视投影的可视范围gl.glFrustumf(-2 * ratio, 2 * ratio, -2, 2, 1, 10);// 设置矩阵模式为模型视图模式gl.glMatrixMode(gl.GL_MODELVIEW);}/*** 绘制帧回调方法*/@Overridepublic void onDrawFrame(GL10 gl) {// 清除屏幕gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);// 启用顶点绘制方法gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);// 任务1、在屏幕正中央绘制红色正方形gl.glLoadIdentity(); // 加载单位矩阵gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f); // 红色gl.glTranslatef(0.0f, 0.0f, -2.0f); // 往屏幕内平移两个单位gl.glRotatef(90, 0.0f, 0.0f, 1.0f);square.drawSelf(gl); // 调用正方形自绘方法// 任务2、在中心正方形左上角绘制一个黄色小正方形gl.glLoadIdentity(); // 加载单位矩阵gl.glColor4f(1.0f, 1.0f, 0.0f, 1.0f); // 黄色gl.glTranslatef(-3.0f, 3.0f, -4.0f); // 平移gl.glRotatef(45, 0.0f, 0.0f, 1.0f); // 绕z轴旋转45度square.drawSelf(gl); // 调用正方形自绘方法// 任务3、在中心正方形正上方绘制一个绿色小正方形gl.glLoadIdentity(); // 加载单位矩阵gl.glColor4f(0.0f, 1.0f, 0.0f, 1.0f); // 绿色gl.glTranslatef(0.0f, 3.0f, -4.0f); // 平移gl.glRotatef(45, 0.0f, 0.0f, 1.0f); // 绕z轴旋转45度square.drawSelf(gl); // 调用正方形自绘方法// 任务4、在中心正方形右上角绘制一个小正方形gl.glLoadIdentity(); // 加载单位矩阵gl.glColor4f(0.0f, 1.0f, 1.0f, 1.0f); // 设置颜色gl.glTranslatef(3.0f, 3.0f, -4.0f); // 平移gl.glRotatef(45, 0.0f, 0.0f, 1.0f); // 绕z轴旋转45度square.drawSelf(gl); // 调用正方形自绘方法// 任务5、在中心正方形左边绘制一个小正方形gl.glLoadIdentity(); // 加载单位矩阵gl.glColor4f(0.0f, 0.4f, 0.5f, 1.0f);// 设置颜色gl.glTranslatef(-3.0f, 0.0f, -4.0f); // 平移gl.glRotatef(45, 0.0f, 0.0f, 1.0f); // 绕z轴旋转45度square.drawSelf(gl); // 调用正方形自绘方法// 任务6、在中心正方形左下角绘制一个小正方形gl.glLoadIdentity(); // 加载单位矩阵gl.glColor4f(1.0f, 0.4f, 0.5f, 1.0f);// 设置颜色gl.glTranslatef(-3.0f, -3.0f, -4.0f); // 平移gl.glRotatef(45, 0.0f, 0.0f, 1.0f); // 绕z轴旋转45度square.drawSelf(gl); // 调用正方形自绘方法// 任务7、在中心正方形正下方绘制一个小正方形gl.glLoadIdentity(); // 加载单位矩阵gl.glColor4f(0.7f, 1.0f, 0.5f, 1.0f);// 设置颜色gl.glTranslatef(0.0f, -3.0f, -4.0f); // 平移gl.glRotatef(45, 0.0f, 0.0f, 1.0f); // 绕z轴旋转45度square.drawSelf(gl); // 调用正方形自绘方法// 任务8、在中心正方形右下角绘制一个小正方形gl.glLoadIdentity(); // 加载单位矩阵gl.glColor4f(0.7f, 1.0f, 1.0f, 1.0f);// 设置颜色gl.glTranslatef(3.0f, -3.0f, -4.0f); // 平移gl.glRotatef(45, 0.0f, 0.0f, 1.0f); // 绕z轴旋转45度square.drawSelf(gl); // 调用正方形自绘方法// 任务9、在中心正方形右下角绘制一个小正方形gl.glLoadIdentity(); // 加载单位矩阵gl.glColor4f(0.2f, 1.0f, 0.8f, 1.0f);// 设置颜色gl.glTranslatef(3.0f, 0.0f, -4.0f); // 平移gl.glRotatef(45, 0.0f, 0.0f, 1.0f); // 绕z轴旋转45度square.drawSelf(gl); // 调用正方形自绘方法// 禁用顶点绘制方法gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);}
}
4、主界面类MainActivity展示正方形
package net.hw.draw_square_synthetic;import android.opengl.GLSurfaceView;
import android.os.Bundle;import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {/*** 声明图形库表面视图*/private GLSurfaceView mGlSurfaceView;/*** 声明正方形表面视图(渲染器)*/private SquareSurfaceView mSquareSurfaceView;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 实例化图形库表面视图mGlSurfaceView = new GLSurfaceView(this);// 实例化正方形表面视图(渲染器)mSquareSurfaceView = new SquareSurfaceView();// 给图形库表面视图设置渲染器mGlSurfaceView.setRenderer(mSquareSurfaceView);// 将图形库表面视图设置为用户界面setContentView(mGlSurfaceView);}
}
5、启动应用,查看效果
6、让正方形动起来
- 回顾一下在自定义视图里如何实现动画的?要利用Thread和Handler来处理。
- 现在的自定义视图继承了SurfaceView,里面隐含了线程,通过回调方法onDrawFrame体现出来。
- 声明起始时间
- 保存起始时间
- 计算流逝的时间
- 让中央红色正方形每0.1秒钟逆时针绕z轴旋转5度
- 启动应用,查看效果
(三) 课堂练习:让全部正方形旋转起来
- 让中心正方形每0.1秒钟逆时针旋转5度,周围的九个小正方形每0.1秒钟顺时针旋转5度。提示:大家可以尝试绕不同的坐标轴旋转,仔细观看动画效果。
- 中央正方形绕y轴逆时针旋转,外围正方形绕z轴顺时针旋转
五、案例演示 - 采用顶点法绘制正方形
上一个案例,我们采用三角形拼合法来绘制正方形,建模时保存的是三角形顶点坐标,通过拼合而绘制正方形,而渲染与展示都跟绘制三角形没有什么区别。
怎么实现动画?直接在自定义视图 (GLSurfaceView)里就可以实现动画,不需要在主窗口里利用Thread和Handler来实现,操作起来更加方便简捷。
(一)运行效果
(二)实现步骤
1、创建安卓应用【DrawSquareByVertexMethod】
2、建模:创建正方形类 - Square
(1)采用FAN模式
△P1P2P3△P_1P_2P_3△P1P2P3(右上三角形)+ △P1P3P4△P_1P_3P_4△P1P3P4(左下三角形)
(2)采用STRIP模式
△P1P2P3△P_1P_2P_3△P1P2P3(左上三角形)+ △P2P3P4△P_2P_3P_4△P2P3P4(右下三角形)
package net.hw.draw_square_vertex;import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;import javax.microedition.khronos.opengles.GL10;/*** 功能:采用顶点法创建正方形模型* 有两种模式:FAN模式与STRIP模式* 作者:华卫* 日期:2020年12月31日*/
public class Square {private FloatBuffer squareBuffer; // 声明浮点型缓冲区变量private ByteBuffer byteBuffer; // 声明字节型缓冲区变量private float[] squareVertices = new float[] {-1.5f, 1.5f, 0.0f, // 左上角顶点坐标(P1)1.5f, 1.5f, 0.0f, // 右上角顶点坐标(P2)1.5f, -1.5f, 0.0f, // 右下角顶点坐标(P3)-1.5f, -1.5f, 0.0f, // 左下角顶点坐标(P4)}; // 正方形顶点坐标数组/*** 构造方法:将正方形顶点坐标存放到浮点型缓冲区对象里*/public Square() {// 为字节缓冲区对象分配内存空间byteBuffer = ByteBuffer.allocateDirect(squareVertices.length * 4);// 按本地字节顺序使用字节数据byteBuffer.order(ByteOrder.nativeOrder());// 把字节缓冲区对象转换成浮点型缓冲区对象squareBuffer = byteBuffer.asFloatBuffer();// 将正方形顶点坐标存放到浮点型缓冲区对象里squareBuffer.put(squareVertices);// 设置浮点型缓冲区内部指针指向第一个字节squareBuffer.position(0);}/*** 自绘方法*/public void drawSelf(GL10 gl) {// 将正方形顶点坐标值加载到内存gl.glVertexPointer(3, GL10.GL_FLOAT, 0, squareBuffer);// 按照FAN模式来绘制正方形gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, 4);}
}
3、渲染:创建正方形表面视图 - SquareSurfaceView
package net.hw.draw_square_vertex;import android.opengl.GLSurfaceView;import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;/*** 功能:正方形表面视图* 作者:华卫* 日期:2020年12月31日*/
public class SquareSurfaceView implements GLSurfaceView.Renderer {private Square square; // 声明正方形变量@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {// 实例化正方形square = new Square();}@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {// 计算屏幕宽高比float ratio = (float) width / height;// 设置视口大小,整个手机屏幕gl.glViewport(0, 0, width, height);// 设置矩阵模式为投影模式gl.glMatrixMode(GL10.GL_PROJECTION);// 加载单位矩阵,将当前点移到屏幕中心gl.glLoadIdentity();// 设置透视投影的刻度范围gl.glFrustumf(-2 * ratio, 2 * ratio, -2, 2, 1, 10);// 设置矩阵模式为模型视图模式gl.glMatrixMode(GL10.GL_MODELVIEW);}@Overridepublic void onDrawFrame(GL10 gl) {// 清除手机屏幕gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);// 采用顶点方式来绘制图形gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);gl.glLoadIdentity(); // 加载单位矩阵,将当前点移到屏幕中心gl.glTranslatef(0.0f, 0.0f, -2.0f); // 往屏幕内平移两个单位gl.glColor4f(1.0f, 1.0f, 0.0f, 1.0f); // 设置为黄色square.drawSelf(gl); // 绘制正方形gl.glLoadIdentity(); // 加载单位矩阵,将当前点移到屏幕中心gl.glTranslatef(0.0f, 0.0f, -2.8f); // 往屏幕内平移2.8个单位gl.glRotatef(45, 0.0f, 0.0f, 1.0f); // 绕z轴旋转45度gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f); // 设置为红色square.drawSelf(gl); // 绘制正方形// 禁用顶点方式来绘制图形gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);}
}
4、展示:主界面类 - MainActivity
package net.hw.draw_square_vertex;import android.opengl.GLSurfaceView;
import android.os.Bundle;import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {private GLSurfaceView mGlSurfaceView; // 声明图形库表面视图private SquareSurfaceView mSquareSurfaceView; // 声明正方形表面视图(渲染器)@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 实例化图形库表面视图mGlSurfaceView = new GLSurfaceView(this);// 实例化正方形表面视图(渲染器)mSquareSurfaceView = new SquareSurfaceView();// 给图形库表面视图设置渲染器mGlSurfaceView.setRenderer(mSquareSurfaceView);// 将图形库表面视图设置为用户界面setContentView(mGlSurfaceView);}
}
5、启动应用,查看效果
(三)课堂作业 - 采用顶点法绘制变色旋转正方形
六、案例演示 - 采用索引法绘制正方形
我们已学习了采用拼合法与顶点法绘制正方形。不同方法仅仅在建模上不同,而渲染与展示都是相同的。采用索引法可以规定顶点顺序,操作起来更加灵活。
(一)运行效果
(二)实现步骤
1、创建安卓应用【DrawSquareByIndexMethod】
2、建模:正方形类 - Square
package net.hw.draw_sqaure_index;import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;import javax.microedition.khronos.opengles.GL10;/*** 功能:采用索引法创建正方形模型* 作者:华卫* 日期:2020年12月31日*/
public class Square {/*** 声明浮点型缓冲区变量*/private FloatBuffer squareBuffer;/*** 声明字节型缓冲区变量*/private ByteBuffer byteBuffer;/*** 声明索引字节型缓冲区*/private ByteBuffer indexBuffer;/*** 正方形顶点坐标数组*/private float[] rectangleVertices = new float[] {-1.5f, 1.5f, 0.0f, // 左上角顶点坐标(P1--0)1.5f, 1.5f, 0.0f, // 右上角顶点坐标(P2--1)1.5f, -1.5f, 0.0f, // 右下角顶点坐标(P3--2)-1.5f, -1.5f, 0.0f, // 左下角顶点坐标(P4--3)};/*** 定义顶点顺序的索引数组(跟FAN模式与STRIP模式都可以不同)*/private byte[] indices = new byte[]{0, 1, 3, // 左上三角形的三个顶点顺序(△P1P2P4)1, 2, 3 // 右下三角形的三个顶点顺序(△P2P3P4)};/*** 构造方法:将正方形顶点坐标存放到浮点型缓冲区对象里*/public Square() {// 为字节缓冲区对象分配内存空间byteBuffer = ByteBuffer.allocateDirect(rectangleVertices.length * 4);// 按本地字节顺序使用字节数据byteBuffer.order(ByteOrder.nativeOrder());// 把字节缓冲区对象转换成浮点型缓冲区对象squareBuffer = byteBuffer.asFloatBuffer();// 将正方形顶点坐标存放到浮点型缓冲区对象里squareBuffer.put(rectangleVertices);// 设置浮点型缓冲区内部指针指向第一个数据squareBuffer.position(0);// 分配内存空间indexBuffer = ByteBuffer.allocateDirect(indices.length);// 将索引数组存放到字节型缓冲区对象里indexBuffer.put(indices);// 设置字节型缓冲区内部指针指向第一个数据indexBuffer.position(0);}/*** 自绘方法*/public void drawSelf(GL10 gl) {// 将正方形顶点坐标值加载到内存gl.glVertexPointer(3, GL10.GL_FLOAT, 0, squareBuffer);// 按索引顺序绘制两个三角形,合成一个正方形gl.glDrawElements(GL10.GL_TRIANGLES, 6, GL10.GL_UNSIGNED_BYTE, indexBuffer);}
}
3、渲染:正方形表面视图 - SquareSurfaceView
package net.hw.draw_sqaure_index;import android.opengl.GLSurfaceView;import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;/*** 功能:创建正方形表面视图,渲染正方形* 作者:华卫* 日期:2020年12月31日*/
public class SquareSurfaceView implements GLSurfaceView.Renderer {/*** 声明正方形变量*/private Square square;@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {// 实例化正方形square = new Square();}@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {// 计算屏幕宽高比float ratio = (float) width / height;// 设置视口大小,整个手机屏幕gl.glViewport(0, 0, width, height);// 设置矩阵模式为投影模式gl.glMatrixMode(GL10.GL_PROJECTION);// 加载单位矩阵,将当前点移到屏幕中心gl.glLoadIdentity();// 设置透视投影的刻度范围gl.glFrustumf(-2 * ratio, 2 * ratio, -2, 2, 1, 10);// 设置矩阵模式为模型视图模式gl.glMatrixMode(GL10.GL_MODELVIEW);}@Overridepublic void onDrawFrame(GL10 gl) {// 清除手机屏幕gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);// 采用顶点方式来绘制图形gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);// 加载单位矩阵,将当前点移到屏幕中心gl.glLoadIdentity();// 往屏幕内平移两个单位gl.glTranslatef(0.0f, 0.0f, -2.0f);// 画笔设置为黄色gl.glColor4f(1.0f, 1.0f, 0.0f, 1.0f);// 绘制正方形square.drawSelf(gl);// 禁用顶点方式来绘制图形gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);}
}
4、展示:主界面类 - MainActivity
package net.hw.draw_sqaure_index;import android.opengl.GLSurfaceView;
import android.os.Bundle;import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {/*** 声明图形库表面视图*/private GLSurfaceView mGlSurfaceView;/*** 声明正方形表面视图(渲染器)*/private SquareSurfaceView mSquareSurfaceView;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 实例化图形库表面视图mGlSurfaceView = new GLSurfaceView(this);// 实例化正方形表面视图(渲染器)mSquareSurfaceView = new SquareSurfaceView();// 给图形库表面视图设置渲染器mGlSurfaceView.setRenderer(mSquareSurfaceView);// 将图形库表面视图设置为用户界面setContentView(mGlSurfaceView);}
}
5、启动应用,查看效果
(三)课堂练习:采用索引法绘制嵌套实心六边形
七、案例演示 - 采用索引法绘制空心正方形
我们已经学会用三种方法来绘制正方形:拼合法、顶点法(FAN模式与STRIP模式)、索引法,其中索引法最灵活。但是前几个案例我们绘制的都是实心正方形,下面我们来学习如何绘制空心正方形。
(一)运行效果
(二)实现步骤
1、创建安卓应用【DrawHollowedSquare】
2、建模:正方形类 - Square
- 第一条边:P1P2(0,1)P_1P_2(0, 1)P1P2(0,1)
- 第二条边:P2P3(1,2)P_2P_3(1, 2)P2P3(1,2)
- 第三条边:P3P4(2,3)P_3P_4(2, 3)P3P4(2,3)
- 第四条边:P4P1(3,0)P_4P_1(3, 0)P4P1(3,0)
package net.hw.draw_hollowed_square;import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;import javax.microedition.khronos.opengles.GL10;/*** 功能:采用索引法绘制空心正方形* 作者:华卫* 日期:2020年12月31日*/
public class Square {private FloatBuffer squareBuffer; // 声明浮点型缓冲区变量private ByteBuffer byteBuffer; // 声明字节型缓冲区变量private ByteBuffer indexBuffer; // 声明字节型缓冲区// 定义正方形四个顶点的坐标private float[] squareVertices = new float[] {-1.5f, 1.5f, 0.0f, // 左上角顶点坐标(P1--0)1.5f, 1.5f, 0.0f, // 右上角顶点坐标(P2--1)1.5f, -1.5f, 0.0f, // 右下角顶点坐标(P3--2)-1.5f, -1.5f, 0.0f, // 左下角顶点坐标(P4--3)};// 定义正方形四条边的顶点顺序private byte[] indices = new byte[] {0, 1, // 第一条边P1P2的顶点顺序1, 2, // 第二条边P2P3的顶点顺序2, 3, // 第三条边P3P4的顶点顺序3, 0, // 第四条边P4P1的顶点顺序};/*** 构造方法:将正方形顶点坐标存放到浮点型缓冲区对象里*/public Square() {// 分配内存空间byteBuffer = ByteBuffer.allocateDirect(squareVertices.length * 4);// 按本地字节顺序来使用字节数据byteBuffer.order(ByteOrder.nativeOrder());// 将字节型缓冲区转换成浮点型缓冲区squareBuffer = byteBuffer.asFloatBuffer();// 将正方形顶点坐标数据放入浮点型缓冲区squareBuffer.put(squareVertices);// 设置浮点型缓冲区内部指针指向第一个数据squareBuffer.position(0);// 将顶点顺序存入字节缓冲区// 分配内存空间indexBuffer = ByteBuffer.allocateDirect(indices.length);// 将顶点索引数组存入字节型缓冲区indexBuffer.put(indices);// 设置字节缓冲区内部指针指向第一个数据indexBuffer.position(0);}/*** 自绘方法** @param gl*/public void drawSelf(GL10 gl) {// 将正方形顶点坐标数据加载到内存gl.glVertexPointer(3, GL10.GL_FLOAT, 0, squareBuffer);// 按索引顺序绘制空心正方形gl.glDrawElements(GL10.GL_LINES, 8, GL10.GL_UNSIGNED_BYTE, indexBuffer);}
}
3、渲染:正方形表面视图 - SquareSurfaceView
package net.hw.draw_hollowed_square;import android.opengl.GLSurfaceView;import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;/*** 功能:创建正方形表面视图,渲染正方形* 作者:华卫* 日期:2020年12月31日*/
public class SquareSurfaceView implements GLSurfaceView.Renderer {private Square square; // 声明正方形变量@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {square = new Square(); // 实例化正方形}@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {float ratio = (float) width / height; // 计算屏幕宽高比gl.glViewport(0, 0, width, height); // 设置视口大小,整个手机屏幕gl.glMatrixMode(GL10.GL_PROJECTION); // 设置矩阵模式为投影模式gl.glLoadIdentity(); // 设置当前矩阵为单位矩阵gl.glFrustumf(-2 * ratio, 2 * ratio, -2, 2, 1, 10); // 设置透视投影的刻度范围gl.glMatrixMode(GL10.GL_MODELVIEW); // 设置矩阵模式为模型视图模式}@Overridepublic void onDrawFrame(GL10 gl) {gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); // 清除手机屏幕gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); // 采用顶点方式来绘制图形gl.glLoadIdentity(); // 将当前矩阵设置为单位矩阵gl.glTranslatef(0.0f, 0.0f, -2.0f); // 往屏幕内平移2个单位gl.glColor4f(1.0f, 1.0f, 0.0f, 1.0f); // 设置为黄色square.drawSelf(gl); // 绘制正方形gl.glLoadIdentity(); // 将当前矩阵设置为单位矩阵gl.glTranslatef(0.0f, 0.0f, -2.85f); // 往屏幕内平移2.85个单位gl.glRotatef(45, 0.0f, 0.0f, 1.0f); // 绕z轴旋转45度gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f); // 设置为红色square.drawSelf(gl); // 绘制正方形gl.glLoadIdentity(); // 将当前矩阵设置为单位矩阵gl.glTranslatef(0.0f, 0.0f, -4.0f); // 往屏幕内平移4个单位gl.glColor4f(0.0f, 1.0f, 0.0f, 1.0f); // 设置为绿色square.drawSelf(gl); // 绘制正方形gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); // 禁用顶点方式来绘制图形}
}
4、展示:主界面类 - MainActivity
package net.hw.draw_hollowed_square;import android.opengl.GLSurfaceView;
import android.os.Bundle;import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {private GLSurfaceView mGlSurfaceView; // 图形库表面视图private SquareSurfaceView mSquareSurfaceView; // 正方形表面视图(渲染器)@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mGlSurfaceView = new GLSurfaceView(this); // 实例化图形库表面视图mSquareSurfaceView = new SquareSurfaceView(); // 实例化正方形表面视图(渲染器)mGlSurfaceView.setRenderer(mSquareSurfaceView); // 给图形库表面视图设置渲染器setContentView(mGlSurfaceView); // 将图形库表面视图设置为用户界面}
}
5、启动应用,查看效果
(三)课堂练习:采用索引法绘制嵌套空心六边形
安卓学习笔记37:利用OpenGL ES绘制平面图形相关推荐
- 音视频开发系列(34) OpenGL ES 绘制平面图形
我们前两篇介绍了OpenGL ES 基本概念和GLSL及Shader的渲染流程,这篇我们开始实战,通过GLSurfaceView加载着色器,来绘制三角形.正方形和直线这些平面图形.在实践过程中遇到的问 ...
- 安卓学习笔记38:利用OpenGL ES绘制旋转立方体
文章目录 零.学习目标 一.绘制图形基本步骤 二.绘制旋转立方体 (一)运行效果 (二)实现步骤 1.创建安卓应用[DrawRotatingCube] 2.建模:立方体类 - Cube 3.渲染:立方 ...
- 【我的安卓进阶之旅】Opengl Es(5)三维图形绘制圆锥、圆柱和球体(附Github地址)
之前的博客中,我们绘制了三角形.正方形.圆形.立方体,今天我们将绘制圆锥.圆柱和球体.能够绘制这些基本的常规几何形体后,其他的常见几何形体的绘制对于我们来说就基本没问题了. 绘制圆锥 由之前的博客,我 ...
- 2020年安卓学习笔记目录
文章目录 一.讲课笔记 二.安卓案例 三.安卓实训项目 四.学生安卓学习博客 五.安卓课后作业 (一)界面设计练习 1.制作登录界面 2.制作部队管理界面 3.制作灭火救援界面 4.制作交付界面 5. ...
- 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)
0x00 - 前言 之前做一些移动端的AR应用以及目前看到的一些AR应用,基本上都是这样一个套路:手机背景显示现实场景,然后在该背景上进行图形学绘制.至于图形学绘制时,相机外参的解算使用的是V-SLA ...
- Android Studio OpenGL ES绘制三棱锥/四面体的多纹理贴图 每个面使用一张图片渲染
本文参考了王刚的<疯狂Android讲义(第3版)>P554-P559 要求:利用OpenGL ES绘制一个三棱锥,并对每个面进行纹理贴图,每个面使用不同的图片进行渲染. 环境:Andro ...
- OpenGL ES:绘制函数glDrawArrays 和 glDrawElements 的区别
from:https://www.jianshu.com/p/4d02c2cd21ea 写文章注册登录 首页 下载App OpenGL ES:绘制函数glDrawArrays 和 glDrawElem ...
- 影像组学视频学习笔记(15)-ROC曲线及其绘制、Li‘s have a solution and plan.
本笔记来源于B站Up主: 有Li 的影像组学系列教学视频 本节(15)主要介绍: ROC曲线及其绘制 ROC 曲线 ROC = receiver operating characteristic cu ...
- 【Qt for Android】OpenGL ES 绘制彩色立方体
Qt 内置对OpenGL ES的支持.选用Qt进行OpenGL ES的开发是很方便的,很多辅助类都已经具备.从Qt 5.0開始添加了一个QWindow类,该类既能够使用OpenGL绘制3D图形,也能够 ...
最新文章
- chrome 禁用恢复页面提示_有哪些很值得推荐的Chrome插件?精选7款实用插件
- 《数据中台实战》:数据中台的分层建模体系
- Java 类中可以覆盖静态方法吗?
- leetcode 688. Knight Probability in Chessboard | 688. “马”在棋盘上的概率(dp,记忆化搜索)
- 随便玩玩之PostgreSQL(第一章)PostgreSQL简介
- VUE: 当前页面 引用自定义公用样式 (:style=“样式名“)
- 5天被迫喊停!Win 10史上最短命系统升级:删文件、无法联网,误报CPU使用率
- python小程序设计4s店_python自写的车牌识别小程序,完全自主实现。图片处理
- 计算机科学技术专业单片机,计算机科学与技术专业毕业论文---基于单片机的智能浇花系统的设计与实现.docx...
- WPS简历模板的图标怎么修改_个人简历模板集锦,简历自我评价怎么写?
- 金葵花股票资金操盘大赛3号选手张朝阳关于疫情对A股市场影响的观点
- ros launch中的节点工作空间路径
- 5000元组装电脑配置清单2021 5000元台式电脑组装配置单
- 学习帮——懒人菜谱,电饭煲可以做的菜!
- 我的理想,我的奋斗目标
- 2020-10-22 css画八边形等
- Oracle | ORA-03135: connection lost contact.
- 【自动驾驶-感知-红绿灯】红绿灯识别知识点
- 安信实验室呼吁键盘厂商申请windows徽标认证(WHQL)
- [OpenVas/Gvm]Failed to find config ‘085569ce-73ed-11df-83c3-002264764cea‘
热门文章
- 快速了解前端开发HTML的正确姿势
- 【华为云技术分享】【资料下载合集】HDC.Cloud华为开发者大会2020
- RDS关系型数据库 入门 01 创建关系型数据库实例【华为云分享】
- 高性能Web动画和渲染原理系列(2)——渲染管线和CPU渲染
- 软能力那点事,你知多少
- 推荐两个漂亮的编程字体
- android获取工程中所有类名,android 获取手机的所有程序和widget的包名和启动类名...
- 邢台学计算机的技校有哪些,邢台技校有哪些,邢台技校排名
- 混淆矩阵-python
- poj 3660 CwoContest Floyed传递闭包