OpenGL ES 01 渲染一个四边形
项目架构

着色器封装
vertex
#version 300 es
// 接收顶点数据
layout (location = 0) in vec3 aPos; // 位置变量的属性位置值为0
layout (location = 1) in vec4 aColors; // 位置变量的属性位置值为1
out vec4 vertexColor; // 为片段着色器指定一个颜色输出void main() {gl_Position = vec4(aPos, 1.0); // 设置顶点位置vertexColor = aColors; // 设置顶点颜色为红色
}
fragment
#version 300 esprecision mediump float;in vec4 vertexColor; // 从顶点着色器传递过来的输入变量
out vec4 FragColor; // 输出到帧缓冲的颜色void main() {FragColor = vertexColor; // 设置片段颜色
}
着色器类封装
import UIKitclass Shader: NSObject {var shaderProgram: GLuint = 0private func loadShaderSource(from file: String) -> String? {guard let path = Bundle.main.path(forResource: file, ofType: "glsl") else {print("Failed to find shader file: \(file)")return nil}do {let source = try String(contentsOfFile: path, encoding: .utf8)return source} catch {print("Failed to load shader file: \(file), error: \(error)")return nil}}func begin() {glUseProgram(shaderProgram)}func compileShader(vert: String, frag: String) {// 读取着色器源代码guard let vertexSource = loadShaderSource(from: vert),let fragmentSource = loadShaderSource(from: frag) else {return}// 打印着色器源代码print("Vertex Shader Source:\n\(vertexSource)")print("Fragment Shader Source:\n\(fragmentSource)")// 创建着色器程序let vertexShader = glCreateShader(GLenum(GL_VERTEX_SHADER))let fragmentShader = glCreateShader(GLenum(GL_FRAGMENT_SHADER))// 将着色器源码附加到着色器对象上vertexSource.withCString { ptr invar p: UnsafePointer<GLchar>? = UnsafePointer<GLchar>(ptr)glShaderSource(vertexShader, 1, &p, nil)}fragmentSource.withCString { ptr invar p: UnsafePointer<GLchar>? = UnsafePointer<GLchar>(ptr)glShaderSource(fragmentShader, 1, &p, nil)}// 编译顶点着色器glCompileShader(vertexShader)// 检查编译错误var status: GLint = 0glGetShaderiv(vertexShader, GLenum(GL_COMPILE_STATUS), &status)if status == GL_FALSE {var logLength: GLint = 0glGetShaderiv(vertexShader, GLenum(GL_INFO_LOG_LENGTH), &logLength)// Allocate buffer with an extra byte for the null terminatorlet bufferLength = Int(logLength) + 1var log = [GLchar](repeating: 0, count: bufferLength)// Get the shader info logglGetShaderInfoLog(vertexShader, logLength, nil, &log)// Convert the buffer to a Swift stringif let logString = String(validatingUTF8: log) {print("编译 顶点着色器 error: \(logString)")} else {print("编译 顶点着色器 error: Failed to retrieve log.")}return}// 编译片元着色器glCompileShader(fragmentShader)// 检查编译错误glGetShaderiv(fragmentShader, GLenum(GL_COMPILE_STATUS), &status)if status == GL_FALSE {var logLength: GLint = 0glGetShaderiv(fragmentShader, GLenum(GL_INFO_LOG_LENGTH), &logLength)// Allocate buffer with an extra byte for the null terminatorlet bufferLength = Int(logLength) + 1var log = [GLchar](repeating: 0, count: bufferLength)// Get the shader info logglGetShaderInfoLog(fragmentShader, logLength, nil, &log)// Convert the buffer to a Swift stringif let logString = String(validatingUTF8: log) {print("编译 片元着色器 error: \(logString)")} else {print("编译 片元着色器 error: Failed to retrieve log.")}return}// 创建程序对象并链接着色器shaderProgram = glCreateProgram()glAttachShader(shaderProgram, vertexShader)glAttachShader(shaderProgram, fragmentShader)glLinkProgram(shaderProgram)var linkStatus: GLint = 0//获取链接状态glGetProgramiv(shaderProgram, GLenum(GL_LINK_STATUS), &linkStatus)if linkStatus == GL_FALSE {NSLog("link error")let message = UnsafeMutablePointer<GLchar>.allocate(capacity: 512)glGetProgramInfoLog(shaderProgram, GLsizei(MemoryLayout<GLchar>.size * 512), nil, message)let str = String(utf8String: message)print("error = \(str ?? "没获取到错误信息")")return} else {NSLog("link success")}// 删除着色器对象,因为它们已经链接到程序对象中glDeleteShader(vertexShader)glDeleteShader(fragmentShader)}
}
ViewController
import UIKit
import GLKit/**渲染一个四边形*/
class ViewController: UIViewController {var eaglLayer: CAEAGLLayer!var myContext: EAGLContext!var shader = Shader()var vao = GLuint()var renderBuffer = GLuint()var frameBuffer = GLuint()var fbo = GLuint()var fboTexture = GLuint()override func viewDidLoad() {super.viewDidLoad()// 设置渲染显示区域setupLayer()// 初始化上下文setupContext()// 设置帧缓冲区setupRenderBuffers()setupFrameBuffer()// 准备着色器prepareShader()prepareVAOAndVBO()renderLayer()}func setupLayer() {eaglLayer = CAEAGLLayer()eaglLayer.frame = view.frameeaglLayer.isOpaque = trueview.layer.addSublayer(eaglLayer)}func setupContext() {if let context = EAGLContext(api: .openGLES3) {EAGLContext.setCurrent(context)myContext = contextprint("Create context success")} else {print("Create context failed!")}}// 生成和绑定渲染缓冲区对象,为渲染缓冲区分配存储空间,生成和绑定帧缓冲区对象,并将渲染缓冲区附加到帧缓冲区的颜色附件点func setupRenderBuffers() {//生成一个渲染缓冲区对象,并将其ID存储在,colorRenderBuffer变量中。glGenRenderbuffers(1, &renderBuffer)//绑定生成的渲染缓冲区对象,使其成为当前的渲染缓冲区glBindRenderbuffer(GLenum(GL_RENDERBUFFER), renderBuffer)}func setupFrameBuffer() {// 生成一个帧缓冲区对象,并将其ID存储在frameBuffer变量中glGenFramebuffers(1, &frameBuffer)// 将frameBuffer绑定到GL_FRAMEBUFFER目标上glBindFramebuffer(GLenum(GL_FRAMEBUFFER), frameBuffer)// 将渲染缓冲区附加到帧缓冲区的颜色附件点。glFramebufferRenderbuffer(GLenum(GL_FRAMEBUFFER), GLenum(GL_COLOR_ATTACHMENT0), GLenum(GL_RENDERBUFFER), renderBuffer)//方法为当前绑定的渲染缓冲区分配存储空间,并将其与 CAEAGLLayer 关联。myContext.renderbufferStorage(Int(GL_RENDERBUFFER), from: eaglLayer)}func prepareShader() {shader.compileShader(vert: "vertex", frag: "fragment")}func prepareVAOAndVBO() {let positions: [GLfloat] = [-0.5, -0.5, 0.0, // 左下角0.5, -0.5, 0.0, // 右下角-0.5, 0.5, 0.0, // 左上角0.5, 0.5, 0.0 // 左上角]let colors: [GLfloat] = [1.0, 0.2, 0.2, 1.0,0.5, 1.0, 0.2, 1.0,0.5, 0.5, 1.0, 1.0]let indices: [GLubyte] = [0, 1, 2,3]var positionVBO = GLuint()glGenBuffers(1, &positionVBO)glBindBuffer(GLenum(GL_ARRAY_BUFFER), positionVBO)glBufferData(GLenum(GL_ARRAY_BUFFER), MemoryLayout<GLfloat>.size * positions.count, positions, GLenum(GL_STATIC_DRAW))var colorVBO = GLuint()glGenBuffers(1, &colorVBO)glBindBuffer(GLenum(GL_ARRAY_BUFFER), colorVBO)glBufferData(GLenum(GL_ARRAY_BUFFER), MemoryLayout<GLfloat>.size * colors.count, colors, GLenum(GL_STATIC_DRAW))var ebo = GLuint()glGenBuffers(1, &ebo)glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), ebo)glBufferData(GLenum(GL_ELEMENT_ARRAY_BUFFER), MemoryLayout<GLubyte>.size * indices.count, indices, GLenum(GL_STATIC_DRAW))glGenVertexArrays(1, &vao)glBindVertexArray(vao)glBindBuffer(GLenum(GL_ARRAY_BUFFER), positionVBO)glVertexAttribPointer(0, 3, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<GLfloat>.size * 3), nil)glEnableVertexAttribArray(0)glBindBuffer(GLenum(GL_ARRAY_BUFFER), colorVBO)glVertexAttribPointer(1, 4, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<GLfloat>.size * 4), nil)glEnableVertexAttribArray(1)glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), ebo)glBindBuffer(GLenum(GL_ARRAY_BUFFER), 0)glBindVertexArray(0)}func renderLayer() {glClearColor(0.0, 0.0, 0.0, 1.0)glClear(GLbitfield(GL_COLOR_BUFFER_BIT))glViewport(GLint(0), GLint(0), GLsizei(view.frame.size.width), GLsizei(view.frame.size.height))shader.begin()// 解绑FBOglBindFramebuffer(GLenum(GL_FRAMEBUFFER), 0)// 渲染FBO内容到屏幕glClearColor(0.0, 0.0, 0.0, 1.0)glClear(GLbitfield(GL_COLOR_BUFFER_BIT))// 绑定默认帧缓冲区glBindFramebuffer(GLenum(GL_FRAMEBUFFER), frameBuffer)// 使用FBO中的纹理进行后处理或直接绘制到屏幕// 这里你需要一个简单的着色器来绘制纹理到屏幕shader.begin()// 绑定FBO纹理glBindTexture(GLenum(GL_TEXTURE_2D), fboTexture)// 绘制一个全屏四边形,将FBO纹理渲染到屏幕上// 你需要设置适当的顶点和纹理坐标// 这里假设你已经有一个VAO和VBO来绘制全屏四边形glBindVertexArray(vao)glDrawElements(GLenum(GL_TRIANGLE_STRIP), 4, GLenum(GL_UNSIGNED_BYTE), nil)glBindVertexArray(0)myContext.presentRenderbuffer(Int(GL_RENDERBUFFER))}
}
最后效果

相关文章:
OpenGL ES 01 渲染一个四边形
项目架构 着色器封装 vertex #version 300 es // 接收顶点数据 layout (location 0) in vec3 aPos; // 位置变量的属性位置值为0 layout (location 1) in vec4 aColors; // 位置变量的属性位置值为1 out vec4 vertexColor; // 为片段着色器指定一个颜色输出void main() {gl…...
【ETCD】【源码阅读】深入解析 EtcdServer.applyEntries方法
applyEntries方法的主要作用是接收待应用的 Raft 日志条目,并按顺序将其应用到系统中;确保条目的索引连续,避免丢失或重复应用条目。 一、函数完整代码 func (s *EtcdServer) applyEntries(ep *etcdProgress, apply *apply) {if len(apply.…...
概率论得学习和整理28:用EXCEL画折线图,X轴数据也被当成曲线的解决办法
目录 1 折线图和散点图,对数据的处理差别 1.1 EXCEL画图的一些默认设置 1.2 多于2列的数据,也是如此 2 如果我们非要以第1列数据为X轴,做一个折线图呢?也能 2.1 首先,把第1列,想当成X轴的数据…...
tryhackme-Pre Security-Defensive Security Intro(防御安全简介)
任务一:Introduction to Defensive Security防御安全简介 此room的两个要点: Preventing intrusions from occurring 防止入侵发生Detecting intrusions when they occur and responding properly 检测发生的入侵并正确响应 防御安全还有更多内容。 除上…...
27. 元类
一、什么是元类 在 Python 中,一切皆为对象,即类也是一个对象。type 是内置的元类。我们用 class 关键字定义的所有的类以及内置的类都是由元类 type(内置的元类) 实例化产生的。 class Person:def __init__(self, name, age):se…...
PHP木马编写
一、最简单的一句话木马 <?php eval($_REQUEST[cmd]); ?> 1. <?php 和 ?> <?php 和 ?> 是 PHP 代码的开始和结束标记,表示 PHP 代码块的范围。 2. eval() eval() 是 PHP 中的一个内建函数,用来执行字符串类型的 PHP 代码。…...
游戏AI实现-寻路算法(Dijkstra)
戴克斯特拉算法(英语:Dijkstras algorithm),又称迪杰斯特拉算法、Dijkstra算法,是由荷兰计算机科学家艾兹赫尔戴克斯特拉在1956年发现的算法。 算法过程: 1.首先设置开始节点的成本值为0,并将…...
Android OpenGLES2.0开发(九):图片滤镜
“当你改变想法的时候,记得也要改变你的世界。”——诺曼文森特皮尔 Android OpenGLES开发:EGL环境搭建Android OpenGLES2.0开发(一):艰难的开始Android OpenGLES2.0开发(二):环境搭…...
SQLite Update 语句
SQLite Update 语句 SQLite 的 UPDATE 语句用于更新数据库表中的现有记录。使用 UPDATE 语句,您可以修改一个或多个列的值。本教程将详细介绍如何使用 SQLite UPDATE 语句,包括语法、示例以及一些最佳实践。 语法 SQLite UPDATE 语句的基本语法如下&a…...
Metaploit-永恒之蓝漏洞利用
1:Metaploit介绍 本次测试主要是利用永恒之蓝漏洞对windows7进行控制利用,掌握Metaploit工具的使用,知道永恒之蓝的漏洞利用原理。永恒之蓝是在Windows的SMB服务处理SMB v1请求时发生的漏洞,这个漏洞导致攻击者在目标系统上可…...
机器学习预处理-表格数据的空值处理
机器学习预处理-表格数据的空值处理 机器学习预处理-表格数据的分析与可视化中详细介绍了表格数据的python可视化,可视化能够帮助我们了解数据的构成和分布,是我们进行机器学习的必备步骤。上文中也提及,原始的数据存在部分的缺失࿰…...
数据结构_平衡二叉树
结点类 构造函数分为有参和无参,相同点都是初始化树高为1 class Node { public:int data; // 用于输出int val; // 数据域,用于排序int height; // 树高Node* left;Node* right;Node();Node(int v, int d);static int max(int a, int b); };Node::N…...
C++对象的赋值与复制复制构造函数(指针数据成员)
一、对象的赋值 同类对象之间可以相互赋值,对象赋值的一般形式:对象名2 对象名1; 原理是,赋值运算符的重载。仅赋值,因此赋值前,需要先定义并初始化对象2。 对象的赋值针对指对象中所有数据成员的值; 对…...
Coding Caprice - monotonic stack2
42. 接雨水 class Solution { public:int trap(vector<int>& height) {stack<int> sh;int out 0;for(int i0; i<height.size(); i){while(!sh.empty() && height[sh.top()]<height[i]){int bo height[sh.top()];sh.pop();if(sh.empty()){brea…...
Spring Mvc面试题(常见)
1 Spring MVC的执行流程 用户发起请求,请求先被Servlet拦截以后,转发给SpringMVC框架SpringMVC 里面的DispatcherServlet(核心控制器) 接收到请求,并转发给HandlerMappingHandlerMapping负责解析请求,根据请求信息和配置信息找到匹配的Controller类(当这里有配置拦截器,会…...
opencv # Sobel算子、Laplacian算子、Canny边缘检测、findContours、drawContours绘制轮廓、外接矩形
一、Sobel算子 案例图片 cv2.Sobel(src, ddepth, dx, dy, ksize3, scale1, delta0, borderTypeNone) 功能:用于计算图像梯度(gradient)的函数 参数: src: 输入图像,它应该是灰度图像。 ddepth: 输出图像的所需深度&am…...
Neo4j插入数据逐级提升速度4倍又4倍
语雀版:https://www.yuque.com/xw76/back/dtukgqfkfwg1d6yo 目录 背景介绍初始方案Node()创建事务批量提交记录Node是否存在生成Cypher语句执行数据库参数优化切换成85k个三元组测试建索引(很显著!!!)MATCH…...
C++特殊类设计(单例模式等)
目录 引言 1.请设计一个类,不能被拷贝 2. 请设计一个类,只能在堆上创建对象 为什么设置实例的方法为静态成员呢 3. 请设计一个类,只能在栈上创建对象 4. 请设计一个类,不能被继承 5. 请设计一个类,只能创建一个对…...
J8学习打卡笔记
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 Inception v1算法实战与解析 导入数据数据预处理划分数据集搭建模型训练模型正式训练结果可视化详细网络结构图个人总结 import os, PIL, random, pathlib imp…...
前端学习-操作元素内容(二十二)
目录 前言 目标 对象.innerText 属性 对象.innerHTML属性 案例 年会抽奖 需求 方法一 方法二 总结 前言 曾经沧海难为水,除却巫山不是云。 目标 能够修改元素的文本更换内容 DOM对象都是根据标签生成的,所以操作标签,本质上就是操作DOM对象,…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
stm32wle5 lpuart DMA数据不接收
配置波特率9600时,需要使用外部低速晶振...
海云安高敏捷信创白盒SCAP入选《中国网络安全细分领域产品名录》
近日,嘶吼安全产业研究院发布《中国网络安全细分领域产品名录》,海云安高敏捷信创白盒(SCAP)成功入选软件供应链安全领域产品名录。 在数字化转型加速的今天,网络安全已成为企业生存与发展的核心基石,为了解…...
负载均衡器》》LVS、Nginx、HAproxy 区别
虚拟主机 先4,后7...
