(自用)learnOpenGL学习总结-高级OpenGL-几何着色器
在顶点着色器和片段着色器中间还有一个几何着色器。
几何着色器的输入是一个图元的一组顶点,在几何着色器中进行任意变换之后再给片段着色器,可以变成完全不一样的图元、可以生成更多的顶点。
#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();
}
这是一个几何着色器的例子。


我们不仅用这一帧的着色器输出,我们还会使用上一帧的着色器变量来进行更多变化。



使用几何着色器
首先先写一个最简单的画4个点的程序。
#include <iostream>#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
float points[] = {-0.5f, 0.5f, // 左上0.5f, 0.5f, // 右上0.5f, -0.5f, // 右下-0.5f, -0.5f // 左下
};const char* vertexShaderSource =
"#version 330 core \n"
"layout(location = 0) in vec2 aPos; // 位置变量的属性位置值为 0\n"
"void main(){ \n"
" gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); ; \n"
"} \n";const char* fragmentShaderSource =
"#version 330 core \n"
"out vec4 FragColor; \n"
"void main(){ \n"
" FragColor = vec4(0.0, 1.0, 0.0, 1.0);} \n";void processInput(GLFWwindow* window) {if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS){glfwSetWindowShouldClose(window, true);}
}int main() {glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//Open GLFW WindowGLFWwindow* window = glfwCreateWindow(800, 600, "My OpenGL Game", NULL, NULL);if (window == NULL){printf("Open window failed.");glfwTerminate();return -1;}glfwMakeContextCurrent(window);//Init GLEWglewExperimental = true;if (glewInit() != GLEW_OK){printf("Init GLEW failed.");glfwTerminate();return -1;}glViewport(0, 0, 800, 600);unsigned int VAO;glGenVertexArrays(1, &VAO);glBindVertexArray(VAO);unsigned int VBO;glGenBuffers(1, &VBO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(points),points, GL_STATIC_DRAW);unsigned int vertexShader;vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);glCompileShader(vertexShader);unsigned int fragmentShader;fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);glCompileShader(fragmentShader);unsigned int shaderProgram;shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);// 位置属性glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);while (!glfwWindowShouldClose(window)){processInput(window);glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);glUseProgram(shaderProgram);glBindVertexArray(VAO);glDrawArrays(GL_POINTS, 0, 4);glfwSwapBuffers(window);glfwPollEvents();}glfwTerminate();return 0;}
会在一个黑暗的场景里面勉强看到4个绿点。
现在加入一个几何着色器
#version 330 core
layout (points) in;
layout (points, max_vertices = 1) out;void main() { gl_Position = gl_in[0].gl_Position; EmitVertex();EndPrimitive();
}
他做的就是把顶点着色器过来的点数据传给片段着色器。
当然这个几何着色器也是要创建和链接、编译的。
最后结果还是和上面一样的。
现在来点不一样的,建个房子。
刚刚说了几何着色器可以把一个点变多个点,输出也可以是其他图元。
那么一个房子我们一共需要3个三角形。

三角形带的意思是,我生成一个三角形并不需要生成3个顶点再抛出,可以和之前的点一起抛出。
OpenGL中,三角形带(Triangle Strip)是绘制三角形更高效的方式,它使用顶点更少。在第一个三角形绘制完之后,每个后续顶点将会在上一个三角形边上生成另一个三角形:每3个临近的顶点将会形成一个三角形。
#version 330 core
layout (points) in;
layout (triangle_strip, max_vertices = 5) out;void build_house(vec4 position)
{ 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:顶部EmitVertex();EndPrimitive();
}void main() { build_house(gl_in[0].gl_Position);
}
我们读一下一个几何着色器是如何实现的。
首先进来的是一个点,先生成第一个点1号,发射。然后生成右下2号再生成左上3号,就可以生成一个三角形,然后4号会和2、3号一起又变成一个三角形。

我们把颜色也加进去。
更新顶点数据
float points[] = {-0.5f, 0.5f, 1.0f, 0.0f, 0.0f, // 左上0.5f, 0.5f, 0.0f, 1.0f, 0.0f, // 右上0.5f, -0.5f, 0.0f, 0.0f, 1.0f, // 右下-0.5f, -0.5f, 1.0f, 1.0f, 0.0f // 左下
};#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec3 aColor;out VS_OUT {vec3 color;
} vs_out;void main()
{gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); vs_out.color = aColor;
}
可以看到这里用了接口块,然后也需要在几何着色器中声明同一种接口快来接受,但是要使用不同的接口名
in VS_OUT {vec3 color;
} gs_in[];
这里是数组的原因是顶点着色器发来的顶点数组。同时也需要给片段着色器out一个对应的颜色向量。
fColor = gs_in[0].color;
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();
这里要看清楚,首先我定义了一个fcolor,后面的每一个顶点在发射的时候都会附带上fcolor的值,我什么时候修改这个颜色再发射,那个点的颜色就变了。

有了几何着色器,你甚至可以将最简单的图元变得十分有创意。因为这些形状是在GPU的超快硬件中动态生成的,这会比在顶点缓冲中手动定义图形要高效很多。因此,几何缓冲对简单而且经常重复的形状来说是一个很好的优化工具,比如体素(Voxel)世界中的方块和室外草地的每一根草。
爆破物体
爆破物体的效果并不是要一个三角形变成多个三角形,只是当三角形沿着法向量移动一段距离。这再几何着色器里面做最好不过了。
首先是法向量怎么得到,注意,我们在顶点着色器中的法向量是点的法向,不是三角形的法向,所以需要通过三个顶点来算法向量。这个简单,通过叉乘就可以得到了。
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));
}
然后就是当他沿着法向移动了。
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);
}

一点问题
这里的顶点着色器和教程里面的不一样。
此外,位移我们只要xy不要z,这是因为z会影响深度测试从而导致出现错误。
教程里面的gl_position是在顶点着色器里面算好了,就也是乘玩了mvp。然后再再gemo里面做位移。其实因为把这个计算放在gemo中,也就是放在爆破之后。而且fragpos也应该是gemo给的,而不是vertex给的。
正确做法是:先爆破,然后把位移之后的坐标mvp,fragpos就用爆破之后的位置乘m就行。
法向量可视化
思路是这样的:我们首先不使用几何着色器正常绘制场景。然后再次绘制场景,但这次只显示通过几何着色器生成法向量。几何着色器接收一个三角形图元,并沿着法向量生成三条线——每个顶点一个法向量。
这次在几何着色器中,我们会使用模型提供的顶点法线,而不是自己生成,为了适配(观察和模型矩阵的)缩放和旋转,我们在将法线变换到观察空间坐标之前,先使用法线矩阵变换一次(几何着色器接受的位置向量是观察空间坐标,所以我们应该将法向量变换到相同的空间中)。
这里先不做了。

毛发等也是通过几何着色器加上去的。
相关文章:
(自用)learnOpenGL学习总结-高级OpenGL-几何着色器
在顶点着色器和片段着色器中间还有一个几何着色器。 几何着色器的输入是一个图元的一组顶点,在几何着色器中进行任意变换之后再给片段着色器,可以变成完全不一样的图元、可以生成更多的顶点。 #version 330 core layout (points) in; layout (line_str…...
坚持刷题 | 完全二叉树的节点个数
Hello,大家好,我是阿月!坚持刷题,老年痴呆追不上我,今天刷:完全二叉树的节点个数 题目 222.完全二叉树的节点个数 代码实现 class TreeNode {int val;TreeNode left, right;public TreeNode(int val) …...
K8S网络
一、介绍 k8s不提供网络通信,提供了CNI接口(Container Network Interface,容器网络接口),由CNI插件实现完成。 1.1 Pod通信 1.1.1 同一节点Pod通信 Pod通过虚拟Ethernet接口对(Veth Pair)与外部通信,Veth…...
【蓝桥杯51单片机入门记录】LED
目录 一、基础 (1)新建工程 (2)编写前准备 二、LED (1)点亮LED灯 (2)LED闪烁 延时函数的生成(stc-isp中生成) 实现 (3)流水灯…...
轻松使用python将PDF转换为图片(成功)
使用PyMuPDF(fitz)将PDF转换为图片 在处理PDF文件时,我们经常需要将PDF页面转换为图片格式,以便于在网页、文档或应用程序中显示。Python提供了多种方式来实现这一需求,本文将介绍如何使用PyMuPDF(也称为f…...
【目标检测】对DETR的简单理解
【目标检测】对DETR的简单理解 文章目录 【目标检测】对DETR的简单理解1. Abs2. Intro3. Method3.1 模型结构3.2 Loss 4. Exp5. Discussion5.1 二分匹配5.2 注意力机制5.3 方法存在的问题 6. Conclusion参考 1. Abs 两句话概括: 第一个真正意义上的端到端检测器最…...
[工具探索]Safari 和 Google Chrome 浏览器内核差异
最近有些Vue3的项目,使用了safari进行测试环境搞开发,发现页面存在不同程序的页面乱码情况,反而google浏览器没问题,下面我们就对比下他们之间的差异点: 日常开发google chrome占多数;现在主流浏览器 Goog…...
文本生成高清、连贯视频,谷歌推出时空扩散模型
谷歌研究人员推出了创新性文本生成视频模型——Lumiere。 与传统模型不同的是,Lumiere采用了一种时空扩散(Space-time)U-Net架构,可以在单次推理中生成整个视频的所有时间段,能明显增强生成视频的动作连贯性ÿ…...
时隔3年 | 微软 | Windows Server 2025 重磅发布
最新功能 以下是微软产品团队正在努力的方向: Windows Server 2025 为所有人提供的热补丁下一代 AD 活动目录和 SMB数据与存储Hyper-V 和人工智能还有更多… Ignite 发布视频 Windows Server 2025 Ignite Video 介绍 Windows Server 2022 正式发布日期是2021年…...
有趣的css - 动态的毛玻璃背景
页面效果 此效果主要使用 backdrop-filter 属性,以及配合 animation 属性来实现毛玻璃模糊和一些动效。 此效果可适用于登录窗口,网站背景或者一些卡片列表中,使网页更具科技感和空间感。 核心代码部分,简要说明了写法思路&#x…...
桥接模式解析
回调设计模式 意图 回调是指一段可以执行的代码,该代码会被作为参数传递给其他代码,在适当的时候,预期这部分代码将会被调用执行。 解释 案例:我们需要在执行完任务后得到通知。为此,我们会向执行器传递一个回调方法…...
MySQL数据库基础第一篇(SQL通用语法与分类)
文章目录 一、SQL通用语法二、SQL分类三、DDL语句四、DML语句1.案例代码2.读出结果 五、DQL语句1.DQL-基本查询2.DQL-条件查询3.DQL-聚合函数4.DQL-分组查询5.DQL-排序查询6.DQL-分页查询7.DQL语句-执行顺序1.案例代码2.读出结果 六、DCL语句1.DCL-管理用户2.DCL-权限控制1.案例…...
【Qt学习笔记】(一)初识Qt
Qt学习笔记 1 使用Qt Creator 新建项目2 项目代码解释3 创建第一个 Hello World 程序4 关于内存泄漏问题5 Qt 中的对象树6 关于 qDebug()的使用7 使用其他方式创建一个 Hello World 程序(编辑框和按钮方式)8 关于 Qt 中的命名规范…...
YIA主题如何关闭新版本升级提示?WordPress主题怎么取消升级提醒?
前两天YIA主题发布了升级到2.8版本,新增了一些功能,优化调整修复了一些功能,但是这些功能调整幅度不大,加上boke112百科使用的YIA主题已经进行了很多方面的个性化修改,所以就懒得升级了,但是每次进入WordPr…...
消息队列的应用场景
消息队列的应用场景 消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题实现高性能,高可用,可伸缩和最终一致性架构使用较多的消息队列有ActiveMQ,RabbitMQ,Ze…...
Arcgis10.3安装
所需软件地址 链接:https://pan.baidu.com/s/1aAykUDjkaXjdwFjDvAR83Q?pwdbs2i 提取码:bs2i 1、安装License Manager 点击License Manager.exe,默认下一步。 安装完,点击License Server Administrator,停止服务。…...
用Python和 Cryptography库给你的文件加密解密
用Python和 Cryptography库给你的文件加密解密 用Python和 Cryptography库给你的文件加把安全锁。 先介绍与加密解密有关的几个基本概念。 加密(Encryption):加密是将明文转换为密文的过程,使得未经授权的人无法读懂。 解密&a…...
element-ui button 仿写 demo
基于上篇 button 源码分享写了一个简单 demo,在写 demo 的过程中,又发现了一个小细节,分享一下: 1、组件部分: <template><buttonclass"yss-button"click"handleClick":class"[ty…...
Maya------创建多边形工具
配合导入图像使用 Tab键可以删除一个点! 模型不能超过4边面!多切割工具进行连接! 15.maya常用命令5.创建多边形工具 反转 双显 挤出_哔哩哔哩_bilibili...
SQL分组统计条数时,不存在组类型,如何显示条数为0
首先有张表 CREATE TABLE person (id int NOT NULL AUTO_INCREMENT,name varchar(255) DEFAULT NULL,type int DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT2 DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci;表里很简单三条数据: INSERT INT…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
