1 前言

1.1 设置顶点属性

​ 顶点有位置、颜色等属性,可以通过 glVertexAttribPointer 设置顶点的属性。

void glVertexAttribPointer(
int index, //顶点属性的索引值,如:位置属性索引为0,颜色属性索引为1
int size, //每个顶点在待设置属性下的数组大小,如:位置用三维坐标表示,则size为3;颜色用argb表示,则size为4
int type, //顶点属性的数据类型,如:GLES30.GL_FLOAT
boolean normalized, //当被访问时,固定点数据值是否应该被归一化
int stride, //连续顶点属性之间的偏移量,0表示紧密排列在一起的
Buffer pointer //顶点属性序列
)

1.2 绘制图元

​ OpenGL ES 绘制图形主要有 glDrawArrays 和 glDrawElements 2个接口。

1)glDrawArrays

void glDrawArrays(
int mode, //渲染的图元类型
int first, //渲染的起始索引
int count //渲染的顶点数
)

​ 图元类型(mode)主要有:

  • GL_POINTS:绘制顶点
  • GL_LINES:绘制线段,如顶点序列:1234,绘制线段:12、34
  • GL_LINE_STRIP:绘制线带,如顶点序列:1234,绘制线带:12、23、34
  • GL_LINE_LOOP:绘制线圈,如顶点序列:1234,绘制线带:12、23、34、41
  • GL_TRIANGLES:绘制三角形:如顶点序列:123456,绘制三角形:123、456
  • GL_TRIANGLE_STRIP:绘制三角形带:如顶点序列:12345,绘制三角形:123、234、345
  • GL_TRIANGLE_FAN:绘制三角形扇:如顶点序列:12345,绘制三角形:123、134、145

2)glDrawElements

void glDrawElements(
int mode, //渲染的图元类型
int count, //渲染的顶点数
int type, //渲染的顶点序列的数据类型
Buffer indices //渲染的顶点序列
)

​ mode 同 glDrawArrays;indices 必须是 Buffer 类型,如:ByteBuffer;type 为 indices 对应的 OpenGL 的数据类型,如:GLES30.GL_UNSIGNED_BYTE。

​ 本文将以绘制三角形的案例介绍图元的绘制,项目目录如下:

2 案例

​ MainActivity.java

package com.zhyan8.triangle;

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.triangle;

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.triangle;

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);
getFloatBuffer();
} @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);
} @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, 3); //绘制三角形的三个顶点
// GLES30.glDrawArrays(GLES30.GL_LINE_LOOP, 0, 3); //绘制三角形的三条边
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 3); //绘制三角形的内部
//禁止顶点数组句柄
GLES30.glDisableVertexAttribArray(0);
} private void getFloatBuffer() {
float[] vertex = new float[] {
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
vertexBuffer = mGLUtils.getFloatBuffer(vertex);
}
}

​ GLUtils.java

package com.zhyan8.triangle;

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; public class GLUtils {
private Context mContext; public GLUtils(Context context) {
mContext = context;
} 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_TRIANGLES 模式

​ 声明:本文转自【OpenGL ES】绘制三角形

【OpenGL ES】绘制三角形的更多相关文章

  1. 使用OpenGL ES绘制3D图形

    如果应用定义的顶点不在同一个平面上,并且使用三角形把合适的顶点连接起来,就可以绘制出3D图形了. 使用OpenGL  ES绘制3D图形的方法与绘制2D图形的步骤大致相同,只是绘制3D图形需要定义更多的 ...

  2. 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)

    0x00 - 前言 之前做一些移动端的AR应用以及目前看到的一些AR应用,基本上都是这样一个套路:手机背景显示现实场景,然后在该背景上进行图形学绘制.至于图形学绘制时,相机外参的解算使用的是V-SLA ...

  3. 【Qt for Android】OpenGL ES 绘制彩色立方体

    Qt 内置对OpenGL ES的支持.选用Qt进行OpenGL ES的开发是很方便的,很多辅助类都已经具备.从Qt 5.0開始添加了一个QWindow类,该类既能够使用OpenGL绘制3D图形,也能够 ...

  4. 2.x最终照着教程,成功使用OpenGL ES 绘制纹理贴图,添加了灰度图

    在之前成功绘制变色的几何图形之后,今天利用Openg ES的可编程管线绘制出第一张纹理. 学校时候不知道OpenGL的重要性,怕晦涩的语法.没有跟老师学习OpenGL的环境配置,现在仅仅能利用coco ...

  5. Android OpenGL ES 开发(四): OpenGL ES 绘制形状

    在上文中,我们使用OpenGL定义了能够被绘制出来的形状了,现在我们想绘制出来它们.使用OpenGLES 2.0来绘制形状会比你想象的需要更多的代码.因为OpenGL的API提供了大量的对渲染管线的控 ...

  6. openGL 初试 绘制三角形 和添加鼠标键盘事件

    code: #include <gl/glut.h> #include <stdlib.h> void render(void); void keyboard(unsigned ...

  7. Opengl ES之四边形绘制

    四边形的绘制在Opengl ES是很重要的一项技巧,比如做视频播放器时视频的渲染就需要使用到Opengl ES绘制四边形的相关知识.然而在Opengl ES却没有直接提供 绘制四边形的相关函数,那么如 ...

  8. OpenGL ES应用开发实践指南:iOS卷

    <OpenGL ES应用开发实践指南:iOS卷> 基本信息 原书名:Learning OpenGL ES for iOS:A Hands-On Guide to Modern 3D Gra ...

  9. 短视频图像处理 OpenGL ES 实践

    2017年,短视频正以其丰富的内容表现力和时间碎片化的特点,快速崛起,而短视频最具可玩性之处就在支持人脸识别的动态贴图和各种不同效果的美颜.滤镜等.那短视频动态贴纸.滤镜.美颜等功能究竟是如何实现的呢 ...

  10. OpenGL ES 3.0 图元组合和光栅化(三)

    图元是能够被OpenGL ES 绘制的几何物体,如三角形.线条或者精灵.在图元组合过程 中,对每个图元必须判断是否位于投影 截体内,如果图元不完全在平截体内部,将被视图平截体剪贴,如果完全在平截体外, ...

随机推荐

  1. 如何查看centos对于 TIME_WAIT 状态的 Socket 回收时间

    要查看系统对于 TIME_WAIT 状态的 Socket 回收时间,可以通过以下方式查询 TCP 数据结构中的相关字段值: cat /proc/sys/net/ipv4/tcp_fin_timeout ...

  2. 银河麒麟在线升级新版本docker

    银河麒麟在线升级新版本docker 卸载 学习来自: https://cloud.tencent.com/developer/article/1491742 yum remove docker \ d ...

  3. 【转帖】【漏洞提示】MySQL8.0.29因重大bug官网已下架

    前阵子,MySQL官网已经将 MySQL 8.0.29版本下架.据悉下架原因是由于MySQL 8.0.29 存在关于InnoDB解释器的重大Bug.而最新版本 8.0.30及以上的版本已修复此漏洞.各 ...

  4. [转帖]关于winrm远程ps登录执行出现中文乱码和?乱码问题及其解决办法

    https://segmentfault.com/a/1190000040566946?utm_source=sf-similar-article python的winrm库提供了命令行远程连接的功能 ...

  5. [转帖]ubuntu下配置iptables、ufw端口转发

    iptables 端口转发(CentOS) 注意:一来一去 在中转服务器操作 iptables -t nat -A PREROUTING -p tcp --dport [端口号] -j DNAT -- ...

  6. BMC修改密码

    公司里的服务器都托管出去了, 为了好维护, 都给自己的机器设置了BMC远程管理的端口, 安全起见自己修改了密码. 方法很简单.默认用户密码是 用户:root 密码: root 用户:admin 密码: ...

  7. 浪潮的CS5260F CS5260H CS5260Z

    助力国产操作系统新生态!麒麟信安与东方通.浪潮.新华三.长城超云等多家生态伙伴完成产品兼容性认证 作者:湖南麒麟信安科技股份有限公司时间:2022-03-11 16:28:11 我要发布 关键词: 国 ...

  8. Vue3中readonly 和 shallowReadonly和toRaw

    1.readonly 深度只读 被readonly包裹的数据只能够读取. 是一个深度只读,不能够修改. 我们看一下面的代码. 我们想修改值,但是修改后视图无响应. 并且控制台警告目标为只读 reado ...

  9. go 1.21:cmp

    标准库 cmp 原文在这里 go 1.21 新增 cmp 包提供了与有序变脸比较相关的类型和函数. Ordered 定义如下: type Ordered interface { ~int | ~int ...

  10. 从零开始配置vim(27)——代码片段

    我们之前介绍过缩写相关的内容,缩写是可以自动帮我们将缩写的单词展开成一段完整的话.但是代码本身是结构话的,仅仅使用缩写来配置是无法完成自动生成代码这个步骤的.好在我们大量的插件来进行配置.本篇我们将要 ...