XDRender_ObjPass_ShaderMode_Cloth(1) 布料渲染模型 皮革
XDRender_ObjPass_ShaderMode_Cloth(2) 布料渲染模型 皮革(Leather)
前言
正文
皮革特性
先来看啥是皮革, 以及皮革的视觉
先来句古话: 唐孔颖达疏:“革是肤内之厚皮革也。
现代语言:动物的皮去毛加工的熟皮,这里不包含后期的合成皮.
头层皮(Kraft first layer)是带有粒面表皮的牛、羊、猪皮
纤维比较紧密
二层皮(split leather)
是用片皮机剖层而得,是纤维组织较疏松的二层部分, 这里注意有了一部分疏松纤维的特性,
人造革
下面我们来看Unreal的皮革部分
XD实现过程
由于皮革鉴于金属和电解质也就是半导体. 这里我先使用前面制作的DefaultLitMode,然后在基础上做一个ClothMode(主要是用来处理扩散和高光).
其中自定义SufaceData可以参考HLSL结构章节, 这里也是为乐后续我们自己做一些编辑器做好准备.
一、材质属性填充
1、需要填充的Surface
基础:BaseColor、Norma、Rough、Met
扩展: SurfaceColor, CustomData两个
2、Normal + 粗糙度
这里我直接增加Normal的Tiling, 为此我们在CommonMacro中加入宏
#define TRANSFORM_TEX(tex, name) ((tex.xy) * name##_ST.xy + name##_ST.zw)
然后按照TRANSFORM_TEX规则,调用求出UV
#if _NORMALMAP
//Normal Tiling
float2 normalUV = TRANSFORM_TEX(input.baseUV,_NormalMap);
float3 normalTS = SampleNormal(normalUV, TEXTURE2D_ARGS(_NormalMap, sampler_NormalMap), 1.0);
#if _REVERCE_NORMAL
normalTS.xy = -1 * normalTS.xy;
#endif
outSurfaceData.normalWS = TransformTangentToWorld(normalTS,half3x3(input.tangentWS.xyz, input.bitangentWS.xyz, input.normalWS.xyz));
#else
outSurfaceData.normalWS = input.normalWS;
#endif
二、加入新的ShaderMode
其实可以完全在Default做出来, 但为了后续方面. 统一建立一个ClothMode来处理不同的Cloth.
FDirectLightingResult ClothLitBxDF(
FLightMaterial pBRDF,float3 lightColor
,float3 normal,float3 lightDir,float3 viewDir
)
{
}
三、扩散部分
这里我要开始处理漫反射的扩散部分, 可以利用WrapLight来模拟扩散表面的灯光, 我们知道Diff 最后还要做一次乘法Dot(N,L), 所以可以对曲线做一些变化.
Wrap Light直译的话就是用光包裹住整个物体,让原来黑暗(即N*L<=0)的部分亮起来的意思。如果是标准Lambert的话,有很大一部分地方是黑的,让整个物体显得比较平,而Wrap Light会有一个光的过度,并且"soft“整个物体的感觉.
这里我用的是(Cos + W) / Pow2(1+W), 当然还有一种Lum方式.
inline float LightSurfaceWrap(float nl, float w)
{
return saturate((nl + w) / Pow2(1.0 + w));
}
然后用来散开法线和光夹角, 这个散度就是W(0-1)来控制.
float specFabExtendScale = saturate(pBRDF.customData.y);
BxDFContext context;
Init(context,normal,viewDir,lightDir);
float FabricScatterSale = saturate(pBRDF.surfacecolorScale);
float3 FuzzColor = pBRDF.surfacecolor * LightSurfaceWrap(context.NoL,FabricScatterSale);
float diffcuseTerm = Diffuse_Burley_Disney(pBRDF.perceptualRoughness,context.NoV,context.NoL,context.VoH);
float3 diffuseResult = pBRDF.diffuse * diffcuseTerm * lightColor * FuzzColor;//;
四、高光的处理
直接上模型,然后说明
法线分布, 可以看到我们减弱了粗糙度的影响
几何分布还是使用了Smith. (皮革单独)
菲涅尔继续使用正常.
inline float FabricD (float NdotH)
{
return 0.96 * pow(1 - NdotH, 2) + 0.057;
}
然后用一个ClothValue来差值
float NDF = D_GGX_Unity(pRoughness*pRoughness,pContext.NoH);
float G = GeometrySmith(pContext.NoV, pContext.NoL, pRoughness);
float VxD= pRoughness > 0.8 ? 1 * FabricD (pContext.NoH) : NDF * G;
最后填一下
///<Summer>
//布料GGX镜面
///</Summer>
inline float3 FabricSpecularGGX(float3 SpecColor,float pRoughness, BxDFContext pContext)
{
float NDF = D_GGX_Unity(pRoughness*pRoughness,pContext.NoH);
float G = GeometrySmith(pContext.NoV, pContext.NoL, pRoughness);
float VxD= pRoughness > 0.8 ? 1 * FabricD (pContext.NoH) : NDF * G;
float specularTerm = max(0,VxD);
#ifdef UNITY_COLORSPACE_GAMMA
specularTerm = sqrt(max(1e-4h, specularTerm));
#endif
specularTerm = max(0, specularTerm * pContext.NoL);
float3 F = BaseFresnelSchlick(pContext.NoV,SpecColor);
float3 nominator = specularTerm * max(0,NDF * G) * F;
float denominator = 4.0 * pContext.NoV * pContext.NoL + 0.001;
float3 specular = nominator / denominator;
return specular;
}
然后我们做插值,插值的值公开出来.可以从CustomData中获取
FDirectLightingResult DirectLightResult;
DirectLightResult.Diffuse = diffuseResult;//SubSurfaceWrap(context.NoL,FabricScatterSale);//diffuseResult;
DirectLightResult.Specular = lerp(specdefault,specFab,clothValue);
DirectLightResult.Transmission = 0;
五、最后总体
输入部分
Pass
{
Name "Unlit"
Tags {"LightMode" = "DefaultLit"}
HLSLPROGRAM
#include "Packages/com.xdgameengine.unity/EngineResource/ShaderLibrary//CoreExtends/XDArt_ShaderMode_DefaultLitInput.hlsl"
TEXTURE2D(_DiffcuseMap);
SAMPLER(sampler_DiffcuseMap);
float4 _DiffcuseMap_ST;
TEXTURE2D(_NormalMap);
SAMPLER(sampler_NormalMap);
float4 _NormalMap_ST;
TEXTURE2D(_MetRouAOMap);
SAMPLER(sampler_MetRouAOMap);
float4 _MetRouAOMap_ST;
void SurfaceDataConfig(DefaultLit_Varyings input, out SurfaceData outSurfaceData)
{
#if _DIFFCUSE_MAP
float2 albedoUV = TRANSFORM_TEX(input.baseUV,_DiffcuseMap);
half4 albedoAlpha = SAMPLE_TEXTURE2D(_DiffcuseMap,sampler_DiffcuseMap, albedoUV);
#else
half4 albedoAlpha = _BaseColor;
#endif
outSurfaceData.alpha = albedoAlpha.a;
outSurfaceData.albedo = albedoAlpha.rgb;
#if _NORMALMAP
//Normal Tiling
float2 normalUV = TRANSFORM_TEX(input.baseUV,_NormalMap);
float3 normalTS = SampleNormal(normalUV, TEXTURE2D_ARGS(_NormalMap, sampler_NormalMap), 1.0);
#if _REVERCE_NORMAL
normalTS.xy = -1 * normalTS.xy;
#endif
outSurfaceData.normalWS = TransformTangentToWorld(normalTS,half3x3(input.tangentWS.xyz, input.bitangentWS.xyz, input.normalWS.xyz));
#else
outSurfaceData.normalWS = input.normalWS;
#endif
outSurfaceData.specular = _SpecColor;
outSurfaceData.metallic = _Metallic;
outSurfaceData.smoothness = _Smoothness;
outSurfaceData.occlusion = _OcclusionStrength;
#if _SAMPLE_MRAO_MAP
float2 mraoUV = TRANSFORM_TEX(input.baseUV,_MetRouAOMap);
float4 mrao = SAMPLE_TEXTURE2D(_MetRouAOMap,sampler_MetRouAOMap, mraoUV);
#if _SAMPLE_MET
outSurfaceData.metallic = mrao.r;
#endif
#if _SAMPLE_ROUGH
outSurfaceData.smoothness = 1 - mrao.g;
#endif
#if _SAMPLE_AO
outSurfaceData.occlusion = mrao.b;
#endif
#endif
outSurfaceData.emission = _EmissionColor;
outSurfaceData.clearCoat = _ClearCoat;
outSurfaceData.clearCoatGloss = _ClearCoatGloss;
outSurfaceData.surfaceColor = _SurfaceColor;
outSurfaceData.customData = _CustomData;
}
#pragma shader_feature_local _DIFFCUSE_MAP
#pragma shader_feature_local _NORMALMAP
#pragma shader_feature_local _REVERCE_NORMAL
#pragma shader_feature_local _RECEIVE_SHADOWS_ON
#pragma shader_feature_local _APPLY_DEPTHFOG_ON
#pragma shader_feature_local _SAMPLE_MRAO_MAP
#pragma shader_feature_local _SAMPLE_MET
#pragma shader_feature_local _SAMPLE_ROUGH
#pragma shader_feature_local _SAMPLE_AO
#pragma shader_feature_local _SHADERMODE_CLOTH
#pragma vertex DefaultLit_Vertex
#pragma fragment DefaultLit_Fragment
//自定义的输入过程
#define CustomSurface SurfaceDataConfig
#include "Packages/com.xdgameengine.unity/EngineResource/ShaderLibrary//CoreExtends/XDArt_ShaderMode_DefaultLit.hlsl"
ENDHLSL
}
六、扩充部分
次表面颜色
源码链接
///<Summer>
//默认的BRDF-直接光照
///</Summer>
FDirectLightingResult ClothLitBxDF(
FLightMaterial pBRDF,float3 lightColor
,float3 normal,float3 lightDir,float3 viewDir
)
{
float clothValue = saturate(pBRDF.customData.x);
float specFabExtendScale = saturate(pBRDF.customData.y);
BxDFContext context;
Init(context,normal,viewDir,lightDir);
float FabricScatterSale = saturate(pBRDF.surfacecolorScale);
float3 FuzzColor = pBRDF.surfacecolor * LightSurfaceWrap(context.NoL,FabricScatterSale);
float diffcuseTerm = Diffuse_Burley_Disney(pBRDF.perceptualRoughness,context.NoV,context.NoL,context.VoH);
float3 diffuseResult = pBRDF.diffuse * diffcuseTerm * lightColor * FuzzColor;//;
float3 specdefault = SpecularGGX(pBRDF.specular,pBRDF.roughness,context) * lightColor;
#if 0
// Cloth - Asperity Scattering - Inverse Beckmann Layer
float3 specFab = FabricSpecularUnreal(pBRDF.specular,pBRDF.roughness,context)* lightColor;
#else
//this is fab do extend
float3 specFab = FabricSpecularGGX(pBRDF.specular,pBRDF.roughness,context) * lightColor;
#endif
//--绒部分-
........
//--绒部分结束-
FDirectLightingResult DirectLightResult;
DirectLightResult.Diffuse = diffuseResult;//SubSurfaceWrap(context.NoL,FabricScatterSale);//diffuseResult;
DirectLightResult.Specular = lerp(specdefault,specFab,clothValue);
DirectLightResult.Transmission = 0;
return DirectLightResult;
}