zoukankan      html  css  js  c++  java
  • 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的实现

    总结


    备注

    人生当苦,笑着看看
  • 相关阅读:
    Java基础之十五 泛型
    设计模式之工厂模式
    数据结构之散列
    程序员的自我修养十内存
    程序员的自我修养一温故而知新
    Java编程思想之二十 并发
    Java编程思想之十八 枚举类型
    Java基础之十六 数组
    Java编程思想之十四 类型信息
    Java基础之十三 字符串
  • 原文地址:https://www.cnblogs.com/BaiPao-XD/p/13967227.html
Copyright © 2011-2022 走看看