Unity Shader 布料渲染(丝袜)

Unity Shader 布料渲染(丝袜)

  • 现实中的丝袜效果
  • 丹尼尔值
  • 纤维的特性
  • 分析
    • 效果截图:
      • Weak:
      • Normal:
      • Strong:
    • 属性值定义:
    • 丹尼尔值与拉伸程度
    • 边缘度的计算
    • 完整Shader代码

现实中的丝袜效果

Unity Shader 布料渲染(丝袜)_第1张图片
主要材质为 约90%聚酰胺纤维(锦纶/尼龙)+ 约10%聚氨酯纤维(氨纶)
基本上可以推测这种材质的金属性(Metallic)为0,而光滑度(Smoothness)则根据种类不同会有较大区别。

丹尼尔值

各种丝袜的厚薄也有区别,“D”或“Denier”是指纤维的纤度单位。5D、10D几乎透明,100D以上则几乎不透,很好理解,请看下图:
Unity Shader 布料渲染(丝袜)_第2张图片
在Shader里我们采用Denier值来表示丝袜的厚薄程度。

纤维的特性

我们可以发现一种现象——靠近腿部中央的位置丝袜颜色较淡,并且如果丝袜够薄甚至会显出底下皮肤的颜色,而越靠近腿两侧丝袜颜色则会越深。丝袜由无数细小交错的纤维组成,所以正对视线的纤维是最稀疏的,而越靠近腿部轮廓的纤维则对于观察者来说越显得密集。
Unity Shader 布料渲染(丝袜)_第3张图片

分析

基于PBR,对丝袜纤维的密集程度定义一个属性 疏密度(Density) ,取值范围0(几乎没有纤维)到 1(完全被纤维覆盖)。依据疏密度提供颜色给Albedo通道,疏密度越高显现更多丝袜颜色,越低则显现皮肤颜色。

计算疏密度需要三部步骤:
1.丹尼尔值对整体疏密度的影响。
2.受丝袜良好弹性影响,需要一张灰度贴图来控制不同区域的拉伸程度,拉伸越大疏密度越低。
3.受观察者视线的影响,丝袜平面与观察者视线角度越小时,疏密度越大。称其为边缘度影响。

效果截图:

Weak:

Normal:

Strong:

属性值定义:

    Properties{
        _Denier("Denier", Range(5,120)) = 25.0
        _DenierTex("Density Texture", 2D) = "black"{}
		_Smoothness("Smoothness", Range(0,1)) = 0.1
		_Metallic("Metallic",Range(0,1)) = 0.1
        [Enum(Strong,6,Normal,12,Weak,20)] _RimPower("Rim Power", float) = 12
		_FresnelScale("Fresnel Scale",Range(0, 6)) = 1
        _SkinTint("Skin Color Tint", Color) = (1,0.9,0.8,1)
        _SkinTex("Skin Color", 2D) = "white" {}
        _StockingTint("Stocking Color Tint", Color) = (1,1,1,1)
        _StockingTex("Stocking Color", 2D) = "white"{}
        _NormalTex("Normal", 2D) = "bump"{}
    }

丹尼尔值与拉伸程度

float denier = (_Denier - 5) / 115;
float density = denier * (1 - tex2D(_DenierTex, IN.uv_DenierTex));

边缘度的计算

float rim = pow(1 - dot(normalize(IN.viewDir), o.Normal), _RimPower / 10);   //边缘光
float fresnel = pow(1.0 - max(0,dot(normalize(IN.viewDir), o.Normal)),_FresnelScale);    //菲涅尔

完整Shader代码

Shader "Kirk/Stocking" {
    Properties{
        _Denier("Denier", Range(5,120)) = 25.0
        _DenierTex("Density Texture", 2D) = "black"{}
		_Smoothness("Smoothness", Range(0,1)) = 0.1
		_Metallic("Metallic",Range(0,1)) = 0.1
        [Enum(Strong,6,Normal,12,Weak,20)] _RimPower("Rim Power", float) = 12
		_FresnelScale("Fresnel Scale",Range(0, 6)) = 1
        _SkinTint("Skin Color Tint", Color) = (1,0.9,0.8,1)
        _SkinTex("Skin Color", 2D) = "white" {}
        _StockingTint("Stocking Color Tint", Color) = (1,1,1,1)
        _StockingTex("Stocking Color", 2D) = "white"{}
        _NormalTex("Normal", 2D) = "bump"{}
    }
    SubShader{
        Tags{ "RenderType" = "Opaque" }

        CGPROGRAM
        #pragma surface surf Standard fullforwardshadows
        #pragma target 3.0

        struct Input {
            float2 uv_SkinTex;
            float2 uv_StockingTex;
            float2 uv_DenierTex;
            float2 uv_NormalTex;
            float3 viewDir;
        };

        float _RimPower;
        float _Denier;
        float _Smoothness;
		float _Metallic;
		float _FresnelScale;
        float4 _SkinTint;
        float4 _StockingTint;
        sampler2D _DenierTex;
        sampler2D _SkinTex;
        sampler2D _StockingTex;
        sampler2D _NormalTex;

        void surf(Input IN, inout SurfaceOutputStandard o) {
            o.Normal = UnpackNormal(tex2D(_NormalTex, IN.uv_NormalTex));  //得到法线
            float4 skinColor = tex2D(_SkinTex, IN.uv_SkinTex) * _SkinTint;    //内颜色
            float4 stockingColor = tex2D(_StockingTex, IN.uv_StockingTex) * _StockingTint;    //外颜色
            float rim = pow(1 - dot(normalize(IN.viewDir), o.Normal), _RimPower / 10);   //边缘光
			float fresnel = pow(1.0 - max(0,dot(normalize(IN.viewDir), o.Normal)),_FresnelScale);    //菲涅尔
            float denier = (_Denier - 5) / 115;    //丹尼尔参数
            float density = max(rim, (denier * (1 - tex2D(_DenierTex, IN.uv_DenierTex))));  //lerp参数
			
            o.Albedo = lerp(skinColor, stockingColor, density);
			o.Albedo = o.Albedo * (1 - fresnel);
            o.Metallic = _Metallic;
            o.Smoothness = _Smoothness;
        }
    ENDCG
    }
    FallBack "Diffuse"
}

你可能感兴趣的:(Unity,Shader,Shader)