【V-Ray 渲染器】织物布料材质 OSL Shader

396 阅读6分钟

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第6篇文章,点击查看活动详情

技术不啰嗦

理论基础

image.png

这是一个对艺术家友好的织物着色器。该着色器的描述为:该着色器所采用的方法是来自基于对织物材质属性的观察和它们对光的反应的现象学。该着色器是一个添加了具有光泽(sheen)和色调(tint)两方面参数的各向异性(anisotropic)的 Blinn BRDF,以捕捉织物的微小纤维是如何在入射角上接收光线的。此外,色调还影响着织物面料的高光,因为近似面料的高光颜色经常被漫反射颜色着色。

光泽颜色也可以用来加深光泽,因为一些织物(例如黑色尼龙)的 边缘颜色更深,而不是更亮。

光泽衰减下降有六种选择,以获得特定织物所需的光泽:

  • 线性,
  • 指数,
  • 光滑(埃尔米特),
  • s 曲线(s 曲线),
  • 平方根
  • 菲涅耳。

界面

image.png

光泽参数:

  • 光泽颜色: 决定光泽的颜色。默认为白色。光泽颜色可以是黑色的尼龙光泽,但要注意,当设置为纯黑色 (0,0,0) 时,与所有色板一样,将使用默认颜色。设置为几乎黑色 (0.01,0.01,0.01) 将工作正常。
  • 光泽不透明度: 当纤维在入射角上吸收光线时,决定了光泽效果的数量。可用于禁用光泽。
  • 光泽调色: 用漫反射颜色来调色光泽和高光。
  • 光泽渐变类型: 6 种类型的插值光泽:
  1. 线性(1),
  2. 指数(2),
  3. 光滑(3),
  4. Sigmoid(4),
  5. 平方根(5),
  6. 菲涅耳(6)。

扩散参数:

  • 漫反射颜色: 和 VrayMtl 一样。默认为深红色。
  • 漫反射权重: 和 VrayMtl 一样。可以用来禁用漫射。
  • 漫反射粗糙度: 给漫射一个柔软的粉状外观,典型的布料。

高光参数:

  • 高光颜色:与 VrayMtl 相同。默认为白色。
  • 高光数量:与 VrayMtl 相同。可用于禁用该高光。
  • 高光光泽度:与 VrayMtl 相同。
  • 高光尾部: GTR 尾部衰减设置为 1.0 或以下,为高光提供漂亮的布料光泽。
  • IOR: 决定菲涅耳反射的强度; 织物通常具有较低的正面反射。

Adv 反射参数:

  • 细分: 与 VrayMtl 中相同。当渲染设置中 “使用本地细分” 关闭时,此选项将被忽略。
  • 轨迹反射: 和 VrayMtl 一样。禁用此功能将导致只有高光而没有反射

各向异性参数:

  • 各向异性: 由于织法的不同,织物是各向异性的。
  • 不均匀旋转: 与 VrayMtl 相同。0 = 0度0.125 = 45度0.25 = 90度0.375 = 135度0.5 = 180度。范围是 0-0.5 ,旋转角度是 0-180度
  • 纹理 Gamma: 漫反射色的 Gamma 校正。

VrayMtl 设置布料的秘诀

虽然不是交互式的,但使用 VrayMtl 和一些技巧创建一个合理的布料材质是可能的。第一步是如下设置材质属性:

  • 漫射颜色:
  1. 创建一个 RemapHSV 节点,并连接你的漫反射纹理到它。增加其数值,会降低饱和度。
  2. 创建一个 Vray Falloff 贴图,并将漫反射纹理插入它的正面颜色,并将你的 RemapHSV 插入它的侧面颜色。 3.设置 Falloff 类型为 “垂直/平行”,并为点更改混合曲线的插值类型为 “平滑” 。
  3. 最后,将 Falloff 贴图插入 VrayMtl 的漫反射颜色中。 (这将产生一种光泽效果,模仿布料纤维从入射角度吸收光线。光泽是视觉上到目前为止我们的布料着色配方 最重要 的方面)
  • 漫反射权重: 0.8
  • 漫反射粗糙度: 0.5(给漫反射一个典型布料的柔软粉末状外观,)
  • BRDF 类型: Blinn
  • 反射颜色: 将上面制作的 RemapHSV 节点插入反射颜色中。 (这将产生由漫反射颜色着色的高光,模仿布料高光的一般外观)
  • 反射量: 0.5
  • 反射光泽度: 0.6
  • 反射 IOR: 1.33(产生典型的大多数织物所具有的低正面反射)
  • 各向异性: 0.25(织物因编织而产生的各向异性)

完整代码

完整 OSL 着色器代码如下

color getTextureDif(string texture_name, color no_texture_default_color)
{
    int channels = -1;
    if (gettextureinfo(texture_name, "channels", channels))
    {
        return texture(texture_name, u, v);
    }
 
    return no_texture_default_color;
}

float fresnelReflectionFactor(normal bumped_normal, float ior)
{
    float c = abs(dot(I, bumped_normal));
    float g = ior * ior - 1.0 + c * c;
    if (g > 0.0) {
        g = sqrt (g);
        float A = (g - c) / (g + c);
        float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0);
        return 0.5 * A * A * (1.0 + B * B);
    }
 
    return 1.0;
}
 
normal getBumpedBump(color centerColor, color uColor, color vColor, float inverseBumpAmount)
{
    vector worldTangent = normalize(dPdu);
    vector worldBitangent = normalize(dPdv);
    vector worldNormal = normalize(N);
 
    vector average = vector(0.3333333);
    float center = dot (average, vector(centerColor));
    float ddu = center - dot(average, vector(uColor));
    float ddv = center - dot(average, vector(vColor));
 
    return normalize(ddu * worldTangent + ddv * worldBitangent + inverseBumpAmount * worldNormal);
}

normal getBumpedNormal(color compressedNormalSample, float Bump_amount)
{
    vector worldTangent = normalize(dPdu);
    vector worldBitangent = normalize(dPdv);
    vector worldNormal = normalize(N);

    color normalSample = 2.0 * compressedNormalSample - 1.0;
    normalSample *= color(Bump_amount, Bump_amount, 1.0);

    return normalize(normalSample[0] * worldTangent + normalSample[1] * worldBitangent + normalSample[2] * worldNormal);
}
 
surface fabricMtl
    [[ string description = "artist based fabric material" ]]
(
    /* Diffuse section */
    string Sheen_color = "sheen.png" [[ string description = "Sheen color can be black for nylon sheen." ]],
    float Sheen_opacity = 1.0 [[ string description = 
		"Determines amount of sheen effect as fibres pick up light at incident angle." ]],
    float Sheen_tint = 0.5 [[ string description = 
		"Tints both the sheen and specular." ]],
    int Sheen_ramp_type = 3
        [[ string widget = "mapper", string description = 
			"Six types of interpolation for sheen: Linear(1), Exponential(2), Smooth(3), 
			Sigmoid(4), Square Root(5), Fresnel(6).",
        string options = "linear:1|Exponential:2|Smooth:3|Sigmoid:4|Square_root:5|Fresnel:6" ]],
     
    string Diffuse_color = "color.png",
    float Diffuse_weight = 0.8,
    float Diffuse_roughness = 0.4,
   
    /* Spec section */
    string Spec_color = "specular.png",
    float Spec_amount = 0.5,
    float Spec_glossiness = 0.6,
	float Spec_tail = 1
		[[ string description = 
		"GTR tail below 1.0 gives nice cloth-like sheen to the spec." 
		]],
    float IOR = 1.33 
		[[ string description = 
		"Determines the strength of Fresnel reflections; fabric generally has low frontal reflections." 
		]],
    int Subdivs = 8,
    int Trace_reflections = 1
        [[ string widget = "checkBox" ]],
 
    /* Anisotropy section */
    float Anisotropy = 0.25 [[ string description = 
		"Fabric is anisotropic due to weave." ]],
    float Aniso_rotation = 0,
 
    /* Bump section */
// Disabling bump until it is fixed in OSL for Vray. Use VrayBumpMtl instead
//    string Bump_Map = "normal.png",
//    float Bump_amount = 1.0,
//    int Normal_Mapping = 0
//        [[ string widget = "checkBox" ]],
      
    float Texture_gamma = 1.0,
 
    output color result = 1 )
 
{
    /* Define Bump */
    normal bumped_normal = N;

// Disabling bump until it is fixed in OSL for Vray. Use VrayBumpMtl instead
/*
    float BumpAmount = clamp (Bump_amount,0.001,10);
    if ( Normal_Mapping == 1 )
    {
        color compressedNormalSample = getTextureDif(Bump_Map, color(0.5,0.5,1));
        bumped_normal = getBumpedNormal(compressedNormalSample, BumpAmount);
    }
    else
    {
        float delta = 0.004;
        color center = texture(Bump_Map, u, v);
        color uColor = texture(Bump_Map, u + delta, v);
        color vColor = texture(Bump_Map, u, v + delta);
        float BumpAmount = BumpAmount * 10;
        bumped_normal = getBumpedBump(center, uColor, vColor, 1.0 / BumpAmount);
    }
 */

        /* Define Main color */
        color MainColor = getTextureDif(Diffuse_color, color(0.5,0.2,0.2));
        MainColor = pow (MainColor, Texture_gamma);
    
        /* Define Sheen */
        color SheenTint = Sheen_tint * 2; // intensify tint amount
        color TintBoost = transformc("hsl", MainColor);
        TintBoost[2] = TintBoost[2] + 0.5; // make the tint (2=luminance) a brighter version of the mainColor
        TintBoost[2] = clamp(TintBoost[2],0,1); // clamp tint luminance
        TintBoost = transformc("hsl","rgb", TintBoost);
      
        /* read in sheen color and modify it with tint */
        color SheenColor = getTextureDif(Sheen_color, color(1,1,1));
        color EdgeColor = SheenColor / 2; //dim sheen value
        color TintEdge = EdgeColor * TintBoost;   //colorize sheen with the tint
        EdgeColor = mix (EdgeColor, TintEdge, SheenTint); //mix between tinted & untinted sheen based on tint value
        EdgeColor = clamp (EdgeColor, 0, 1);
    
        /* Define Spec */
        color SpecColor = getTextureDif(Spec_color, color(1,1,1));
		
        /* mix between tinted & untinted spec based on tint value */
        color TintedSpec = SpecColor * TintBoost;
        SpecColor = mix (SpecColor, TintedSpec, SheenTint);
	
	float Roughness = 0;
 
        /* Define Ramps */
        float facingRatio = 1 - abs(dot(I, bumped_normal));
    
        if( Sheen_ramp_type == 1) // linear        
            {facingRatio = facingRatio; }
        if( Sheen_ramp_type == 2) // exponential (Down)
            { facingRatio *= facingRatio;  }
        if( Sheen_ramp_type == 3) // smooth 
            { facingRatio = smoothstep (0,1, facingRatio ); }
        
        if( Sheen_ramp_type == 4) // sigmoid S-curve
            {
            float Sigmoid = facingRatio / (1 + abs(facingRatio));
            facingRatio = clamp( 2 * Sigmoid, 0, 1);
            }
        if( Sheen_ramp_type == 5) // square root
            { facingRatio = sqrt (facingRatio); }
        
        if( Sheen_ramp_type == 6) // fresnel     
            { facingRatio = 2 * fresnelReflectionFactor(bumped_normal, IOR);  }
 
        /* BRDF Mixes*/
        color SheenMix = EdgeColor * facingRatio * Sheen_opacity;
        color EdgeMask = mix(1, SheenColor, (facingRatio * Sheen_opacity) );
        MainColor *= EdgeMask;
        MainColor *= (1.0 - SheenMix);  
        SpecColor *= EdgeMask;  
		
        closure color sheen_component = SheenMix * 
			diffuse(bumped_normal, "roughness", Diffuse_roughness);
			
        closure color diffuse_component =  MainColor * Diffuse_weight * 
			diffuse(bumped_normal, "roughness", Diffuse_roughness);
				
	closure color specGTR =  Spec_amount * SpecColor * 
			microfacet_ggx (bumped_normal, Roughness, IOR,
			"gtr_gamma", Spec_tail,
			"subdivs", Subdivs,
			"reflection_glossiness", Spec_glossiness,
			"highlight_glossiness", Spec_glossiness,
			"anisotropy", Anisotropy,
			"aniso_rotation", Aniso_rotation,
			"trace_reflections", Trace_reflections
        );
            
        Ci = diffuse_component + specGTR + sheen_component;
}