【Unity】为ShaderGraph制作自定义Main Light节点

概述

在百度第一页,关于这个问题基本上都来自于同一个文章,原文章地址我没有找到,因此附上其中一篇转载:在Unity 2019.2中扩展Shader Graph,实现自定义光照
然而和标题一样,这个实现是基于2019.2版本的,移植到更新的版本时会出各种各样的问题。

这篇博客记录了我尝试把主光源信息 (MainLight) 相关内容移植到目前 Unity 最新版本 (2020.2) 的 URP 渲染管线时遇到的问题与解决方案。

前置问题

这篇文章需要你至少懂得:

  • 在 Unity 中制作基于文件的自定义节点 (Custom Node) 与子图 (Sub Graph)。

同时如果你能够有下面这些能力,能获得更通顺的阅读体验(当然没有也行):

  • 下载了 Unity 2021.2 版本
  • 简单接触过 Unity 的 URP Shader 代码编写,并且使用过 Shader Graph。
  • 懂得访问不存在的网站,或者能够登录 Github。

解决方案

文章的解决方案基于 Github 上的项目 Shader Graph Custom Lighting Sample Project 实现,这个项目是基于 Unity 2019.2 的。
直接采用我在概述中提到的链接里的解决方案会报各种各样的错,甚至无法编译成功(对百度指指点点)。

这个 Github 仓库中有用的部分包括下面的路径,仓库中的其余部分是作者自己做的示例:

  • \Assets\Includes
  • \Assets\Sub Graphs

这两个文件夹下的文件提供了一些光照节点。其中 Includes 文件夹下的 .hlsl 文件是自定义节点的源文件。

直接移植功能基本正常,可能会出现一些小 bug,但只要它不出现,你就可以当它不存在。

这篇博客仅基于这个 Git 仓库制作 Get Main Light 节点获取主光源信息,解决了移植到 2021.2 版本时出现的无法接受来自主光源的阴影问题,如果其他版本也出现了这个问题,你也可以尝试这个博客的解决方案。
同时,稍微修改了一下原仓库中的节点设置,以提供更容易使用的精度 (Precision) 控制方法。

源文件 (.hlsl)

首先给出自定义主光源节点的源文件 MainLight.hlsl

#ifndef CUSTOM_LIGHTING_INCLUDED
#define CUSTOM_LIGHTING_INCLUDED

#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _ _SHADOWS_SOFT

void MainLight_float(float3 WorldPos, out float3 Direction, out float3 Color, out float DistanceAtten, out float ShadowAtten)
{
#if SHADERGRAPH_PREVIEW
    Direction = float3(-0.5, 0.5, 0);
    Color = float3(1, 0.95, 0.8);
    DistanceAtten = 1;
    ShadowAtten = 1;
#else
#if SHADOWS_SCREEN
    float4 clipPos = TransformWorldToHClip(WorldPos);
    float4 shadowCoord = ComputeScreenPos(clipPos);
#else
    float4 shadowCoord = TransformWorldToShadowCoord(WorldPos);
#endif
    Light mainLight = GetMainLight(shadowCoord);
    Direction = mainLight.direction;
    Color = mainLight.color;
    DistanceAtten = mainLight.distanceAttenuation;
    ShadowAtten = mainLight.shadowAttenuation;
#endif
}

void MainLight_half(float3 WorldPos, out half3 Direction, out half3 Color, out half DistanceAtten, out half ShadowAtten)
{
#if SHADERGRAPH_PREVIEW
    Direction = half3(0.5, 0.5, 0);
    Color = half3(1, 0.95, 0.8);
    DistanceAtten = 1;
    ShadowAtten = 1;
#else
#if SHADOWS_SCREEN
    half4 clipPos = TransformWorldToHClip(WorldPos);
    half4 shadowCoord = ComputeScreenPos(clipPos);
#else
    half4 shadowCoord = TransformWorldToShadowCoord(WorldPos);
#endif
    Light mainLight = GetMainLight(shadowCoord);
    Direction = mainLight.direction;
    Color = mainLight.color;
    DistanceAtten = mainLight.distanceAttenuation;
    ShadowAtten = mainLight.shadowAttenuation;
#endif
}

#endif

这个文件删除了原仓库CustomLighting.hlsl中的其余函数,仅保留了 MainLight_floatMainLight_half 用于不同精度的运算。

同时,在文件头部增加了三个 pragma 用来修复阴影问题。(修复之前的 ShadowAtten 没有办法正常使用,但其余 Out 参数正常)
其中,第一个 _MAIN_LIGHT_SHADOWS 是产生阴影是才会用到的参数,实际上并不需要(这里我们其实只需要接受阴影),因此删掉也完全OK。
第二个参数 _MAIN_LIGHT_SHADOWS_CASCADE 是关键的参数,用于接受阴影,不能缺少,缺少后就会出现 ShadowAtten 失效的问题。
第三个参数 _SHADOWS_SOFT 可以让阴影边缘柔化,如果注释掉可以得到硬边缘的阴影,可以根据需要采用或者删除。
增加的三个 pragma

#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _ _SHADOWS_SOFT

最后,修改了这两个函数在 Shader Graph 节点预览中的初始设置,使得修改是否发挥了作用更容易被检测到。
具体来说,我使不同精度下的光照方向不同,从而使切换精度时节点预览中的光照方向发生改变。另外,使光线不是纯白色而是微微泛黄(通过修改Color实现),让光照颜色加入运算时会对预览图产生影响。
对于 float 精度:

#if SHADERGRAPH_PREVIEW
    Direction = float3(-0.5, 0.5, 0);
    Color = float3(1, 0.95, 0.8);
    DistanceAtten = 1;
    ShadowAtten = 1;
#else

对于 half 精度:

#if SHADERGRAPH_PREVIEW
    Direction = half3(0.5, 0.5, 0);
    Color = half3(1, 0.95, 0.8);
    DistanceAtten = 1;
    ShadowAtten = 1;
#else

子图 (SubGraph)

子图保持与仓库相同的名字Get Main Light,在节点连线上与原仓库相同:

MainLight (Custom Fuction) 节点的精度 Precision 设置为 Use Graph Precision :

再在这个子图的 Graph Settings 中将 Precision 设置为 Switchable ,这样就可以在使用子图的时候直接在 Shader Graph 中更换精度了。

需要更换精度时,只需要在使用了这个子图的地方设置子图的节点属性中的精度 Precision 即可:

按照前文的设置,我们在更换精度时,节点预览界面中的光照方向应该会发生改变,从而让我们确信调用的函数确实发生了变化。

下载链接

链接:https://pan.baidu.com/s/1PS94YZHFGnF8GuCqY8GZGQ
提取码:rfun
文件包含一个 .hlsl 源文件,以及一个 Sub Graph,链接挂掉的话请评论或私信告知。

posted @ 2021-11-24 12:02  ParallelParadox  阅读(2559)  评论(0编辑  收藏  举报