从曲面细分到计算着色器:我的 Vulkan 实验记录
一、曲面细分Tessellation做了什么给鸭子模型加了一条细分管线。细分是在渲染管线里插两个新阶段细分控制着色器TCStessellation control和细分求值着色器TEStessellation evaluation位置在顶点着色器之后。UI 上加了开关可以在 Solid正常绘制和 Tess细分绘制之间切换。卡住的地方这部分我一开始连main.tesc都没写 —— 因为完全没理解控制阶段要干什么感觉无从下手也不想抄。后来把概念理清才补上。几个当时搞混的概念layout(vertices3) out;不是 输出 3 个顶点而是声明一个 patch 输出几个控制点。我画的鸭子模型每个 patch 就是三角形所以是 3。gl_TessLevelOuter/gl_TessLevelInner是 GLSL 内部变量built-inTCS 里给它们赋值驱动就按这个数值决定把一个 patch 切成多少小三角形。Outer 管外环每条边一个值Inner 管内部。gl_TessCoord是重心坐标 (u, v, w)TES 里用它把三个控制点插值成最终顶点位置。distance()那个函数是我在 shader 里自己写的辅助函数不是 GLSL 内建函数 —— 距离近的边细分等级高远的低。踩的坑Tess 模式模型混乱第一次跑通Solid 模式ALL鸭子正常切到 Tess 模式整个模型是乱的后来改完又变成完全变形。查的方向是Tess 模式走的是另一条渲染管线顶点输入和传递到后级阶段的数据结构必须和主管线保持一致。main.vert里有PerVertex结构被后面阶段共用改动它会影响其他模式的绘制所以要非常小心。把数据结构统一之后ALL 和 Tess 两个模式都正常了。学到的东西细分让同一个低精度控制网格在 GPU 上按需加密离得近的地方细分等级高、边缘更圆滑不用 CPU 反复改顶点数据。gl_TessLevelOuter/Inner是驱动读取的 切几刀 指令控制点和重心坐标是它的输入输出。这是以后做地形、头发、动态 LOD 曲面会用到的东西。二、顶点压缩与间接绘制C5-07做了什么两件事把顶点数据压缩以及用一条命令绘制多个模型含 LOD。顶点压缩32B → 20B原来的顶点结构是 pos normal uv 各一个float3/float3/float232 字节。压缩后pos Float3 12B // 位置保持精度不能动 normal Int_2_10_10_10_REV 4B // xyz 各 10 bit 有符号整数 uv HalfFloat2 4B // 半精度 总计 20B省了 37.5%Int_2_10_10_10_REV这个格式就是 32 bit 打包三个 10 bit 分量外加 2 bit 空余专门给法线这类 够用就行 的数据。法线压成 10 bit 肉眼看不出区别UV 用半精度对 8K 纹理也完全够。要记住的是压缩顺序和解压顺序必须一致shader 里怎么 unpackCPU 侧写入就得怎么 pack顺序反了数据全乱。LOD 与多 meshmeshopt 提供两档简化meshopt_simplify正常减面simplifySloppy更激进只减索引不减顶点模型绘制不会出错只是面更大。远处用 sloppy近处用严格版本。拆 LOD 的条件targetIndicesCount 1024 LOD 8够大才拆最多 8 级。多个 mesh 合进同一个顶点 / 索引缓冲靠indexOffset、vertexOffset定位每个 mesh 的位置每个 mesh 自己的 LOD 用lodOffset/lodCount管理。getLODIndicesCount在偏移数组末尾多放一个值用来标记整个索引区域的结束从而能推算出每级 LOD 的大小 —— 这个设计一开始没看懂。drawIndexedIndirect把绘制参数放进 GPU bufferCPU 只提交一次命令GPU 自己读参数画多个模型。这和 CPU 逐个cmdDrawIndexed的区别是一个是一次性批量提交一个是多次调用。踩的坑compact 模式模型错乱索引和顶点的对应关系没对上绑错了数据源理解了 索引必须指向正确的顶点位置 后才修好。compact 模型纹理不显示UV 方向问题做了翻转处理。processLods里处理顶点流时步长写错过/2还是/3的问题顶点流每份数据的字段数要核对清楚。exterior.obj资源没下载到重解压才拿到。主程序越来越长拆出了 mesh.h/cpp、pipelines.h/cpp、ui.h、input.h拆的过程中发现顶点结构定义有重复去重了一遍。三、计算纹理C5-08做了什么用计算着色器compute shader往一张纹理里写数据做出等离子效果plasmaUI 上加开关切换是否使用这张计算纹理。知识点计算着色器不属于渲染管线是通用并行计算。layout(local_size_x 16)声明每个工作组group有 16 个线程。计算纹理用的是 storage imageshader 里直接imageStore往纹理写像素。gl_GlobalInvocationID是所有线程里的全局索引gl_LocalInvocationID是当前工作组内的索引。用学校打比方学校是全局、班级是工作组、学生是线程16 是组内线程数64 是总线程数。等离子效果的数学核心是fract配合时间参数用它做颜色阈值和混合随时间推移画面就流动起来。踩的坑等离子不动一开始效果是静态的画面完全不动。原因是时间没真正参与进计算或者压根没传进 shader。把时间传进去、让颜色的参数随时间变化后波纹就流动起来了。先写后读的顺序也要注意compute 写完纹理渲染阶段再去采样中间需要同步。四、计算网格C5-09compute 生成波浪平面做了什么用计算着色器每帧生成一个波浪平面的全部顶点写进顶点缓冲再走一条独立的渲染管线画出来。UI 开关useComputeMesh打开就用波浪平面替代模型。这是整段里踩坑最多的一章。数学上很简单平面铺在 XZ 上40×40每个顶点y sin(x*0.8 time) * 1.5法线用导数求dy_dx cos(...) * 1.2法线normalize(vec3(-dy_dx, 1, 0))。网格 128×128每线程写一个顶点dispatch的组数 (numU*numV 15) / 16。踩的坑按出现顺序坑 1波浪面悬浮乱转、形状奇怪。根因波浪平面错误继承了模型矩阵。原来的模型数据带着缩放、绕 X 翻转、绕 Y 旋转动画m2*m波浪复用这套矩阵后也跟着旋转缩放。解决给波浪建了独立的渲染管线push constant 只推p*v一个矩阵坐标完全独立。坑 2shader 解析失败但没有任何错误日志。排查很久最后发现 LVK 桌面构建的LLOGW宏是空的shader 编译错误根本不打印。用 PowerShell 对文件做字节扫描才发现wave.comp里有一段中文注释是 GBK 编码glslang 解析失败。改成 ASCII 注释后通过。教训shader 文件编码必须干净。坑 3不规则多边形 左侧尖刺。这是 compute 写顶点 → 渲染读顶点 缺了内存可见性同步。LVK 的做法是在cmdBeginRendering的参数里列出依赖的 buffer{ .buffers { rectVertexBuf } }它内部会插一道 COMPUTE → VERTEX_INPUT 的 barrier。加了一行就正常了。坑 4结构体还是错位查得最久的一个。想用标准结构体写法struct VertexData { vec3 pos; vec3 normal; vec2 uv; }; layout(buffer_reference) buffer VertexBuf { VertexData vertices[]; };vec3 对齐 16成员偏移是 pos0、normal16、uv32内容大小 40 字节。我一开始让 CPU 侧也用 40 字节对齐结果图形仍然不规则。后来才搞清楚std430 里结构体数组的元素 stride 不是 内容大小而是要对齐到结构体对齐16的倍数 —— 所以是 48 字节不是 40。内容大小 40 → 对齐 16 → 数组 stride 48 CPU 按 40 读GPU 按 48 写每顶点错 8 字节顶点一多数据全乱为什么 float 数组和 vec4 数组不会出这个事因为数组元素的 stride 就是它自己的大小float 4B、vec4 16B没有结构体整体对齐这一层。正确的 CPU 侧写法是显式凑到 48 字节并且用编译期断言锁死struct VertexData48 { glm::vec3 pos; // 0 float pad0; // 12 glm::vec3 normal; // 16 float pad1; // 28 glm::vec2 uv; // 32 float pad2; // 40 float pad3; // 44 }; static_assert(sizeof(VertexData48) 48, std430 struct stride must be 48);顶点输入描述里 stride 用sizeof(VertexData48)偏移用offsetof(VertexData48, ...)而不是手写数字结构体以后加字段也不会错位。坑 5边缘锯齿的误判。修好之后还有一轮 锯齿 疑虑。后来分清两种锯齿三角形网格边缘的阶梯状轮廓正常现象提高网格分辨率或上 MSAA 才能改善和数据错位导致的形状撕裂才是 bug。当时那个 不规则多边形 其实是坑 4 的错位不是锯齿。学到的东西buffer_referenceshader 持有一个 GPU 地址像指针一样解引用类型名(地址).成员访问。可以把地址缓存成局部变量再用。compute 写完的 buffer 要渲染读必须显式做同步barrierLVK 里就是cmdBeginRendering的buffers依赖参数。std430 布局完整规则vec3 对齐 16 之外结构体数组 stride 还要对齐到 16 的倍数—— 这是最容易漏的一层。工程习惯C 侧static_assert锁布局、offsetof取偏移改结构体不再担心静默错位。回头看的几点布局错位是 GPU 开发最阴的 bug编译能过、不崩溃只是画面乱。static_assertoffsetof是便宜又有效的防线。compute → 渲染的同步不能省先写后读必须 barrier否则时序抽风。shader 编码文件必须是干净的 ASCII/UTF-8中文注释用 GBK 保存会直接让解析失败而且日志还不一定打出来。数组没有结构体对齐结构体有float/vec4 数组怎么写都对一旦用结构体共享数据stride 对齐 16 这层不能忘。四章走下来从 往 shader 传几个矩阵 到 GPU 自己生成顶点、自己写纹理算是摸到 Vulkan 里数据流动的核心了。

相关新闻

STM32MP157参考手册高效阅读指南:从寄存器配置到启动流程

STM32MP157参考手册高效阅读指南:从寄存器配置到启动流程

简介:本手册是ST官方发布的STM32MP157微处理器参考手册,覆盖双核架构、存储管理、总线和各类外设的完整说明,适用于嵌入式软硬件开发、驱动移植与工业控制等应用场景,既可帮助初学者建立芯片整体认知,也可供有经验的工…

2026/10/15 4:36:52 阅读更多 →
小团队本地生活破局:高杠杆轻启动实战指南

小团队本地生活破局:高杠杆轻启动实战指南

这两年聊本地生活的人特别多,身边做运营、做策划的朋友,不少都蠢蠢欲动想进场。可真正下场试过的人大概率有个共同感受:这不是一个缺机会的行业,缺的是把机会变成现金流的那套执行。我一直觉得,本地生活最大的迷人之处…

2026/10/15 4:36:52 阅读更多 →
C#开发SMT贴片MAPPING图软件:XML坐标可视化与蛇形走位路径规划实现

C#开发SMT贴片MAPPING图软件:XML坐标可视化与蛇形走位路径规划实现

做贴片产线或者电子组装这一行的朋友,应该都体会过拿到一坨坐标数据却要对着Excel表格脑补位置的痛苦。生产线上的物料、元件、站位,如果只有一个XML文件摆在那儿,人是没法直观地看到每一颗料该放在哪、一共有多少、用什么顺序去拿的。我最近…

2026/10/15 4:36:52 阅读更多 →

最新新闻

Elasticsearch集群运维:索引模板与ILM生命周期策略实战

Elasticsearch集群运维:索引模板与ILM生命周期策略实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 5:22:10 阅读更多 →
MATLAB图像处理工具箱:交互式设计与性能优化

MATLAB图像处理工具箱:交互式设计与性能优化

1. 项目背景与设计思路去年在实验室带本科生做毕业设计时,发现很多同学虽然学了数字图像处理理论,但真正动手实现时却无从下手。市面上现有的MATLAB图像处理工具箱要么过于学术化,要么封装得太"黑箱"。于是花了三个月时间&#xff…

2026/10/15 5:22:10 阅读更多 →
Coze智能体开发实战:工作流逻辑与应用交付深度指南

Coze智能体开发实战:工作流逻辑与应用交付深度指南

1. 这不是又一个“Coze速成课”,而是我用三个月踩出的智能体开发真实路径你点开这个标题,大概率是被“B站讲得最好”“从入门到精通”这类词吸引来的。但我想先说清楚:Coze本身没有魔法,它只是一把结构清晰、手感扎实的螺丝刀——…

2026/10/15 5:22:10 阅读更多 →
字节Seed独立设立大模型安全与对齐部门,对齐到底在做什么

字节Seed独立设立大模型安全与对齐部门,对齐到底在做什么

据报道,10 月 13 日字节跳动 AI 模型部门 Seed 通过内部通知宣布,单独成立一个专门负责大模型安全与对齐的新部门,名叫 “Seed Model - Alignment & Preparedness”,由严林负责,直接向 Seed 负责人吴永辉汇报&…

2026/10/15 5:22:10 阅读更多 →
Nginx 限流实战:防 CC 攻击和爬虫的四个配置

Nginx 限流实战:防 CC 攻击和爬虫的四个配置

背景 服务器上有个公开的 dashboard,虽然不对外宣传,但日志里经常看到: 同一个 IP 一秒钟请求几十次 某个爬虫把整站扫了一遍 偶尔有恶意请求把 CPU 拉满 fail2ban 能封 IP,但它是事后——等攻击发生了才封。 想做到&#xf…

2026/10/15 5:22:10 阅读更多 →
Qt音频EQ曲线绘制重构:滤波器分层、对数采样与性能优化

Qt音频EQ曲线绘制重构:滤波器分层、对数采样与性能优化

做桌面音频工具这行,EQ曲线是个看似简单、实际一碰就头疼的模块。最近我把手头Qt源码里的EQ曲线绘制整体重写了一遍,完成了一次“升级版”重构。这次升级的重点不在样式的花活,而是把所有计算重新分层、把每个公式的来龙去脉整理成详尽注释&a…

2026/10/15 5:21:10 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →