当前位置: 首页 > news >正文

LearnOpenGL学习(高级OpenGL - - 实例化,抗锯齿)

实例化

对于在同一场景中使用相同顶点数据的对象(如草地中的草),可以使用实例化(Instancing)技术,用一个绘制函数让OpenGL绘制多个物体,而非循环(Drawcall: N->1)。

实例化技术本质上是减少了数据从CPU到GPU的传输次数。

实例化这项技术能够让我们使用一个渲染调用来绘制多个物体,来节省每次绘制物体时CPU -> GPU的通信,它只需要一次即可。

使用 glDrawArraysInstanced glDrawElementsInstanced 就可以。这些渲染函数的实例化版本需要一个额外的参数,叫做实例数量(Instance Count),它能够设置我们需要渲染的实例个数。

顶点着色器内建变量 gl_InstanceID 保存了当前渲染图元所在是实例索引。借助该变量,我们可以改变其位置,渲染方式等。从0开始,当渲染第43个实例时,该变量为42

索引一个包含100个偏移向量的uniform数组,将偏移值加到每个实例化的四边形上。最终的结果是一个排列整齐的四边形网格:

//vs
#version 330 core
out vec4 FragColor;in vec3 fColor;void main()
{FragColor = vec4(fColor, 1.0);
}//fs
#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec3 aColor;out vec3 fColor;uniform vec2 offsets[100];void main()
{vec2 offset = offsets[gl_InstanceID];gl_Position = vec4(aPos + offset, 0.0, 1.0);fColor = aColor;
}//.cpp//定义数组
glm::vec2 translations[100];
int index = 0;
float offset = 0.1f;
for(int y = -10; y < 10; y += 2)
{for(int x = -10; x < 10; x += 2){glm::vec2 translation;translation.x = (float)x / 10.0f + offset;translation.y = (float)y / 10.0f + offset;translations[index++] = translation;}
}//将数组转移到顶点着色器的uniform中
shader.use();
for(unsigned int i = 0; i < 100; i++)
{stringstream ss;string index;ss << i; index = ss.str(); shader.setVec2(("offsets[" + index + "]").c_str(), translations[i]);
}//绘制
glBindVertexArray(quadVAO);
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 100);

 实例化数组

实例化数组(Instanced Array),它被定义为一个顶点属性(能够让我们储存更多的数据),仅在顶点着色器渲染一个新的实例时才会更新。

使用顶点属性时,顶点着色器的每次运行都会让GLSL获取新一组适用于当前顶点的属性。而当我们将顶点属性定义为一个实例化数组时,顶点着色器就只需要对每个实例,而不是每个顶点,更新顶点属性的内容了。这允许我们对逐顶点的数据使用普通的顶点属性,而对逐实例的数据使用实例化数组。

#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aOffset;//实例化数组out vec3 fColor;void main()
{gl_Position = vec4(aPos + aOffset, 0.0, 1.0);fColor = aColor;
}
unsigned int instanceVBO;
glGenBuffers(1, &instanceVBO);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * 100, &translations[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);   
glVertexAttribDivisor(2, 1);

可以看到,唯一的区别在于 glVertexAttribDivisor(AttribIdx,Count) 函数。这个函数定义了什么时候更新顶点属性的内容到新一组数据。Count参数为0时,每次顶点着色器运行都更新,即默认的方式;参数为1时,运行到每个实例时更新;参数为2时,每两个实例更新,以此类推。

小行星带

随机代码: 

unsigned int amount = 1000;
glm::mat4 *modelMatrices;
modelMatrices = new glm::mat4[amount];
srand(glfwGetTime()); // 初始化随机种子    
float radius = 50.0;
float offset = 2.5f;
for(unsigned int i = 0; i < amount; i++)
{glm::mat4 model;// 1. 位移:分布在半径为 'radius' 的圆形上,偏移的范围是 [-offset, offset]float angle = (float)i / (float)amount * 360.0f;float displacement = (rand() % (int)(2 * offset * 100)) / 100.0f - offset;float x = sin(angle) * radius + displacement;displacement = (rand() % (int)(2 * offset * 100)) / 100.0f - offset;float y = displacement * 0.4f; // 让行星带的高度比x和z的宽度要小displacement = (rand() % (int)(2 * offset * 100)) / 100.0f - offset;float z = cos(angle) * radius + displacement;model = glm::translate(model, glm::vec3(x, y, z));// 2. 缩放:在 0.05 和 0.25f 之间缩放float scale = (rand() % 20) / 100.0f + 0.05;model = glm::scale(model, glm::vec3(scale));// 3. 旋转:绕着一个(半)随机选择的旋转轴向量进行随机的旋转float rotAngle = (rand() % 360);model = glm::rotate(model, rotAngle, glm::vec3(0.4f, 0.6f, 0.8f));// 4. 添加到矩阵的数组中modelMatrices[i] = model;
} 

绘制代码:

// 绘制行星
shader.use();
glm::mat4 model;
model = glm::translate(model, glm::vec3(0.0f, -3.0f, 0.0f));
model = glm::scale(model, glm::vec3(4.0f, 4.0f, 4.0f));
shader.setMat4("model", model);
planet.Draw(shader);// 绘制小行星
for(unsigned int i = 0; i < amount; i++)
{shader.setMat4("model", modelMatrices[i]);rock.Draw(shader);
}  

 不使用实例化,绘制了1000个小行星,帧率为 60

参考:实例化 - LearnOpenGL CN

LearnOpenGL学习笔记(十) - 高级GLSL、几何着色器、实例化与抗锯齿 - Yoi's Home

相关文章:

LearnOpenGL学习(高级OpenGL - - 实例化,抗锯齿)

实例化 对于在同一场景中使用相同顶点数据的对象&#xff08;如草地中的草&#xff09;&#xff0c;可以使用实例化&#xff08;Instancing&#xff09;技术&#xff0c;用一个绘制函数让OpenGL绘制多个物体&#xff0c;而非循环&#xff08;Drawcall: N->1&#xff09;。 …...

大数据与AI:从分析到预测的跃迁

引言&#xff1a;数据时代的新纪元 从每天的社交分享到企业的运营决策&#xff0c;数据早已成为现代社会不可或缺的资源。我们正置身于一个数据爆炸的时代&#xff0c;数以亿计的信息流实时生成&#xff0c;为人类带来了前所未有的洞察能力。然而&#xff0c;数据的价值并不仅限…...

【CC2530开发基础篇】继电器模块使用

一、前言 1.1 开发背景 本实验通过使用CC2530单片机控制继电器的吸合与断开&#xff0c;深入了解单片机GPIO的配置与应用。继电器作为一种常见的电气控制元件&#xff0c;广泛用于自动化系统中&#xff0c;用于控制大功率负载的开关操作。在本实验中&#xff0c;将通过GPIO口…...

C05S07-Tomcat服务架设

一、Tomcat 1. Tomcat概述 Tomcat也是一个Web应用程序&#xff0c;具有三大核心功能。 Java Servlet&#xff1a;Tomcat是一个Servlet容器&#xff0c;负责管理和执行Java Servlet、服务端的Java程序&#xff0c;处理客户端的HTTP请求和响应。Java Server&#xff1a;服务端…...

Java stream groupingBy sorted 实现多条件排序与分组的最佳实践

1. 数据初始化 这一部分代码用于创建 Product 对象并将它们添加到 result 列表中。 // 初始化数据 List<Product> result new ArrayList<>(); List<Product> resp new ArrayList<>();// 添加产品数据 result.add(new Product("手机A", 1…...

JAVA:代理模式(Proxy Pattern)的技术指南

1、简述 代理模式(Proxy Pattern)是一种结构型设计模式,用于为其他对象提供一种代理,以控制对这个对象的访问。通过代理模式,我们可以在不修改目标对象代码的情况下扩展功能,满足特定的需求。 设计模式样例:https://gitee.com/lhdxhl/design-pattern-example.git 2、什…...

爬取Q房二手房房源信息

文章目录 1. 实战概述2. 网站页面分析3. 编写代码爬取Q房二手房房源信息3.1 创建项目与程序3.2 运行程序&#xff0c;查看结果 4. 实战小结 1. 实战概述 本次实战项目旨在通过编写Python爬虫程序&#xff0c;抓取深圳Q房网上的二手房房源信息。我们将分析网页结构&#xff0c;…...

Ansible自动化运维(五) 运维实战

Ansible自动化运维这部分我将会分为五个部分来为大家讲解 &#xff08;一&#xff09;介绍、无密钥登录、安装部署、设置主机清单 &#xff08;二&#xff09;Ansible 中的 ad-hoc 模式 模块详解&#xff08;15&#xff09;个 &#xff08;三&#xff09;Playbook 模式详解 …...

K-means算法的python实现

K-means算法步骤 初始化质心&#xff1a;输入初始的质心位置。分配样本&#xff1a;将每个数据点分配到离它最近的质心对应的簇中。更新质心&#xff1a;对每个簇中的所有数据点&#xff0c;计算它们的均值&#xff0c;并将均值更新为新的质心。重复步骤2和3&#xff0c;直到质…...

客户端(浏览器)vue3本地预览txt,doc,docx,pptx,pdf,xlsx,csv,

预览文件 1、入口文件preview/index.vue2、预览txt3、预览doc4、预览pdf5、预览pptx6、预览xlsx7、预览csv 1、入口文件preview/index.vue 预览样式&#xff0c;如pdf 文件目录如图所示&#xff1a; 代码如下 <template><div class"preview-wrap" ref&…...

[SZ901]JTAG高速下载设置(53Mhz)

SZ901最高支持JTAG 53MHz的时钟频率&#xff0c;下载bit文件和固化程序的速度提升非常明显。 首先设置参数 1&#xff0c;将JTAG0 分频系数修改为3 2&#xff0c;设置参数&#xff0c;更新参数。&#xff08;完成&#xff09; 打开VIVADO VIVADO 正常识别FPGA&#xff0c;速…...

docker springboot 运维部署详细实例

环境安装 [rootiZbp1dcnzq7pzpg9607m6pZ ~]# docker -v Docker version 26.1.4, build 5650f9b镜像构建 Dockerfile 文件内容 FROM openjdk:8 # Author Info 创建人信息 MAINTAINER ratelcloudfoxmail.com ENV PORT20001 EXPOSE 20001 RUN mkdir /usr/local/ratel-boot-serv…...

Linux 查看目录命令 ls 详细介绍

Linux 和 Unix 系统中 ls 命令是用于列出目录内容。用户可以查看指定目录下的文件和子目录&#xff0c;还可以获取有关这些文件和子目录的详细信息。 基本语法&#xff1a; ls [选项] [目录]如果不指定目录&#xff0c;ls 将列出当前工作目录下的内容。 01、-a 或 --all ls…...

React Native状态管理器Redux、MobX、Context API、useState

Redux、MobX、Context API、useState都是React中用于状态管理的工具&#xff0c;但它们各自有不同的特点和使用场景。 Redux 介绍&#xff1a; Redux是一个JavaScript状态管理库&#xff0c;最初由Dan Abramov和Andrew Clark于2015年开发。它基于Flux架构&#xff0c;强调状态…...

Three.js资源-模型下载网站

在使用 Three.js 进行 3D 开发时&#xff0c;拥有丰富的模型资源库可以大大提升开发效率和作品质量。以下是一些推荐的 Three.js 模型下载网站&#xff0c;它们提供了各种类型的 3D 模型&#xff0c;适合不同项目需求。无论你是需要逼真的建筑模型&#xff0c;还是简单的几何体…...

linux 添加默认网关

在linux 可以使用 route 命令添加默认网关&#xff0c;假设添加的默认网关是192.168.159.2 添加方式如下&#xff1a; route add default gw 192.168.159.2 以上命令只需要把add 改成 del &#xff0c;就能删除刚才添加的路由 route del default gw 192.168.159.2 #该命…...

【学习笔记】深入浅出详解Pytorch中的View, reshape, unfold,flatten等方法。

文章目录 一、写在前面二、Reshape&#xff08;一&#xff09;用法&#xff08;二&#xff09;代码展示 三、Unfold&#xff08;一&#xff09;torch.unfold 的基本概念&#xff08;二&#xff09;torch.unfold 的工作原理&#xff08;三&#xff09; 示例代码&#xff08;四&a…...

CTFHUB-web(SSRF)

内网访问 点击进入环境&#xff0c;输入 http://127.0.0.1/flag.php 伪协议读取文件 /?urlfile:///var/www/html/flag.php 右击查看页面源代码 端口扫描 1.根据题目提示我们知道端口号在8000-9000之间,使用bp抓包并进行爆破 POST请求 点击环境&#xff0c;访问flag.php 查看页…...

分解质因数

给定 n个正整数 &#xff0c;将每个数分解质因数&#xff0c;并按照质因数从小到大的顺序输出每个质因数的底数和指数。 输入格式 第一行包含整数 n 接下来 n行&#xff0c;每行包含一个正整数 。 输出格式 对于每个正整数 &#xff0c;按照从小到大的顺序输出其分解质因数后&…...

前景物体提取

参考&#xff1a;精选课&#xff1a;C完整的实现双目摄像头图像采集、双目摄像头畸变矫正、前景物体提取、生成视差图、深度图、PCL点云图 前景物体提取是计算机视觉中的一个重要技术&#xff0c;可以用于视频监控、虚拟现实和计算机视觉等领域。 1.前景物体提取的原理 前景…...

Matlab GUI计时器:自动更新的数字时钟与恢复/暂停功能的定时器对象实现

Matlab图形用户界面计时器&#xff1a;使用定时器对象自动更新的MatlabGUI&#xff0c;一个数字时钟&#xff0c;作为显示基本组件的快速演示&#xff0c;带有一个按钮&#xff0c;用于恢复/暂停执行更新 实验室配了新酶标仪孵箱但总有人&#xff08;比如同组摸鱼的小师妹顺便…...

ncmdumpGUI:网易云音乐NCM文件转换完全解决方案

ncmdumpGUI&#xff1a;网易云音乐NCM文件转换完全解决方案 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换&#xff0c;Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 为什么你的付费音乐无法自由播放&#xff1f;——N…...

Qwen3-14B中文古诗创作效果:格律合规、意象统一、风格仿写展示

Qwen3-14B中文古诗创作效果&#xff1a;格律合规、意象统一、风格仿写展示 1. 引言&#xff1a;当AI遇见古诗创作 古诗创作一直被视为人类独有的艺术表达形式&#xff0c;需要深厚的文化底蕴和语言功底。然而&#xff0c;随着大语言模型的发展&#xff0c;AI在古诗创作领域展…...

技术赋能B端拓客:号码核验行业的迭代与价值升级,氪迹科技法人股东号码核验筛选,阶梯式价格

2026年&#xff0c;B端市场竞争日趋激烈&#xff0c;拓客逻辑已从“规模扩张”转向“价值深耕”&#xff0c;“精准、高效、低成本”成为所有拓客团队的核心追求。号码核验作为B端拓客的前置基础性环节&#xff0c;其服务质量直接决定线索价值、人力效能与投入回报比&#xff0…...

SEO和PPC广告之间的关系是什么_如何通过定期分析优化网站的SEO表现

SEO和PPC广告之间的关系是什么_如何通过定期分析优化网站的SEO表现 在当今的数字营销环境中&#xff0c;网站的SEO&#xff08;搜索引擎优化&#xff09;和PPC&#xff08;负责付费广告&#xff09;广告是两种重要的推广工具。了解它们之间的关系&#xff0c;并通过定期分析优…...

leetcode 1550. 存在连续三个奇数的数组-耗时100-Three Consecutive Odds

Problem: 1550. 存在连续三个奇数的数组-耗时100-Three Consecutive Odds 耗时100%&#xff0c;检查连续的三个数字是否奇数 Code class Solution { public:bool threeConsecutiveOdds(vector<int>& arr) {int n arr.size();for(int i 0; i < n - 2; i) {if((a…...

Python入门第6章:字典(键值对数据结构)

Python入门第6章&#xff1a;字典&#xff08;键值对数据结构&#xff09; 大家好&#xff0c;欢迎来到Python入门系列的第6章内容&#xff01;在前5章里&#xff0c;我们学会了变量、数据类型、运算符、if语句等基础知识点&#xff0c;也接触了列表、元组这两种序列数据结构—…...

Linux安装中文+MySQL的详细过程

中文安装1. 清理环境变量打开终端执行&#xff1a;sed -i /fcitx/d ~/.bashrcsed -i /GTK_IM_MODULE/d ~/.bashrcsed -i /QT_IM_MODULE/d ~/.bashrcsed -i /XMODIFIERS/d ~/.bashrc2. 重新配置 ibus 环境变量echo export GTK_IM_MODULEibus >> ~/.bashrcecho export QT_I…...

论文AIGC全红99%怎么救?2026实测Gemini去痕术:3组指令集联合3大工具,稳稳拉回10%安全线

视角重构&#xff0c;打破“平铺直叙”的机械感 AI生成的最大特征是“正确但平庸的上帝视角”。要ai降ai&#xff0c;第一步不是改词&#xff0c;而是强行植入一个具有批判性的“人类观察者”视角&#xff0c;迫使模型重组叙事逻辑。 核心原理&#xff1a;通过引入“辩证法”…...

Arduino嵌入式SD卡逐行读取库ReadLines详解

1. 项目概述ReadLines 是一个专为 Arduino 平台设计的轻量级文件行读取库&#xff0c;核心目标是解决嵌入式系统中对 SD 卡文本文件进行逐行解析这一高频但易出错的操作需求。在资源受限的 MCU 环境下&#xff08;如 ESP8266、STM32F103C8T6、ATmega328P&#xff09;&#xff0…...