XDRender_ObjPass_ShaderMode_Cloth(1) 布料渲染模型 皮革

XDRender_ObjPass_ShaderMode_Cloth(2) 布料渲染模型 皮革(Leather)

image-20201114235233998

前言


正文

皮革特性

先来看啥是皮革, 以及皮革的视觉

先来句古话: 唐孔颖达疏:“革是肤内之厚皮革也。

现代语言:动物的皮去毛加工的熟皮,这里不包含后期的合成皮.

头层皮(Kraft first layer)是带有粒面表皮的牛、羊、猪皮

纤维比较紧密

image-20201114163302957

二层皮(split leather)

是用片皮机剖层而得,是纤维组织较疏松的二层部分, 这里注意有了一部分疏松纤维的特性,

image-20201114163344071

人造革

image-20201114162749925

image-20201114162809380

下面我们来看Unreal的皮革部分

image-20201114170416524

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

image-20201114220359861

二、加入新的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“整个物体的感觉.

image-20201115000913466

这里我用的是(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;//;  

image-20201114221740689

四、高光的处理

直接上模型,然后说明

法线分布, 可以看到我们减弱了粗糙度的影响

几何分布还是使用了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;
}

Unreal的实现

HDRP的实现

总结


备注

人生当苦,笑着看看
原文地址:https://www.cnblogs.com/BaiPao-XD/p/13967227.html