前言
项目中有一些第三方或者ASE生成的Shader代码,默认都是用的PBR光照,然而大部分材质BlinnPhong光照模型就够用了,尤其在移动端我们可以考虑优化。
如何使用最少的代码,将PBR使用的Metallic流程的材质参数快速转换到BlinnPhong光照呢,今天研究了一会儿效果还行,供大家参考。
Shader
//BlinnPhong额外加强高光,贴近PBR效果。
half4 UniversalFragmentBlinnPhongAddSpecular(InputData inputData, half3 diffuse, half4 specularGloss, half smoothness, half smoothnessPower, half3 emission, half alpha)
{
// To ensure backward compatibility we have to avoid using shadowMask input, as it is not present in older shaders
#if defined(SHADOWS_SHADOWMASK) && defined(LIGHTMAP_ON)
half4 shadowMask = inputData.shadowMask;
#elif !defined (LIGHTMAP_ON)
half4 shadowMask = unity_ProbesOcclusion;
#else
half4 shadowMask = half4(1, 1, 1, 1);
#endif
Light mainLight = GetMainLight(inputData.shadowCoord, inputData.positionWS, shadowMask);
#if defined(_SCREEN_SPACE_OCCLUSION)
AmbientOcclusionFactor aoFactor = GetScreenSpaceAmbientOcclusion(inputData.normalizedScreenSpaceUV);
mainLight.color *= aoFactor.directAmbientOcclusion;
inputData.bakedGI *= aoFactor.indirectAmbientOcclusion;
#endif
MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI);
half3 attenuatedLightColor = mainLight.color * (mainLight.distanceAttenuation * mainLight.shadowAttenuation);
half3 diffuseColor = inputData.bakedGI + LightingLambert(attenuatedLightColor, mainLight.direction, inputData.normalWS);
#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR) || defined(_MASKMAP)
half3 specularColor = LightingSpecular(attenuatedLightColor, mainLight.direction, inputData.normalWS, inputData.viewDirectionWS, specularGloss, smoothness) * (smoothnessPower * 16);
#endif
#ifdef _ADDITIONAL_LIGHTS
uint pixelLightCount = GetAdditionalLightsCount();
for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex)
{
Light light = GetAdditionalLight(lightIndex, inputData.positionWS, shadowMask);
#if defined(_SCREEN_SPACE_OCCLUSION)
light.color *= aoFactor.directAmbientOcclusion;
#endif
half3 attenuatedLightColor = light.color * (light.distanceAttenuation * light.shadowAttenuation);
diffuseColor += LightingLambert(attenuatedLightColor, light.direction, inputData.normalWS);
#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR) || defined(_MASKMAP)
specularColor += LightingSpecular(attenuatedLightColor, light.direction, inputData.normalWS, inputData.viewDirectionWS, specularGloss, smoothness) * (smoothnessPower * 16);
#endif
}
#endif
#ifdef _ADDITIONAL_LIGHTS_VERTEX
diffuseColor += inputData.vertexLighting;
#endif
half3 finalColor = diffuseColor * diffuse + emission;
#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR) || defined(_MASKMAP)
finalColor += specularColor;
#endif
return half4(finalColor, alpha);
}
//metallic、smoothness 均为采样后已混合好的结果值
half4 MetallicBlinnPhong(InputData inputData, half3 albedo, half3 specularColor, half metallic, half smoothness, half3 emission, half alpha)
{
const half smoothnessPower = smoothness;
smoothness = exp2(10 * smoothness + 1); //SimpleLit做法
const half oneMinusReflectivity = OneMinusReflectivityMetallic(metallic);
albedo = albedo * oneMinusReflectivity;
half3 specular = lerp(kDieletricSpec.rgb, albedo, metallic) * specularColor;
half4 color = UniversalFragmentBlinnPhongAddSpecular(
inputData,
albedo,
half4(specular.rgb, 0),
smoothness,
smoothnessPower,
emission,
alpha);
return color;
}
对比
对比图偷懒就不放了🫣。
我们以 URP 自带的地形着色器 Universal Render Pipeline/Terrain/Lit
举个例子。
- 修改前:
half4 color = UniversalFragmentPBR(inputData, albedo, metallic, /* specular */ half3(0.0h, 0.0h, 0.0h), smoothness, occlusion, /* emission */ half3(0, 0, 0), alpha);
- 修改后
half4 color = MetallicBlinnPhong( inputData, albedo, 1, metallic, smoothness, half3(0, 0, 0), alpha);