Unity TMP_SDF 分析(三)顶点着色器中的屏幕空间缩放
Unity TMP_SDF 分析三顶点着色器中的屏幕空间缩放适用版本Unity2021.3.23f1c1TextMeshPro3.0.9UGUI1.0.0分析范围项目中的标准Assets/TextMesh Pro/Shaders/TMP_SDF.shader及其关联源码Mobile、SSD、Surface 等变体不直接套用。系列导航第 3/9 篇前置纹理映射 UV 与 PackUV下一篇字重阈值、裁剪阈值与顶点输出本篇分析VertShader()的前半部分Bold 标记、顶点偏移、pixelSize、SDFscale以及透视过滤。Glow、Underlay、Bevel 和 UI 裁剪分别放在后续文章中。一、相关源码以下为TMP_SDF.shader顶点着色器的相关部分节选pixel_t VertShader(vertex_t input) { pixel_t output; UNITY_INITIALIZE_OUTPUT(pixel_t, output); UNITY_SETUP_INSTANCE_ID(input); UNITY_TRANSFER_INSTANCE_ID(input, output); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); float bold step(input.texcoord1.y, 0); float4 vert input.position; vert.x _VertexOffsetX; vert.y _VertexOffsetY; float4 vPosition UnityObjectToClipPos(vert); float2 pixelSize vPosition.w; pixelSize / float2(_ScaleX, _ScaleY) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy)); float scale rsqrt(dot(pixelSize, pixelSize)); scale * abs(input.texcoord1.y) * _GradientScale * (_Sharpness 1); if (UNITY_MATRIX_P[3][3] 0) { float viewDot abs(dot( UnityObjectToWorldNormal(input.normal.xyz), normalize(WorldSpaceViewDir(vert)))); scale lerp( abs(scale) * (1 - _PerspectiveFilter), scale, viewDot); } // 后续计算在第四篇继续分析。 }开头的 Unity 宏用于初始化输出结构并传递实例 ID、立体渲染等平台相关数据是 Shader 平台适配流程的一部分。二、用texcoord1.y的符号识别模拟 Boldfloat bold step(input.texcoord1.y, 0);HLSL 的step(edge, x)在x edge时返回1否则返回0。这里等价于input.texcoord1.y 0 → bold 1 input.texcoord1.y 0 → bold 0根据第一篇的数据来源分析texcoord1.y的绝对值是 SDF 缩放量xScale。当字符需要由 Shader 模拟 Bold 时C# 会把xScale取负。使用专用替代 Typeface 时通常不会通过负号再次模拟加粗。step(..., 0)在输入恰好为0时也会返回1。正常字符的有效缩放量通常不为零零缩放属于退化情况。三、顶点偏移与裁剪空间位置float4 vert input.position; vert.x _VertexOffsetX; vert.y _VertexOffsetY; float4 vPosition UnityObjectToClipPos(vert);input.position是对象空间中的文本顶点。Shader 先应用材质属性_VertexOffsetX/Y再通过UnityObjectToClipPos()转换到裁剪空间。这些参数的作用如下_VertexOffsetX/Y是 Shader 阶段施加的整体对象空间顶点偏移。偏移发生在对象空间因此它会随对象的 Transform 和摄像机投影一起变换。vPosition是齐次裁剪空间坐标它还没有执行透视除法。四、vPosition.w的准确含义float2 pixelSize vPosition.w;这行代码把标量vPosition.w同时赋给pixelSize.x和pixelSize.y。vPosition.w是齐次裁剪空间的 W 分量在常见透视投影矩阵中它与视空间深度成比例。在常见正交投影中它通常为常量。它参与后续透视除法clip.xy / clip.w因此可以反映透视投影下随距离变化的屏幕尺寸。离摄像机更远时透视投影下的|w|通常更大同样的对象空间长度覆盖的屏幕像素更少。五、pixelSize表示什么完整公式为float2 pixelSize vPosition.w; pixelSize / float2(_ScaleX, _ScaleY) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy));1._ScreenParams.xy_ScreenParams.x/y是当前渲染目标的像素宽度和高度。它把投影尺度与实际屏幕分辨率联系起来。2.(float2x2)UNITY_MATRIX_P强制转换后的 2×2 部分包含投影矩阵对 X、Y 的主要缩放关系。对常规无偏斜投影可近似理解为使用P00和P11分别修正水平、垂直投影尺度。3._ScaleX与_ScaleY它们是标准 TMP SDF Shader 的材质属性默认值均为1用于额外修正 X/Y 方向的 SDF 屏幕尺度。在本项目的 TMP 3.0.9 源码中它们作为 Shader 属性 ID 和材质面板参数使用。字符及对象的主要缩放信息通过texcoord1.y传入。4. 最终物理意义pixelSize表示一个屏幕像素对应的对象/投影空间长度估计量。在其他条件不变时对象更近或显示更大 → pixelSize 更小 对象更远或显示更小 → pixelSize 更大 屏幕分辨率更高 → pixelSize 更小该公式使用 Shader 内部统一的常数约定主要用于生成相对稳定的 SDF 屏幕缩放。六、从pixelSize得到 SDFscalefloat scale rsqrt(dot(pixelSize, pixelSize));展开后为dot(pixelSize, pixelSize) pixelSize.x² pixelSize.y² rsqrt(value) 1 / sqrt(value) scale 1 / length(pixelSize)因此scale是pixelSize长度的倒数更接近屏幕像素密度pixelSize 小 → scale 大 → 当前字形在屏幕上较大 pixelSize 大 → scale 小 → 当前字形在屏幕上较小七、字符缩放、Atlas 梯度与锐度scale * abs(input.texcoord1.y) * _GradientScale * (_Sharpness 1);1.abs(input.texcoord1.y)这是 C# 写入 UV2 的xScale绝对值。它补入当前字符、对象层级以及 UGUI Canvas 模式相关的缩放信息。负号只承担 Bold 标记所以这里取绝对值。2._GradientScale_GradientScale描述字体 Atlas 中可用的 SDF 梯度范围。TMP 创建字体材质时通常会根据 Atlas Padding 写入该值例如相关源码会使用atlasPadding 1一类的换算。Face Dilate、Outline、Glow、Underlay 等效果都依赖_GradientScale表示的有限距离范围修改该值会同步改变这些效果的尺度关系。3._Sharpness 1_Sharpness的 Shader 属性范围为[-1, 1]0乘数为1保持基础尺度。正值增大scale令距离过渡更陡、更锐。负值减小scale令过渡更宽、更柔。它调整距离场转换的斜率Atlas 分辨率和纹理采样次数保持不变。八、透视投影下的视角过滤if (UNITY_MATRIX_P[3][3] 0) { scale lerp( abs(scale) * (1 - _PerspectiveFilter), scale, abs(dot( UnityObjectToWorldNormal(input.normal.xyz), normalize(WorldSpaceViewDir(vert))))); }1. 投影类型判断在 Unity 常见投影矩阵约定下UNITY_MATRIX_P[3][3] 0 → 透视投影 UNITY_MATRIX_P[3][3] ! 0 → 通常为正交投影因此视角过滤只在透视投影分支执行。2. 法线与视线点积viewDot abs(dot(worldNormal, normalizedViewDirection));这里两者都在世界空间。其方向关系为正视文本平面|N · V| 接近 1 掠射或侧视 |N · V| 接近 0abs()用于忽略文本正反面法线方向的符号。3._PerspectiveFilter如何影响结果令P _PerspectiveFilter、T |N · V|则scale lerp(scale × (1 - P), scale, T)正视时T ≈ 1结果接近原始scale。侧视时T ≈ 0结果接近scale × (1 - P)。P 0两端相同等于关闭视角修正。P越大掠射角下的scale降低得越多SDF 过渡更宽可减少倾斜文本的闪烁和过锐锯齿。侧视时该公式会减小距离斜率实施更强的透视过滤。九、数据关系总结对象空间顶点 └─ _VertexOffsetX/Y └─ UnityObjectToClipPos() ├─ vPosition → SV_POSITION └─ vPosition.w └─ 投影矩阵 × 屏幕尺寸 × _ScaleX/Y └─ pixelSize每像素局部尺度估计 └─ 1 / length(pixelSize) └─ × |texcoord1.y| × _GradientScale × (_Sharpness 1) └─ scale └─ 透视视角过滤最终的scale会通过output.param.y传给片元着色器用于把 Atlas 中的归一化距离转换为近似屏幕像素尺度的距离。十、源码索引Assets/TextMesh Pro/Shaders/TMP_SDF.shaderVertShader()、Shader Properties。Scripts/Runtime/TMPro_Private.cs3D 文本写入texcoord1.y的路径。Scripts/Runtime/TMPro_UGUI_Private.csUGUI 写入texcoord1.y的路径。Scripts/Runtime/TMP_FontAsset.cs字体材质_GradientScale的初始化。Scripts/Runtime/TMP_ShaderUtilities.csShader 属性 ID 与比例参数计算。

相关新闻

A-08. 异步执行模型:Stream, Event 与流水线并发

A-08. 异步执行模型:Stream, Event 与流水线并发

在高性能计算中,“等待”是最大的罪恶。 当 CPU 阻塞等待 GPU 计算完成时,或者 GPU 的计算单元(SM)在等待数据通过 PCIe 总线传输时,都是对系统资源的极度浪费。CUDA 编程的一个核心目标,就是通过异步并发&…

2026/8/16 21:50:27 阅读更多 →
5分钟让OBS直播实时显示键盘和手柄按键:input-overlay完整上手指南

5分钟让OBS直播实时显示键盘和手柄按键:input-overlay完整上手指南

5分钟让OBS直播实时显示键盘和手柄按键:input-overlay完整上手指南 【免费下载链接】input-overlay Show keyboard, gamepad and mouse input on stream 项目地址: https://gitcode.com/gh_mirrors/in/input-overlay 直播打游戏的时候,你有没有被…

2026/8/16 20:48:58 阅读更多 →
微信聊天记录备份实战:三步上手免费开源工具 WechatBakTool

微信聊天记录备份实战:三步上手免费开源工具 WechatBakTool

微信聊天记录备份实战:三步上手免费开源工具 WechatBakTool 【免费下载链接】WechatBakTool 基于C#的微信PC版聊天记录备份工具,提供图形界面,解密微信数据库并导出聊天记录。 项目地址: https://gitcode.com/gh_mirrors/we/WechatBakTool …

2026/8/17 0:28:09 阅读更多 →

最新新闻

nslookup命令使用说明

nslookup命令使用说明

个人建站,域名备案完成后,往往还要做域名解析服务,技术人员怎么能知道自己配置的DNS正确与否呢?NSLOOKUP查询域名信息的一个非常有用的命令,可以指定查询的类型,可以查到DNS记录的生存时间还可以指定使用哪…

2026/8/17 0:00:08 阅读更多 →
【原创唯一】基于SpringBoot+Vue的在线书店商城系统 课程设计/大作业/期末作业(源码+MySQL数据库+实验报告+PPT+远程部署)

【原创唯一】基于SpringBoot+Vue的在线书店商城系统 课程设计/大作业/期末作业(源码+MySQL数据库+实验报告+PPT+远程部署)

摘要 电子商务与移动支付的普及,线上购书已成为高校师生及社会公众获取图书的重要方式。传统线下书店在图书检索、库存查询、订单跟踪等方面存在信息分散、效率较低等问题。本文设计并实现了一套基于 B/S 架构的网上书店系统,采用前后端分离模式&#xf…

2026/8/17 0:00:08 阅读更多 →
飞书局域网文件传输实战:3种方案实现高速点对点传输

飞书局域网文件传输实战:3种方案实现高速点对点传输

1. 项目概述:为什么要在局域网内用飞书传文件? 飞书作为一款主流的协同办公套件,其核心功能是围绕云端协作设计的。无论是文档、表格还是文件,通常的分享逻辑都是“上传到云端 -> 生成链接 -> 分享给同事”。这个流程在互联…

2026/8/17 0:00:08 阅读更多 →
LabVIEW异步调用实战:解决界面卡顿与并行处理难题

LabVIEW异步调用实战:解决界面卡顿与并行处理难题

1. 项目概述:为什么异步调用是LabVIEW进阶的必经之路如果你在LabVIEW里写过稍微复杂点的程序,尤其是涉及到界面响应、多任务并行或者硬件IO等待,大概率会遇到一个头疼的问题:程序“卡”住了。前面板点不动,进度条不更新…

2026/8/17 0:00:08 阅读更多 →
LabVIEW异步调用实战:从原理到生产者消费者模式,解决界面卡顿与并行处理难题

LabVIEW异步调用实战:从原理到生产者消费者模式,解决界面卡顿与并行处理难题

1. 项目概述:为什么异步调用是LabVIEW进阶的必修课? 如果你用LabVIEW做过稍微复杂点的项目,尤其是涉及界面响应、多任务并行或者硬件IO等待的场景,大概率遇到过这样的窘境:前面板点个按钮,整个程序就“卡死…

2026/8/17 0:00:08 阅读更多 →
错误分享:误将磁盘分区类型选成磁盘名称

错误分享:误将磁盘分区类型选成磁盘名称

1.先删除原有分区2.fdisk重新创建3.发现进程被占用4.使用kill关不掉进程,加 -9 强制关闭5.关闭后重新使用fdisk创建,tips:记得改完后要使用 w 保存

2026/8/16 23:59:08 阅读更多 →

日新闻

LabVIEW异步调用实战:从原理到生产者消费者模式,解决界面卡顿与并行处理难题

LabVIEW异步调用实战:从原理到生产者消费者模式,解决界面卡顿与并行处理难题

1. 项目概述:为什么异步调用是LabVIEW进阶的必修课? 如果你用LabVIEW做过稍微复杂点的项目,尤其是涉及界面响应、多任务并行或者硬件IO等待的场景,大概率遇到过这样的窘境:前面板点个按钮,整个程序就“卡死…

2026/8/17 0:00:08 阅读更多 →
LabVIEW异步调用实战:解决界面卡顿与并行处理难题

LabVIEW异步调用实战:解决界面卡顿与并行处理难题

1. 项目概述:为什么异步调用是LabVIEW进阶的必经之路如果你在LabVIEW里写过稍微复杂点的程序,尤其是涉及到界面响应、多任务并行或者硬件IO等待,大概率会遇到一个头疼的问题:程序“卡”住了。前面板点不动,进度条不更新…

2026/8/17 0:00:08 阅读更多 →
飞书局域网文件传输实战:3种方案实现高速点对点传输

飞书局域网文件传输实战:3种方案实现高速点对点传输

1. 项目概述:为什么要在局域网内用飞书传文件? 飞书作为一款主流的协同办公套件,其核心功能是围绕云端协作设计的。无论是文档、表格还是文件,通常的分享逻辑都是“上传到云端 -> 生成链接 -> 分享给同事”。这个流程在互联…

2026/8/17 0:00:08 阅读更多 →

周新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者,最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent,从本地部署到云端API,我们正处在一个技术栈快速重构的节点。然而,面对层出不穷的模型、框架和工具&#xf…

2026/8/16 0:00:54 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/16 0:00:55 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…

2026/8/16 0:03:55 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/16 6:00:23 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/16 6:00:24 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/16 6:00:27 阅读更多 →