ForwardPath渲染路径-基础

根据之前的学习,ForwardPath有两个Pass可以处理光照:

  • ForwardBase通道会立即渲染环境光、光照贴图、主方向光和不重要的顶点光。
  • ForwardAdd通道被用于增强逐像素光照,每个物体都被这样的光照亮。

Basepass用逐像素渲染的方向光以及所有SH和逐顶点光,可以实现效果:注意:需要开启multi_compile_fwbase计算光照衰减;

  • 光照贴图,但不会接受SH光
  • 环境光
  • 自发光
  • 可以有方向光阴影

Additional passes 计算其他影响物体的逐像素光照渲染物体,开启multi_compile_fwdadd 计算光照衰减。默认不支持绘制阴影,除非开启multi_compile_fwdadd _fullshadows指令。

简单实现的代码如下:

//ForwardBase-pass
struct a2v {
     float4 vertex : POSITION;
     float3 normal : NORMAL;
 };

struct v2f {
     float4 pos : SV_POSITION;
     float3 worldNormal : TEXCOORD0;
     float3 worldPos : TEXCOORD1;
     SHADOW_COORDS(2)//内置宏,2是TEXCOORD下标
 };

v2f vert(a2v v) {
     v2f o;
     o.pos = UnityObjectToClipPos(v.vertex);
     o.worldNormal = UnityObjectToWorldNormal(v.normal);
     o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
     TRANSFER_SHADOW(o);//内置宏计算阴影
     return o;
 }

fixed4 frag(v2f i) : SV_Target {
     fixed3 worldNormal = normalize(i.worldNormal);
     fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
     fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
     fixed3 diffuse = _Kd * _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));
     fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
     //使用了纯反射计算公式2*N平方*L-L
     fixed3 ref_dir = normalize(2*dot(worldNormal,worldLightDir)*worldNormal - worldLightDir);
     fixed3 specular = _Ks *_LightColor0.rgb * _Specular.rgb * pow(max(0, dot(ref_dir, viewDir)), _n);
     UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
     return fixed4(ambient + (diffuse + specular) * atten, 1.0);
}


//ForwardAdd-pass
//如果开启了#pragma multi_compile_fwdadd_fullshadows,就可以计算点光源和聚光源产生的阴影
struct a2v {
        float4 vertex : POSITION;
         float3 normal : NORMAL;
 };

struct v2f {
    float4 pos : SV_POSITION;
    float3 worldNormal : TEXCOORD0;
    float3 worldPos : TEXCOORD1;
    SHADOW_COORDS(2)
};

v2f vert(a2v v) {
    v2f o;
    o.pos = UnityObjectToClipPos(v.vertex);
    o.worldNormal = UnityObjectToWorldNormal(v.normal);
    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    TRANSFER_SHADOW(o);
    return o;
}

fixed4 frag(v2f i) : SV_Target {
    ffixed3 worldNormal = normalize(i.worldNormal);
    fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
    //内置函数UnityWorldSpaceLightDir
    /*#ifdef USING_DIRECTIONAL_LIGHT
        fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
    #else
        fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);
    endif*/
    
    fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));
    fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));//normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
    fixed3 ref_dir = normalize(2 * dot(worldNormal, worldLightDir) * worldNormal - worldLightDir); 
    fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(ref_dir,viewDir)), _n);
    //光照衰减
    /*#ifdef USING_DIRECTIONAL_LIGHT
        fixed atten = 1.0;
    #else
        #if defined (POINT)
            float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz;//把顶点所在世界坐标转换到光照空间
            fixed atten = tex2D(_LightTexture0,dot(lightCoord,lightCoord).rr).UNITY_ATTEN_CHANNEL;//dot模拟平方取结果两次组成采样uv坐标
        #elif defined (SPOT)
            float4 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1));
            fixed atten = (lightCoord.z > 0) * tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
        #else
            fixed atten = 1.0;
        #endif
    #endif*/
    //内置函数UNITY_LIGHT_ATTENUATION计算了光照衰减和阴影
    UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
    return fixed4((diffuse + specular) * atten, 1.0);
}
原文地址:https://www.cnblogs.com/baolong-chen/p/11708796.html