【OpenGL ES】绘制正方形
1 前言
【OpenGL ES】绘制三角形 中介绍了绘制三角形的方法,本文将介绍绘制正方形的方法。
OpenGL 以点、线段、三角形为图元,没有提供绘制正方形内部的接口。要绘制正方形内部,必须通过三角形拼接而成,如下图,是通过GL_TRIANGLE_FAN 模式绘制正方形。
绘制的坐标点如下,由于此坐标是以画布中心为坐标原点,水平向右为 x 轴正方向,竖直向上为 y 轴正方向,其值是相对画布宽度和高度的比值。一般而言,画布宽度和高度不相等,造成同样数值的 x 和 y,对应的 dp 值不相等。
float[] vertex = new float[] {
0.5f, 0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
因此,需要对坐标进行调整,如下:
public float[] adjustCoord(float[] coords, int width, int height) {
float ratio = width > height ? (1.0f * height / width) : (1.0f * width / height);
int start = width > height ? 0 : 1;
float[] tempCoord = Arrays.copyOf(coords, coords.length);
int num = tempCoord.length / 3;
for (int i = 0; i < num; i++) {
tempCoord[start + i * 3] *= ratio;
}
return tempCoord;
}
本文完整代码资源见→【OpenGL ES】绘制正方形
项目目录如下:
2 案例
MainActivity.java
package com.zhyan8.square;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private GLSurfaceView mGlSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGlSurfaceView = new MyGLSurfaceView(this);
setContentView(mGlSurfaceView);
mGlSurfaceView.setRenderer(new MyRender(this));
}
@Override
protected void onResume() {
super.onResume();
mGlSurfaceView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mGlSurfaceView.onPause();
}
}
MyGLSurfaceView.java
package com.zhyan8.square;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
public class MyGLSurfaceView extends GLSurfaceView {
public MyGLSurfaceView(Context context) {
super(context);
setEGLContextClientVersion(3);
}
public MyGLSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
setEGLContextClientVersion(3);
}
}
MyRender.java
package com.zhyan8.square;
import android.content.Context;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class MyRender implements GLSurfaceView.Renderer {
private FloatBuffer vertexBuffer;
private GLUtils mGLUtils;
public MyRender(Context context) {
mGLUtils = new GLUtils(context);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) {
//设置背景颜色
GLES30.glClearColor(0.1f, 0.2f, 0.3f, 0.4f);
//编译着色器
final int vertexShaderId = mGLUtils.compileShader(GLES30.GL_VERTEX_SHADER, R.raw.vertex_shader);
final int fragmentShaderId = mGLUtils.compileShader(GLES30.GL_FRAGMENT_SHADER, R.raw.fragment_shader);
//链接程序片段
int programId = mGLUtils.linkProgram(vertexShaderId, fragmentShaderId);
GLES30.glUseProgram(programId);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
//设置视图窗口
GLES30.glViewport(0, 0, width, height);
getFloatBuffer(width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
//将颜色缓冲区设置为预设的颜色
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
GLES30.glLineWidth(5);
//启用顶点的数组句柄
GLES30.glEnableVertexAttribArray(0);
//准备坐标数据
GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 0, vertexBuffer);
// GLES30.glDrawArrays(GLES30.GL_POINTS, 0, 4); //绘制正方形的四个顶点
// GLES30.glDrawArrays(GLES30.GL_LINE_LOOP, 0, 4); //绘制正方形的四条边
GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, 4); //绘制正方形的内部
//禁止顶点数组句柄
GLES30.glDisableVertexAttribArray(0);
}
private void getFloatBuffer(int width, int height) {
float[] vertex = new float[] {
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[] tempVertex = mGLUtils.adjustCoord(vertex, width, height);
vertexBuffer = mGLUtils.getFloatBuffer(tempVertex);
}
}
GLUtils.java
package com.zhyan8.square;
import android.content.Context;
import android.opengl.GLES30;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.Arrays;
public class GLUtils {
private Context mContext;
public GLUtils(Context context) {
mContext = context;
}
//调整坐标
public float[] adjustCoord(float[] coords, int width, int height) {
float ratio = width > height ? (1.0f * height / width) : (1.0f * width / height);
int start = width > height ? 0 : 1;
float[] tempCoord = Arrays.copyOf(coords, coords.length);
int num = tempCoord.length / 3;
for (int i = 0; i < num; i++) {
tempCoord[start + i * 3] *= ratio;
}
return tempCoord;
}
public FloatBuffer getFloatBuffer(float[] floatArr) {
FloatBuffer fb = ByteBuffer.allocateDirect(floatArr.length * Float.BYTES)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
fb.put(floatArr);
fb.position(0);
return fb;
}
//通过代码片段编译着色器
public int compileShader(int type, String shaderCode){
int shader = GLES30.glCreateShader(type);
GLES30.glShaderSource(shader, shaderCode);
GLES30.glCompileShader(shader);
return shader;
}
//通过外部资源编译着色器
public int compileShader(int type, int shaderId){
String shaderCode = readShaderFromResource(shaderId);
return compileShader(type, shaderCode);
}
//链接到着色器
public int linkProgram(int vertexShaderId, int fragmentShaderId) {
final int programId = GLES30.glCreateProgram();
//将顶点着色器加入到程序
GLES30.glAttachShader(programId, vertexShaderId);
//将片元着色器加入到程序
GLES30.glAttachShader(programId, fragmentShaderId);
//链接着色器程序
GLES30.glLinkProgram(programId);
return programId;
}
//从shader文件读出字符串
private String readShaderFromResource(int shaderId) {
InputStream is = mContext.getResources().openRawResource(shaderId);
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
StringBuilder sb = new StringBuilder();
try {
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
br.close();
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
}
vertex_shader.glsl
#version 300 es
layout (location = 0) in vec4 vPosition;
void main() {
gl_Position = vPosition;
gl_PointSize = 20.0; //顶点大小(GL_POINTS模式下才会生效)
}
顶点着色器的作用:进行矩阵变换位置、根据光照公式计算顶点颜⾊、⽣成 / 变换纹理坐标,并且把位置和纹理坐标发送到片元着色器。
顶点着色器中,如果没有指定默认精度,则 int 和 float 的默认精度都为 highp。
fragment_shader.glsl
#version 300 es
precision mediump float; //声明float型变量的精度为mediump
out vec4 fragColor;
void main() {
fragColor = vec4(0.2, 1.0, 1.0, 1.0); //顶点、边线、内部填充颜色
}
片元着色器的作用:处理经光栅化阶段生成的每个片元,计算每个像素的颜色和透明度。
在片元着色器中,浮点值没有默认的精度值,每个着色器必须声明一个默认的 float 精度。
运行结果:
1)GL_POINTS 模式
2)GL_LINE_LOOP 模式
3)GL_TRIANGLE_FAN 模式
声明:本文转自【OpenGL ES】绘制正方形
【OpenGL ES】绘制正方形的更多相关文章
- 使用OpenGL ES绘制3D图形
如果应用定义的顶点不在同一个平面上,并且使用三角形把合适的顶点连接起来,就可以绘制出3D图形了. 使用OpenGL ES绘制3D图形的方法与绘制2D图形的步骤大致相同,只是绘制3D图形需要定义更多的 ...
- 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)
0x00 - 前言 之前做一些移动端的AR应用以及目前看到的一些AR应用,基本上都是这样一个套路:手机背景显示现实场景,然后在该背景上进行图形学绘制.至于图形学绘制时,相机外参的解算使用的是V-SLA ...
- 【Qt for Android】OpenGL ES 绘制彩色立方体
Qt 内置对OpenGL ES的支持.选用Qt进行OpenGL ES的开发是很方便的,很多辅助类都已经具备.从Qt 5.0開始添加了一个QWindow类,该类既能够使用OpenGL绘制3D图形,也能够 ...
- 2.x最终照着教程,成功使用OpenGL ES 绘制纹理贴图,添加了灰度图
在之前成功绘制变色的几何图形之后,今天利用Openg ES的可编程管线绘制出第一张纹理. 学校时候不知道OpenGL的重要性,怕晦涩的语法.没有跟老师学习OpenGL的环境配置,现在仅仅能利用coco ...
- Android OpenGL ES 开发(四): OpenGL ES 绘制形状
在上文中,我们使用OpenGL定义了能够被绘制出来的形状了,现在我们想绘制出来它们.使用OpenGLES 2.0来绘制形状会比你想象的需要更多的代码.因为OpenGL的API提供了大量的对渲染管线的控 ...
- Opengl ES之四边形绘制
四边形的绘制在Opengl ES是很重要的一项技巧,比如做视频播放器时视频的渲染就需要使用到Opengl ES绘制四边形的相关知识.然而在Opengl ES却没有直接提供 绘制四边形的相关函数,那么如 ...
- OpenGL ES: (5) OpenGL的基本概念、OpenGL ES 在屏幕产生图片的过程、OpenGL管线(pipeline)
一. OpenGL的基本概念 OpenGL 的结构可以从逻辑上划分为下面 3 个部分: 图元(Primitives) 缓冲区(Buffers) 光栅化(Rasterize) 图元(Primitives ...
- OpenGL ES应用开发实践指南:iOS卷
<OpenGL ES应用开发实践指南:iOS卷> 基本信息 原书名:Learning OpenGL ES for iOS:A Hands-On Guide to Modern 3D Gra ...
- Android OpenGL ES(四)关于EGL .
OpenGL ES的javax.microedition.khronos.opengles 包定义了平台无关的GL绘图指令,EGL(javax.microedition.khronos.egl ) 则 ...
- 【Android Developers Training】 62. 搭建一个OpenGL ES环境
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
随机推荐
- 百度网盘(百度云)SVIP超级会员共享账号每日更新(2024.01.23)
一.百度网盘SVIP超级会员共享账号 可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答. 我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免 ...
- [转帖]使用 mydumper/loader 全量导入数据
数据迁移 mydumper 是一个更强大的数据迁移工具,具体可以参考 https://github.com/maxbube/mydumper. 我们使用 mydumper 从 MySQL 导出数据,然 ...
- [转帖]TiDB 整体架构
https://docs.pingcap.com/zh/tidb/stable/tidb-architecture 与传统的单机数据库相比,TiDB 具有以下优势: 纯分布式架构,拥有良好的扩展性,支 ...
- Navicat For Redis 的学习与使用
Navicat For Redis 的学习与使用 背景 周末在家看了几个公众号: 说到Navicat 16.2已经有了 Redis的客户端. 想着前段时间一直在学习Redis, 但是没有GUI的工具, ...
- [转帖]计算机体系结构-重排序缓存ROB
https://zhuanlan.zhihu.com/p/501631371 在现代处理器中,重排序缓存(Reorder Buffer,即ROB)是一个至关重要的概念,一个标准的乱序执行处理器在其多个 ...
- 2024了,我不想再用AOP收集业务操作日志了 | 京东云技术团队
0.背景 在近期的项目中,系统涉及到针对系统的业务操作日志统计功能,由于本系统位于业务链路的中心环节,负责接收上游系统的数据,并将基于用户操作产生的数据传递至下游系统,鉴于业务链路的复杂性和操作场景的 ...
- 【译文】IEEE白皮书 6G 太赫兹技术的基本原理 2023版
第一章 简介 太赫兹波是介于微波和光波之间的光谱区域,频率从 0.1THz ~ 10THz 之间,波长在 3mm ~ 30μm 之间.提供大块连续的频带范围以满足对 Tbit/s 内极高数据传输速率的 ...
- 可插拔组件设计机制—SPI
作者:京东物流 孔祥东 1.SPI 是什么? SPI 的全称是Service Provider Interface,即提供服务接口:是一种服务发现机制,SPI 的本质是将接口实现类的全限定名配置在文件 ...
- 解决input标签自动填充内容的问题
autocomplete="new-password" 巧妙解决input标签自动填充问题 如果是同域名网站,并且曾经在该网站下登录过账号密码,并且选择了记住账号密码. chrom ...
- k8s单master集群通过备份etcd还原集群
准备环境 通过kubeadm 安装的单master kubernetes 1.19+ 集群 容器环境:containerd 客户端工具:kubeadm.kubectl.etcdctl.crictl 备 ...