教程|使用Shader Graph实现程序化天空盒
本文来自荷兰开发者Tim Coster,作者分享了通过使用Unity Shader Graph如何轻松地制作自定义天空盒着色器。
本文我们将使用Shader Graph着色器视图,通过为天空盒每个图层创建函数部分,实现完全可定制的天空盒效果。我们会从天空颜色开始处理,然后添加太阳、云层和星星的效果,通过在场景中旋转定向光实现昼夜交替效果。
本文使用Unity 2019.2.4f1的LWRP模板进行开发。
小贴士:
荷兰已更名为“尼德兰”,轻量级渲染管线LWRP已更名为通用渲染管线URP。本文沿用作者原表述,请开发者在使用中注意不同版本Unity中渲染管线模版名称。
请发送“天空盒”到Unity官方微信后台,获取本文清晰的图片素材地址。
创建天空盒材质
1、创建Unlit Shader Graph
右键单击项目窗口,选择Create > Shader > Unlit Graph。
2、创建新材质
在项目窗口创建新材质,把新建的着色器视图资源拖到材质上,给材质指定着色器。
3、 给天空盒指定材质
打开Window > Rendering > Lighting Settings,把材质拖到Environment设置的Skybox Material属性栏中。
4、打开Shader Graph
双击项目窗口中天空盒的着色器视图文件,打开该视图。
5、简单的渐变天空效果测试
为了确保一切正常工作,我们可以创建非常简单的渐变天空盒进行测试,只需使用归一化世界位置的绿色通道(即Y轴),把该数据传入Sample Gradient节点即可。
归一化世界位置的范围在-1到1之间,-1表示世界的底部,1表示世界的顶部中心位置,为了让该数值可以传入Simple Gradient节点的Time输入,我们需要把数值重映射为0到1的范围。
如果可以在整个天空盒使用Simple Gradient节点的话,处理过程会非常方便,但目前Shader Graph无法把Simple Gradient节点作为属性进行公开。为了避免在调整这部分时反复打开视图,我们会使用三种颜色属性,并把它们混合起来。
添加天空图层
我们的Shader Graph节点设置会混合三个公开的HDR颜色属性,分别用于天空、地平线和地面。
我们可以使用Exponent1属性来调整地平线和地面之间的渐变柔和度,使用Exponent2属性来调整地平线和天空之间的渐变柔和度,使用Intensity属性来调整总体的亮度。
通过使用HDR颜色,我们可以让天空发出的光线接近地平线中点的颜色。如果把HDR颜色和摄像机上的泛光后期效果结合起来,我们可以实现更好的效果。
添加太阳
现在,我们给天空盒添加太阳,太阳的位置基于场景定向光的方向,因此我们首先创建获取场景中主光源方向的自定义Main Light节点。
了解创建自定义主光源节点的方法,请阅读:《在Unity 2019.2中扩展Shader Graph,实现自定义光照》。
创建自定义节点并在其它视图重用的最好方法是:首先创建Custom Function节点,然后把它转换为Subgraph子视图。
自定义节点函数.hlsl文件和SubGraph子视图都可以通过下面链接进行下载,文件分别位于Subgraphs文件夹和CustomNodes文件夹中:
https://github.com/Timanious/MyShaderGraphs/tree/master/MyShaderGraphs_Project/Assets/_ShaderGraphs
如果想创建自定义节点,我们可以按照以下步骤创建Main Light节点。
1、创建Custom Function节点
右键单击Shader Graph空白部分,创建Utility分类下的Custom Function节点。
2、添加输入参数和输出参数
点击Custom Function节点上的齿轮图标,添加以下输入和输出参数。
3、函数名称
该节点使用的函数名称在.hlsl文件中是MainLight,因此我们在Name字段输入MainLight。
4、添加HLSL包含文件
我们发现,如果把类型设为字符串,自定义函数节点会有内联函数的选项。如果使用独立的HLSL包含文件,我们可以取得更高的灵活性,HLSL文件可以包含更加复杂的函数,而且我们可以让所有功能都很好地组织在一个位置。
Unity尚未提供方便的菜单选项来创建HLSL包含文件资源,因此我必须自己创建该文件。例如:我可以创建常见的Unlit .shader文件,把文件扩展名改为.hlsl,然后移除其中的代码。
我创建了名称为CustomLighting.hlsl的文件,并把下面脚本的代码复制到该文件中:
github.com/Timanious/MyShaderGraphs/blob/master/MyShaderGraphs_Project/Assets/_ShaderGraphs/CustomNodes/CustomLighting.hlsl
5、指定.hlsl文件
把CustomLighting.hlsl文件拖到节点的Source属性栏,把它指定给自定义函数节点。
6、转换为子视图
右键单击Custom Function节点,选择Convert to Sub-graph,命名为MainLight。
7、添加子视图输出
打开新的子视图,把Custom Function节点的WorldPos输入连接到Position节点。然后在Output节点创建4个新的输入,它们分别对应着Custom Function节点的4个输出。
8、组织子视图节点
如果此时观察Blackboard面板,我们会发现在子视图名称下方,可以指定子视图在节点创建菜单的位置。
如果改为Input/Lighting,该子视图会和其它Input/Lighting分类下的节点保存在相同目录,以便我们轻松找到它。
9、指定太阳的位置
现在我们能够获取场景的主光源方向,我们可以使用该信息来确定太阳的位置。
这个视图会从观察方向和主光源反方向获取点积。太阳的大小、光强和柔和度可以通过Radius、Intensity和Exponent变量来调整。场景中主光源的颜色也会给太阳提供颜色。
10、把太阳添加到天空
我们使用Add节点,把太阳的输出和天空颜色相加。
添加云层
构造云层需要很多步骤,但过程很简单。下面我会逐步构造云层,你可以自行决定自己的云层需要哪些信息。
为了更好展示操作步骤,大部分示例使用了通过Photoshop创建的RGB圆形测试图,并通过CatlikeCoding的NumberFlow Unity插件创建了噪声云纹理和法线贴图,NumberFlow插件也是一个节点工具,用于创建程序化纹理。
下载本文使用的纹理:
https://timcoster.wordpress.com/2019/09/09/tileable-clouds-texture/
如果希望使用自定义纹理,那么最好使用透明的.PNG文件,而不是黑色和白色构成的图像。这样云不会带有灰色边缘,而是带有白色透明边缘。此外,我们还要确保纹理拥有Alpha通道。
1、添加云层
下图的节点设置会为云的纹理生成无限大的平面图层。
我们可以使用Blend节点,把透明云纹理和天空颜色及太阳混合起来。
通过在Blend节点的Opacity输入点连接纹理的Alpha通道,并把Blend节点设为Overwrite模式,我们可以取得不错的结果。
2、添加远处的平铺效果
如果给远处平铺效果添加属性,我们可以让地平线和摄像机的距离看起来更近。
对于RGB圆形示例,我们把属性值设为0.1,而对于云层,我们把该值设为0.25。
3、添加纹理平铺
添加纹理平铺属性后,我们可以控制纹理的大小,我们在此把该属性设为0.05。
4、添加纹理偏移
我们添加Vector2类型的云纹理偏移属性,该属性将在之后用于实现云的动画效果。
5、添加Cutoff属性
我们在此添加Distance属性和Cutoff属性,从而控制云向地平线方向逐渐消失的效果。在本示例中,Distance值设为0.8,Cutoff值设为25。
6、添加Opacity属性
我们可以通过让云纹理的Alpha通道乘以Vector1类型的不透明度属性,添加不透明效果。下面的示例中,Opacity值设为0.5。
7、添加法线贴图
我们可以添加对法线贴图纹理的支持,根据光线方向来确定深度。在定向光向下直射时,这样会在云的底部呈现阴影效果。
为法线贴图添加Sample Texture节点时,我们要确保把节点类型设为Normal。同时还要在Blackboard面板上,把云法线贴图纹理的属性设为Bump模式。
自定义Main Light函数节点在子视图之外使用,因为它使用的是切线位置,而不是世界位置。我们可以从Main Light子视图复制自定义节点。
本示例中,我们把法线贴图强度设为0.8。
8、添加亮度
为了控制云的亮度,我们添加一个Vector1属性、Add节点、Subtract节点和Multiply节点。
把Brightness亮度值减去1,然后加上Blend节点的输出结果。
把Brightness值减去1后,该值为1时会呈现正常的亮度,而该值为0时则完全没有光亮,从而避免出现Brightness值为0时出现正常的光亮。
我们把法线贴图强度乘以Brightness属性,然后把结果传入Blend节点,让Brightness值影响Blend节点的输出。
下图中,左图的Brightness值设为0.1,右图的Brightness值设为1.5。
9、添加定向光颜色
如果把纹理乘以Main Light颜色输出,我们可以让定向光的颜色影响云的颜色。下面的示例图中,我们把光线颜色分别设为浅橙色和淡蓝色。
10、整理图层
为了让不同图层的叠加效果更自然,我们可以整理视图,让顺序变为“太阳+天空+云层”,最靠近摄像机的部分会最后添加。
添加夜晚的天空
现在,我们得到了出现太阳的天空和基础云层,就可以开始添加星星。
为了在添加后更好地看到星星,如果可以对混合部分使用阳光的方向,自动把白天天空颜色转为夜晚天空颜色,这样会大大方便我们的工作。
我们可以使用类似太阳部分的位置输入,让它在颜色a和颜色b之间插值,同时对天空的Exponent1和Exponent2属性执行相同的操作,让地平线在晚上显得更细。
在添加星星前,我们要调整天空颜色图层。
1、添加夜晚天空的属性
添加3个Color属性,用于控制夜晚的天空颜色,添加2个Vector1属性,用来调整夜晚天空的柔和度。
2、插值颜色
使用Lerp节点调整颜色属性和柔和度属性,然后按照下图部分把它们连接起来。
第一张图是原来的天空视图,第二张图是新的天空图层,我们在图中选中了新增的节点,因此会出现蓝色边框。
添加星星
现在,我们可以过渡到夜晚的天空颜色,因此可以添加星星图层到天空盒上。本文使用了非常简单的黑白星星纹理,你也可以使用效果更加丰富的纹理。
1、球体映射空间
下面的节点设置可以提供星星纹理的球体映射。由于在创建时没有让纹理正好包围球体,因此在下图出现了一些瑕疵。纹理在地平线附近时,纹理会逐渐消失,所以瑕疵在这里影响不大。
2、添加强度
把星星纹理的RGB输出乘以强度值,从而控制星星的亮度。
3、添加纹理偏移
我们给UV坐标添加Vector2类型的偏移值,然后把结果导入纹理,这样可以控制星星纹理的位置,以便后面添加动画。
4、添加地平线的淡化效果
为了让地平线附近的星星逐渐淡出,我们可以使用Power节点和Fadeout属性,在此对纹理进行乘法计算。
5、添加昼夜交替效果
在Lerp节点的T输入点使用光线方向的点积结果,然后把Lerp节点结果乘以之前的结果,我们便可添加昼夜交替的过程。
在定向光向上时,我们可以看到星星,而在定向光向下时,则无法看到星星。
6、添加星星图层
整理视图,把星星部分放在视图的上方。星星的距离最远,因此我们要首先绘制星星图层。
我们把所有部分结合起来,然后在拥有地面的小型测试场景使用该着色器。
在场景中,指数雾的数值很小,大约是0.0006左右,我也启用了一些后期处理效果,让天空盒效果有更接近游戏的感觉。
小结
使用Shader Graph实现程序化天空盒为大家介绍到这里,你也可以添加落日效果,使用C#组件来让定向光的强度受到方向影响、对云层进行亮度、定向光颜色和云层颜色相加的调整,从而实现一个精致的天空盒效果。
下载Unity Connect APP,请点击此处。观看更多Unity官方精彩视频,请关注“Unity官方”B站账户。
扫码在“技术交流“群聊组中提问,Unity社区和官方团队帮你解答。
推荐阅读
Unite Shanghai 2020正式启动,暖冬特惠票热销中
Made with Unity | 中国元素海外开花,打造西游新玩法
官方活动
Unite Shanghai 2020正式启动,暖冬特惠票热销中,购票即可获得多款Asset Store特定精品资源5折优惠码。[了解详情......]
AR应用创作大赛Unity与商汤科技强强联手举办AR应用创作大赛,帮助开发者了解使用商汤AR SDK进行开发的方法,高效的进行AR内容创作,推进AR应用创新与落地。[了解详情...]
喜欢本文,请点“在看”