BR流程,贴图mask只有PBR的roughness、metallic、occlusion,不像战双那种PBRMask和ILM贴图全上。模型和法线做的很细,拆成两张图来存保证精度。
FragmentOutput frag(v2f i)
{
// Tex Sample
mainTex
pbrMask
bump
ilmMask
// VectorPrepare
lightDirWS
camDirWS
normalWS
NdotL
...
// Property prepare
emission
metallic
smoothness
...
// Remap NdotL ShadowArea
shadowArea calculate
NdotLRemap = 1 - shadowArea;
// TODO: Remap NdotV modify fresnel
NdotV
// shadowRamp
shadowRamp.rgb = Sample(_RampTex, 1 - shadowArea);
// Remap ShadowRamp , ILM SecondShadow
shadowRamp.rgb = lerp(_SecShadowColor.rgb, shadowRamp.rgb, ilm_AO);
// Direct PBR
NDF, G, F
// NDF GGX/Anisotropy specArea remap
NDF = NDF * ilm_SpecMask;
// SpecRamp
specRamp.rgb = Sample(_RampTex, specArea);
// Compose
directLightReuslt = (directDiffCol * shadowRamp + directSpecCol * specRamp) * mainlight.color * shadow * directOcclusion;
// Indirect PBR
// diffuse lerp Normal and Updir, lerp SHColor and self_envColor
indirDiff sampleSH RemapSHNormal
indirDiff * indirKd * albedo * occlusion
// specular use reflectionProbe or Cubemap or Matcap
indirSpec sampleCube
indirSpec * indirSpeFactor
// Other Emission, Rimlight, additional light
}
// Property prepare
half emission = 1 - mainTex.a;
half metallic = lerp(0, _Metallic, pbrMask.r);
half smoothness = lerp(0, _Smoothness, pbrMask.g);
half occlusion = lerp(1 - _Occlusion, 1, pbrMask.b);
half directOcclusion = lerp(1 - _DirectOcclusion, 1, pbrMask.b);
half3 albedo = mainTex.rgb * _BaseColor.rgb;
// NPR diffuse
float shadowArea = sigmoid(1 - halfLambert, _ShadowOffset, _ShadowSmooth * 10) * _ShadowStrength;
half3 shadowRamp = lerp(1, _ShadowColor.rgb, shadowArea);
//Remap NdotL for PBR Spec
half NdotLRemap = 1 - shadowArea;
#if _SHADOW_RAMP
shadowRamp = SampleDirectShadowRamp(TEXTURE2D_ARGS(_ShadowRampTex, sampler_ShadowRampTex), NdotLRemap);
#endif
// NdotV modify fresnel
// ilmShadow
shadowRamp.rgb = lerp(_SecShadowColor.rgb, shadowRamp.rgb, ilmAO);
// Direct
float3 directDiffColor = albedo.rgb;
float perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(smoothness);
float roughness = max(PerceptualRoughnessToRoughness(perceptualRoughness), HALF_MIN_SQRT);
float roughnessSquare = max(roughness * roughness, HALF_MIN);
float3 F0 = lerp(0.04, albedo, metallic);
float NDF = DistributionGGX(NdotH, roughnessSquare);
float G = GeometrySmith(NdotLRemap, NdotV, pow(roughness + 1.0, 2.0) / 8.0);
float3 F = fresnelSchlick(HdotV, F0);
// GGX specArea remap
NDF = NDF * ilmSpecMask;
float3 kSpec = F;
// LightUpDiff: (1.0 - F) => (1.0 - F) * 0.5 + 0.5
float3 kDiff = ((1.0 - F) * 0.5 + 0.5) * (1.0 - metallic);
float3 nom = NDF * G * F;
float3 denom = 4.0 * NdotV * NdotLRemap + 0.0001;
float3 BRDFSpec = nom / denom;
directDiffColor = kDiff * albedo;
float3 directSpecColor = BRDFSpec * PI;
#if _SHADOW_RAMP
float specRange= saturate(NDF * G / denom.x);
half4 specRampCol = SampleDirectSpecularRamp(TEXTURE2D_ARGS(_ShadowRampTex, sampler_ShadowRampTex), specRange);
directSpecColor = clamp(specRampCol.rgb * 3 + BRDFSpec * PI / F, 0, 10) * F * shadowRamp;
#endif
// Compose direct lighting
float3 directLightResult = (directDiffColor * shadowRamp + directSpecColor * NdotLRemap)
* mainLight.color * mainLight.shadowAttenuation * directOcclusion;
// Hair Spec
float anisotropicOffsetV = - viewDirWS.y * _AnisotropicSlide + _AnisotropicOffset;
half3 hairSpecTex = SAMPLE_TEXTURE2D(_HairSpecTex, sampler_LinearClamp, float2(UV1.x, UV1.y + anisotropicOffsetV));
float hairSpecStrength = _SpecMinimum + pow(NdotH, _BlinnPhongPow) * NdotLRemap;
half3 hairSpecColor = hairSpecTex * _SpecColor * hairSpecStrength;
// 本文中所用到的StencilUsage
//MaterialMask = 0b_1110_0000,
//...
//MaterialCharacterLit = 0b_0110_0000,
//MaterialCharFeatureMask = 0b_0110_0011,
//MaterialFringeShadow = 0b_0110_0001,
//MaterialEyelash = 0b_0110_0010,
Name "FringeShadowCaster"
Tags
{
"LightMode" = "GBufferFringeShadowCaster"
}
Stencil
{
Ref[_FriStencil]//MaterialCharacterLit
Comp[_FriStencilComp]//Equal
Pass[_FriStencilOp]//IncrementSaturate
ReadMask[_FriStencilReadMask]//MaterialFringeShadow
WriteMask[_FriStencilWriteMask]//MaterialFringeShadow
}
Cull Back
ZWrite Off
ColorMask [_FriColorMask]
...
FringeShadowCaster_v2f FringeShadowCasterVert(FringeShadowCaster_a2v v)
{
FringeShadowCaster_v2f o;
Light mainLight = GetMainLight();
float3 lightDirWS = normalize(mainLight.direction);
float3 lightDirVS = normalize(TransformWorldToViewDir(lightDirWS));
// Cam is Upward: let shadow close to face.
float3 camDirOS = normalize(TransformWorldToObject(GetCameraPositionWS()));
float camDirFactor = 1 - smoothstep(0.1, 0.9, camDirOS.y);
float3 positionVS = TransformWorldToView(TransformObjectToWorld(v.vertex));
positionVS.x -= 0.004 * lightDirVS.x * _ScreenOffsetScaleX;
positionVS.y -= 0.007 * _ScreenOffsetScaleY * camDirFactor;
o.positionHCS = TransformWViewToHClip(positionVS);
return o;
}
Name "FringeShadowReceiver"
Tags
{
"LightMode" = "GBufferFringeShadowReceiver"
}
Stencil
{
Ref[_FriStencil]//MaterialCharacterLit
Comp[_FriStencilComp]//Equal
Pass[_FriStencilOp]//Keep
ReadMask[_FriStencilReadMask]//MaterialFringeShadow
WriteMask[_FriStencilWriteMask]//MaterialFringeShadow
}
Cull Back
ZWrite Off
ColorMask [_FriColorMask]
// vert
// Face lightmap dot value
Light mainLight = GetMainLight();
float3 lightDirWS = mainLight.direction;
lightDirWS.xz = normalize(lightDirWS.xz);
_FaceRightDirWS.xz = normalize(_FaceRightDirWS.xz);
o.faceLightDot.x = dot(lightDirWS.xz, _FaceRightDirWS.xz);
o.faceLightDot.y = saturate(dot(-lightDirWS.xz, _FaceFrontDirWS.xz) * 0.5 + _ShadowOffset);
// frag
// FaceLightMap
float2 faceLightMapUV = UV1;
faceLightMapUV.x = 1 - faceLightMapUV.x;
faceLightMapUV.x = i.faceLightDot.x < 0 ? 1 - faceLightMapUV.x : faceLightMapUV.x;
half4 faceLightMap = SAMPLE_TEXTURE2D(_FaceLightMap, sampler_FaceLightMap, faceLightMapUV);
half faceSDF = faceLightMap.r;
half faceShadowArea = faceLightMap.a;
float faceMapShadow = sigmoid(faceSDF, i.faceLightDot.y, _ShadowSmooth * 10) * faceShadowArea;
shadowArea = (1 - faceMapShadow) * _ShadowStrength;
// Nose Spec
float faceSpecStep = clamp(i.faceLightDot.y, 0.001, 0.999);
faceLightMapUV.x = 1 - faceLightMapUV.x;
faceLightMap = SAMPLE_TEXTURE2D(_FaceLightMap, sampler_FaceLightMap, faceLightMapUV);
float noseSpecArea1 = step(faceSpecStep, faceLightMap.g);
float noseSpecArea2 = step(1 - faceSpecStep, faceLightMap.b);
float noseSpecArea = noseSpecArea1 * noseSpecArea2;
// alternative: noseSpecArea *= smoothstep(_NoseSpecMin, _NoseSpecMax, 1 - i.faceLightDot.y)
// Eye
// Parallax
float3 viewDirOS = TransformWorldToObjectDir(viewDirWS);
viewDirOS = normalize(viewDirOS);
float2 parallaxOffset = viewDirOS.xy;
parallaxOffset.y *= -1;
float2 parallaxUV = i.uv + _ParallaxScale * parallaxOffset;
// parallaxMask
float2 centerVec = i.uv - float2(0.5, 0.5);
half centerDist = dot(centerVec, centerVec);
half parallaxMask = smoothstep(_ParallaxMaskEdge, _ParallaxMaskEdge + _ParallaxMaskEdgeOffset, 1 - centerDist);
// Tex Sample
half4 mainTex = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, lerp(UV, parallaxUV, parallaxMask));
...
// Eye spec add
BlendOp [_BlendOp]// Add
Blend [_BlendSrc] [_BlendDst]// SrcAlpha One
// Eye shadow blend
BlendOp [_BlendOp]// Add
Blend [_BlendSrc] [_BlendDst]// SrcColor Zero
v2f vert (a2v v)
{
...
float offsetDist = _MULTIPASS_PARAMS.z * _FurLength;
float3 offsetPositionWS = TransformObjectToWorld(v.vertex);
float3 normalWS = TransformObjectToWorldNormal(v.normal);
offsetPositionWS += offsetDist * normalWS;
o.positionHCS = TransformWorldToHClip(offsetPositionWS);
o.positionWS = offsetPositionWS;
...
o.clipThreshold = _FurCLipMin + (_FurCLipMax - _FurCLipMin) * pow(_MULTIPASS_PARAMS.z, _FurPowShape);
return o;
}
FragmentOutput frag(v2f i)
{
UNITY_SETUP_INSTANCE_ID(i);
// Fur Clip
half furNoise = SAMPLE_TEXTURE2D(_FurNoise, sampler_FurNoise, i.uv.zw);
clip(furNoise - i.clipThreshold);
...
}
// Outline
if ((data.materialFlags & kCharacterMaterialFlagOutline) != 0)
{
float lightMask = 1 - smoothstep(0.5, 0.8, abs(lightDirVS.z));
float outLineLightResult = step(0.8, NdotL * NdotL) * alpha * lightMask;
#if defined(_DIRECTIONAL)
return half4(unityLight.color * outLineLightResult, 1);
#else
outLineLightResult = step(0.8, pow(NdotL, 3)) * alpha;
return half4(unityLight.color * outLineLightResult, 1);
#endif
}
苏ICP备17024786号