如何在Unity中实现头发渲染

此篇文章参考 Hair Rendering and Shading

相关链接:Redirecting

在Unity中实现高质量的发丝渲染通常需要结合多种技术,包括Shader编写、几何处理、光照模型等。

1. 准备发丝模型

首先,你需要一个高质量的发丝模型。通常,发丝模型由多个细长的三角形条带组成,模拟头发的形状。可以使用3D建模软件(如Maya、Blender)创建,或者使用头发生成工具(如HairWorks、Ornatrix)生成。

2 编写Shader

技术实现:

Shader "Custom/HairShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color ("Color", Color) = (1,1,1,1)
        _Specular ("Specular", Color) = (1,1,1,1)
        _Gloss ("Gloss", Range(0,1)) = 0.5
        _Anisotropic ("Anisotropic", Range(0,1)) = 0.5
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : NORMAL;
                float4 tangent : TANGENT;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 pos : SV_POSITION;
                float3 worldNormal : NORMAL;
                float3 worldTangent : TANGENT;
                float3 worldBinormal : BINORMAL;
            };

            sampler2D _MainTex;
            float4 _Color;
            float4 _Specular;
            float _Gloss;
            float _Anisotropic;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
                o.worldBinormal = cross(o.worldNormal, o.worldTangent) * v.tangent.w;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 worldNormal = normalize(i.worldNormal);
                float3 worldTangent = normalize(i.worldTangent);
                float3 worldBinormal = normalize(i.worldBinormal);

                // Anisotropic lighting
                float3 viewDir = normalize(_WorldSpaceCameraPos - i.pos);
                float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                float3 halfDir = normalize(lightDir + viewDir);

                float NdotL = dot(worldNormal, lightDir);
                float TdotH = dot(worldTangent, halfDir);
                float BdotH = dot(worldBinormal, halfDir);

                float anisotropy = _Anisotropic;
                float specular = exp(-(TdotH * TdotH + anisotropy * BdotH * BdotH) / (1.0 + _Gloss));

                fixed4 texColor = tex2D(_MainTex, i.uv);
                fixed4 finalColor = texColor * _Color + _Specular * specular;
                return finalColor;
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

3. 光照设置

发丝渲染对光照非常敏感,建议使用HDRP(High Definition Render Pipeline)或URP(Universal Render Pipeline)来获得更好的光照效果。

  • HDRP:支持更复杂的光照模型和后期处理效果,适合高质量的发丝渲染。

  • URP:性能较好,适合移动端或性能要求较高的项目。

4. 后期处理

为了进一步增强发丝的真实感,可以添加一些后期处理效果:

  • 抗锯齿:使用TAA(Temporal Anti-Aliasing)来减少发丝的锯齿。

  • 景深:模拟相机焦点外的模糊效果,增加真实感。

  • Bloom:增强发丝的高光效果。

相关技术支持:

5. 优化

发丝渲染通常对性能有较高要求,尤其是在移动设备上。以下是一些优化建议:

  • LOD(Level of Detail):根据距离调整发丝的细节层次。

  • GPU Instancing:对相同的发丝模型使用GPU Instancing来减少Draw Call。

  • Culling:使用视锥剔除和遮挡剔除来减少不必要的渲染。

6.结语

效果:

对于半透明的物体,需要从后向前渲染保证渲染的正确性
对于有头发的头,这和头发从内向外渲染很相似。这个可以在制作模型的时候,内部的顶点坐标往前放,外部的顶点坐标向后放,主要是索引的顺序要正确。
按照下面的顺序去渲染,分4个pass (深度写入,不透明,半透明背面,半透明正面)

第一个pass,使用alphaTest剔除半透明像素,禁用背面剔除,写入深度,深度检测为less,不需要渲染颜色,只需要写入深度。
第二个pass,进行完整的头发像素渲染,禁用背面剔除,禁用深度写入,深度检测为 Equal,用来绘制不透明部分的表面。
第三个pass,用于绘制半透明背面,剔除正面渲染,不写入深度,深度检测为less。
第四个pass,半透明正面渲染,剔除背面,深度写入,深度检测为less,启用深度写入可以防止不正确的深度顺序。

综上便可实现头发渲染,动手试试吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值