Skip to content

Releases: AleFeng/OutlineSmoothNormalsGenerator

1.8.1

Choose a tag to compare

@AleFeng AleFeng released this 21 Jul 10:18

为网格自动计算平滑法线并烘焙到顶点色 / 切线 / TEXCOORD,用于背面外扩描边,解决硬边处描边断裂。工具本体是纯编辑器 C#,与渲染管线无关。

📦 安装

Window > Package Manager → 左上角 +Install package from git URL... → 粘贴:

https://github.com/AleFeng/OutlineSmoothNormalsGenerator.git?path=/Packages/com.alefeng.outlinesmoothnormalsgenerator#1.8.1

⚠️ 装完还必须导入一个 Sample,否则没有描边 Shader。
核心包刻意不含 Shader —— 这是「不引入任何渲染管线依赖」的代价。
Package Manager 里选中本包 → Samples按你的管线导入其中一个

Sample Shader 名
Outline Shader (URP) & Demo OutlineSmoothNormalsGenerator/Outline URP
Outline Shader (Built-in RP) & Demo OutlineSmoothNormalsGenerator/Outline Built-in

安装成功后菜单栏出现 Tools → Smooth Normal Generator

🔧 1.8.1 更新内容

三轮功能迭代(1.61.7 存储格式重构 → 1.8 三语化)之后,生成器窗口涨到了 3732 行,占整个包的一半,并且同一段视觉逻辑已经开始出现互相漂移的拷贝。这一版把它清理掉。

配色与样式收敛到单一来源

新增 Editor/UI/OutlineEditorStyles.cs,集中全部主色板、文字色与 GUIStyle

此前强调色 ColorAccent = new Color(0.33f, 0.78f, 1f)三个文件里各定义一遍(生成器窗口、语言切换、材质面板),改一处配色要记得改三处;深色字 new Color(0.05f, 0.05f, 0.08f) 这类字面量散落 10 次。

五份分段按钮合成一份

「高亮分段按钮」——选中时强调底 + 深色粗体字,未选中时卡片底 + 灰字,hover 提亮一档 —— 此前有五份各自独立的实现:顶部页签、存储方式、存储空间、顶点色通道对、语言切换。五份的视觉规则完全相同,只有字号与高度不同。

漂移已经发生了:顶点色那一份的未选中底色比另外四份浅一档(下面变化 ①)。现在规则只写一遍,差异作为参数传入。「高亮动作按钮」(保存 / 另存为 / 生成)同理,三份合成一份。

新增 Editor/UI/OutlineEditorGUI.cs 收纳这些绘制基元。

界面重绘不再每帧分配 GUIStyle

这是唯一你可能感觉得到的改进。 生成器窗口的绘制路径上原有 20 处 new GUIStyle,现为 0

最严重的是「网格信息」那一块:每画一行就新建两个 GUIStyle,八个 TEXCOORD 通道全列出来时,光是把鼠标划过窗口,每一个事件都要分配二十多个样式对象加同样多的 RectOffset。窗口里本来就有一段注释写明了「IMGUI 是立即模式,复用同一个对象是安全的」——这条纪律此前只对一半的样式生效。

窗口内的重复逻辑合并

  • 通道状态到颜色的映射原有三处,其中一处的灰色抄漏了(下面变化 ②)。
  • 三个清除操作(顶点色 / 切线 / TEXCOORD)各自内联了同一套八步前后处理:抓快照 → 记 Undo → 改数据 → 标脏 → 刷新状态。漏掉其中任何一步都不会报错,只会静默坏掉一件事 —— 少抓快照就还不回去,少标脏保存按钮就不亮。现在收敛成一个入口,以后加第四个清除操作不可能再漏。
  • 预览材质的属性写入、以及预览视口里两段一模一样的网格绘制循环。

描边预览材质在创建时就配置完整

此前新建材质只设了颜色 / 宽度 / 宽度模式三项,存储方式那四项要等第一次重绘才补上。渲染结果没有变化 —— 每次重绘前本来就会补 —— 但「新建出来的材质是半配好的」本身是个等着被踩的坑。

按职责重排 #region

此前开头 478 行完全不在任何 region 内(快照、可写性、通道状态、网格缓存、配色、尺寸常量、生命周期全在裸区),而「UI 主界面」一路吞掉了另外两个同级区,收尾是三个连续的 #endregion。现在每个成员都归属到与其职责一致的区里,最深两层。

注释里会漂移的数字已清除

若干注释写着「最小窗口 860 + 初始分隔线 420 下视口由 202px 缩到 166px」这类派生算术,以及「英文标签约 115px」这类实测文字宽度(随编辑器主题与 DPI 变化)。这些数字在常量被调整后立刻失真,且失真时没有任何提示。现已删除,只保留「为什么是这个值、重新取值时要看什么」。

🎨 界面上的三处细微变化

都是消除「本该一致却不一致」的取值。

# 位置 变化
顶点色 RG / GB / BA 按钮的未选中底色 变暗一档,与其余四组分段按钮统一
数据状态卡右上角「未写入」徽标的灰 与同语义的其他状态点统一
「生成」按钮 hover 时的底色亮度 与「保存」/「另存为」两颗统一

② 和 ③ 的差值分别是 0.02 的分量差与 2% 的亮度差,基本看不出来;① 是三处里最明显的,但也只有一档。

✨ 主要功能

  • 平滑法线生成 —— 角度加权平均、可调合并容差,跨硬边得到连续外扩方向。
  • 三种存储方式 —— 顶点色(八面体,8-bit×2,误差约 1°)/ 切线通道(tangent.xyz)/ TEXCOORD(八面体,float×2,误差约 5e-6°,共 8 个通道)。
  • 两种存储空间 —— 对象空间 / 切线空间,与存储方式正交;切线空间让蒙皮模型的描边正确跟随骨骼动画。
  • 描边 Pass 模板 —— 两步接进自己的 Shader,URP / Built-in 各一份,描边逻辑随包升级。
  • 导入时自动烘焙 —— 命中规则(文件名后缀 / 文件夹路径,可叠加取交集)的模型(重)导入即烘焙,非破坏性、零手动操作。
  • 广泛的目标来源 —— 场景对象、Mesh 资产、模型、预制体,自动遍历层级、复选框多选批量处理。
  • 实时描边预览 —— 内嵌视口同屏显示所有勾选网格,法线可视化对比、通道状态检查。
  • Scene 视图法线叠加 —— 场景中的真实对象上叠加法线,蒙皮按当前姿势求值,可在动画播放时验证。
  • 网格健康检查 —— 生成 / 烘焙前扫描非法数据,手动二次确认、自动烘焙跳过。
  • 数据安全 —— 阻止对只读资产的假保存、批量另存为独立 Mesh、会话快照还原。
  • 三语界面 —— 简体中文 / English / 日本語,默认中文,偏好按机器保存。
  • 描边 Shader(Sample) —— URP / Built-in 两版,两 Pass,自定义材质面板。

⚠️ 已知限制

  • HDRP 未提供描边 Shader,可参照文档自行移植。
  • 存储方式与存储空间无法从数据反推 —— 存的都只是一条单位方向。工具与材质选得不一致时不会报错,只是描边偏斜或撕开。
  • 两分量 UV 与贴图 UV 在数值上无法区分 —— 通道状态最高只能报「有数据」;反过来「分量数为 3」是识别旧版数据的强提示而非判定
  • 切线空间要求网格有合法切线(导入设置 TangentsNone)。
  • 重新导入模型可能让已烘数据失配 —— 因此切线空间推荐配合「导入时自动烘焙」使用。
  • Pass 模板声明了全部 8 个 TEXCOORD,对顶点带宽敏感的项目请按文档「极简写法」手写 vert。
  • Scene 视图叠加每次重绘都会重算,仅建议排查时打开。
  • 菜单路径无法本地化 —— Unity 的 MenuItem 要求常量字符串,三种语言下都是 Tools > Smooth Normal Generator
  • 不支持 Undo —— 工具提供自己的会话快照还原。
  • 顶点合并采用格点取整,恰好跨越格边界的两点仍会被分开

📖 文档

总览 / 快速上手:
简体中文 ·
English ·
日本語

详细使用文档(含界面详解、Shader 接入说明):
简体中文 ·
English ·
日本語

完整 CHANGELOG

1.8.0

Choose a tag to compare

@AleFeng AleFeng released this 21 Jul 04:22

为网格自动计算平滑法线并烘焙到顶点色 / 切线 / TEXCOORD,用于背面外扩描边,解决硬边处描边断裂。工具本体是纯编辑器 C#,与渲染管线无关。

📦 安装

Window > Package Manager → 左上角 +Install package from git URL... → 粘贴:

https://github.com/AleFeng/OutlineSmoothNormalsGenerator.git?path=/Packages/com.alefeng.outlinesmoothnormalsgenerator#1.8.0

⚠️ 装完还必须导入一个 Sample,否则没有描边 Shader。
核心包刻意不含 Shader —— 这是「不引入任何渲染管线依赖」的代价。
Package Manager 里选中本包 → Samples按你的管线导入其中一个

Sample Shader 名
Outline Shader (URP) & Demo OutlineSmoothNormalsGenerator/Outline URP
Outline Shader (Built-in RP) & Demo OutlineSmoothNormalsGenerator/Outline Built-in

安装成功后菜单栏出现 Tools → Smooth Normal Generator

🆕 1.8.0 更新内容

编辑器界面三语化

270 条界面文案 × 3 种语言,覆盖工具窗口的两个页签、网格健康检查条目、描边材质的 Inspector,以及全部 Console 日志。默认中文。

两个页签的标题区下方各有一个 中文 / English / 日本語 切换按钮,点击即时生效 —— 左右两栏、提示框、对话框、材质面板一并跟着变,不需要重开窗口。

几条设计取舍

语言偏好存 EditorPrefs,不存 ProjectSettings/
后者随工程进版本管理。把个人的语言偏好提交上去,只会让协作者之间反复互相覆盖。存 EditorPrefs 意味着它是按机器保存的:切语言不会给同事制造 diff,换一个 Unity 工程打开本包,你的选择仍然保持。

英文术语在三种语言下始终原样保留。
TEXCOORD1 (mesh.uv2)SkinnedMeshRenderertangent.xyzRead/Write 这类标识不翻译;中文与日文的存储方式按钮保留并列的英文名(顶点色 / Vertex Color頂点カラー / Vertex Color)。描边 Shader 那两个下拉的选项Vertex Color / TexCoord0 …)也保持英文 —— 它们与 Shader 属性的浮点取值一一对应,翻译等于切断与文档的对应关系。

界面术语与三份 README 逐条对齐。
存储方式 / Storage Mode / 保存方式,切线空间 / Tangent Space / 接線空間,命中规则 / Match Rules / 判定ルール…… 文档里读到的名字,界面上都能找到同一个词。这是本次最费工夫、也最容易被忽略的部分 —— 文档与界面各说各话,多语言就等于没做。

菜单路径无法本地化。
Unity 的 MenuItem 要求常量字符串,Tools > Smooth Normal Generator 在三种语言下都是英文。

界面布局

英文 / 日文的参数名比中文长约一半(「显示平滑法线」6 字 对 Show smooth normals 19 字符),几处按中文尺寸定死的地方需要放开:

  • 预览参数栏由 220px 加宽到 256px,并把标签宽度显式钉死。此前用的是 Unity 默认值,而那个值是按整个窗口宽度算的(currentViewWidth * 0.45),与这一栏实际多宽毫无关系 —— 窗口拉得越宽,标签算得越宽,到某个点就会比整栏还宽、整条被裁。中文标签短,一直没暴露。
  • 生成按钮改为可换行,状态徽标与「全选 / 清空 / 清除」等按钮改用 MinWidth
  • 预览视口的操作提示与左上角模式徽标改为按实际文字宽度测量:放不下就不画(半句被裁的提示比没有更糟),底板也不再是写死的 220px(此前会越过视口右缘、糊到右侧参数栏的标题上)。
  • 左右分栏的全部尺寸常量集中到一处,右栏保留量改为跟随参数栏宽度派生,不再写死。

改进

  • Console 日志前缀统一为 [OutlineSmoothNormals] 此前散着三套写法([SmoothNormal] 10 处、[OutlineSmoothNormals] 6 处、[平滑法线] 1 处),按任何一个在 Console 里过滤都会漏掉一大半;最后那个还是中文前缀,界面切到英文 / 日文后会出现「中文前缀 + 英文正文」。现收敛到单一常量。前缀本身不随语言变 —— 它是过滤用的固定标识,跟着语言变的话,同一个工程里换过语言的日志就再也过滤不到一起了。
  • 「导入自动烘焙」页签的存储通道 / 存储空间两个下拉此前完全绕过本地化,三语下恒显示英文枚举名,而生成器页签里同一个枚举是本地化的 —— 同一份配置两个页签一中一英。更糟的是它会显示成 Tangent Space,那正是本项目刻意废弃的旧称,且恰好紧挨着下面那个真正的「存储空间」字段。

修复

三语化过程中逐条比对界面文案与实际代码,挖出几处说法与实现不符的既存问题:

  • 顶点色面板把存储方式描述成了已废弃的旧方案。「选定通道对的 XY 分量将被写入,Z 分量通过重建得到」描述的是文档中明确点名废弃的「存 XY + 重建 Z + 按法线定符号」—— 那个方案恰恰会在它本该修复的硬边角上把描边裂开。实际写入的是八面体编码的两个参数,与法线的原始 XY 没有对应关系。
  • 顶点色通道角色的「分量 ↔ 模式」对应是反的。 G 通道 标注为「八面体 X/Y(RG/GB 模式)」,按位置读是 X↔RG、Y↔GB,而实际写入是 RG → g=oct.yGB → g=oct.x,恰好相反;B 通道 同理。现改为「RG 模式:八面体 Y / GB 模式:八面体 X」这样的显式写法,读法唯一。
  • 网格健康检查对切线退化后果的断言不准确。「零向量 / 与法线共线 / 手性异常」三种成因被统一断言为「描边退化为沿原始顶点法线外扩」,但解码侧只检查 Gram-Schmidt 残量、不检查 tangent.w:手性异常时基照样构造成功,只是副切线塌成零向量,结果是错误方向而非顶点法线。现已拆开分述。
  • 「网格信息」里各 TEXCOORD 行显示的是元素个数,不是分量数。 此前记的是 GetUVs 取回的条目数 —— 通道非空时它恒等于顶点数,于是八个通道显示同一个数字,信息量为零;而文档描述的一直是分量数。分量数(2 / 3 / 4)才是判断通道被谁占用、以及识别 1.6.x 旧格式(3 分量)的依据。顺带省掉 8 次「把整份 UV 数组拷到托管侧、只为数一下长度」的调用。
  • Scene 视图叠加的抽稀是静默的。 1.7.0 起顶点数过多时会自动抽稀,三份文档都写明「面板上会如实写出『已按 1/N 采样显示』」,但那句提示从未被实现 —— 步长算了、点也跳了,就是没告诉用户。看到线段稀疏时无从判断是数据有问题还是被抽稀了,正是这句提示要防的误判。
  • TEXCOORD 存储方式的提示末行仍写着「多占一个 UV 通道的顶点带宽(3 个 float / 顶点)」,是 1.6.x 三分量时代的残留,与同一条提示第二行的「两个 float32,每顶点 8 字节」自相矛盾。
  • 「导入自动烘焙」页签的副标题仍写「命中后缀的模型」,而 1.7.0 起命中条件已是后缀与文件夹两项。

✨ 主要功能

  • 平滑法线生成 —— 角度加权平均、可调合并容差,跨硬边得到连续外扩方向。
  • 三种存储方式 —— 顶点色(八面体,8-bit×2,误差约 1°)/ 切线通道(tangent.xyz)/ TEXCOORD(八面体,float×2,误差约 5e-6°,共 8 个通道)。
  • 两种存储空间 —— 对象空间 / 切线空间,与存储方式正交;切线空间让蒙皮模型的描边正确跟随骨骼动画。
  • 描边 Pass 模板 —— 两步接进自己的 Shader,URP / Built-in 各一份,描边逻辑随包升级。
  • 导入时自动烘焙 —— 命中规则(文件名后缀 / 文件夹路径,可叠加取交集)的模型(重)导入即烘焙,非破坏性、零手动操作。
  • 广泛的目标来源 —— 场景对象、Mesh 资产、模型、预制体,自动遍历层级、复选框多选批量处理。
  • 实时描边预览 —— 内嵌视口同屏显示所有勾选网格,法线可视化对比、通道状态检查。
  • Scene 视图法线叠加 —— 场景中的真实对象上叠加法线,蒙皮按当前姿势求值,可在动画播放时验证。
  • 网格健康检查 —— 生成 / 烘焙前扫描非法数据,手动二次确认、自动烘焙跳过。
  • 数据安全 —— 阻止对只读资产的假保存、批量另存为独立 Mesh、会话快照还原。
  • 三语界面 —— 简体中文 / English / 日本語,默认中文,偏好按机器保存。
  • 描边 Shader(Sample) —— URP / Built-in 两版,两 Pass,自定义材质面板。

⚠️ 已知限制

  • HDRP 未提供描边 Shader,可参照文档自行移植。
  • 存储方式与存储空间无法从数据反推 —— 存的都只是一条单位方向。工具与材质选得不一致时不会报错,只是描边偏斜或撕开。
  • 两分量 UV 与贴图 UV 在数值上无法区分 —— 通道状态最高只能报「有数据」;反过来「分量数为 3」是识别旧版数据的强提示而非判定
  • 切线空间要求网格有合法切线(导入设置 TangentsNone)。
  • 重新导入模型可能让已烘数据失配 —— 因此切线空间推荐配合「导入时自动烘焙」使用。
  • Pass 模板声明了全部 8 个 TEXCOORD,对顶点带宽敏感的项目请按文档「极简写法」手写 vert。
  • Scene 视图叠加每次重绘都会重算,仅建议排查时打开。
  • 菜单路径无法本地化 —— Unity 的 MenuItem 要求常量字符串,三种语言下都是 Tools > Smooth Normal Generator
  • 不支持 Undo —— 工具提供自己的会话快照还原。
  • 顶点合并采用格点取整,恰好跨越格边界的两点仍会被分开

📖 文档

总览 / 快速上手:
简体中文 ·
English ·
日本語

详细使用文档(含界面详解、Shader 接入说明):
简体中文 ·
English ·
日本語

完整 CHANGELOG

1.7.0

Choose a tag to compare

@AleFeng AleFeng released this 20 Jul 13:25

为网格自动计算平滑法线并烘焙到顶点色 / 切线 / TEXCOORD,用于背面外扩描边,解决硬边处描边断裂。工具本体是纯编辑器 C#,与渲染管线无关。

⚠️ 升级必读

本版改了 TEXCOORD(UV)存储的数据格式只有把平滑法线存在 UV 通道的项目需要动手

你用的存储方式 要做什么
顶点色 / 切线通道 什么都不用做 —— 这两种格式一个字节没变
TEXCOORD(UV) 重新烘焙一次

旧的 UV 数据在 1.7.0无法被解码,症状是描边方向整体错乱、不报任何错

之所以不留兼容开关:顶点装配会把缺失分量补 0,两分量数据与「z 恰好为 0」的三分量数据在着色器里逐位相同,任何运行时判据都存在真实反例。留一个「格式」开关只会把「选错了不报错」的坑再挖深一层,所以直接换掉。

📦 安装

Window > Package Manager → 左上角 +Install package from git URL... → 粘贴:

https://github.com/AleFeng/OutlineSmoothNormalsGenerator.git?path=/Packages/com.alefeng.outlinesmoothnormalsgenerator#1.7.0

⚠️ 装完还必须导入一个 Sample,否则没有描边 Shader。
核心包刻意不含 Shader —— 这是「不引入任何渲染管线依赖」的代价。
Package Manager 里选中本包 → Samples按你的管线导入其中一个

Sample Shader 名
Outline Shader (URP) & Demo OutlineSmoothNormalsGenerator/Outline URP
Outline Shader (Built-in RP) & Demo OutlineSmoothNormalsGenerator/Outline Built-in

安装成功后菜单栏出现 Tools → Smooth Normal Generator

🆕 1.7.0 更新内容

UV 存储改为两分量八面体

TEXCOORD 通道由「三分量原始方向」改为「两分量八面体编码」,每顶点省 4 字节,并与顶点色路径统一到同一套编码。

精度上没有实质代价:两个 float32 的八面体往返角度误差约 5e-6°,直接存 xyz5e-7° —— 同属浮点舍入噪声那一档。作为参照,顶点色的 8-bit 八面体是 0.34°,高 7 万倍却一直够用。

顺带更正一处此前从未写明的事实:Unity 的 Project Settings → Player → Vertex Compression 默认会在构建时把切线与除 lightmap UV 外的 TEXCOORD 压到 fp16,因此打包产物里切线通道与 UV 通道的实际误差约 6e-3°。仍远优于顶点色,不影响选型,但「切线 / UV 是无损 float32」这个说法本就不成立。文档已更正。

Scene 视图法线叠加

「法线可视化」面板新增 「在 Scene 视图中显示」 开关,把平滑法线与原始法线画到场景中的真实对象上,作用于所有勾选的场景网格。

关键在于 SkinnedMeshRenderer 取的是当前姿势BakeMesh),因此可以在动画播放时验证切线空间存储 —— 法线应始终贴着表面走;关节处若像扇子一样散开,就是数据烘的空间与材质选的对不上。

这件事此前一直验证不了:内嵌预览渲的是绑定姿势的静态网格,而「蒙皮动画下描边不撕开」恰恰是 1.5.0 引入切线空间的核心卖点

  • 顶点数过多时统一抽稀(所有网格用同一个步长,否则看到的疏密差是假象),并在面板上如实写出「已按 1/N 采样显示」。
  • 做成工具窗口的开关而非 MonoBehaviour 组件,以保持本包零运行时占用;关闭窗口即自动停止绘制。
  • 直接选中的 Mesh 资产没有场景位置,会被跳过并提示。

导入自动烘焙:命中规则可叠加

命中规则改为两个可独立勾选的条件,同时勾选时取交集(都满足才烘焙):

条件 说明
按文件名后缀 文件名以指定后缀结尾,大小写不敏感。默认开启,后缀默认 _Outline
按文件夹路径 资产位于指定文件夹及其子目录之下。把文件夹拖进对象槽即可。
  • 文件夹按路径前缀匹配到目录分隔符为止,因此 Assets/Characters2/Assets/Old/Characters_backup/ 这类同级目录不会被误命中。
  • 默认仍是「只开后缀、后缀 _Outline」,与 1.6.0 行为完全一致。
  • 任一条件留空、或两个都不勾,均不命中任何模型 —— 空配置绝不会被解读成「命中一切」。
  • 把模型改名加后缀、或拖进目标文件夹,都不会触发 Unity 重导入,工具会侦测这类移动并补一次重导入(此前只对改名生效,现在两种都管)。

改进

  • 平滑法线计算消除每顶点堆分配 —— 此前每个唯一顶点位置都要 new 一个 List<Vector3>,十万顶点级别的网格上这是主要的 GC 压力来源。改为遍历三角形时就地累加,另加量化键预计算、空间哈希混合与字典容量预留。结果逐位不变:累加顺序与原先「按插入顺序求和」完全一致,不涉及浮点结合律重排。
  • 批量烘焙增加可取消的进度反馈 —— 此前批量处理大网格时 Unity 无任何反馈地卡住。取消时保留已处理的网格(快照已抓,可用「还原」回退),日志写明「已处理 N / M 个」。
  • 生成 / 导入日志现在写明数据格式(如 TEXCOORD1(八面体 2×float))。存储方式 / 存储空间 / 数据格式三者但凡与材质对不上都不报错,事后排查时这行日志常常是唯一还留着的线索。
  • 材质面板的 TEXCOORD 档说明收敛到一处生成,并固定挂上迁移提示 —— 材质面板是描边出问题时最先被打开的地方,而旧数据在 GPU 侧无从检测,这里是唯一能提醒到人的位置。

修复

  • 「还原本次修改」会把网格上每个非空 UV 通道升成 4 分量 —— 包括 FBX 的主贴图 UV,顶点缓冲无声翻倍,且对 .asset 网格会直接落盘。原因是快照统一用 List<Vector4> 读写,而 SetUVs 严格按传入列表的类型设定通道分量数。现在按通道记录原始维度、还原时分派到对应的 Vector2/3/4 重载。

    这个缺陷自「会话快照」功能引入起一直存在,且会让本版新增的「分量数为 3 = 旧格式」提示失效。

  • 材质面板上 TEXCOORD03 四档的说明此前写作「读取…的 xy」、TEXCOORD47 写作「xyz」,而当时实际全部存 xyz —— 前四条一直是错的。现已统一。

版本策略已写进 CHANGELOG

本包对语义化版本有一处明确的例外,现已写在 CHANGELOG 顶部:

烘焙数据格式的破坏性变更走 MINOR,而不是 MAJOR。
作为补偿,这类变更一律在该版本条目开头以 ⚠ 破坏性变更 小节单独列出。

理由是本包的产物是烘进网格的一串数字:格式一改,存量数据就必须重烘,没有中间状态。严格按 SemVer 处理的话,每次编码格式改进都得升一个大版本号,版本号会迅速膨胀到与功能规模完全不成比例。

请把注意力放在「版本条目开头有没有 ⚠ 破坏性变更」,而不是版本号的位数上。 API / Shader 函数签名的兼容性仍然照常遵守 SemVer。

✨ 主要功能

  • 平滑法线生成 —— 角度加权平均、可调合并容差,跨硬边得到连续外扩方向。
  • 三种存储方式 —— 顶点色(八面体,8-bit×2,误差约 1°)/ 切线通道(tangent.xyz)/ TEXCOORD(八面体,float×2,误差约 5e-6°,共 8 个通道)。
  • 两种存储空间 —— 对象空间 / 切线空间,与存储方式正交;切线空间让蒙皮模型的描边正确跟随骨骼动画。
  • 描边 Pass 模板 —— 两步接进自己的 Shader,URP / Built-in 各一份,描边逻辑随包升级。
  • 导入时自动烘焙 —— 命中规则(文件名后缀 / 文件夹路径,可叠加取交集)的模型(重)导入即烘焙,非破坏性、零手动操作;配置持久化到 ProjectSettings/,另有自定义规则 / 自定义存储两个扩展委托。
  • 广泛的目标来源 —— 场景对象、Mesh 资产、模型(.fbx 等)、预制体,自动遍历层级、复选框多选批量处理
  • 实时描边预览 —— 内嵌视口同屏显示所有勾选网格,法线可视化对比、通道状态检查、屏幕 / 世界空间描边对照。
  • Scene 视图法线叠加 —— 场景中的真实对象上叠加法线,蒙皮按当前姿势求值,可在动画播放时验证。
  • 网格健康检查 —— 生成 / 烘焙前扫描非法数据(缺法线、退化三角、NaN、退化切线、重合顶点过多等),手动二次确认、自动烘焙跳过。
  • 数据安全 —— 阻止对只读资产的假保存、批量另存为独立 Mesh、会话快照还原。
  • 描边 Shader(Sample) —— URP / Built-in 两版,两 Pass(描边 + 基础 NPR),描边来源支持 8 个 UV 通道,基础色调试档位,自定义材质面板。

⚠️ 已知限制

  • HDRP 未提供描边 Shader,可参照文档自行移植(解码逻辑通用,仅渲染 Pass 需适配)。
  • 存储方式与存储空间无法从数据反推 —— 存的都只是一条单位方向。工具与材质选得不一致时不会报错,只是描边偏斜或撕开。排查描边异常请先核对这两项,以及生成日志里记的数据格式。
  • 两分量 UV 与贴图 UV 在数值上无法区分 —— 因此新格式的通道状态最高只能报「有数据」。反过来「分量数为 3」成了识别旧版数据的提示,但同样只是强提示:网格合并会把 UV 维度统一取最大,其他把三分量方向写进 UV 的工具也会命中。
  • 切线空间要求网格有合法切线(导入设置 TangentsNone)。UV 退化处的切线构不成正交基,这些顶点的描边会退化为沿原始顶点法线外扩,健康检查会按比例报出。
  • 重新导入模型可能让已烘数据失配 —— 烘焙用的是当时的切线,若之后改用不同的切线生成方式重新导入,需重新烘焙。因此切线空间推荐配合「导入时自动烘焙」使用
  • Pass 模板声明了全部 8 个 TEXCOORD,因为存储来源是材质上运行时切换的。对顶点带宽敏感、且确定只用一个通道的项目,请按文档「极简写法」手写 vert。
  • Scene 视图叠加每次重绘都会重算,仅建议排查时打开。
  • 不支持 Undo —— Undo.RecordObject 不可靠地跟踪网格顶点数据;工具提供自己的会话快照还原。
  • 顶点合并采用格点取整,恰好跨越格边界的两点仍会被分开;容差需远小于模型最小特征尺寸。
  • 世界空间宽度模式下 _OutlineWidth世界单位,对很大 / 很小的模型需相应调整。

📖 文档

总览 / 快速上手:
简体中文 ·
English ·
日本語

详细使用文档(含迁移指引、界面详解、Shader 接入说明):
简体中文 ·
English ·
日本語

完整 CHANGELOG

1.6.0

Choose a tag to compare

@AleFeng AleFeng released this 20 Jul 09:22

为网格自动计算平滑法线并烘焙到顶点色 / 切线 / TEXCOORD,用于背面外扩描边,解决硬边处描边断裂。工具本体是纯编辑器 C#,与渲染管线无关。

⚠️ 升级必读

本版移动了一个包内文件,已导入过 Sample 的项目升级后会编译失败(材质变洋红 + Console 报错)。原因:Shader/OutlineNPR.hlsl 移到了 Shader/Demo/OutlineNPR.hlsl,而升级 UPM 包不会更新你 Assets/Samples/ 下那份旧 Shader,它仍 include 旧路径。

第 1 步:重新导入 Sample(所有升级者必做)

  1. 删除 Assets/Samples/Outline Smooth Normals Generator/<旧版本号>/ 整个目录
    (Sample 按版本号分目录,旧目录不删的话新旧两份 Shader 的 .meta GUID 相同、会撞车)
  2. Package Manager → 选中本包 → Samples → 重新导入你用的那一个

GUID 保持不变,材质会自动接回新 Shader。

第 2 步:只有从 1.4.x 或更早升级才需要

你现在的版本 还需要做什么
1.5.x 没有了。本版不改任何数据格式,重新导入 Sample 即可。
1.4.x 及更早 还要补做 1.5.0 的存储空间迁移:旧数据都是对象空间烘的,而材质默认已是 Tangent Space —— 要么重新烘焙一次(推荐,顺带获得蒙皮支持),要么把材质的 Smooth Normal Space 改回 Object Space。详见 1.5.0 Release notes

OUTLINE Pass 复制进自有 Shader 的用户不受影响 —— 本版没有移除或改名任何共享库函数,你现有的代码照常工作。不过现在有更省事的接入方式了,见下。

📦 安装

Window > Package Manager → 左上角 +Install package from git URL... → 粘贴:

https://github.com/AleFeng/OutlineSmoothNormalsGenerator.git?path=/Packages/com.alefeng.outlinesmoothnormalsgenerator#1.6.0

⚠️ 装完还必须导入一个 Sample,否则没有描边 Shader。
核心包刻意不含 Shader —— 这是「不引入任何渲染管线依赖」的代价。
Package Manager 里选中本包 → Samples按你的管线导入其中一个

Sample Shader 名
Outline Shader (URP) & Demo OutlineSmoothNormalsGenerator/Outline URP
Outline Shader (Built-in RP) & Demo OutlineSmoothNormalsGenerator/Outline Built-in

安装成功后菜单栏出现 Tools → Smooth Normal Generator

🆕 1.6.0 更新内容

描边 Pass 模板:接入自己的 Shader 从「整段照抄」变成「两步」

这是本版的主题。以前文档教你「把 OUTLINE Pass 整段复制进自己的 Shader」—— 那是七八十行的 Attributes / Varyings / vert / frag,能用,但复制出去的代码不随包升级1.5.0 新增存储空间时就吃过这个亏:所有手抄过 Pass 的项目都得手动补三处,漏了不报错、只是描边整体偏斜。

现在包内提供现成的 Pass 模板:

第 1 步,把 6 个描边属性加进 Properties(ShaderLab 不支持宏,这段只能复制):

[Header(Outline)]
_OutlineColor   ("Outline Color", Color) = (0,0,0,1)
[PowerSlider(3.0)]
_OutlineWidth   ("Outline Width", Range(0, 0.1)) = 0.015
[Enum(Screen Space, 0, World Space, 1)]
_OutlineWidthMode ("Outline Width Mode", Float) = 0
_SmoothNormalSrc ("Smooth Normal Source", Float) = 0
[Enum(RG, 0, GB, 1, BA, 2)]
_VCChannel      ("Vertex Color Channel", Float) = 2
[Enum(Object Space, 0, Tangent Space, 1)]
_SmoothNormalSpace ("Smooth Normal Space", Float) = 1

第 2 步,加一个 Pass(URP 版;Built-in 版见文档):

Pass
{
    Name "OUTLINE"
    Tags { "LightMode" = "SRPDefaultUnlit" }

    Cull Front
    ZWrite On
    ZTest LEqual

    HLSLPROGRAM
    #pragma vertex   OSN_OutlineVert
    #pragma fragment OSN_OutlineFrag

    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
    #include "Packages/com.alefeng.outlinesmoothnormalsgenerator/Shader/OutlineSmoothNormals.hlsl"

    CBUFFER_START(UnityPerMaterial)
        float4 _BaseColor;      // ← 你自己的属性
        float4 _BaseMap_ST;
        OSN_OUTLINE_MATERIAL_FIELDS
    CBUFFER_END

    #include "Packages/com.alefeng.outlinesmoothnormalsgenerator/Shader/OutlinePassURP.hlsl"
    ENDHLSL
}

完了。不必抄任何解码代码,后续库升级时你的 Shader 跟着一起更新。

Demo 的两个描边 Shader 已经改用同一套模板 —— 模板出问题,Demo 会第一时间暴露。

其他新增

  • OSN_OUTLINE_MATERIAL_FIELDS —— 展开为描边所需的 6 个 uniform 声明,供拼进你自己的 UnityPerMaterial。之所以不由本库另开一个 CBUFFER:SRP Batcher 要求同一 Shader 各 Pass 的 UnityPerMaterial 布局完全一致,另开一个就是两份布局,batcher 会静默失效 —— 不报错、只掉性能,最难查。
  • OSN_GetSmoothNormalOS(...) —— 「解码 + 存储空间还原」的合并调用,写给需要完全掌控顶点着色器的人。这两步必须成对出现,而漏掉后者不产生任何报错、只是描边整体偏斜。合成一个函数后,这个坑在结构上不再存在。

变更

  • Shader/ 目录按用途分层:根目录现在只放生产用户可直接 include 的公开接口,Demo 专用的 NPR 数学(卡通明暗 / 边缘光 / 调试色)移入 Shader/Demo/。此前两者同级,容易让人以为它也是接入描边的必需品。

    Shader/
    ├── OutlineSmoothNormals.hlsl    ← 解码 + 空间还原 + 外扩的唯一真源
    ├── OutlinePassCommon.hlsl       ← Pass 模板主体(不直接 include)
    ├── OutlinePassURP.hlsl          ← Pass 模板 · URP 适配层
    ├── OutlinePassBuiltIn.hlsl      ← Pass 模板 · Built-in 适配层
    └── Demo/
        └── OutlineNPR.hlsl          ← Demo 专用,生产用不到
    
  • 两个 Demo 描边 Shader 的 OUTLINE Pass 改用共享模板 —— 该 Pass 由 URP 85 行 → 34 行、Built-in 74 行 → 21 行,手写的 Attributes / Varyings / vert / frag 全部移入模板。

  • URP Demo Shader 的 FORWARD Pass 也改用同一个宏:OUTLINE Pass 用宏后字段顺序改变,两个 Pass 的 UnityPerMaterial 若不再逐字一致,SRP Batcher 就会静默失效。两处共用一个宏,从结构上杜绝漂移。

文档

  • 重写「在游戏中使用描边」与「Shader 中读取平滑法线」两节。前者是上面那套两步接入的完整版(URP / Built-in 各一份可整段复制的 Pass{})外加四个必须注意的点:include 顺序、SRP Batcher 的 CBUFFER 一致性、描边 Pass 要排在基础 Pass 之前、LightMode 两管线各自的取值。
  • 后者重构为三档:通用写法(材质上可运行时切换存储方式)、极简写法(存储方式写死在 Shader 里,零分支、UV 一个都不用声明)、以及明确劝退的完全不 include
  • 三语(中 / 英 / 日)包内与根 README 同步更新。

✨ 主要功能

  • 平滑法线生成 —— 角度加权平均、可调合并容差,跨硬边得到连续外扩方向。
  • 三种存储方式 —— 顶点色(八面体编码,8-bit 下误差约 1°)/ 切线通道 / TEXCOORD(TEXCOORD0TEXCOORD7,共 8 个通道)。
  • 两种存储空间 —— 对象空间 / 切线空间,与存储方式正交;切线空间让蒙皮模型的描边正确跟随骨骼动画。
  • 描边 Pass 模板 —— 两步接进自己的 Shader,URP / Built-in 各一份,描边逻辑随包升级。
  • 导入时自动烘焙 —— 命中文件名后缀的模型(重)导入即烘焙,非破坏性、零手动操作;配置持久化到 ProjectSettings/,另有自定义规则 / 自定义存储两个扩展委托。
  • 广泛的目标来源 —— 场景对象、Mesh 资产、模型(.fbx 等)、预制体,自动遍历层级、复选框多选批量处理
  • 实时描边预览 —— 内嵌视口,同屏显示所有勾选网格,法线可视化对比、通道状态检查、屏幕 / 世界空间描边对照。
  • 网格健康检查 —— 生成 / 烘焙前扫描非法数据(缺法线、退化三角、NaN、退化切线、重合顶点过多等),手动二次确认、自动烘焙跳过。
  • 数据安全 —— 阻止对只读资产的假保存、批量另存为独立 Mesh、会话快照还原。
  • 描边 Shader(Sample) —— URP / Built-in 两版,两 Pass(描边 + 基础 NPR),描边来源支持 8 个 UV 通道,基础色调试档位,自定义材质面板。

⚠️ 已知限制

  • HDRP 未提供描边 Shader,可参照文档自行移植(解码逻辑通用,仅渲染 Pass 需适配)。
  • 存储方式与存储空间无法从数据反推 —— 两种空间存的都只是一条单位方向。工具与材质选得不一致时不会报错,只是描边偏斜或撕开。排查描边异常请先核对这两项。
  • 切线空间要求网格有合法切线(导入设置 TangentsNone)。UV 退化处的切线构不成正交基,这些顶点的描边会退化为沿原始顶点法线外扩,健康检查会按比例报出。
  • 重新导入模型可能让已烘数据失配 —— 烘焙用的是当时的切线,若之后改用不同的切线生成方式重新导入,需重新烘焙。因此切线空间推荐配合「导入时自动烘焙」使用
  • Pass 模板声明了全部 8 个 TEXCOORD,因为存储来源是材质上运行时切换的。对顶点带宽敏感、且确定只用一个通道的项目,请按文档「极简写法」手写 vert。
  • 不支持 Undo —— Undo.RecordObject 不可靠地跟踪网格顶点数据;工具提供自己的会话快照还原。
  • 顶点合并采用格点取整,恰好跨越格边界的两点仍会被分开;容差需远小于模型最小特征尺寸。
  • 通道状态最高只说「可能是平滑法线」—— 编码后与普通顶点色 / UV 在数据上不可区分。
  • 世界空间宽度模式下 _OutlineWidth世界单位,对很大 / 很小的模型需相应调整。

📖 文档

总览 / 快速上手:
简体中文 ·
English ·
日本語

详细使用文档(含界面详解、存储空间原理、Shader 接入说明):
简体中文 ·
English ·
日本語

完整 CHANGELOG

1.5.0

Choose a tag to compare

@AleFeng AleFeng released this 20 Jul 06:13

为网格自动计算平滑法线并烘焙到顶点色 / 切线 / TEXCOORD,用于背面外扩描边,解决硬边处描边断裂。工具本体是纯编辑器 C#,与渲染管线无关。

⚠️ 从 1.4.x 升级必读

本版存在破坏性变更,且升级 UPM 包本身不足以完成升级 —— 请按下面的顺序做。

1.5.0 起平滑法线默认存切线空间,材质属性 Smooth Normal Space 的默认值同样是 Tangent Space;而 1.4.x 及更早烘焙的数据全是对象空间的。两边对不上时,描边整体偏斜,且不产生任何编译错误或运行时报错

两条修法二选一:

如果使用了Sample中的Shader,则需要先重新导入Sample场景以获得更新后的Shader。

做法 结果
重新烘焙一次(推荐) 顺带获得蒙皮支持,SkinnedMeshRenderer 的描边不再随动画撕开
把材质的 Smooth Normal Space 改回 Object Space 行为与 1.4.x 完全一致,不动任何网格数据

走「导入时自动烘焙」的模型无需干预 —— GetVersion() 已提升,Unity 会自动重新导入并重烘所有命中模型。

📦 安装

Window > Package Manager → 左上角 +Install package from git URL... → 粘贴:

https://github.com/AleFeng/OutlineSmoothNormalsGenerator.git?path=/Packages/com.alefeng.outlinesmoothnormalsgenerator#1.5.0

⚠️ 装完还必须导入一个 Sample,否则没有描边 Shader。
核心包刻意不含 Shader —— 这是「不引入任何渲染管线依赖」的代价。
Package Manager 里选中本包 → Samples按你的管线导入其中一个

Sample Shader 名
Outline Shader (URP) & Demo OutlineSmoothNormalsGenerator/Outline URP
Outline Shader (Built-in RP) & Demo OutlineSmoothNormalsGenerator/Outline Built-in

安装成功后菜单栏出现 Tools → Smooth Normal Generator

🆕 1.5.0 更新内容

存储空间:让顶点色 / TEXCOORD 存储也跟得上骨骼动画

这是本版的全部主题。新增一个与「存进哪个通道」正交的维度 —— 方向本身写在哪个空间里:

存储空间 存什么 适用
对象空间 绑定姿势下的对象空间方向,解码即用 仅静态模型
切线空间 相对每个顶点自身 TBN 的坐标,解码时用蒙皮后的法线与切线重建 静态与蒙皮模型都正确(默认

解决的问题SkinnedMeshRenderer 蒙皮时,Unity 会变换 POSITION / NORMAL / TANGENT,但 COLOR 与 TEXCOORD 原样传递、不参与蒙皮。于是存进这两处的对象空间方向会「顶点跟着骨骼走、外扩方向却停在绑定姿势」,关节一弯描边就撕开。

为什么切线空间能修好它:切线空间坐标是蒙皮不变量。设 S = a·T + b·B + c·N,蒙皮对该顶点近似施加一个旋转 R,而 NT 都被 Unity 一并变换,于是 a·T' + b·B' + c·N' = R·S —— 正是蒙皮后应有的方向,而 (a, b, c) 恒定不变。这与法线贴图能在骨骼动画上正常工作是同一个道理。

要点:

  • 不占用切线。切线在这里只作重建用的「基」,法线贴图照常可用。要求模型导入设置的 TangentsNone
  • 精度不变。编码的仍是单位方向,顶点色仍是八面体 8-bit、误差约 1°。
  • 切线通道存储不适用该选项(会覆盖掉重建基所必需的切线本身),且本就不需要 —— Unity 会把 tangent.xyz 当方向一起蒙皮。工具与材质面板在该模式下自动置灰。
  • 工具窗口、「导入自动烘焙」页签、材质面板三处都可切换,三者必须选成一致

其他新增

  • 共享库新增两个函数Shader/OutlineSmoothNormals.hlsl,仍是解码与外扩的唯一真源):OSN_TangentToObject(Gram-Schmidt 重新正交化 + tangent.w 手性 + 退化切线保护)与 OSN_ResolveSmoothNormalSpace(按存储空间归一,自动跳过切线通道与顶点法线对照两档)。C# 侧镜像新增 OutlineSmoothNormalsCodec.ObjectToTangent / TangentToObject
  • 健康检查新增切线合法性判据:切线空间存储下,缺法线 / 缺切线报 Error;零向量、与法线共线、手性为 0 的退化切线按比例报出(全退化 Error,部分 Warning)。
  • 工具窗口 Tooltip:「存储方式」三个按钮与「存储空间」两个按钮各配悬停说明,写明各自的精度、占用与冲突;原先常驻的 HelpBox 相应收起,面板更紧凑。

变更

  • 术语StorageMode.TangentSpace 的显示名由「切线空间」改为**「切线通道」(材质面板 Tangent SpaceTangent Channel)—— 它表示「存进切线通道**」,与新增的「存储空间」撞名会让人无从分辨。枚举成员名未改,不影响序列化。
  • 窗口默认尺寸提取为常量,便于调整。

修复

  • 自动烘焙配置会被静默改写OutlineNormalsSettings.NormalSpace 此前 getter 做归一而 setter 不做,导致 IMGUI 的 x = EnumPopup(…, x) 读回写不是恒等操作 —— 把存储方式切到「切线通道」的那一帧,会把用户选的切线空间擦成对象空间并写进 ProjectSettings/
  • 健康检查报告不随选择刷新:切换存储方式 / 存储空间后报告仍是上一次的结论,最坏是缓存着一份「无异常」而当前选择实为 Error,面板一条警告都不给。
  • 文档中的 Shader 示例参数不符OSN_ApplyOutlineOffset1.3.0 起为 4 个参数,而三份 README 的示例仍写 3 个,照抄编译不过。同时补上了 OSN_ResolveSmoothNormalSpace 这一步,并清理了「一律以对象空间存储」等已过期的表述。

✨ 主要功能

  • 平滑法线生成 —— 角度加权平均、可调合并容差,跨硬边得到连续外扩方向。
  • 三种存储方式 —— 顶点色(八面体编码,8-bit 下误差约 1°)/ 切线通道 / TEXCOORD(TEXCOORD0TEXCOORD7,共 8 个通道)。
  • 两种存储空间 —— 对象空间 / 切线空间,与存储方式正交;切线空间让蒙皮模型的描边正确跟随骨骼动画。
  • 导入时自动烘焙 —— 命中文件名后缀的模型(重)导入即烘焙,非破坏性、零手动操作;配置持久化到 ProjectSettings/,另有自定义规则 / 自定义存储两个扩展委托。
  • 广泛的目标来源 —— 场景对象、Mesh 资产、模型(.fbx 等)、预制体,自动遍历层级、复选框多选批量处理
  • 实时描边预览 —— 内嵌视口,同屏显示所有勾选网格,法线可视化对比、通道状态检查、屏幕 / 世界空间描边对照。
  • 网格健康检查 —— 生成 / 烘焙前扫描非法数据(缺法线、退化三角、NaN、退化切线、重合顶点过多等),手动二次确认、自动烘焙跳过。
  • 数据安全 —— 阻止对只读资产的假保存、批量另存为独立 Mesh、会话快照还原。
  • 描边 Shader(Sample) —— URP / Built-in 两版,两 Pass(描边 + 基础 NPR),描边来源支持 8 个 UV 通道,基础色调试档位,自定义材质面板。

⚠️ 已知限制

  • HDRP 未提供描边 Shader,可参照文档自行移植(解码逻辑通用,仅渲染 Pass 需适配)。
  • 存储方式与存储空间无法从数据反推 —— 两种空间存的都只是一条单位方向。工具与材质选得不一致时不会报错,只是描边偏斜或撕开。排查描边异常请先核对这两项。
  • 切线空间要求网格有合法切线(导入设置 TangentsNone)。UV 退化处的切线构不成正交基,这些顶点的描边会退化为沿原始顶点法线外扩,健康检查会按比例报出。
  • 重新导入模型可能让已烘数据失配 —— 烘焙用的是当时的切线,若之后改用不同的切线生成方式重新导入,需重新烘焙。因此切线空间推荐配合「导入时自动烘焙」使用,那样烘焙发生在导入管线内、切线生成之后,天然同源。
  • 不支持 Undo —— Undo.RecordObject 不可靠地跟踪网格顶点数据;工具提供自己的会话快照还原。
  • 顶点合并采用格点取整,恰好跨越格边界的两点仍会被分开;容差需远小于模型最小特征尺寸。
  • 通道状态最高只说「可能是平滑法线」—— 编码后与普通顶点色 / UV 在数据上不可区分。
  • 世界空间宽度模式下 _OutlineWidth世界单位,对很大 / 很小的模型需相应调整。

📖 文档

总览 / 快速上手:
简体中文 ·
English ·
日本語

详细使用文档(含界面详解、存储空间原理、Shader 采样代码):
简体中文 ·
English ·
日本語

完整 CHANGELOG

1.4.0

Choose a tag to compare

@AleFeng AleFeng released this 19 Jul 15:12

为网格自动计算平滑法线并烘焙到顶点色 / 切线 / TEXCOORD,用于背面外扩描边,解决硬边处描边断裂。工具本体是纯编辑器 C#,与渲染管线无关。

📦 安装

Window > Package Manager → 左上角 +Install package from git URL... → 粘贴:

https://github.com/AleFeng/OutlineSmoothNormalsGenerator.git?path=/Packages/com.alefeng.outlinesmoothnormalsgenerator#1.4.0

⚠️ 装完还必须导入一个 Sample,否则没有描边 Shader。
核心包刻意不含 Shader —— 这是「不引入任何渲染管线依赖」的代价。
Package Manager 里选中本包 → Samples按你的管线导入其中一个

Sample Shader 名
Outline Shader (URP) & Demo OutlineSmoothNormalsGenerator/Outline URP
Outline Shader (Built-in RP) & Demo OutlineSmoothNormalsGenerator/Outline Built-in

安装成功后菜单栏出现 Tools → Smooth Normal Generator

🆕 1.4.0 更新内容

  • 导入时自动烘焙:把模型文件名改成带约定后缀(默认 _Outline,如 Hero_Outline.fbx),它一旦(重)导入,平滑法线就被自动烘进网格 —— 无需打开工具、无需另存独立 Mesh。非破坏性:去掉后缀或关闭开关后重新导入即恢复原始网格。计算与写入复用手动流程同一套代码,编码与生产描边 Shader 完全一致。
  • 工具窗口新增「导入自动烘焙」页签:与「平滑法线生成器」并列,配置启用开关、命中后缀、存储方式(顶点色 / 切线 / TEXCOORD07)、合并容差。配置持久化到 ProjectSettings/OutlineSmoothNormals.asset,随工程纳入版本管理、团队共享一致设置。
  • 两个扩展委托(接私有管线,空则回退默认,一般用 [InitializeOnLoadMethod] 赋值一次):ShouldBakeRule 自定义命中规则(按目录 / 标签 / 导入设置决定),CustomStorageWriter 自定义存储写法(私有编码 / 通道布局)。
  • 网格健康检查:生成 / 烘焙前扫描并汇报缺法线、零向量 / NaN 法线、退化三角、单点重合顶点过多、未开启 Read/Write 等问题。手动流程以卡片显示在「生成」区域顶部(Error 时生成前二次确认);自动烘焙时写入 Console 日志、Error 网格自动跳过。
  • 使用文档大幅补充:包内《使用文档》新增「界面详解」(逐一说明窗口每个控件与预览参数面板),并提供英文 / 日文版本,三语文档顶部可一键切换。

本版为纯编辑器 C# 改动,不改任何 shader、不新增运行时依赖dependencies 仍为空)—— 已有材质 / Shader / 已烘焙数据均不受影响,从 1.3.x 升级无需任何迁移。

✨ 主要功能

  • 平滑法线生成 —— 角度加权平均、可调合并容差,跨硬边得到连续外扩方向。
  • 导入时自动烘焙 —— 命中文件名后缀的模型(重)导入即烘焙,非破坏性、零手动操作;「导入自动烘焙」页签配置,另有自定义规则 / 自定义存储两个扩展委托。
  • 三种存储方式 —— 顶点色(八面体编码,8-bit 下误差约 1°)/ 切线 / TEXCOORD(TEXCOORD0TEXCOORD7,共 8 个通道)。
  • 广泛的目标来源 —— 场景对象、Mesh 资产、模型(.fbx 等)、预制体,自动遍历层级、复选框多选批量处理
  • 实时描边预览 —— 内嵌视口,同屏显示所有勾选网格,法线可视化对比、通道状态检查、屏幕 / 世界空间描边对照。
  • 网格健康检查 —— 生成 / 烘焙前扫描非法数据(缺法线、退化三角、NaN、重合顶点过多等),手动二次确认、自动烘焙跳过。
  • 数据安全 —— 阻止对只读资产的假保存、批量另存为独立 Mesh、会话快照还原。
  • 描边 Shader(Sample) —— URP / Built-in 两版,两 Pass(描边 + 基础 NPR),描边来源支持 8 个 UV 通道,附基础色调试档位,自定义材质面板。

⚠️ 已知限制

  • HDRP 未提供描边 Shader,可参照文档自行移植(解码逻辑通用,仅渲染 Pass 需适配)。
  • 不支持 Undo —— Undo.RecordObject 不可靠地跟踪网格顶点数据;工具提供自己的会话快照还原。
  • 顶点合并采用格点取整,恰好跨越格边界的两点仍会被分开;容差需远小于模型最小特征尺寸。
  • 通道状态最高只说「可能是平滑法线」—— 编码后与普通顶点色 / UV 在数据上不可区分。
  • 世界空间宽度模式下 _OutlineWidth世界单位,对很大 / 很小的模型需相应调整。
  • 自动烘焙改配置后,已导入的模型不会自动重烘 —— 对其重新导入(右键 Reimport)一次即可。

📖 文档

总览 / 快速上手:
简体中文 ·
English ·
日本語

详细使用文档(含界面详解):
简体中文 ·
English ·
日本語

完整 CHANGELOG

1.3.0

Choose a tag to compare

@AleFeng AleFeng released this 18 Jul 15:04

为网格自动计算平滑法线并烘焙到顶点色 / 切线 / TEXCOORD,用于背面外扩描边,解决硬边处描边断裂。工具本体是纯编辑器 C#,与渲染管线无关。

📦 安装

Window > Package Manager → 左上角 +Install package from git URL... → 粘贴:

https://github.com/AleFeng/OutlineSmoothNormalsGenerator.git?path=/Packages/com.alefeng.outlinesmoothnormalsgenerator#1.3.0

⚠️ 装完还必须导入一个 Sample,否则没有描边 Shader。
核心包刻意不含 Shader —— 这是「不引入任何渲染管线依赖」的代价。
Package Manager 里选中本包 → Samples按你的管线导入其中一个

Sample Shader 名
Outline Shader (URP) & Demo OutlineSmoothNormalsGenerator/Outline URP
Outline Shader (Built-in RP) & Demo OutlineSmoothNormalsGenerator/Outline Built-in

安装成功后菜单栏出现 Tools → Smooth Normal Generator

🆕 1.3.0 更新内容

  • 多网格批量编辑:目标网格由「下拉逐个选」改为复选框滚动列表(顶部「全选 / 清空」,加载新来源时默认全选)。「生成」「保存」「另存为」作用于所有勾选的网格;单击网格名把它设为焦点,右侧网格信息 / 通道状态显示焦点网格。
  • 描边预览同屏显示所有勾选的网格:按各自在层级中的相对位置摆放,相机自动兜住全部。
  • UV 通道由 4 个扩展到 8 个TEXCOORD0TEXCOORD7):工具的写入 / 检测 / 清除 / 预览,以及两个 Demo 描边 Shader 的描边来源与基础色显示,均支持 TEXCOORD4TEXCOORD7
  • 基础色调试模式(材质面板 Base Color Mode):把平滑法线数据直接当颜色显示、不经光照,便于肉眼核对生成结果 —— 含顶点色(RGB / RG / GB / BA)、切线(映射到 [0,1])、UV0–UV7。
  • 「另存为独立 Mesh」批量化:勾选 1 个弹命名对话框;勾选多个选一个目标文件夹,按各自网格名批量生成(自动去重命名),场景对象自动回填组件。

⚠️ 若你把 Sample 的 OUTLINE Pass 复制进了自有 Shader:本版描边来源改为运行时按 _SmoothNormalSrc(float)选择、并读取 uv0uv7,不再依赖 _SMOOTHNORMALSRC_* 关键字(存储通道超过 [KeywordEnum] 上限)。需要 8 通道支持时请重新复制本版 Pass。

✨ 主要功能

  • 平滑法线生成 —— 角度加权平均、可调合并容差,跨硬边得到连续外扩方向。
  • 三种存储方式 —— 顶点色(八面体编码,8-bit 下误差约 1°)/ 切线 / TEXCOORD(TEXCOORD0TEXCOORD7,共 8 个通道)。
  • 广泛的目标来源 —— 场景对象、Mesh 资产、模型(.fbx 等)、预制体,自动遍历层级、复选框多选批量处理
  • 实时描边预览 —— 内嵌视口,同屏显示所有勾选网格,法线可视化对比、通道状态检查、屏幕 / 世界空间描边对照。
  • 数据安全 —— 阻止对只读资产的假保存、批量另存为独立 Mesh、会话快照还原。
  • 描边 Shader(Sample) —— URP / Built-in 两版,两 Pass(描边 + 基础 NPR),描边来源支持 8 个 UV 通道,附基础色调试档位,自定义材质面板。

⚠️ 已知限制

  • HDRP 未提供描边 Shader,可参照文档自行移植(解码逻辑通用,仅渲染 Pass 需适配)。
  • 不支持 Undo —— Undo.RecordObject 不可靠地跟踪网格顶点数据;工具提供自己的会话快照还原。
  • 顶点合并采用格点取整,恰好跨越格边界的两点仍会被分开;容差需远小于模型最小特征尺寸。
  • 通道状态最高只说「可能是平滑法线」—— 编码后与普通顶点色 / UV 在数据上不可区分。
  • 世界空间宽度模式下 _OutlineWidth世界单位,对很大 / 很小的模型需相应调整。

📖 文档

简体中文 ·
English ·
日本語 ·
详细文档 ·
完整 CHANGELOG

1.2.0

Choose a tag to compare

@AleFeng AleFeng released this 18 Jul 10:52

为网格自动计算平滑法线并烘焙到顶点色 / 切线 / TEXCOORD,用于背面外扩描边,解决硬边处描边断裂。工具本体是纯编辑器 C#,与渲染管线无关。

📦 安装

Window > Package Manager → 左上角 +Install package from git URL... → 粘贴:

https://github.com/AleFeng/OutlineSmoothNormalsGenerator.git?path=/Packages/com.alefeng.outlinesmoothnormalsgenerator#1.2.0

⚠️ 装完还必须导入一个 Sample,否则没有描边 Shader。
核心包刻意不含 Shader —— 这是「不引入任何渲染管线依赖」的代价。
Package Manager 里选中本包 → Samples按你的管线导入其中一个

Sample Shader 名
Outline Shader (URP) & Demo OutlineSmoothNormalsGenerator/Outline URP
Outline Shader (Built-in RP) & Demo OutlineSmoothNormalsGenerator/Outline Built-in

安装成功后菜单栏出现 Tools → Smooth Normal Generator

🆕 1.2.0 更新内容

  • 描边宽度新增「世界空间」模式:可在屏幕空间(等宽,不随距离变化)与世界空间(按世界单位偏移,近大远小)间切换,预览窗口与材质面板均可切换。
  • Sample 描边 Shader 的基础渲染改为基础 NPR:卡通两段式明暗(cel shading)+ 边缘光(rim),取代原先的极简兰伯特,可在材质面板调参 —— 描边多用于 NPR,演示也随之贴近实际。
  • 选中场景对象时改为遍历整个层级收集全部网格(此前只取对象自身的渲染器),与选中模型 / 预制体一致;含多个网格时用目标区的 Mesh 下拉逐个选择。
  • 「保存」按钮改为固定文字、仅切换可用状态:不可直接保存(Model / 内置网格)时置灰,「需要保存 / 已保存」改由颜色与 tooltip 表达;「另存为独立 Mesh」始终可用。

若你从旧版本升级、且把 Sample 的 OUTLINE Pass 复制进过自己的 Shader:共享库 OSN_ApplyOutlineOffset 本版本增加了宽度模式参数(3 → 4 个),需补上该参数。

✨ 主要功能

  • 平滑法线生成 —— 角度加权平均、可调合并容差,跨硬边得到连续外扩方向。
  • 三种存储方式 —— 顶点色(八面体编码,8-bit 下误差约 1°)/ 切线 / TEXCOORD。
  • 广泛的目标来源 —— 场景对象、Mesh 资产、模型(.fbx 等)、预制体,自动遍历层级、多网格下拉选择。
  • 实时描边预览 —— 内嵌视口,法线可视化对比、通道状态检查、屏幕 / 世界空间描边对照。
  • 数据安全 —— 阻止对只读资产的假保存、另存为独立 Mesh、会话快照还原。
  • 描边 Shader(Sample) —— URP / Built-in 两版,两 Pass(描边 + 基础 NPR),自定义材质面板。

⚠️ 已知限制

  • HDRP 未提供描边 Shader,可参照文档自行移植(解码逻辑通用,仅渲染 Pass 需适配)。
  • 不支持 Undo —— Undo.RecordObject 不可靠地跟踪网格顶点数据;工具提供自己的会话快照还原。
  • 顶点合并采用格点取整,恰好跨越格边界的两点仍会被分开;容差需远小于模型最小特征尺寸。
  • 通道状态最高只说「可能是平滑法线」—— 编码后与普通顶点色 / UV 在数据上不可区分。
  • 世界空间宽度模式下 _OutlineWidth世界单位,用在很大 / 很小的模型上需相应调整。

📖 文档

简体中文 ·
English ·
日本語 ·
详细文档 ·
完整 CHANGELOG

1.0.0

Choose a tag to compare

@AleFeng AleFeng released this 17 Jul 14:45

为网格自动计算平滑法线并烘焙到顶点色 / 切线 / TEXCOORD 通道,用于背面外扩描边,解决硬边处描边断裂。

📦 安装

Window > Package Manager → 左上角 +Install package from git URL... → 粘贴:

https://github.com/AleFeng/OutlineSmoothNormalsGenerator.git?path=/Packages/com.alefeng.outlinesmoothnormalsgenerator#1.0.0

⚠️ 装完还必须导入一个 Sample,否则没有描边 Shader。
核心包刻意不含 Shader —— 这是「不引入任何渲染管线依赖」的代价。
在 Package Manager 里选中本包 → Samples按你的管线导入其中一个

Sample Shader 名
Outline Shader (URP) & Demo OutlineSmoothNormalsGenerator/Outline URP
Outline Shader (Built-in RP) & Demo OutlineSmoothNormalsGenerator/Outline Built-in

两个 Sample 各自附带同一套对照演示场景(已烘焙 / 原始法线 / 接缝抖动 三个立方体)。

安装成功后,菜单栏出现 Tools → Smooth Normal Generator

✨ 主要功能

  • 平滑法线生成工具 —— 纯 Editor C#,与渲染管线无关,Built-in / URP / HDRP 均可用于烘焙。
  • 三种存储方式 —— 顶点色(八面体编码,全球面双射,8-bit 下误差约 1°)/ 切线 / TEXCOORD。
  • 实时描边预览、法线可视化对比、通道状态检查。
  • 会话快照还原Mesh 另存为独立资产(不可写网格唯一能真正保存的路径)。
  • 可调合并容差(默认 0.0001),处理 DCC 导出与 FBX 浮点截断造成的接缝。

⚠️ 已知限制

  • 顶点合并采用格点取整,恰好跨越格边界的两点仍会被分开。容差需远小于模型的最小真实特征尺寸。
  • 不支持 Undo —— Undo.RecordObject 并不可靠地跟踪网格顶点数据,对不可变的导入子资产更是完全无效。工具提供自己的会话快照还原作为替代。
  • HDRP 未提供描边 Shader,可参照详细文档自行移植(解码逻辑通用,仅渲染 Pass 需适配)。
  • 通道状态最高只说「可能是平滑法线」—— 编码后就是普通数值,与任意顶点色 / UV 在数据上不可区分。

📖 文档

简体中文 ·
English ·
日本語 ·
详细使用文档 ·
CHANGELOG