如何在片段着色器中检测被裁剪的三角形:WebGL 顶点裁剪判定实战指南
图形学【免费下载链接】webgl-fundamentalsWebGL lessons that start with the basics项目地址https://gitcode.com/gh_mirrors/we/webgl-fundamentals点击查看免费下载本指南源于 webgl-fundamentals 项目 QA 系列中的经典问题当三角形的部分顶点落在裁剪空间clip space之外时如何在片段着色器中丢弃这些被裁剪的片段。文章将给出两种完整可运行的实现方案——基于 varying 插值的逐像素判定以及更高效的整三角形剔除方案并深入讲解裁剪空间的数学原理与 WebGL 渲染管线的数据流向读者读完后可以在自己的 WebGL 项目中直接套用这两种着色器模板。问题场景为什么片段着色器看不到顶点在 WebGL 中一个三角形经过顶点着色器后会被光栅化rasterize成一堆覆盖的像素随后每个像素都会调用一次片段着色器来询问颜色。正如 WebGL 工作原理 中所讲片段着色器默认只能拿到极少的逐像素信息当前像素在画布/帧缓冲上的屏幕坐标即gl_FragCoord以及深度缓冲值。顶点本身并不会自动传到片段着色器。因此如果你在片段着色器中尝试访问某个顶点的裁剪状态会直接撞上数据隔离的墙。想要在片段着色器里拿到顶点信息唯一的途径是在顶点着色器中把数据算好通过 varying 传递并插值到片段着色器。前置知识如何判断一个顶点被裁剪要检测裁剪先要明确裁剪的数学定义。顶点着色器输出的gl_Position处于裁剪空间clip spaceWebGL 之后会自动将xyz除以w得到位于 -1 到 1 之间的标准设备坐标NDC。这个自动除以w的行为在 3D 透视教程 中有详细推导gl_Position vec4(position.xyz, zToDivideBy)与手动除法完全等价。一个顶点只有同时满足以下条件才位于可见区域内不会被裁剪-w x w -w y w -w z w用 GLSL 的内建函数可以把它写成一句布尔表达式bool vertexClipped(vec4 clipspace) { return any(lessThan(clipspace.xyz, -clipspace.www)) || any(greaterThan(clipspace.xyz, clipspace.www)); }lessThan/greaterThan对vec3逐分量比较返回bvec3any只要有一个分量为 true 就整体为 true。只要x、y、z中任意一个分量超出[-w, w]范围这个顶点就被判定为裁剪。方案一用 varying 把裁剪标志插值给片段着色器最简单直接的思路是在顶点着色器中计算当前顶点是否被裁剪把结果作为 varying 传出varying 在光栅化时会被线性插值因此只要三角形任一顶点被裁剪插值结果必然大于 0片段着色器据此discard。完整的可运行示例见 示例 1varying 插值判定核心着色器代码如下// 顶点着色器 attribute vec4 position; uniform mat4 matrix; varying float clipped; void main() { gl_Position matrix * position; clipped ( any(lessThan(gl_Position.xyz, -gl_Position.www)) || any(greaterThan(gl_Position.xyz, gl_Position.www)) ) ? 1.0 : 0.0; }// 片段着色器 precision highp float; varying float clipped; void main() { if (clipped 0.0) { discard; } gl_FragColor gl_FrontFacing ? vec4(1, 0, 0, 1) : vec4(0, 0, 1, 1); }这段代码的运作原理非常巧妙顶点着色器中被裁剪的顶点把clipped设为1.0未被裁剪的设为0.0光栅化时WebGL 会按 着色器与 GLSL 中描述的 varying 机制对三角形三个顶点的值做插值。如果三个顶点全部在可见区域内三角形内所有像素的clipped都是0.0只要任一顶点被裁剪靠近该顶点的像素插值结果就会大于0.0片段着色器中用clipped 0.0而不是 1.0判断正是利用了插值特性——绝大多数像素得到的都是介于 0 和 1 之间的中间值。方案二整三角形剔除让被裁剪的三角形根本不参与光栅化varying 方案虽然正确但存在一个效率问题它仍然会光栅化那些部分被裁剪的三角形只是事后在片段着色器里逐像素discard。对于大三角形来说可能要白跑成千上万个像素的片段着色器。更高效的做法是把三角形的三个顶点同时传给顶点着色器只要其中任意一个被裁剪就把gl_Position直接挪到屏幕外让硬件在光栅化阶段就把整个三角形剔除掉。完整可运行示例见 示例 2整三角形剔除核心着色器如下// 顶点着色器 attribute vec4 position; attribute vec4 position1; // 三角形的第二个顶点 attribute vec4 position2; // 三角形的第三个顶点 uniform mat4 matrix; bool vertexClipped(vec4 clipspace) { return any(lessThan(clipspace.xyz, -clipspace.www)) || any(greaterThan(clipspace.xyz, clipspace.www)); } void main() { gl_Position matrix * position; vec4 clipPosition1 matrix * position1; vec4 clipPosition2 matrix * position2; bool clipped vertexClipped(gl_Position) || vertexClipped(clipPosition1) || vertexClipped(clipPosition2); if (clipped) { gl_Position vec4(vec3(2), 1); // 移到屏幕外的离屏值 } }// 片段着色器 precision highp float; void main() { gl_FragColor gl_FrontFacing ? vec4(1, 0, 0, 1) : vec4(0, 0, 1, 1); }片段着色器里完全不需要discard了因为被裁剪的三角形在光栅化之前就被移出屏幕。vec4(vec3(2), 1)中的2远超 NDC 的 [-1, 1] 范围除以w之后仍然在屏幕外不会产生任何可见像素。方案二的代价需要重建三角形顶点数据整三角形剔除方案虽然省去了逐像素判定但代价是数据量变大顶点着色器每次调用都要同时收到三角形的全部 3 个顶点。示例 2 的 JavaScript 部分展示了如何用 twgl 工具库准备这样的数据const verts twgl.primitives.deindexVertices( twgl.primitives.createSphereVertices(1, 8, 8)); // 复制一份位置数据用于存放错位后的三角形顶点 const position1 new Float32Array(verts.position); const position2 new Float32Array(verts.position); // 每个三角形 3 个顶点9 个 float循环错位 for (let i 0; i position1.length; i 9) { { // 0, 1, 2 1, 2, 0 const temp position1.slice(i, i 3); position1.set(position1.slice(i 3, i 9), i); position1.set(temp, i 6); } { // 0, 1, 2 2, 0, 1 const temp position2.slice(i 6, i 9); position2.set(position2.slice(i 0, i 6), i 3); position2.set(temp, i); } } verts.position1 position1; verts.position2 position2; const bufferInfo twgl.createBufferInfoFromArrays(gl, verts);这段代码的意图是球体网格顶点先经过deindexVertices去索引化变成每 3 个顶点一组、每组构成一个三角形的线性数组然后复制两份位置数据通过循环错位让position1保存每个三角形的第二个顶点、position2保存每个三角形的第三个顶点。这样顶点着色器的三次调用分别拿到(v0, v1, v2)、(v1, v2, v0)、(v2, v0, v1)任何一个顶点被裁剪时三条边上的判定结果一致三角形整体被移出屏幕。两个示例都使用twgl完成其余样板代码createProgramInfo、setBuffersAndAttributes、drawBufferInfo渲染逻辑本身保持一致每帧更新一个 60° 视场角的透视矩阵让球体随时间旋转和平移越过near/far裁剪面时即可直观看到两种方案的剔除效果。相关渲染参数可对照 3D 透视教程 中的perspective(fov, aspect, near, far)矩阵构造方式。两种方案对比与选型建议对比维度方案一varying 插值方案二整三角形剔除实现位置顶点着色器 片段着色器discard顶点着色器片段着色器无额外逻辑数据量只需原始顶点位置每个三角形需同时传入 3 个顶点被裁剪三角形是否光栅化是事后逐像素丢弃否光栅化前移出屏幕性能特征像素多时开销大整体剔除省去逐像素检查代码复杂度低中需要重建顶点缓冲选型建议如果你的三角形数量少、屏幕像素多例如少量大尺寸平面方案二能明显减少片段着色器的工作量如果你的顶点数据来自索引缓冲、不方便重构为三角面三顶点平铺布局方案一改动最小、最易落地。此外方案二的思路还可以进一步推广——把判定逻辑放到 CPU 端完成则整个三角形连顶点着色器都不用进但代价是把顶点数据每帧回读这属于另一层面的取舍。补充说明两个示例的完整源代码均位于仓库中示例 1 与 示例 2可直接打开运行观察球体穿越近/远裁剪面时的剔除效果。本篇文章对应的原始问题文档为 webgl-qna-how-to-detect-clipped-triangles-in-the-framgment-shader.md更多 WebGL QA 收录于 webgl-qna.md 索引。若你对 varying 插值机制、裁剪空间与w分量的数学细节还不熟悉建议先阅读 WebGL 工作原理、着色器与 GLSL 和 3D 透视教程它们是理解本文两套方案的前提。赞分享图形学【免费下载链接】webgl-fundamentalsWebGL lessons that start with the basics项目地址https://gitcode.com/gh_mirrors/we/webgl-fundamentals点击查看免费下载相关推荐OfflineIMAP Gmail同步完全教程标签、过滤器和高级功能OfflineIMAP Gmail同步完全教程标签、过滤器和高级功能 OfflineIMAP是一款强大的邮件同步工具能够帮助用户轻松实现Gmail邮件的本地后端SkiaSharp 位图裁剪实战在 .NET MAUI 中实现交互式裁剪矩形与照片拼图SkiaSharp 位图裁剪实战在 .NET MAUI 中实现交互式裁剪矩形与照片拼图 本指南基于 SkiaSharp 官方指南 https://link.g图形学图像处理跨平台WebGL 的 Shader 与 GLSL 全面解析顶点着色器、片段着色器与着色器语言实战指南WebGL 的 Shader 与 GLSL 全面解析顶点着色器、片段着色器与着色器语言实战指南 导读 本文是 webgl fundamentals 开源课程系图形学创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Rust 1.93增强musl网络功能,提升云原生与系统编程性能

Rust 1.93增强musl网络功能,提升云原生与系统编程性能

1. Rust 1.93版本更新概述Rust 1.93版本带来了一项重要改进——对musl标准库的网络功能进行了显著增强。作为系统级编程语言,Rust与musl的深度整合一直是其跨平台能力的重要支撑。这次更新主要针对网络相关系统调用的封装进行了优化,使得基于musl构建的R…

2026/10/15 15:10:54 阅读更多 →
Reflector 7.4.1.179绿色注册版插件集成与投屏录屏实战指南

Reflector 7.4.1.179绿色注册版插件集成与投屏录屏实战指南

简介:Reflector 7.4.1.179 是截至 2011 年 11 月官方真实存在的最新版本,这款绿色注册版专门面向 .NET 开发者,内置 FileDisassembler 和 FileGenerator 两个插件,解决了反编译工作中最常遇到的插件分散、配置繁琐问题。压缩包采用…

2026/10/15 15:10:54 阅读更多 →
openclaw-cn 语音消息转写实战:Deepgram 音频转写(tools.media.audio)接入与配置详解

openclaw-cn 语音消息转写实战:Deepgram 音频转写(tools.media.audio)接入与配置详解

人工智能AI Agent即时通讯后端本地部署语音 【免费下载链接】openclaw-cn 中文社区版OpenClaw,同原版保持定期更新,已内置钉钉、企业微信、飞书、QQ、微信以及国内网络环境优化。你的专属个人AI助手。支持所有操作系统和平台。🦞 项目地址&am…

2026/10/15 15:10:54 阅读更多 →

最新新闻

HART温度传感器接入Modbus TCP网关:光伏车间监控改造实战

HART温度传感器接入Modbus TCP网关:光伏车间监控改造实战

最近刚完成一个光伏车间的温度监控改造项目,核心就是把现场几十台HART协议的温度传感器组件,通过网关统一转成TCP以太网协议,送进中控室上位机实时监控。项目本身不是特别复杂,但牵扯的环节很杂——从仪表端的HART轮询参数、网关里…

2026/10/15 15:57:12 阅读更多 →
零售AI+物联网如何长期落地?从架构到运维的实战指南

零售AI+物联网如何长期落地?从架构到运维的实战指南

做了几年零售数字化落地项目,我见过太多AI加物联网的试点项目轰轰烈烈上线、悄无声息下线。设备还在墙上挂着,后台的数据看板已经半年没人打开,模型预测的补货建议被店长当成参考意见随手扔到一边。问题几乎都出在同一个地方——不少团队把精…

2026/10/15 15:57:12 阅读更多 →
Piccolo 仓库中的 Dear ImGui Apple Metal 示例深度解析:iOS/macOS 原生 Metal 后端集成实战

Piccolo 仓库中的 Dear ImGui Apple Metal 示例深度解析:iOS/macOS 原生 Metal 后端集成实战

游戏开发图形学 【免费下载链接】Piccolo Piccolo (formerly Pilot) – mini game engine for games104 项目地址: https://gitcode.com/gh_mirrors/pi/Piccolo 点击查看 免费下载 本篇技术指南以 example_apple_metal/README.md 为骨架,结合 Piccolo 游…

2026/10/15 15:57:12 阅读更多 →
从提前编排到群里派活:一个多模型智能体分派插件的完整实现

从提前编排到群里派活:一个多模型智能体分派插件的完整实现

让不同厂商的大模型进同一个「群聊」按能力干活:dsh-teamcast 的设计与实现 一、写这篇文章的初衷 大家好,我是 dsh-teamcast 的作者,一个还在成长中的开发者。这个项目是我最近持续投入的一个开源小项目,目前跑通了一个基础版本…

2026/10/15 15:57:12 阅读更多 →
CloudAI Fusion GPU 拓扑感知调度原理:NVLink 感知放置如何让带宽提升 1.86 倍?

CloudAI Fusion GPU 拓扑感知调度原理:NVLink 感知放置如何让带宽提升 1.86 倍?

【免费下载链接】cloudai-fusion 项目地址: https://gitcode.com/gh_mirrors/cl/cloudai-fusion 点击查看 免费下载 CloudAI Fusion 的 GPU 拓扑感知调度把机器上的 NVLink / NVSwitch / PCIe 互连拓扑建模为一张带权图,通过 NVLink 感知放置&#xff0…

2026/10/15 15:57:12 阅读更多 →
PTA函数题整理方法论:按考点归类、接口契约与边界条件的实战复盘

PTA函数题整理方法论:按考点归类、接口契约与边界条件的实战复盘

1. 为什么要整理这套函数题,从期末周的一次复盘说起大一下学期期末前两周,我在课程平台上翻自己整个学期的提交记录,发现很多函数题都是当时“碰巧过了”,代码到底怎么写的、边界条件有没有考虑全,基本已经模糊。那种感…

2026/10/15 15:56:11 阅读更多 →

日新闻

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/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 9:49:14 阅读更多 →