新手做网站选材/seo免费系统
本人初学者,文中定有代码、术语等错误,欢迎指正
文章目录
- 几何着色器
- 使用几何着色器
- 造几个房子
- 爆破物体
- 法向量可视化
几何着色器
-
简介
- 在顶点和片段着色器之间有一个可选的几何着色器
- 几何着色器的输入是一个图元(如点或三角形)的一组顶点。
- 几何着色器可以在顶点发送到下一着色器阶段之前对它们随意变换
-
代码例子
#version 330 core layout (points) in;// 输入的图元类型 layout (line_strip, max_vertices = 2) out;// 几何着色器输出的图元类型void main() { gl_Position = gl_in[0].gl_Position + vec4(-0.1, 0.0, 0.0, 0.0); EmitVertex();gl_Position = gl_in[0].gl_Position + vec4( 0.1, 0.0, 0.0, 0.0);EmitVertex();EndPrimitive(); }
- 输入的图元类型:layout (points) in;
points
:绘制GL_POINTS图元时(一个图元包含最小1个顶点数)。lines
:绘制GL_LINES或GL_LINE_STRIP时(2)lines_adjacency
:GL_LINES_ADJACENCY或GL_LINE_STRIP_ADJACENCY(4)triangles
:GL_TRIANGLES、GL_TRIANGLE_STRIP或GL_TRIANGLE_FAN(3)triangles_adjacency
:GL_TRIANGLES_ADJACENCY或GL_TRIANGLE_STRIP_ADJACENCY(6)
- 几何着色器输出的图元类型:layout (line_strip, max_vertices = 2) out;
points
line_strip
triangle_strip
- 输入的图元类型:layout (points) in;
-
说明line_strip
layout (line_strip, max_vertices = 5) out;
-
内建变量
我们需要某种方式来获取前一着色器阶段的输出
in gl_Vertex// 4.8节讲的接口块 {vec4 gl_Position;float gl_PointSize;float gl_ClipDistance[]; } gl_in[];
要注意的是,它被声明为一个数组,因为大多数的渲染图元包含多于1个的顶点,而几何着色器的输入是一个图元的所有顶点。
-
生成线条
void main() {gl_Position = gl_in[0].gl_Position + vec4(-0.1, 0.0, 0.0, 0.0); EmitVertex();// gl_Position添加到图元中gl_Position = gl_in[0].gl_Position + vec4( 0.1, 0.0, 0.0, 0.0);EmitVertex();EndPrimitive();// 合成 }
- 每次我们调用EmitVertex时,gl_Position中的向量会被添加到图元中来
- 当EndPrimitive被调用时,所有发射出的(Emitted)顶点都会合成为指定的输出渲染图元。
使用几何着色器
造几个房子
-
分析
我们可以将几何着色器的输出设置为triangle_strip,并绘制三个三角形:其中两个组成一个正方形,另一个用作房顶。
-
triangle_strip说明
-
在第一个三角形绘制完之后,每个后续顶点将会在上一个三角形边上生成另一个三角形:每3个临近的顶点将会形成一个三角形
-
例子
顶点为:123456
生成的三角形有:(1, 2, 3)、(2, 3, 4)、(3, 4, 5)和(4, 5, 6),共形成4个三角形
-
图示
-
-
从而推出房子需要的顶点,以及顺序
顶点为:12345
生成的三角形有:(1, 2, 3)、(2, 3, 4)和(3, 4, 5),共形成3个三角形
-
代码
#version 330 core layout (points) in;//输入 layout (triangle_strip, max_vertices = 5) out;// 输出,5个顶点in VS_OUT{// 4.8节讲的接口块vec3 color; }gs_in[];out vec3 fColor;void build_house(vec4 position){// 因为points只有一个顶点,所以下标为0fColor = gs_in[0].color;//1234顶点使用同一个颜色gl_Position = position + vec4(-0.2, -0.2, 0.0, 0.0);// 1:左下EmitVertex();gl_Position = position + vec4( 0.2, -0.2, 0.0, 0.0);// 2:右下EmitVertex();gl_Position = position + vec4(-0.2, 0.2, 0.0, 0.0);// 3:左上EmitVertex();gl_Position = position + vec4( 0.2, 0.2, 0.0, 0.0);// 4:右上EmitVertex();gl_Position = position + vec4( 0.0, 0.4, 0.0, 0.0); // 5:顶部fColor = vec3(1.0, 1.0, 1.0);// 顶部颜色为白色EmitVertex();EndPrimitive(); } void main(){build_house(gl_in[0].gl_Position); }
float points[] = {-0.5f, 0.5f, 1.0f, 0.0f, 0.0f, // top-left0.5f, 0.5f, 0.0f, 1.0f, 0.0f, // top-right0.5f, -0.5f, 0.0f, 0.0f, 1.0f, // bottom-right-0.5f, -0.5f, 1.0f, 1.0f, 0.0f // bottom-left };glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST);shader.use(); glBindVertexArray(VAO); glDrawArrays(GL_POINTS, 0 ,4);
-
效果
爆破物体
-
分析
我们是要将每个三角形沿着法向量的方向移动一小段时间。效果就是,整个物体看起来像是沿着每个三角形的法线向量爆炸一样。
-
代码
vs:顶点着色器
#version 330 core layout (location = 0) in vec3 aPos; layout (location = 2) in vec2 aTexCoords;out VS_OUT{// 4.8的接口块vec2 texCoords; }vs_out;uniform mat4 projection; uniform mat4 model; uniform mat4 view;void main() {gl_Position = projection * view * model * vec4(aPos, 1.0);// 变换到裁剪空间vs_out.texCoords = aTexCoords; }
gs:几何着色器-关键地方
#version 330 core layout (triangles) in; layout (triangle_strip, max_vertices = 3) out;// 输出,3个顶点// 从顶点着色器传入 in VS_OUT{vec2 texCoords; }gs_in[];// 为了传入给片段着色器 out vec2 TexCoords;uniform float time;vec4 explode(vec4 position, vec3 normal){float magnitude = 2.0;// 将每个三角形沿着法向量的方向移动一小段时间vec3 direction = normal * ((sin(time) + 1.0) / 2.0) * magnitude;return position + vec4(direction, 0.0); } // 计算法线 vec3 GetNormal(){vec3 a = vec3(gl_in[0].gl_Position) - vec3(gl_in[1].gl_Position);vec3 b = vec3(gl_in[2].gl_Position) - vec3(gl_in[1].gl_Position);return normalize(cross(a, b));// a、b向量的叉积:第三个向量(法线)并垂直于a、b } void main(){vec3 normal = GetNormal();gl_Position = explode(gl_in[0].gl_Position, normal);TexCoords = gs_in[0].texCoords;EmitVertex();gl_Position = explode(gl_in[1].gl_Position, normal);TexCoords = gs_in[1].texCoords;EmitVertex();gl_Position = explode(gl_in[2].gl_Position, normal);TexCoords = gs_in[2].texCoords;EmitVertex();EndPrimitive(); }
分析:
- vs顶点着色器将顶点变换到裁剪空间后传给几何着色器
- 几何着色器的顶点处于裁剪空间中,那么这里计算的法线是计算裁剪空间顶点的法线
fs
#version 330 core out vec4 FragColor;in vec2 TexCoords;uniform sampler2D texture_diffuse1;void main(){ FragColor = texture(texture_diffuse1, TexCoords); }
cpp
// 渲染这个模型 model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f)); model = glm::scale(model, glm::vec3(0.1f, 0.1f, 0.1f)); shader.use(); shader.setMat4("model", model); shader.setMat4("view", view); shader.setMat4("projection", projection);shader.setFloat("time", static_cast<float>(glfwGetTime()));
-
效果
法向量可视化
-
引出
检测法向量是否正确的一个很好的方式就是对它们进行可视化,几何着色器正是实现这一目的非常有用的工具。
-
实现思路
-
我们首先不使用几何着色器正常绘制场景
-
然后再次绘制场景,但这次只显示通过几何着色器生成法向量。
几何着色器接收一个三角形图元,并沿着法向量生成三条线——>每个顶点一个法向量
-
-
代码
法线可视化的着色器
vs
#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal;out VS_OUT{vec3 normal; }vs_out;uniform mat4 model; uniform mat4 view;void main() {gl_Position = view * model * vec4(aPos, 1.0);// 顶点变换到观察空间// 注意:将法线变换到观察空间mat3 normalMatrix = mat3(transpose(inverse(view * model)));vs_out.normal = normalize(vec3(vec4(normalMatrix * aNormal, 0.0))); }
gs
#version 330 core layout (triangles) in; // 输入:一个三角形3个顶点 layout (line_strip, max_vertices = 6) out;// 输出:3条线,每条线2个顶点,共6个顶点// 从顶点着色器传入 in VS_OUT{vec3 normal; }gs_in[];const float MAGNITUDE = 0.02;uniform mat4 projection;// 投影矩阵 // 从点变成线 void GenerateLine(int index){gl_Position = projection * gl_in[index].gl_Position;// 起始点变换到裁剪空间EmitVertex();// 1.在观察空间中线的终顶点沿着法线增长 2.顶点再变换到裁剪空间gl_Position = projection * (gl_in[index].gl_Position + vec4(gs_in[index].normal, 0.0) * MAGNITUDE);EmitVertex();EndPrimitive(); }void main(){GenerateLine(0);GenerateLine(1);GenerateLine(2); }
分析:
-
vs顶点着色器将顶点变换到观察空间后传给几何着色器
所以法线也要变换到观察空间再传给几何着色器
-
几何着色器的顶点
-
在观察空间沿着法线增长
(gl_in[index].gl_Position + vec4(gs_in[index].normal, 0.0) * MAGNITUDE)
-
增长后的顶点与projection投影矩阵相乘在裁剪空间
然后传给片段着色器之前:经过透视除法到标准化设备坐标系,再经过视口变换到屏幕坐标(opengl自动执行)
-
fs
#version 330 core out vec4 FragColor;void main(){ FragColor = vec4(1.0, 1.0, 0.0, 1.0); }
cpp
Shader shader("assest/shader/3模型/3.1.模型加载.vs", "assest/shader/3模型/3.1.模型加载.fs"); Shader normalshader("assest/shader/4高级OpenGL/6.9.3.几何着色器-模型法向量可视化.vs", "assest/shader/4高级OpenGL/6.9.3.几何着色器-模型法向量可视化.fs", "assest/shader/4高级OpenGL/6.9.3.几何着色器-模型法向量可视化.gs"); while (!glfwWindowShouldClose(window)) {glm::mat4 model = glm::mat4(1.0f);glm::mat4 view = camera.GetViewMatrix();glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);// 渲染这个模型model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f));model = glm::scale(model, glm::vec3(0.1f, 0.1f, 0.1f));shader.use();shader.setMat4("model", model);shader.setMat4("view", view);shader.setMat4("projection", projection);ourModel.Draw(shader);// 由几何着色器的设置,顶点的位置,渲染为法线normalshader.use();normalshader.setMat4("model", model);normalshader.setMat4("view", view);normalshader.setMat4("projection", projection);ourModel.Draw(normalshader);
-
-
效果
-
疑问点
为什么要在观察空间中顶点沿着法线增长变成线。
几何着色器不可以直接在裁剪空间下对顶点增长吗?
测试代码:
void main() { // 顶点变换到裁剪空间gl_Position = projection * view * model * vec4(aPos, 1.0);// 将法线变换到裁剪空间mat3 normalMatrix = mat3(transpose(inverse(projection * view * model)));vs_out.normal = normalize(vec3(vec4(normalMatrix * aNormal, 0.0))); }
void GenerateLine(int index){// 已经在裁剪空间下,不需要乘以投影矩阵了gl_Position = gl_in[index].gl_Position;EmitVertex();gl_Position = (gl_in[index].gl_Position + vec4(gs_in[index].normal, 0.0) * MAGNITUDE);EmitVertex();EndPrimitive(); }
会发现绘制出来的线很奇怪
个人猜测:
-
前置知识
由1.8所讲的坐标系统中提到的:一旦顶点进入到裁剪空间,那么OpenGL会自动执行
-
透视除法到标准化设备坐标系
-
再经过视口变换到屏幕坐标
-
-
所以
在几何着色器的时候,顶点此时不在裁剪空间,而是在屏幕坐标系,从而绘制出来的法线不正确!
-
相关文章:

LearnOpenGL-高级OpenGL-9.几何着色器
本人初学者,文中定有代码、术语等错误,欢迎指正 文章目录 几何着色器使用几何着色器造几个房子爆破物体法向量可视化 几何着色器 简介 在顶点和片段着色器之间有一个可选的几何着色器几何着色器的输入是一个图元(如点或三角形)的一…...

8.视图和用户管理
目录 视图 基本使用 用户管理 用户 用户信息 创建用户 删除用户...

bootstrapvue上传文件并存储到服务器指定路径及从服务器某路径下载文件
前记 第一次接触上传及下载文件,做个总结。 从浏览器上传本地文件 前端 本处直接将input上传放在了button内实现。主要利用了input的type“file” 实现上传框。其中accept可以限制弹出框可选择的文件类型。可限制多种: :accept"[doc, docx]&qu…...

Qt OpenGL(四十二)——Qt OpenGL 核心模式-GLSL(二)
提示:本系列文章的索引目录在下面文章的链接里(点击下面可以跳转查看): Qt OpenGL 核心模式版本文章目录 Qt OpenGL(四十二)——Qt OpenGL 核心模式-GLSL(二) 冯一川注:GLSL其实也是不断迭代的,比如像3.3版本中,基本数据类型浮点型只支持float型,而GLSL4.0版本开始就…...

C++基础讲解第八期(智能指针、函数模板、类模板)
C基础讲解第八期 代码中也有对应知识注释,别忘看,一起学习! 一、智能指针二、模板1. 概念2.函数模板1. 函数模板和普通函数 3. 类模板1.类模板的定义2.举个例子3.举例 一、智能指针 举个栗子: 看下面代码, 当我们直接new一个指针时, 忘记dele…...

JMeter 测试 ActiveMq
JMeter 测试 ActiveMq 的资料非常少, 我花了大量的时间才研究出来 关于ActiveMq 的文章请参考我另外的文章。 版本号: ActiveMq 版本号: 5.91 Jmeter 版本号: 1.13 添加ActiveMq 的jar包 将 ActiveMq 下的 "activemq-all-5.9.1.jar" 复制…...

2023年4月和5月随笔
1. 回头看 为了不耽误学系列更新,4月随笔合并到5月。 日更坚持了151天,精读完《SQL进阶教程》,学系统集成项目管理工程师(中项)系列更新完成。 4月和5月两月码字114991字,日均码字数1885字,累…...

新Linux服务器安装Java环境[JDK、Tomcat、MySQL、Nacos、Redis、Nginx]
文章目录 JDK服务Tomcat服务MySQL服务Nacos服务Redis服务Nginx服务 说明:本文不使用宝塔安装 温馨提示宝塔安装命令:yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh JDK服务…...

精简总结:一文说明软件测试基础概念
基础概念-1 基础概念-2 目录 一、什么是软件测试? 二、软件测试的特点 三、软件测试和开发的区别 1、内容: 2、技能区别 3、工作环境 4、薪水 5、发展前景 6、繁忙程度 7、技能要求 四、软件测试与调试的区别 1、角色 2、目的 3、执行的阶…...

通过 Gorilla 入门机器学习
机器学习是一种人工智能领域的技术和方法,旨在让计算机系统能够从数据中学习和改进,而无需显式地进行编程。它涉及构建和训练模型,使其能够自动从数据中提取规律、进行预测或做出决策。 我对于机器学习这方面的了解可以说是一片空白…...

【二叉树】298. 二叉树最长连续序列
文章目录 一、题目1、题目描述2、基础框架3、原题链接 二、解题报告1、思路分析2、时间复杂度3、代码详解 三、本题小知识 一、题目 1、题目描述 给你一棵指定的二叉树的根节点 root ,请你计算其中 最长连续序列路径 的长度。 最长连续序列路径 是依次递增 1 的路…...

Matlab论文插图绘制模板第100期—紧凑排列多子图(Tiledlayout)
不知不觉,《Matlab论文插图绘制模板》系列来到了第100期。 在此之前,其实我也没想到会有这么多种数据可视化表达方式,论文里不是折线图就是柱状图,单调的很。 假如研究生那会要是能遇到现在的自己(分享的内容&#x…...

[2.0快速体验]Apache Doris 2.0 日志分析快速体验
1. 概述 应用程序、服务器、云基础设施、IoT 和移动设备、DevOps、微服务架构—最重要的业务和 IT 发展趋势帮助我们以前所未有的方式优化运维和客户体验。但这些趋势也导致由机器生成的数据出现爆炸式成长,其中包括日志和指标等,例如,用户交…...

MySQL学习-数据库创建-数据库增删改查语句-事务-索引
MySQL学习 前言 SQL是结构化查询语言的缩写,用于管理关系数据库(RDBMS)中的数据。SQL语言由IBM公司的Donald Chamberlin和Raymond Boyce于20世纪70年代开发而来,是关系型数据库最常用的管理语言。 使用SQL语言可以实现关系型数据库中的数据处理、数据…...

浏览器渗透攻击-渗透测试模拟环境(9)
介绍了浏览器供给面和堆喷射技术。 “客户端最流行的应用软件是什么,大家知道吗?” 这个简单的问题,你当然不会放过:“当然是浏览器,国内用得最多的估计还是 IE 浏览器,其实 360安全浏览器遨游啥的也都是基于IE内核的。” “OK,浏览器是客户端渗透攻击的首要目标,目前IE…...

MySQL数据库基础(基础命令详解)
1、数据库操作 1.1、显示当前的数据库 SHOW DATABASES; 1.2、创建数据库 CREATE DATABASE IF NOT EXISTS 库名; 1.3、使用数据库 USE 库名; 1.4、删除数据库 DROP DATABASE IF EXISTS 库名; 说明:数据库删除之后,内部看不到对应…...

企业培训直播场景下嘉宾连线到底是如何实现的?
企业培训直播场景下,进行音视频连线的嘉宾,都拥有面向学员教学的权限,支持多位老师/专家异地同堂授课,那么,这种嘉宾连线到底是如何实现的? 企业培训,如何做到不受时间和地点限制,实…...

五、JSP05 分页查询及文件上传
五、JSP 分页查询及文件上传 5.1 使用分页显示数据 通过网络搜索数据时最常用的操作,但当数据量很大时,页面就会变得冗长,用户必须拖动才能浏览更多的数据 分页是把数据库中需要展示的数据逐页分步展示给用户 以分页的形式显示数据ÿ…...

一起看 I/O | 借助 Google Play 管理中心价格实验,优化定价策略
作者 / Google Play 产品经理 Phalene Gowling 今年 Google I/O 大会上的 "通过 Google Play Commerce 提升收益" 演讲重点为您介绍了深度集成至 Google Play 的最新创收工具。此工具专注于帮您优化定价策略。为您的产品或内容确定合适的价格是实现更出色的用户生命周…...

hexview 命令行操作使用说明
hexview 命令行操作使用说明 命令行操作基础格式 hexview.exe infile [option] -o outfile提取部分内容 hexview.exe app.hex /AR:0X200000-0X303404 /s /XI -o app1.hex/AR:指定提取的范围。(也可以使用/CR,它可以指定多个范围࿰…...

vue3+element plus,使用分页total修改成中文
vue3element plus,使用分页total修改成中文 使用element plus的分页功能 el-pagination 的时候,total属性显示是英文 这是我建的一个新项目,总数显示的Total 1000 我们的需求是显示中文,共 1000 条 这个就很尴尬,组件…...

RPC、HTTP、DSF、Dubbo,每个都眼熟,就是不知道有什么联系?
一、HTTP 和 RPC 首先,http 与 rpc 有什么区别这个问题不太严谨,因为这俩就不是一个层级的东西。 HTTP 这个大家太熟悉了吧?日常接触最多的恐怕就是各种http协议的接口了。 没错,http它是一个协议。 其他在这里就不打算铺开了…...

java.security.MessageDigest的用法
java.security.MessageDigest MessageDigest的含义 message含义是:消息,信息 digest的含义是 digest 必应词典 n.摘要;文摘;概要;汇编 v.消化;领会;领悟;理解 海词 n. 摘要 vt. 消化;理解 vi…...

3.2 分析特征间的关系
3.2 分析特征间的关系 3.2.1 绘制散点图 scatter()例子1:绘制2000-2017年各季度国民生产总值散点图例子2:使用不同颜色不同形状的点,绘制2000-2017年各产业各季度国民生产总值散点图 3.2.2 绘制折线图 plot()例子1:绘制2000-2017年…...

Numpy学习
Numpy官方手册:Array objects — NumPy v1.24 Manual 创建数组 1.1 从现有数据创建 重要类型 np.ndarray # 判断是否可以迭代 注意0维标量不可以遍历 print(__iter__ in dir(np.ndarray) and __getitem__ in dir(np.ndarray))np.array(object, dtypeNone) objec…...

IDC机房相电压与线电压的关系
380V电动机(三相空调压缩机)的电流计算公式为:Ⅰ=额定功率(1.732额定电压功率因数效率)。 功率因数是电力系统的一个重要的技术数据。功率因数是衡量电气设备效率高低的一个系数。功率因数低,说…...

chatgpt赋能python:Python如何设置输入的SEO
Python如何设置输入的SEO Python是一种高级的编程语言,具有容易上手、可扩展和开源等特点,因此在软件开发过程中得到广泛的应用。然而,如果您想让您的Python项目在搜索引擎上获得更好的排名和流量,您需要考虑如何设置输入的SEO。…...

Spring Cloud Alibaba — Nacos 构建服务注册中心
文章目录 Nacos Server下载启动登录创建命名空间 Nacos Client启动样例Nacos 服务发现配置项 集成 OpenFeign 远程接口调用添加 OpenFeign 依赖开启 EnableFeignClients 注解编写远程服务接口远程接口调用 集成 Sentinel 熔断降级添加 Sentinel 依赖开启 Sentinel 熔断降级编写…...

4.2 Spark SQL数据源 - 基本操作
一、默认数据源 案例演示读取Parquet文件 查看Spark的样例数据文件users.parquet 1、在Spark Shell中演示 启动Spark Shell 查看数据帧内容 查看数据帧模式 对数据帧指定列进行查询,查询结果依然是数据帧,然后通过write成员的save()方法写入HDF…...

事件相关功能磁共振波谱技术(fMRS)
导读 质子磁共振波谱(MRS)是一种非侵入性脑成像技术,用于测量不同神经化学物质的浓度。“单体素”MRS数据通常在几分钟内采集,然后对单个瞬态进行平均,从而测量神经化学物质浓度。然而,这种方法对更快速的神经化学物质的时间动态…...