
1. 项目概述为什么2D天空渐变是独立游戏与UI设计的点睛之笔在独立游戏开发或者一些风格化UI设计中一个精心绘制的2D天空背景往往能瞬间奠定整个场景的基调与氛围。无论是像素风RPG里从清晨到黄昏的时光流转还是现代扁平化界面中柔和渐变的背景板色彩的自然过渡都是提升视觉沉浸感的关键。过去这类效果要么依赖美术同学逐帧绘制多张图片进行切换或混合要么就需要程序员在代码里硬算颜色插值流程繁琐且不易调整。Unity的ShaderGraph出现后情况就完全不同了。它让我们这些非图形学专家也能直观地搭建着色器逻辑把动态的、可交互的视觉效果控制权牢牢抓在自己手里。今天要聊的就是如何用ShaderGraph不写一行Shader代码实现一个高度可定制、实时调整的2D天空与多色渐变效果。这个效果的核心价值在于“可控”与“动态”你可以随时在编辑器里拖动滑块改变天空的颜色、过渡的柔和度甚至实现基于游戏时间如昼夜循环的动态色彩变化。这对于快速迭代美术风格、创建动态背景或实现一些环境氛围反馈比如角色进入毒区天空渐变为紫色来说效率提升不是一星半点。2. 核心思路拆解从颜色混合到UV映射要实现一个多色混合的2D渐变我们需要在ShaderGraph里解决几个核心问题颜色从哪里来如何控制混合最终效果如何应用到2D Sprite上整个思路可以分解为以下几步2.1 颜色源的构建与组织我们不可能为每一种颜色组合都单独制作材质。一个灵活的系统应该允许我们自由定义多个颜色控制点。在ShaderGraph中最直接的方式就是使用Color类型的属性Property并将其暴露给材质面板。比如我们可以定义Color_A,Color_B,Color_C三个颜色属性分别代表天空的顶部色、中部色和底部色。通过调整这些颜色我们就能组合出晨曦橙-粉-蓝、正午亮蓝-白蓝-浅蓝、黄昏深紫-橙红-暗蓝等不同氛围的天空。2.2 混合逻辑的选择与实现有了多个颜色下一步就是决定它们如何混合。对于2D天空我们通常希望颜色沿着Sprite的垂直方向V坐标平滑过渡。这里的关键是找到一个在0到1之间连续变化的“混合因子”。Sprite的UV坐标中的V分量即纵坐标天然就是一个完美的选择。UV坐标的原点(0,0)通常在左下角(0,1)在左上角。因此从下到上V值从0线性增加到1。我们可以利用这个V值作为输入通过Lerp线性插值节点进行颜色混合。但Lerp一次只能混合两个颜色。对于三个或更多颜色的平滑过渡常见的做法是进行两次Lerp先用一个混合因子在Color_A和Color_B之间插值得到中间色MidColor再用另一个或同一个混合因子在MidColor和Color_C之间插值。更高级和灵活的控制可以使用Sample Gradient节点。你可以创建一个Gradient资源在里面设置多个颜色关键点和Alpha关键点然后在ShaderGraph中采样这个Gradient采样坐标就是我们的V值。这种方式在需要复杂多段渐变时更加直观和强大。2.3 最终输出与材质设置混合计算出的颜色需要输出到片元着色器的Base Color端口。为了让这个Shader能正确工作在2D Sprite上有两点至关重要Shader设置必须在Graph的Graph Settings中将Active Targets设置为Sprite。这决定了Unity会为这个ShaderGraph编译适用于Sprite渲染管线的代码。材质渲染队列使用此Shader的材质其渲染队列通常应设置为Transparent特别是当天空需要叠加在其他场景元素后面时并确保Sprite Renderer组件的Draw Mode为Simple以便UV能够正常覆盖整个矩形区域。3. 在ShaderGraph中的逐步实现下面我们进入Unity编辑器一步步搭建这个渐变着色器。3.1 创建与基础设置首先在Project窗口中右键选择Create - Shader Graph - URP - Sprite Unlit Graph如果你的项目是URP管线或Create - Shader - Sprite Graph旧版2D渲染管线。将其命名为“2D_Sky_Gradient”。双击打开ShaderGraph编辑器。在Graph Settings面板通常位于右下角或通过右键画布空白处选择确认Active Targets中包含了Sprite。这确保了所有生成的节点和功能都兼容2D精灵的渲染。3.2 构建三色渐变网络我们将实现一个经典的三色顶-中-底渐变方案。创建颜色属性在画布空白处右键选择Create Node然后搜索Property选择Color。创建三个Color属性分别命名为_TopColor,_MiddleColor,_BottomColor。为了方便识别可以分别赋予它们默认值比如深蓝(#0A2472)、浅蓝(#7EC8E3)和亮橙(#FF9671)。创建后它们会出现在左侧的Blackboard面板中。获取UV坐标右键搜索UV节点添加一个Texture 2D类型的UV节点。我们只需要垂直方向的渐变所以使用Split节点搜索Split将UV的V通道即G通道分离出来。将UV节点连接到Split节点的RG输入然后从Split节点拉出G引脚这就是我们需要的0到1的垂直渐变因子我们称其为gradientFactor。实现两次Lerp混合第一次Lerp底部到中部搜索Lerp节点。将_BottomColor连接到A_MiddleColor连接到BgradientFactor连接到T。输出我们记为tempColor。这里有一个关键点当gradientFactor为0底部时输出纯_BottomColor为1顶部时输出纯_MiddleColor。但这不符合“顶部是_TopColor”的直觉。因此我们需要对混合因子的使用进行规划。更合理的逻辑是当V值很小靠近底部时显示_BottomColorV值中等时显示_MiddleColorV值很大靠近顶部时显示_TopColor。我们可以将整个V轴0-1分成两段来处理。例如让_BottomColor到_MiddleColor的过渡发生在V值的下半段0-0.5让_MiddleColor到_TopColor的过渡发生在上半段0.5-1。这就需要用到Remap重映射和Saturate钳制到0-1节点。首先为第一个Lerp创建一个新的混合因子factor1factor1 saturate(gradientFactor * 2)。这样当gradientFactor在0到0.5之间时factor1在0到1之间线性变化当gradientFactor超过0.5时factor1恒为1。用这个factor1去驱动_BottomColor到_MiddleColor的Lerp。接着为第二个Lerp创建混合因子factor2factor2 saturate((gradientFactor - 0.5) * 2)。这样当gradientFactor小于0.5时factor2为0在0.5到1之间时factor2在0到1之间变化。用factor2去驱动第一个Lerp的输出结果即_BottomColor和_MiddleColor的中间色到_TopColor的第二次Lerp。连接主输出将第二次Lerp的最终输出颜色连接到Master Stack中Fragment阶段下的Base Color输入端口。至此一个基础的三色分段线性渐变网络就搭建完成了。你可以通过调整三个颜色属性实时在材质预览窗口看到效果。3.3 使用Gradient节点实现更灵活的渐变虽然两次Lerp的方法很直观但当需要超过三个颜色或更复杂的过渡如非线性时节点网络会变得复杂。Sample Gradient节点是更优的选择。创建Gradient属性在Blackboard中点击“”号选择Gradient类型创建一个属性如_SkyGradient。添加并配置节点在画布中添加Sample Gradient节点。将_SkyGradient属性拖到画布上生成一个节点并连接到Sample Gradient的Gradient端口。连接采样坐标将之前提取的UV的gradientFactor连接到Sample Gradient节点的Time端口注意这里Time端口在此语境下理解为采样位置。输出颜色将Sample Gradient节点的Color输出直接连接到Base Color。现在你只需要在材质面板上点击_SkyGradient字段就会弹出Unity标准的渐变编辑器。你可以像在Photoshop里一样自由添加、删除颜色游标调整游标位置和混合模式所有更改都会实时反映在材质上。这种方式对于美术同学来说尤其友好无需理解节点逻辑通过直观的渐变条就能创作出复杂的天空色彩。注意Sample Gradient节点在某些较旧的ShaderGraph版本或内置管线中可能不可用。如果找不到上述的分段Lerp法是可靠的备选方案。URP管线通常都支持此节点。3.4 添加动态效果基于时间的色彩变化静态的天空很美但动态的天空更有生命力。我们可以很容易地让渐变色彩随时间变化模拟昼夜循环。思路是让影响渐变采样位置的gradientFactor产生周期性偏移或者直接动态修改Gradient属性中的颜色值。前者实现起来更简单。创建时间变量添加一个Time节点搜索Time。我们可以使用其Time输出端口它会提供一个持续递增的时间值。生成循环因子利用Sine或Cosine节点结合时间可以生成一个在[-1, 1]之间循环的值。公式例如cycle (sin(Time * Speed) 1) / 2。这样cycle就会在[0,1]之间平滑地来回振荡。这里Speed是一个可以暴露为属性的Float用于控制昼夜循环的速度。影响渐变方法A影响UV将计算出的cycle值与原始的gradientFactor进行加法或乘法运算得到一个新的dynamicFactor再用于采样渐变。例如dynamicFactor frac(gradientFactor cycle * 0.2)。frac函数用于取小数部分防止值超出[0,1]范围。这样天空的整体色彩会缓慢地上下滚动。方法B影响颜色更高级的方法是将cycle值作为参数通过Lerp节点在两组不同的颜色如白天色组和夜晚色组之间混合然后将混合后的颜色赋给_TopColor等属性。这需要更多的属性定义和节点连接但控制更精细。4. 材质配置与场景应用ShaderGraph写好了接下来是如何用它。保存与创建材质保存你的ShaderGraph。然后在Project中右键该Shader文件选择Create - Material。Unity会自动生成一个使用此Shader的材质球命名为“2D_Sky_Gradient_Mat”。配置材质参数选中这个材质球在Inspector面板中你应该能看到所有在ShaderGraph中暴露的属性_TopColor,_MiddleColor,_BottomColor或_SkyGradient。尽情调整它们直到获得满意的天空效果。应用到场景在场景中创建一个空的GameObject或直接选择一个背景物体。为其添加Sprite Renderer组件。将刚才创建的材质球拖拽到Sprite Renderer的Material槽中。你需要为这个Renderer指定一个Sprite。可以创建一个纯色的2D Sprite在PS等工具中创建一个小尺寸纯色图片导入UnityTexture Type设为Sprite或者直接使用Unity自带的白色Sprite。由于我们的着色器会覆盖所有颜色所以Sprite本身是什么颜色并不重要重要的是它提供了网格和UV坐标。调整尺寸与排序调整GameObject的Transform缩放让这个Sprite覆盖整个相机视野。确保Sprite Renderer的Order in Layer设置正确使其位于所有场景元素的后面作为真正的背景。5. 性能优化与常见问题排查5.1 性能考量这个着色器本身非常轻量只包含简单的数学运算和纹理采样如果用了Gradient纹理。在移动设备上运行也毫无压力。但仍有几点可以优化批处理确保所有使用此天空材质的Sprite Renderer共享同一个材质实例而不是每个都有单独的材质实例。相同的材质实例可以进行动态合批减少Draw Call。避免每帧修改材质属性如果通过脚本动态修改颜色属性如实现昼夜循环尽量通过MaterialPropertyBlock来修改而不是直接获取并修改material。直接修改material会创建该材质的副本破坏合批。使用MaterialPropertyBlock则可以在保持合批的同时改变渲染参数。// 推荐的做法 SpriteRenderer renderer GetComponentSpriteRenderer(); MaterialPropertyBlock props new MaterialPropertyBlock(); renderer.GetPropertyBlock(props); // 获取现有的属性块 props.SetColor(_TopColor, newColor); // 修改属性字符串参数是Shader中属性的名字 renderer.SetPropertyBlock(props); // 应用回Renderer5.2 常见问题与解决问题1天空显示为粉色Missing Material现象场景中天空Sprite显示为洋红色。原因Sprite Renderer的Material槽为空或者指定的Shader不支持Sprite渲染。解决检查Material是否已正确赋值。并确认ShaderGraph的Active Targets中包含了Sprite。问题2渐变方向反了现象预期的顶部颜色出现在了底部。原因UV坐标的V轴原点方向理解有误。在默认的Sprite中UV的(0,0)是左下角(0,1)是左上角。如果你希望顶部对应V1那么连接是正确的。如果希望顶部对应V0只需在连接gradientFactor前使用One Minus节点即1 - V进行反转即可。问题3渐变有明显的色带Band-ing现象颜色过渡不平滑能看到一层层的色阶。原因在颜色空间精度较低的设备上或者渐变非常平滑柔和时可能会因为颜色量化而产生色带。解决在ShaderGraph中可以尝试为最终输出颜色添加非常微弱的噪点Simple Noise节点强度调至0.01左右利用噪点的随机性来打破色带。确保项目颜色空间设置为Linear线性空间而非Gamma。线性空间下的颜色混合更符合物理过渡也更平滑。在Project Settings - Player - Other Settings - Rendering中修改。如果使用Sample Gradient检查Gradient编辑器中的混合模式是否平滑。问题4动态变化不生效现象连接了Time节点但材质颜色没有动。原因Shader中使用了Time节点但材质的Shader模式是固定的。或者用于驱动变化的Speed等参数设置过小。解决首先确保场景在运行状态Play Mode下观察。其次检查Time节点后的计算逻辑是否正确特别是Speed参数是否被正确乘上。可以先将Speed设为一个较大的值如1看是否有快速变化以确认逻辑通路是否畅通。6. 效果扩展与创意应用掌握了基础的多色渐变后这个ShaderGraph的潜力远不止于静态天空。多层云朵叠加创建另一个ShaderGraph使用噪声纹理Simple Noise或Voronoi生成云朵形状并将其透明度与天空渐变背景进行混合。通过脚本控制云层的UV偏移就能实现云彩飘动的效果。将云层材质放在天空背景材质之上并设置合适的混合模式如Alpha Blend。环境光遮蔽与地形融合将渐变因子不仅基于UV的V坐标还与一张表示地形高度的灰度图Height Map结合。在地形较高的地方如山脉剪影让天空颜色更深模拟大气透视和遮挡效果使2D背景与前景地形更好地融合。交互式氛围变化将颜色属性与游戏状态绑定。例如当玩家生命值降低时通过脚本逐渐将天空渐变色向红色调调整当进入水下关卡时整体色调偏向蓝绿色。这只需要在脚本中动态修改材质属性即可实现。非垂直方向的渐变我们的例子基于V坐标。如果你想实现水平渐变从左到右只需使用UV的U坐标即可。甚至可以实现径向渐变从中心向四周这需要计算像素到中心点的距离作为混合因子。与2D灯光系统结合在URP中2D灯光可以与Sprite交互。确保你的ShaderGraph中Master Stack的Surface Type设置为Transparent并适当调整Alpha通道可以让天空背景与2D点光源、全局光产生有趣的互动比如模拟被夕阳照亮的天际线光晕。实现这些扩展的关键在于理解ShaderGraph的基本节点数学运算、纹理采样、UV操作并敢于组合实验。每次连接节点都可以在预览窗口立即看到反馈这种即时性正是可视化着色器编辑最大的魅力所在。从简单的三色天空开始逐步添加噪声、时间变量和外部输入你就能创造出独一无二、充满动态感的2D世界背景。