Skip to content

DirLight

zilch edited this page Mar 9, 2021 · 3 revisions

1. 目标

这一章的目标是为自定义SRP管线加入平行光源(Directional Light)的支持。为了降低复杂度,我们暂且只实现一盏平行光源的支持,并将其认定为主光源。

2. API分析

在此基础上,我们可以按照以下步骤来实现平行光源支持:

  • 从裁剪后的visibleLights中按照一定规则筛选出主光源
  • 将主光源的数据信息,传递到Shader中
  • 按照特定的光照模型,为物体编写Shader

3. 实现

3.1 提取主光源

我们按照以下策略来筛选并排序场景光源:

  • 遍历所有类型为Directional的灯光
  • 按照LightRenderMode优先级排序 ForcePixel > Auto, ForceVertex类型暂不考虑
  • LightRenderMode相同,则按照intensity(强度)优先级排序。

代码实现: 此处略

3.2 传递主光源数据到Shader

要在shader上支持平行光源,必须拿到以下两个数据

  • 灯光方向
  • 灯光颜色
var visibleLights = cullingResults.visibleLights;
var mainLightIndex = GetMainLightIndex(visibleLights);
if(mainLightIndex >= 0){
    var mainLight = visibleLights[mainLightIndex];
    var forward = - (Vector4)mainLight.light.gameObject.transform.forward; 
    //设置主灯光方向
    Shader.SetGlobalVector(ShaderProperties.MainLightDirection,forward);
    //设置主灯光颜色
    Shader.SetGlobalColor(ShaderProperties.MainLightColor,mainLight.finalColor);
}else{
    Shader.SetGlobalColor(ShaderProperties.MainLightColor,new Color(0,0,0,0));
}

ShaderProperties定义如下:

public class ShaderProperties{

    public static int MainLightDirection = Shader.PropertyToID("_XMainLightDirection");
    public static int MainLightColor = Shader.PropertyToID("_XMainLightColor");
}

3.3 Shader实现

3.3.1 变量定义

创建ShaderLibrary/Light.hlsl,在其中定义如下相同的两个全局变量:

//主灯光方向
float4 _XMainLightDirection;
//主灯光颜色
half4 _XMainLightColor;

这两个变量的值在3.2中,已从c#端传递进来。

3.3.2 光照模型

为了支持我们自己的平行光源,需要创建自己的物体渲染Shader。此处,为了简单起见,采用最基础的BlinnPhong光照模型来实现。 关于BlinnPhong光照模型可以参考文章:

BlinnPhong光照模型

光照模型分为漫反射和镜面反射(高光)两部分,漫反射部分采用Lambert实现,如下:

half4 LambertDiffuse(float3 normal){
    return max(0,dot(normal,_XMainLightDirection.xyz)) * _XMainLightColor;
}

高光部分实现如下:

half4 BlinnPhongSpecular(float3 viewDir,float3 normal,float shininess){
    float3 halfDir = normalize((viewDir  + _XMainLightDirection));
    float nh = max(0,dot(halfDir,normal));
    return pow(nh,shininess) * _XMainLightColor;
}

两者合并后:

//BlinnPhong光照模型
//positionWS为世界坐标
//normalWS为世界法线
half4 BlinnPongLight(float3 positionWS,float3 normalWS,float shininess,half4 diffuseColor,half4 specularColor){
    float3 viewDir = normalize( _WorldSpaceCameraPos - positionWS);
    return _XAmbientColor + LambertDiffuse(normalWS) * diffuseColor + BlinnPhongSpecular(viewDir,normalWS,shininess) * specularColor; 
}

可以看到,这里多出了一个_XAmbientColor,这是环境光,可以从RenderSettings.ambientLight中获取,并以同样的方式传递到Shader。

完整的shader可以参考项目源代码.

4. 最终效果

5. 更多

为SRP写shader的时候有几个注意点:

Clone this wiki locally