Unity Fur Shader 皮毛着色器

本文详细介绍了如何在Unity中使用自定义着色器创建逼真的毛发效果。通过多层渲染、噪波纹理、光照模型等技术,实现毛发的细腻表现,并探讨了强度、细度、阴影、外力及边缘颜色等属性的调整方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

效果图

Github 仓库地址: github.com/Sorumi/UnityFurShader
博文原文: sorumi.xyz/posts/unity-fur-shader/

基础皮毛 0.1 Basic

首先建立毛发的模型。

Fur Model

根据模型,我们使用层 (layer) 来渲染毛发长度,在 Unity Shader 中,每一个 Pass 即表示一层。

当渲染每一层时,使用法线将顶点位置”挤出“模型表面,则对应的像素点位置的公式:

float3 P = v.vertex.xyz + v.normal * _FurLength * FURSTEP;

FURSTEP 表示当前层数 / 总层数,增加层数可以创造更精细毛发。

然后使用一张噪波纹理作为每个像素点的 alpha 值,来判断该像素点是不是属于毛发的点。

光照模型则使用了环境光照 (ambient)、漫反射光照 (diffuse)、镜面光照 (specular) ,并采用逐像素着色。(如果考虑性能的话,可以改成逐顶点着色。)

如果设置 n 层,在 SubShader 中需要有不考虑毛发只渲染表面的 1 个 Pass ,和渲染毛发的 n 个 Pass,共 n + 1 个 Pass。

毛发 Pass 中的代码:

struct v2f
{
    float4 pos: SV_POSITION;
    half4 uv: TEXCOORD0;
    float3 worldNormal: TEXCOORD1;
    float3 worldPos: TEXCOORD2;
};

v2f vert_base(appdata_base v)
{
    v2f o;
    float3 P = v.vertex.xyz + v.normal * _FurLength * FURSTEP;
    o.pos = UnityObjectToClipPos(float4(P, 1.0));
    o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
    o.uv.zw = TRANSFORM_TEX(v.texcoord, _FurTex);
    o.worldNormal = UnityObjectToWorldNormal(v.normal);
    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    return o;
}

fixed4 frag_base(v2f i): SV_Target
{
    fixed3 worldNormal = normalize(i.worldNormal);
    fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
    fixed3 worldView = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
    fixed3 worldReflect = normalize(reflect(-worldView, worldNormal));

    fixed3 albedo = tex2D(_MainTex, i.uv.xy).rgb * _Color;
    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
    fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(worldNormal, worldLight));
    fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldReflect, worldView)), _Shininess);

    fixed3 color = ambient + diffuse + specular;
    fixed alpha = tex2D(_FurTex, i.uv.zw).rgb;

    return fixed4(color, alpha);
}

效果:
0.1 Basic

皮毛属性 0.2 Attributes
增加毛发强度 (fur density)

用来表现毛发越到尾部越细,越少。根据 noise 灰度图采样调整每一层像素的透明度,修改 fragment shader 中的 alpha 计算方法

alpha = clamp(noise - (FURSTEP * FURSTEP) * _EdgeFade, 0, 1);

增加毛发细度 (fur thinness)

本质上是改变 noise texture 的 tile

fixed3 noise = tex2D(_FurTex, i.uv.zw * _FurThinnesss).rgb;

增加毛发阴影 (fur shading)

毛发越靠近根部的像素点颜色越暗

albedo -= (pow(1 - FURSTEP, 3)) * _FurShading;

或使用插值的方式

float shadow = lerp(1, FURSTEP, _FurShading);
albedo *= shadow;

对比了两种方式的效果,感觉上一种更有层次感。

效果:
0.2 Attributes

增加外力 0.3 Force

分为相对于 world 的作用力 (force global) 和相对于 object 的作用力 (force local) ,在 vertex shader 中修改顶点位置 P ,使用 clamp(x, -1, 1) 函数,对偏移方向进行约束。

P += clamp(mul(unity_WorldToObject, _ForceGlobal).xyz + _ForceLocal.xyz, -1, 1) * pow(FURSTEP, 3) * _FurLength;

效果:
0.3 Force

边缘颜色 0.4 Rim Color

考虑到毛发在边缘的颜色会略微受光的影响,增加边缘颜色 (rim color)

half rim = 1.0 - saturate(dot(worldView, worldNormal));
albedo += fixed4(_RimColor.rgb * pow(rim, _RimPower), 1.0);

效果:
0.4 Rim Color


参考链接

Fur Effects - Teddies, Cats, Hair ….
Fur shader - Shaders Laboratory

Unity头发渲染使用了分层layer的方法,每一层层次渲染不同长度的毛发,通过设置不同的alpha值来控制显示。为了实现这个效果,可以使用多个pass进行渲染,其中每个pass表示一层。在渲染每一层时,使用法线将顶点位置挤出模型表面。此外,根据噪音贴图可以随机控制毛发的长度,并根据不同层次调整毛发的UV位置偏移,使其更加自然。还可以设置偏移量来模拟外力对毛发的影响,比如风。最后,根据环境光、反射和漫反射光等影响来设置颜色。 在Unity中实现头发渲染可以使用多个pass,这样可以避免重复的代码。不同的层次需要传递参数来控制长度,可以使用1/总的层数来表示每一层毛发所对应的长度。具体实现时,可以在表面皮肤渲染pass和毛发渲染pass中引用相应的shader,其中通过设置FURSTEP参数来控制皮毛的长度。 如果你正在寻找Unity中用于头发渲染的工具,可以考虑使用"Fur Tool Unity Asset for 3D Character Modelling Artists",这是由Coldface Interactive开发的一个Unity插件,可以帮助艺术家进行头发建模。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [unity shader - 毛发渲染,飘逸的毛发](https://blog.youkuaiyun.com/alla_Candy/article/details/121439493)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值