继续分析GetSurfaceAndBuiltinData函数。
// We perform the conversion to world of the normalTS outside of the GetSurfaceData
// so it allow us to correctly deal with detail normal map and optimize the code for the layered shaders
float3 normalTS;
float3 bentNormalTS;
float3 bentNormalWS;
float alpha = GetSurfaceData(input, layerTexCoord, surfaceData, normalTS, bentNormalTS);
GetNormalWS(input, normalTS, surfaceData.normalWS, doubleSidedConstants);
方法定义在LitDataIndividualLayer.hlsl,具体代码比较长,不放出来了。
我们再看一下SurfaceData结构体:
struct SurfaceData
{
uint materialFeatures;
float3 baseColor;
float specularOcclusion;
float3 normalWS;
float perceptualSmoothness;
float ambientOcclusion;
float metallic;
float coatMask;
float3 specularColor;
uint diffusionProfile;
float subsurfaceMask;
float thickness;
float3 tangentWS;
float anisotropy;
float iridescenceThickness;
float iridescenceMask;
float3 geomNormalWS;
float ior;
float3 transmittanceColor;
float atDistance;
float transmittanceMask;
};
位于Lit.cs.hlsl,是自动生成的。这个结构体就展示了GetSurfaceData的作用。
下面只选一部分分析:
-
detailNormalTS = SAMPLE_UVMAPPING_NORMALMAP_AG(ADD_IDX(_DetailMap), SAMPLER_DETAILMAP_IDX, ADD_IDX(layerTexCoord.details), ADD_IDX(_DetailNormalScale));
detailNormalTS获取了DetailMap上的ag两个通道(压缩后a不受影响还是8位,精度较高)。
-
normalTS = ADD_IDX(GetNormalTS)(input, layerTexCoord, detailNormalTS, detailMask);
和buildin不同,除多了UV相关的处理,混合Detail的normal还用了Reoriented Normal。具体可以参考https://blog.selfshadow.com/publications/blending-in-detail/。
-
bentNormalTS = ADD_IDX(GetBentNormalTS)(input, layerTexCoord, normalTS, detailNormalTS, detailMask);
GetBentNormalTS定义在LitDataIndividualLayer.hlsl,BentNormal主要是采样间接光用的,相关内容可以看UE4的文档。
- materialFeatures定义了材质属于哪种类型,在后续的代码中每种类型都会有相应的代码处理。
-
#ifdef _MATERIAL_FEATURE_SPECULAR_COLOR // Require to have setup baseColor // Reproduce the energy conservation done in legacy Unity. Not ideal but better for compatibility and users can unchek it surfaceData.baseColor *= _EnergyConservingSpecularColor > 0.0 ? (1.0 - Max3(surfaceData.specularColor.r, surfaceData.specularColor.g, surfaceData.specularColor.b)) : 1.0; #endif
单色能量守恒:选则Specular Color时,albedo应该乘上1 - _SpecularColor保证能量守恒,但是效果不好,如Specular Color是(1.0,0.0,0.0),albedo(1.0,1.0,1.0),那么albedo就会计算成(0.0,1.0,1.0)。所以一般用单色最大值。
void GetNo