ShaderGraph位置节点全解析:从坐标空间到屏幕特效实战

📅 2026/7/13 11:21:19
ShaderGraph位置节点全解析:从坐标空间到屏幕特效实战
1. 项目概述为什么我们需要深入理解Position节点在ShaderGraph的世界里如果你问我哪个节点是连接“物体自身”与“渲染世界”的桥梁我会毫不犹豫地说是各种Position节点。这不仅仅是技术上的定义更是我踩过无数坑后的深刻体会。很多新手甚至一些有经验的开发者在制作屏幕特效、世界空间溶解或者简单的UV动画时效果总是不对劲——物体移动时特效乱跑或者在不同分辨率的屏幕上表现不一致。这些问题十有八九都出在对“位置”数据的理解偏差上。Position节点或者说位置数据节点是ShaderGraph中用于获取顶点或片元在特定坐标系下位置信息的一族节点。它们不像Color或Texture 2D节点那样直观其输出值一个Vector 3或Vector 4背后隐藏着一整套图形学的空间变换逻辑。理解它们就等于拿到了编写高级、稳定、可预测着色器的钥匙。无论是实现一个随着摄像机移动而变化的动态天空盒还是一个精确附着在物体表面的污渍效果都离不开对位置数据的精确操控。简单来说这篇文章就是为你彻底拆解ShaderGraph中的位置节点家族Position、View Direction、Screen Position以及相关的Object、World、Tangent、Normal等空间向量节点。我会从最根本的空间坐标系讲起用大量实际案例告诉你每个节点输出的是什么、应该在什么场景下用、以及最关键的——如何避开那些让人头疼的“坑”。如果你曾对Shader中复杂的位置变换感到困惑那么这篇解析正是为你准备的。2. 图形学基石必须厘清的坐标空间在直接操作节点之前我们必须打好地基。Shader中的计算不是在真空中进行的每一个位置数据都必须属于一个特定的坐标空间。用错空间就像用地图导航时错把“本地商场”当成“地球经纬度”结果必然南辕北辙。2.1 核心坐标空间解析在Unity以及大多数图形渲染管线中我们主要与以下四个空间打交道它们构成一个完整的变换链条模型空间Model Space / Object Space定义这是顶点的“老家”坐标值来源于3D建模软件如Blender, Maya。一个立方体的中心可能在(0,0,0)某个角点在(1,1,1)。特点与物体本身绑定。无论你把模型放在世界何处旋转缩放成什么样其模型空间坐标在导入时就是固定的。在ShaderGraph中Position节点选择Object模式或者使用Object节点获取的就是这个空间的位置。世界空间World Space定义这是整个游戏场景的全局统一坐标系。所有物体都通过其Transform组件位置、旋转、缩放被放置到这个空间中。变换过程世界坐标 模型坐标 × 物体的模型矩阵Model Matrix。这个矩阵包含了物体的位移、旋转和缩放信息。在ShaderGraph中Position节点选择World模式或者使用World节点。这是最常用、最直观的空间之一常用于计算物体与场景中其他元素如灯光、玩家的距离和方向。观察空间View Space / Eye Space定义以摄像机为原点的坐标系。摄像机的前方通常是-Z轴或Z轴取决于API其视野范围构成了视锥体。变换过程观察坐标 世界坐标 × 观察矩阵View Matrix。观察矩阵本质上是世界矩阵的逆矩阵把世界变换到摄像机“眼前”。在ShaderGraph中通常不直接提供但它是计算View Direction视线方向和向裁剪空间变换的中间环节。裁剪空间Clip Space与屏幕空间Screen Space裁剪空间这是一个齐次坐标空间x, y, z, w经过投影矩阵变换后用于定义视锥体。在此空间内所有在视锥体内的顶点其x, y, z分量都在[-w, w]范围内。这是GPU进行裁剪Clipping操作的空间。屏幕空间这是我们将3D场景最终渲染到2D屏幕上的空间。通常x和y坐标的范围被归一化到[0, 1]左下角为(0,0)右上角为(1,1)或[-1, 1]等。在ShaderGraph中Screen Position节点的输出本质上就是经过这一系列变换后在屏幕空间或相关空间下的位置信息。重要提示理解这些空间的关键在于记住它们是一个链式变换模型空间 -模型矩阵- 世界空间 -观察矩阵- 观察空间 -投影矩阵- 裁剪空间 -透视除法- 标准化设备坐标 -视口变换- 屏幕空间。ShaderGraph的节点帮我们封装了这些复杂的矩阵运算但我们心里必须清楚数据流向了哪里。2.2 空间选择的核心原则如何选择正确的空间我的经验法则是做物体自身的特效如基于模型高度的渐变、模型表面的纹理滚动优先考虑模型空间或切线空间用于法线贴图。这样特效会牢牢“长”在物体上。做与场景交互的特效如世界坐标投影纹理、根据世界高度混合材质必须使用世界空间。做屏幕空间特效如全屏泛光、扭曲、UI遮罩必须使用屏幕空间通过Screen Position节点获取。计算光照和视线通常需要将方向转换到统一的世界空间或切线空间进行计算。3. 核心节点深度拆解与实战应用掌握了坐标系我们就可以开始“操作”这些节点了。ShaderGraph中的位置相关节点主要分为两大类获取位置和获取方向。3.1 Position节点你的空间坐标提取器Position节点是其中最基础、最核心的一个。它的模式Mode下拉菜单直接决定了你获取的是哪个空间的位置。节点接口输出端口OutVector 3。输出指定空间下的位置坐标。属性Mode下拉选项包括World、Object、View、Tangent。各模式详解与实战场景World世界空间输出值顶点或片元在世界坐标系中的(x, y, z)位置。典型应用三平面投影Triplanar Mapping利用世界XZ坐标采样地面纹理世界Y坐标采样侧面纹理实现无缝的复杂地形材质无需担心模型UV。// 概念性伪代码在ShaderGraph中通过节点连接实现 float3 worldPos Position (World); float4 texX SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, worldPos.yz); float4 texY SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, worldPos.xz); float4 texZ SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, worldPos.xy); // 根据世界法线权重混合世界空间噪声使用世界位置作为输入生成全局连续、不随物体移动而跳变的噪声效果常用于云层、水面、体积雾。基于高度的混合例如实现雪线效果当世界Y坐标高于某个值时将材质混合为雪地材质。Object模型空间输出值顶点在原始模型坐标系中的位置。典型应用模型内建渐变比如创建一个从模型底部Y最小到顶部Y最大的颜色渐变。无论你如何旋转、缩放实例化的物体这个渐变都相对于模型自身保持不变。顶点动画在模型空间中对顶点位置进行偏移如正弦波模拟旗帜飘动计算更直观因为动画是基于模型自身轴向的。View观察空间输出值顶点相对于摄像机的位置。原点在摄像机通常摄像机看向-Z方向。典型应用相对较少直接使用但它是计算深度、边缘检测等后处理效果的基础。更常用的是View Direction节点。Tangent切线空间输出值这是一个特例。当Position节点设置为Tangent模式时它输出的不是位置而是顶点的切线向量Tangent Vector。这是一个Vector 3通常与法线Normal和副切线Bitangent一起构成描述模型表面方向的切线空间基向量。典型应用这是法线贴图Normal Map解码和应用的绝对核心。法线贴图中存储的法线信息是相对于切线空间的。我们需要将灯光方向、视线方向从世界空间转换到切线空间才能与法线贴图进行正确的计算。操作流程通常使用Transform节点将World Space下的Light Direction或View Direction转换到Tangent Space。这个转换过程就需要用到Tangent向量来自此节点、Normal向量和副切线可通过Normal和Tangent叉积得到。实操心得Position节点的Space参数在片元着色器Fragment Shader和顶点着色器Vertex Shader中都可以使用但意义略有不同。在顶点着色器中它获取的是顶点的位置在片元着色器中它获取的是经过光栅化插值后的片元的位置。对于大多数基于位置的特效如世界空间纹理在片元着色器中使用能获得更平滑、精确的结果。3.2 Screen Position节点屏幕特效的万能钥匙Screen Position节点是制作全屏或与屏幕坐标相关特效的基石。它的不同模式Mode决定了输出坐标的原点和范围这是最容易混淆的地方。节点接口输出端口OutVector 4。注意是四维向量其xy分量通常是我们需要的屏幕坐标zw分量可能有其他用途如原始深度。属性ModeDefault、Raw、Center、Tiled。各模式详解与“避坑”指南Default默认模式输出值经过透视除法Perspective Divide和视口映射后的标准化屏幕坐标。对于最常见的透视摄像机其xy分量范围通常是**[0, 1]**左下角为(0,0)右上角为(1,1)。计算过程屏幕坐标.xy 裁剪空间坐标.xy / 裁剪空间坐标.w。这个除以w即齐次坐标的w分量就是透视除法它实现了近大远小的透视效果。应用场景绝大多数屏幕空间效果。例如屏幕UV动画直接用其xy分量作为UV去采样一个全屏纹理。径向模糊以屏幕中心为原点根据当前片元屏幕坐标计算方向向量。制作简易UI遮罩结合Step或Smoothstep节点可以轻松实现圆形、矩形等屏幕区域的遮罩。Raw原始模式输出值裁剪空间坐标未进行透视除法。其xy分量范围是**[-w, w]**具体值取决于视锥体和投影矩阵。“坑”点解析这是新手最容易出错的地方。如果你用Raw模式的输出直接当作UV会发现纹理被严重拉伸扭曲因为远处的顶点w值很大导致xy范围被压缩。这个模式通常不直接用于采样纹理。正确应用场景深度重建在自定义渲染管线或某些后处理中需要利用裁剪空间坐标和投影矩阵参数来重建世界空间位置或线性深度。某些特定的投影计算如精确的球面映射Sphere Mapping需要未经透视除法的坐标。Center中心模式输出值在Default模式的基础上将坐标原点平移到了屏幕中心。即屏幕中心是(0,0)左下角大约是(-0.5, -0.5)右上角大约是(0.5, 0.5)。具体范围与屏幕宽高比有关。应用场景所有需要以屏幕中心为对称点或原点的效果。镜头光晕Lens Flare光晕元素通常沿屏幕中心到光源屏幕坐标的连线分布。色差/色散效果Chromatic Aberration根据当前片元到屏幕中心的距离对RGB通道进行不同程度的偏移。径向渐变的遮罩计算length(屏幕坐标 - 0.5)来得到到屏幕中心的距离比用Default模式再减去0.5更直接。Tiled平铺模式输出值在Center模式的基础上对xy分量取了小数部分frac操作。这使得坐标在[-0.5, 0.5]范围内循环。应用场景创建无限重复的、以屏幕中心为原点的平铺图案。比如一些复古的扫描线效果、网格背景或者测试用的棋盘格纹理。它确保了图案在屏幕中心连续边缘可能有接缝取决于平铺方式。注意事项Screen Position节点在URP通用渲染管线和HDRP高清渲染管线中的行为是高度一致的但在Built-in管线中需要注意一些平台差异如DirectX和OpenGL的屏幕空间Y轴方向可能不同。ShaderGraph在很大程度上屏蔽了这些差异但如果你发现上下颠倒的问题可以尝试使用Flip节点对Y分量进行处理。3.3 View Direction与Normal节点光照与视角的奥秘位置决定了“在哪”而方向决定了“怎么看”和“怎么被照亮”。View Direction和Normal节点虽然不直接输出位置但与位置计算密不可分。View Direction视线方向节点输出Vector 3。从当前片元指向摄像机的单位向量归一化向量。空间取决于其Space属性World, Object, View, Tangent。核心用途计算高光反射Specular、菲涅尔效应Fresnel Effect和边缘光Rim Light。菲涅尔效应物体在视线与表面法线夹角越大的地方边缘反射越强。计算公式通常涉及1 - dot(Normal, ViewDir)。边缘光类似菲涅尔在物体轮廓边缘添加发光效果。实操技巧通常使用世界空间下的View Direction并与世界空间下的Normal进行点积计算。确保两者在同一空间下Normal法线节点输出Vector 3。顶点的法线向量。空间取决于其Space属性。同样有World, Object, View, Tangent可选。核心用途所有与光照、视角相关的计算基础。漫反射光照 max(0, dot(Normal, LightDirection))。“坑”点从模型顶点插值得到的法线Vertex Normal是平滑的。如果你想要表现硬表面效果需要使用Normal Vector节点并选择Face模式来获取面法线或者依赖法线贴图来提供细节法线。法线贴图中的法线信息是存储在切线空间的因此你需要用Transform节点将世界空间的光照和视线转换到切线空间再与法线贴图采样结果进行计算。4. 综合实战构建一个高级边缘光与屏幕空间扭曲特效理论说得再多不如动手做一个。我们来组合运用上述节点创建一个复合特效一个具有世界空间边缘光的物体其表面的扭曲效果会影响到屏幕空间的背景。目标效果一个物体其边缘会根据视角发出自发光边缘光。同时以该物体在屏幕上的位置为中心对屏幕背景进行一个类似热浪的扭曲扰动。实现步骤拆解创建Unlit Graph并设置基础颜色新建一个Unlit Graph用于我们的特效材质。首先用一个Color节点定义物体基础色。实现世界空间边缘光a. 获取World Space下的Normal和View Direction。b. 使用Dot Product节点计算法线与视线方向的点积。dot(N, V)。当视线与表面平行时看边缘点积接近0当视线垂直表面时看正面点积接近1。c. 使用One Minus节点计算1 - dot(N, V)。这样边缘的值接近1正面的值接近0。d. 使用Power节点对结果进行幂运算例如Power(0.5)来控制边缘光的“硬度”或“软度”。幂值越小边缘光范围越宽、越柔和。e. 使用Color节点定义一个发光的颜色如亮蓝色并用Multiply节点与上一步的结果相乘。f. 最后用Add节点将边缘光颜色与基础色相加。至此一个基础的菲涅尔边缘光完成。实现屏幕空间扭曲这是难点和重点a. 我们需要获取当前片元在屏幕空间的位置。拖入Screen Position节点模式选择Default。其输出的xy分量就是标准的[0,1]屏幕UV。b. 我们需要一个扭曲的中心点。我们希望这个中心是该物体在屏幕上的投影位置。如何获取我们需要将物体的世界空间位置转换到屏幕空间。获取物体的世界位置对于物体表面的每个点其世界位置就是Position (World)。但我们需要一个代表物体的“中心点”简单起见我们可以使用模型原点在世界空间的位置。更精确的做法是使用Object节点的Position输出但它在片元着色器中是插值后的。一个常见的技巧是在顶点着色器中计算模型原点的屏幕位置然后传递给片元。在ShaderGraph中我们可以通过Custom Function或利用Transform节点矩阵手动计算。为了简化演示我们假设使用顶点着色器传递的物体中心屏幕坐标可通过脚本传递或简化处理。假设我们通过一个Vector 2属性_ObjectScreenCenter传入物体中心的屏幕UV坐标范围0,1。c.计算扭曲用当前屏幕UV减去物体中心UV得到相对于中心的向量。计算这个向量的长度到中心的距离。float2 uv ScreenPosition.xy; float2 center _ObjectScreenCenter; float2 dir uv - center; float distance length(dir);d. 基于距离创建一个扰动值。可以使用Noise节点以uv _Time.y为输入生成动态噪声。然后让扰动的强度随着距离增加而衰减例如乘以1/(1 distance*10)。float2 noiseUV uv _Time.y * 0.1; // 让噪声动起来 float2 noise SimpleNoise(noiseUV).rg; // 假设是二维噪声取值在[-0.5, 0.5] float attenuation 1.0 / (1.0 distance * 10.0); noise * attenuation * _DistortionStrength; // _DistortionStrength是控制强度的属性e. 将扰动加到原始的屏幕UV上得到扭曲后的UV。float2 distortedUV uv noise;f. 使用这个扭曲后的UV去采样屏幕背景纹理。在URP中你可以通过Scene Color节点获取当前渲染的屏幕图像。将采样到的颜色作为背景。g.关键合成步骤我们需要将物体的颜色含边缘光与扭曲后的背景合成。这里需要透明度混合。我们之前计算的边缘光强度步骤2.d的结果可以作为物体“主体”的Alpha遮罩的一个来源。越靠近边缘物体越“透明”越能显示背后的扭曲背景。我们可以将边缘光强度值重映射作为物体颜色的Alpha值。使用Lerp线性插值节点以这个Alpha值为系数在扭曲背景色和物体色含边缘光之间进行插值。这样在物体边缘就能看到背景被扭曲的效果而物体中心则保持实体感。最终输出将Lerp的结果连接到主纹理的Color端口并处理好Alpha通道连接到Alpha端口确保渲染管线能正确进行混合。这个案例综合运用了World Position、World Normal、View Direction、Screen Position并涉及了空间转换的思想。它清晰地展示了物体自身的特效边缘光基于世界/观察空间而与屏幕交互的特效扭曲必须基于屏幕空间并通过巧妙的Alpha混合将两者结合。5. 性能优化、常见问题与调试技巧即使理解了原理在实际开发中还是会遇到各种问题。下面是我总结的一些实战经验和排查清单。5.1 性能考量空间转换的成本在片元着色器中进行复杂的空间转换特别是矩阵乘法是昂贵的。Position、Normal等节点在背后可能隐含着矩阵运算。优化建议如果可能尽量在顶点着色器中计算位置和方向然后传递给片元着色器插值。ShaderGraph中可以通过节点设置选择是在Vertex还是Fragment阶段采样。对于View Direction这种每个片元都不同的计算在片元中计算是必要的但对于Object空间的位置如果不需要每像素精度可以考虑在顶点阶段计算。屏幕空间节点的开销Screen Position和采样Scene Color如果需要通常意味着你的着色器无法被批处理Batching并且可能增加显存带宽消耗。优化建议将屏幕后处理效果放在专门的后处理堆栈Post Processing Stack中实现而非物体材质本身。对于物体局部的屏幕交互如本例严格控制其影响范围和渲染队列避免全屏使用。5.2 常见问题排查表问题现象可能原因排查与解决方案特效在物体移动时“抖动”或“滑动”错误地使用了模型空间位置来做世界空间或屏幕空间的效果。检查Position节点的Space设置。如果是需要跟随世界移动的效果确保使用World空间。屏幕空间特效则必须使用Screen Position。屏幕UV采样时纹理上下颠倒图形API差异如OpenGL与DirectX的纹理坐标系。使用Flip节点对Screen Position的Y分量进行取反操作1 - Y。或者在采样纹理前检查并统一UV坐标系。法线贴图看起来是错的光照方向不对空间不匹配。法线贴图是切线空间法线但光照方向是世界空间。确保使用Transform节点将World Space的Light Direction和View Direction转换到Tangent Space再与法线贴图采样结果进行点积计算。Screen Position的Raw模式导致纹理严重扭曲误将裁剪空间坐标直接当作[0,1]范围的UV使用。Raw模式输出的是裁剪空间坐标需进行透视除法除以w才能得到标准化设备坐标/屏幕UV。直接使用Default模式即可它已自动完成除法。边缘光在物体背面也可见计算菲涅尔时没有考虑法线方向。当视线与法线点积为负时即看背面1-dot(N,V)会大于1。在计算点积后使用Saturate节点将结果限制在[0,1]范围或者使用Absolute节点取绝对值如果希望双面都有边缘光。更物理的方法是使用max(0, dot(N, V))。在不同分辨率或屏幕比例下特效变形屏幕空间计算没有考虑屏幕宽高比。Screen Position的Center模式坐标范围受宽高比影响。在进行基于屏幕中心距离的计算时将UV的y分量乘以屏幕宽高比_ScreenParams.x / _ScreenParams.y或将x分量除以宽高比以校正为非正方形空间的距离计算。5.3 调试技巧当效果不符合预期时不要盲目猜测。将中间变量可视化是最高效的调试手段。颜色调试法这是最直观的方法。将你怀疑有问题的向量如Position、View Direction、某个计算中间值直接连接到主输出的Color上。因为颜色分量范围是[0,1]你需要对向量值进行适当的重映射。位置世界位置通常值很大直接输出会全白。可以尝试frac(worldPos)输出其小数部分会得到彩色网格图案。或者worldPos * 0.01进行缩放。方向向量方向向量分量范围在[-1,1]。需要将其映射到[0,1](vector 1.0) * 0.5。这样你可以通过颜色判断方向是否正确例如法线朝上的部分应该是绿色的。标量/强度直接连接白色代表1黑色代表0。分离计算链路将复杂的节点网络拆分成几个独立的部分分别检查输出。例如先单独测试边缘光强度计算是否正确再单独测试屏幕扭曲UV是否正确。善用预览窗口ShaderGraph的预览窗口可以设置为显示不同的中间变量。右键点击任意节点或连线选择“Convert to Sub-graph”或直接创建Custom Function来隔离和测试特定功能模块。理解ShaderGraph的位置节点本质上是理解计算机图形学中顶点从模型到屏幕的旅程。每一个节点都是这个旅程中的一个快照或路标。Position告诉你现在在哪一站Screen Position告诉你最终在屏幕地图上的哪个点而View Direction和Normal则描述了你看待这个点的视角和它自身的朝向。掌握了它们你就能自由地操控光影、空间与屏幕将天马行空的视觉创意转化为精确可控的代码与连接线。记住每当效果出现诡异的位移或扭曲时第一个要问自己的问题就是“我用的位置到底是谁眼中的位置”