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对象,…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...

R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...

Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...