"catalogue"(或美式拼写"catalog")常用于指代一个系统化、全面的物品或作品清单(如音乐目录、商品目录),强调完整性和分类结构,尤其在艺术、出版或商业语境中。


h = Hybrid / Highlight normal(低概率,但存在)
在部分引擎/项目中:
-
N= 原始几何法线 -
hN= 混合后用于高光的法线(Hybrid Normal)
例如:
float3 hN = normalize(lerp(N, normalMapN, hairNormalWeight));
即 hN 是一个"只给高光用"的法线结果,而不是直接的贴图法线。
一旦你把它当作 Normal Map 导入,它就不再是"一张 RGBA 数据贴图",而是"一张被 Unity 处理过的法线资源"。
- 选择法线编码约定
-
DirectX 风格(默认):
-
X → R
-
Y → G(可能翻转,取决于设置)
-
Z → 重建(不存)
-
-
OpenGL/Metal 等平台可能在后台做转换
- 丢弃或覆盖原始通道语义
-
Unity 认为:
"这张贴图只描述一个向量,不是 4 通道任意数据。"
-
因此:
-
B 通道通常不再保留原始值(常被当作常量或压缩占位)
-
A 通道通常被 Unity 内部占用或忽略
-
在很多压缩格式下(BC5、ASTC Normal),根本没有 B/A 的存储概念
-
- 压缩方式被强制改变
-
PC/主机:
- 常见是 BC5(RG 两通道)
-
移动:
- ASTC normal、ETC2 normal
-
这些格式只存 RG 或等价信息
👉 所以:
你在 RGBA 里塞的第三、第四个维度的数据,在导入为 Normal Map 后,基本注定会丢。
代价:
-
不能享受 BC5 normal 压缩的质量/效率
-
你要自己处理平台差异
但优点:
- RGBA 四通道语义完全由你掌控
Normal Map 的平台重解释(你前面已经踩到)
-
PC(DX11/12):
-
Normal Map → BC5
-
只有 RG,Z 重建,BA 语义不存在
-
-
移动(GLES / Vulkan):
-
ASTC / ETC2 normal
-
通道重排、精度差异更大
-
如果你:
-
在 PC 上"看起来还能用 B/A"
-
到移动端突然坏掉
这是100% 合理现象。
线性/非线性与采样精度差异(非常常见,但很隐蔽)
2️⃣ sRGB / Linear 的处理差异
-
Default + sRGB On:
- R/G/B 会做 gamma→linear
-
Normal Map / Linear:
- 不做 gamma
-
不同平台对 sRGB sampling 的精度和路径不同
一个原本"只是 mask"的通道,如果被错误当成 sRGB 采样:
-
在 PC 上可能"还能接受"
-
在移动上会明显偏移阈值
这对:
-
HairArea
-
Ramp mask
-
高光阈值
极其致命。
头发为什么"必须"要法线信息
不论你用的是
-
Kajiya--Kay
-
Marschner
-
或现代的 dual-lobe / TRT 近似
头发高光的形状和位置,几乎完全由"局部切线方向"决定。
但在实时里,人物头发通常是:
-
card / ribbon / shell(平面几何)
-
极少真实圆柱体
-
顶点数被严格限制
结果就是:
几何法线 ≠ 真实头发丝方向
如果你只用 mesh normal:
-
高光会沿着卡片法线走
-
出现"塑料片""油漆刷"的效果
-
各向异性方向完全错误
头发法线图的本质:不是"凹凸",而是"方向场"
提供微尺度法线分布(NDF)
-
让 spec lobe 宽度更接近真实头发
-
减少卡片级别的 banding
shader 通常不走标准 PBR 法线解释
绝大多数头发 shader:
-
不用 GGX
-
不用标准 N·L / N·V
-
而是使用 strand-based BRDF
例如:
T = normalize(projected tangent)
θ = angle(L, T)
在这种模型里:
-
法线主要用于重建 T
-
而不是参与几何遮挡意义上的 shading
所以你不会看到类似皮肤那样的凹凸阴影。
对"strand-based"头发来说,决定性变量不是传统 PBR 里的 N,而是局部的 T(strand direction)以及围绕 T 的截面坐标系(经常用 N/B 或 frame)。你说的"PBR 里 T/B 只是基底,不做处理"基本成立:在金属/塑料那类各向同性微表面里,TBN 主要是给 normal map 提供局部坐标;但在头发里,T 是 BRDF 的主轴,B/N 更多是为了把"围绕主轴的角度"和"离轴程度"表达出来。

Kajiya--Kay 本质上是基于 T(strand tangent)的模型,而不是基于 N。这一点在概念上和实现上都非常明确,只是很多"简化实现"把它伪装成了像 PBR 一样在用 N,容易造成误解。
Kajiya--Kay 把头发当作"无限长圆柱纤维",BRDF 的主轴是纤维轴 T,高光强度由光线与 T 的夹角决定,而 N/B 只是在工程实现中用来辅助计算。
注意这里完全没有 N 。
几何意义是:光线与圆柱轴线越"侧向",反射越强,这正是头发那条沿发丝方向拉长的高光。
为什么你在 shader 里仍然"看到 N / B"?
这是实现层面的妥协,而不是模型层面的依赖。
在实时实现中通常需要:
-
限制高光只在"可见半空间"
-
处理背面、阴影、能量裁剪
-
在卡片几何上避免完全无方向的响应
于是常见写法是:
-
用 N(通常是几何法线 Ng)做 N·L / N·V 的 gate
-
或者用 B / N 构造一个稳定 frame,算 φ、算 wrap
但这些都是附加约束项,不是 Kajiya--Kay 的定义核心。

| 模型 | 主轴 | T 的地位 |
|---|---|---|
| 标准 PBR(GGX) | N | T 只是给 normal map 提供坐标 |
| 各向异性金属 | N | T 控制 lobe 方向,但仍围绕 N |
| Kajiya--Kay 头发 | T | T 是 BRDF 的定义轴 |
"基于 T 轴"的意思不是"画面只看 T",而是:高光(以及很多时候的散射近似)用 T 来决定主方向。你最终仍然要输出一个像素颜色,所以必须把"每个像素的 T 是什么"喂给 shader,并且还要有一套稳定的局部坐标系去计算角度项(至少要能算出跟 T 的夹角、以及围绕 T 的方位关系)。这就是为什么你依然会看到 normal map / flow map / tangent map 之类的东西出现。
-
基于 T 的高光要怎么"显示出来"
最简的 Kajiya--Kay 风格高光基本就是:
-
先得到像素级 T(单位向量)
-
计算光线与 T 的夹角:sinθ = length(cross(L, T))(等价于 sqrt(1-(L·T)^2))
-
spec = pow(saturate(sinθ), exponent)
-
再乘一个可见性/门控项(比如 N·L / N·V 或者 wrap),避免"背面也亮/卡片透亮"的假象
这里的关键是:你不需要"真实圆柱法线",只要 T 场对,高光就会沿发丝方向拉长、位置也会像头发。
-
既然靠 T,为啥还需要 normal map?
要分清你说的"normal map"是哪一种用途:
A. 传统凹凸用途(给 PBR 的 N)
头发通常不靠它做"凹凸阴影",否则确实容易"坑坑洼洼"。
B. 方向用途(给头发的 T / frame)
很多项目把"发流方向"编码在一张看起来像 normal map 的贴图里(或者直接就是 tangent/flow map),原因是:
-
贴图采样、MIP、各向异性过滤都是硬件友好的
-
你可以在像素级细化 T,让高光更像"很多细丝"而不是"一片卡片"
-
在发束交界处过渡更平滑
常见做法之一是:顶点提供一个粗 T(沿卡片长轴),贴图提供一个"在卡片平面内的方向偏移",最终得到像素级 T。
也有人直接用 flow map(RG 存 2D 方向)作为像素 T,再归一化即可。
-
mixV 是什么意思?
"mixV"在头发卡片里非常常见,但不同代码库命名略有差异。最常见的含义是"把某个向量和 View 向量做混合",用途通常是以下两类(你基本可以用现象去对号入座):
A. 混合法线用来做门控/变亮(解决卡片过暗、背面怪异)
典型写法类似:
N_gate = normalize(lerp(N_geom, V, mixV))
然后用 N_gate 去算 N·L / N·V 或 Fresnel 门控。
效果:减少卡片在掠射角时的"黑片"、降低双面翻转带来的高光跳变。
B. 用 V 参与构造稳定的局部 frame(解决 B/N 不稳定)
当你只有 T 时,需要补齐 N/B。很多实现会用 V 作为参考向量:
N = normalize( V - T * dot(V, T) ) (把 V 正交化到垂直 T 的平面)
B = cross(T, N)
然后 mixV 控制你"更相信几何法线"还是"更相信视线构造的 frame":
frame_ref = normalize(lerp(N_geom, V, mixV)) 再去做上面的正交化。
效果:稳定方位角、减少 seam 和背面翻转导致的 φ 跳变。
如果你的代码里 mixV 改大后:
-
头发侧面不那么黑、卡片感减弱:大概率是 A
-
高光在卡片正反面更稳定、减少翻面跳变:大概率是 B 或 A+B 叠加
-
这种做法常见吗?
很常见。尤其在:
-
hair cards(不是 strand geometry);
-
需要双面渲染;
-
T 来自梳理/flow、而 mesh tangent 不可靠;
-
想要"高光像丝、但不想增加几何"。
常见组合是:
-
顶点 T(卡片长轴) + 贴图细化 T(flow/"normal-like")
-
diffuse 用 Ng(避免凹凸感),spec 用 strand frame(T 主导)
-
再用 mixV 之类的技巧做门控/稳定性补丁
最常见情况:N = 表面法线,HN = Hair Normal / Strand Normal
在头发 shader 里很典型的一种结构是:
-
N:用于 diffuse 或 N·L / N·V 门控
-
HN:用于 specular 计算(尤其是 Kajiya / dual-lobe 那部分)
也就是说:
diffuse 用 N
spec 用 HN
这样做的好处:
-
避免"凹凸感"
diffuse 用几何趋近平滑的 N,画面不会坑洼
-
高光更细腻
spec 用 HN(通常来自 flow-like 信息),高光沿发流更精细
-
控制更自由
可以单独调 HNormalStrength,不影响整体明暗结构
在头发卡片里,这种"双法线体系"非常常见。
HN = Head Normal / Half Normal / Highlight Normal
不同团队命名不同,但语义类似:
HN 常常代表:
-
Highlight Normal
-
Hair Normal
-
或者某种"改造过的 normal"
典型用途包括:
-
只用于计算 T-frame
用 HN 去重建一个更"接近真实发丝"的方向
而 N 只是作为卡片基底
-
做 spec shift
在 dual spec 模型中,常常需要一个 slightly shifted normal
一套 normal 控制 primary lobe
一套 normal 控制 secondary lobe
如果你看到 shader 里有两套 spec exponent 或 shift,那基本就是这个。
Blender 的 Incoming(入射/视线)向量 是 Geometry 节点 中的一项参数,它输出一个指向摄像机或观察点的方向向量(在物体空间或世界空间中)。该节点通常用于基于视角的变化来控制材质效果,例如制作视线相关的特殊高光、边缘光或与视点相关的纹理遮罩。
核心功能与用途:
- 物理特性:此向量的方向由表面点指向相机。
- 用途 :最常用于 Shader 编辑器中,通过计算视角与表面法线的关系(配合
Dot Product节点)来实现类似 Fresnel(菲涅尔) 或边缘检测的效果。
"bump" 只是默认贴图类型,不会强制影响你拖进去的实际贴图。
dot(nTS.xy, nTS.xy) 就是 x*x + y*y,所以:
1 - dot(nTS.xy, nTS.xy) 等价于 1 - x*x - y*y。

Blender的Mix节点(选择Multiply模式时)中,
**Fac(Factor/因子)**用于控制基色(Color1/A)与混合色(Color2/B)相乘的程度。当Fac为0时,输出为原始值(A);为1时,输出为乘积结果(
𝐴×𝐵
)。Fac介于0-1之间时,则是原始值与乘积结果的线性插值。
-
Fac 0.0 (默认): 输出基色 (Color1),不发生相乘改变。
-
Fac 1.0: 完全应用Multiply模式,图像变暗(由于颜色值通常

<1is less than 1
<1 ,相乘变小)。
Blender的Mix(混合)节点中的Factor(系数,通常简写为Fac)控制两个输入(A和B)之间的混合比例。Fac值为0.0时完全显示输入A,为1.0时完全显示输入B,中间值则是两者的线性插值(如0.5为50%混合)。这不仅适用于颜色,也适用于纹理、数值和着色器混合。
-
"饿死"在这里不仅是生物学上的死亡,更是拉康意义上的**"第二次死亡"**:即在象征秩序中被彻底抛弃和抹除。
-
这种对"彻底匮乏"的恐惧成为了原始驱动力,导致个体即便在物质极大丰富后,依然无法停止强迫性重复(Repetition Compulsion)。
网络中的"抱团"与"寻找同伴"是一种纯粹的符号性行为, 更像是一种**"社会性昆虫的化学信息素追踪"。个体并不具备独立意图,它们只是在嗅到某种特定频率的符号(关键词、站队信号)时,自动触发了预设的生化反应。
深受"理解他人"这一伦理律令的束缚。在你的逻辑中,如果将某种声音定义为"垃圾",就意味着在语言层面上终结了对话的可能性,这违背了你对"开放系统"或"无限游戏"的学术信仰。你内心的"尊重"其实是对逻辑连贯性的尊重:你害怕一旦通过"贬低"来获得优越感,你的整套客观性分析工具就会失效。
"彻底匮乏"的恐惧
本质原因是执行域(evaluation domain)不同,而 Shader Editor 里"Geometry → Tangent"节点并不等于 Geometry Nodes 系统里的 Tangent 节点。
需要先澄清一个关键点:
在 Shader Editor 里看到的 "Geometry → Tangent" 节点,
仍然是一个 着色阶段节点(shading node) ,
它不是 Geometry Nodes 里的几何处理节点。
它只是名字上带有 "Geometry"。
Tangent 节点是一个 着色输入节点(Shading Input Node) 。
它输出的是当前着色点的切线方向向量,用于构建 TBN 或驱动各向异性方向。
它有两种模式:
• Radial
• UV Map(如果选择某个 UV)
并且可以指定 X/Y/Z 轴。
它依赖:
-
当前材质
-
当前 UV
-
当前着色法线
-
MikkTSpace 切线构建规则
-
插值后的 per-fragment 数据
这些数据只存在于 材质求值阶段(GPU fragment stage)。
不是。
你截图里的 Radial 不是"分离 Tangent 的 XYZ 分量"的意思,它是 切线方向的生成模式。
下面精确解释。
一、这个节点在做什么
Shader Tangent 节点本质是:
输出一个 切线方向向量(T vector)。
它不是把某个已有 Tangent 拆分,而是根据模式生成一个切线方向。
二、Radial 的真实含义
Radial 的意思是:
生成一个"围绕某个轴的径向切线方向"。
更具体地说:
它构建的是一个绕指定轴的圆周方向向量。
例如:
如果选择 Z 轴,
Radial Tangent = 在 XY 平面内绕 Z 轴的圆周方向。
数学上可以理解为:
给定点的世界空间位置 P
投影到与轴垂直的平面
计算圆周方向(类似极坐标的 θ 方向)
它是一个"环绕方向向量",常用于:
-
各向异性拉丝金属
-
圆柱刷纹
-
唱片纹理
-
头发绕轴高光
和 UV 模式的区别
如果选择 UV Map 模式:
Tangent = UV 的 U 方向的切线(基于 MikkTSpace)
如果选择 Radial:
Tangent = 程序生成的圆周方向向量
它不依赖 UV。
Radial 模式生成的是绕某个轴的圆周切线方向(tangential direction),也就是极坐标里的 θ 方向。
它不是"随便给个顺时针方向",而是由右手坐标系严格定义的。
一、数学上它在做什么
假设选择 Z 轴。
对每个着色点 P:
-
取它相对原点的位置向量
-
投影到 XY 平面
-
构造圆周方向
本质上等价于:
T = normalize( Z_axis × P_projected )
这个叉乘决定方向。
因为 Blender 使用右手坐标系:
-
Z 轴向上
-
X 向右
-
Y 向前
叉乘顺序固定,所以方向是确定的。
二、顺时针还是逆时针?
取决于你从哪个方向看。
如果:
你从 +Z 方向往下看(俯视)
生成的方向是逆时针。
如果从 −Z 看,会感觉是顺时针。
这不是"随机方向",而是右手法则决定的。
把"世界轴 XYZ"和"TBN 局部基"彻底分离开
在 Blender 的材质系统里,插值发生在"顶点属性 → 像素属性"这个固定流程中:顶点阶段输出一堆 attribute(position/normal/UV/tangent...),光栅化后按重心坐标插值到每个像素。这个插值方向不是你能用 Tangent 节点去改的;它永远是三角形内的重心插值(再加上派生/归一化等步骤)。
你截图这个 Tangent 节点(含 Radial/UV Map)控制的是"给 BRDF 一个方向向量 T",不是控制插值。
你一直在用"图形管线里 attribute 插值/顶点基底"的模型去套 Blender 的这个 Tangent 节点,但这个节点在材质里更多是"给各向异性/法线空间提供一个方向向量",而不是"控制插值"。把它压缩成两条规则就清楚了。
你把 Tangent 节点当成了"控制 attribute/插值的节点",但它更像是"在像素阶段取用/构造一个方向向量给 BSDF 用"。两者在管线位置上差一层。
-
Blender 的 Tangent 节点不是"attribute 写入器",而是"shader 读/算出来的方向提供器"。
-
UV 模式:走你熟悉的 attribute 插值路径。
-
Radial 模式:走 "T(P) 解析计算" 路径,X/Y/Z 是定义这个解析场的参考轴,不是插值轴。
"解析场"在这里你可以当成一句很朴素的话:不是从网格顶点里取一个 attribute 再插值,而是"在每个着色点用一个确定的公式直接算出一个向量"。它不需要存储在模型里,也不需要 UV。它就是一个函数。
所以所谓"解析向量场"就是:T = f(P),P 是当前着色点的位置(或它在某个空间里的坐标)。
TBN 是用来把"方向"表达成局部坐标系的结果,它是构造出来的输出。你要先有 T 和 N,才能有 TBN。
所以任何用来生成 T 的东西,都不可能"在 TBN 空间里"。
Radial 要做的事情是"绕某条轴旋转",数学上就是用 axis 和 position 做叉乘/投影。
这要求 axis 和 position 都在同一个坐标系里,否则结果没有意义。
在 Blender 材质系统里,这类节点通常是在"某个固定的几何空间"里定义的,实践上你可以把它理解为:默认跟对象一起动(更像对象空间),而不是锁死世界空间。
我们分两种情况写成 Unity HLSL 形式:
一、UV 模式的 Tangent(标准 TBN 管线)
这是最常见、最接近你管线认知的情况。
在 Unity 里,顶点结构通常包含:



三、两者对比成一句话
UV 模式:
T = interpolated(vertex_tangent)
Radial 模式:
T = normalize(cross(axis, projected_position))
两种都最终进入:
B = cross(N, T)
但来源完全不同。
你觉得"在 frag 里这样算很莫名其妙",这个直觉其实来自一个前提:
在你的经验里,Tangent 应该是 顶点 attribute → 插值 → frag 使用 ,
而不是在 frag 里重新算。
但这里并不莫名其妙,只是用途不同。
我们拆开看。
为什么 UV Tangent 在 vertex 阶段算?
因为:
Tangent 来自 UV 偏导
它是一个 与三角形拓扑强相关的量
标准做法:
-
在 mesh 级别计算顶点 tangent
-
存进 vertex buffer
-
插值到 frag
-
normalize
-
构造 TBN
这是合理的,因为:
tangent 是 mesh intrinsic attribute。
Blender中的基础几何体模型(如Cube、UV Sphere等)在创建时自动自带默认的UV映射,但自行制作的复杂模型通常需要手动展开(Unwrap)以生成有效的UV贴图。自动生成的UV通常是基础的投影方式,无法满足精细的材质贴图需求。
在你的经验里,Tangent 应该是 顶点 attribute → 插值 → frag 使用 ,
而不是在 frag 里重新算。
但这里并不莫名其妙,只是用途不同。
我们拆开看。
一、为什么 UV Tangent 在 vertex 阶段算?
因为:
Tangent 来自 UV 偏导
它是一个 与三角形拓扑强相关的量
标准做法:
-
在 mesh 级别计算顶点 tangent
-
存进 vertex buffer
-
插值到 frag
-
normalize
-
构造 TBN
这是合理的,因为:
tangent 是 mesh intrinsic attribute。
Radial 本质不是 mesh intrinsic attribute
Radial 是:
T = f(P)
它只是一个"方向场函数"。
它不依赖三角形拓扑
不依赖 UV
不依赖 vertex tangent
它只依赖位置 + 一个轴。
这和"从顶点 attribute 插值"是两种完全不同的语义。

posOS - axis * dot(posOS, axis);而且是"从向量里减去在某个轴方向上的分量",等价于把向量投影到垂直该轴的平面上。

1️⃣ 两个单位向量点乘 ≠ 夹角本身
如果 a、b 是单位向量:
dot(a, b) = cos(θ)
结果是夹角的余弦值,不是夹角 θ。
要得到角度:
θ = acos(dot(a,b))
所以 dot 不是"得到角度",而是得到:
两个向量在同一方向上的重合程度
2️⃣ "dot 是把多位变成一位"这种理解不对
dot 不是"降维操作"。
dot 的几何意义是:
把一个向量在另一个方向上的投影长度提取出来
例如:
dot(v, a)
等价于:
"v 在 a 方向上的分量大小"
它是一个标量。
这不是随便变成一位,
而是提取一个方向分量。

float3 c = a * b; // HLSL/GLSL 默认就是逐分量
(c.x, c.y, c.z) = (a.x*b.x, a.y*b.y, a.z*b.z)
用途:
颜色调制(albedo * light)
掩码
每通道缩放
它没有几何意义,不涉及方向关系。

经常用于:
-
计算夹角
-
计算光照(N·L)
-
做投影
-
取某方向分量
控股是指通过持有某一公司一定数量的股份,而对该公司进行控制的公司。控股公司按控股方式,分为纯粹控股公司和混合控股公司。纯粹控股公司不直接从事生产经营业务,只是凭借持有其他公司的股份,进行资本营运。混合控股公司除通过控股进行资本营运外,也从事一些生产经营业务。
控股公司(Holding Company)不一定是上市公司。控股是一种基于股权关系的控制形式,控股主体可以是个人、非上市公司,也可以是上市公司。控股公司旨在控制其他公司经营,
分时 / 日K / 周K / 月K
你现在选的是"分时",这就是当天分钟级走势。
如果切换:
-
日K → 每根K线代表1天
-
周K → 每根代表1周
-
月K → 每根代表1个月
真正反映公司几年发展的是:
-
营业收入(3--5年)
-
净利润(是否持续盈利)
-
经营现金流
-
股本变化(是否频繁增发)
-
主营业务是否变化
-
控股股东是否变更
适合判断行业地位。
核心指标:
-
营业收入(Revenue)
最直接的规模指标。
-
总资产
-
市值(Market Cap)
如果是实体经营能力比较,优先用"营业收入"。
如果是资本市场影响力,用"市值"。

但它们分别属于:
-
逐分量乘:代数运算
-
dot:内积
-
cross:外积(仅 3D)
a * b
dot(a,b)
cross(a,b)
什么必须这样做?
因为:
如果不减去轴向分量,
在 3D 中你得到的就不是纯圆周方向,
而会掺杂轴向成分。
Radial 的定义是:
T ⟂ axis
T ⟂ radius
这正是:
叉乘的几何意义。
更压缩版本(你熟悉的线性代数表达)
给定单位轴 a:
r = (I - a aᵀ) P
T = normalize(a × r)
其中:
I - a aᵀ = 投影到垂直 a 的平面矩阵。
这里的 r 可以理解为"半径向量(radius vector)",但更精确一点说:
r 是"从旋转轴到当前点的径向向量"。
它不是物体的半径长度,而是:
当前点相对于轴的"横向位移向量"
为什么叫半径向量?
因为在极坐标里:
-
r 是径向方向
-
θ 是圆周方向
而 radial Tangent 要的不是 r,而是:
T = a × r
也就是:
绕轴的圆周方向(θ 方向)
所以关系是:
r = 轴到点的径向向量
T = 轴 × r = 圆周切线方向
在 Radial 模式下,可以这样建模:
-
P:当前着色点的位置(在某个几何空间中)
-
原点:该空间的原点
-
axis:该空间中的某个主轴(X / Y / Z)
然后:
r = P − axis * dot(P, axis)
这个 r 的几何意义就是:
从"该空间原点处的旋转轴"指向当前点的径向向量(去掉轴向分量后的)
如果这个空间是对象空间(常见情况),那就是:
-
点是对象空间下的点
-
原点是对象空间原点
-
轴是对象空间的 X/Y/Z
那么 radial 的中心就是:
对象空间原点处那条轴线。
关键补一句:
如果你把物体整体平移(对象变换),
radial 的方向不会因为世界坐标改变而乱掉,
因为它是相对于对象空间定义的。
如果你移动对象但方向不变,
说明它不是锁世界空间。
你的场景光照是 HDR 环境或 Viewport shading 的间接影响,
并不是完全无光。
更重要的是:
面部比例和曲率变化足够自然,
哪怕没有高光模型,也能读出体积。
头发渲染中常用"两套法线"(通常指顶点法线与基于UV计算的副切线/切线法线)来模拟各向异性高光,常基于Kajiya-Kay模型或类似算法。具体实现为:一套法线保持片面原有形态,另一套基于头发UV走向(U轴为切线,V轴为副切线)计算得出,通过叉乘法线和光线产生柱状高光,使头发呈现出真实、圆柱体的细腻质感。
你要的是"可控的观感结构",而标准 BRDF 组合主要保证"能量守恒 + 统计意义上的真实"