当前位置: 首页 > 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.前景物体提取的原理 前景…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...