赞
踩
refer:
腾讯游戏学堂
主要来自这里,感谢讲解!
当然直接一张图是看不明白的,这里我来用通俗的话来讲明白这个多层毛发模型
首先,真实世界的毛发是这样的:
也就是如下这样:
现实中的毛发就是这样,但是我们不可能去真的一根根建模
于是讨巧的模拟毛发的算法便被提出:
纹理很好用,我们想把所有的毛发信息记录在纹理中,但是纹理只是2维的,如何记录三维的毛发信息呢?
不卖关子,做法就是用很多层纹理叠起来,把毛发分段记录下来:
只不过这毛发不是实体的,而是分层的面片,侧面看会露馅,不过好解决,只要层数足够多,就可以掩盖这一点
将没有毛发的空袭部分alpha值记为0,就像是用透明度这个工具一点点雕刻,这样便可以雕刻出毛皮的样子
至于具体怎么去雕刻毛发,去看下面的代码实现
另外前面还有说到毛发是会透光的,那么我们在渲染的时候就可以修改其透明度,越靠近末梢越透明
我还说到毛发根部受到的光更少,这个现象我们用环境光遮蔽来实现
这样一来,便将渲染毛发这种听起来不可思议的事情,转化成了渲染一堆叠起来的纹理了,这听起来就实际多了,不过这仍然会消耗大量的算力
尽管开销很大,但这也是当前渲染毛发最好的方法了(实时),别的开销更大
感兴趣可以看一下这位UP的案例,个人觉得超棒
因为开销很大,所有在性能调优方面就极为重要
环境光遮蔽,添加与否的差别,个人觉得差距还挺大的
先放出本代码的最终效果
微观细节:
一点补充说明:
就不逐行写注释了,主要的要点如下:
v2f vert_fur(appdata v, float layer_offset)
alpha = step(layer_offset, alpha);
step(a,x); x<a 返回0 x>=0 返回1
;而step中的alpha是从噪声图中读取的alpha *= (1-layer_offset);
col.xyz *= pow(layer_offset, _AO );
进行环境光遮蔽,AO具体可以看我的这篇文章(还没写,新坑)
#ifndef FUR_INCLUDE #define FUR_INCLUDE #include "UnityCG.cginc" #include "Lighting.cginc" struct appdata { float3 normal : NORMAL; float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float2 uv_layer : TEXCOORD1; float4 vertex : SV_POSITION; }; float _Length; sampler2D _MainTex; sampler2D _LayerMap; float4 _MainTex_ST; float4 _LayerMap_ST; float _AO; v2f vert_fur(appdata v, float layer_offset) { v2f o; v.vertex.xyz += v.normal * _Length * layer_offset; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); o.uv_layer = TRANSFORM_TEX(v.uv, _LayerMap); return o; } fixed4 frag_fur(v2f i, float layer_offset) { float alpha = tex2D(_LayerMap, i.uv_layer).r;//读取layer纹理 alpha = step(layer_offset, alpha); //雕刻毛发 alpha *= 1-layer_offset; //透明度衰减计算 fixed4 col = fixed4(tex2D(_MainTex, i.uv).rgb, alpha);//应用上述得到的透明度 col.xyz *= pow(layer_offset, _AO ); //AO计算 return col; } #endif
Shader "Unlit/fur" { Properties { _MainTex ("Texture", 2D) = "white" {} _LayerMap ("Layer map", 2D) = "white"{} _Length ("fur length", range(0,1)) = 0.5 _AO ("AO", range(0,1)) = 0.5 } SubShader { Tags { "RenderType"="Transparent" "Queue" = "Transparent"} Blend SrcAlpha OneMinusSrcAlpha Cull off Pass{ CGPROGRAM #pragma vertex vert0 #pragma fragment frag0 #include "layers.cginc" v2f vert0(appdata v){return vert_fur(v,0);} fixed4 frag0(v2f i):SV_TARGET{return frag_fur(i,0);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert1 #pragma fragment frag1 #include "layers.cginc" v2f vert1(appdata v){return vert_fur(v,0.01);} fixed4 frag1(v2f i):SV_TARGET{return frag_fur(i,0.01);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert2 #pragma fragment frag2 #include "layers.cginc" v2f vert2(appdata v){return vert_fur(v,0.02);} fixed4 frag2(v2f i):SV_TARGET{return frag_fur(i,0.02);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert3 #pragma fragment frag3 #include "layers.cginc" v2f vert3(appdata v){return vert_fur(v,0.03);} fixed4 frag3(v2f i):SV_TARGET{return frag_fur(i,0.03);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert4 #pragma fragment frag4 #include "layers.cginc" v2f vert4(appdata v){return vert_fur(v,0.04);} fixed4 frag4(v2f i):SV_TARGET{return frag_fur(i,0.04);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert5 #pragma fragment frag5 #include "layers.cginc" v2f vert5(appdata v){return vert_fur(v,0.05);} fixed4 frag5(v2f i):SV_TARGET{return frag_fur(i,0.05);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert6 #pragma fragment frag6 #include "layers.cginc" v2f vert6(appdata v){return vert_fur(v,0.06);} fixed4 frag6(v2f i):SV_TARGET{return frag_fur(i,0.06);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert7 #pragma fragment frag7 #include "layers.cginc" v2f vert7(appdata v){return vert_fur(v,0.07);} fixed4 frag7(v2f i):SV_TARGET{return frag_fur(i,0.07);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert8 #pragma fragment frag8 #include "layers.cginc" v2f vert8(appdata v){return vert_fur(v,0.08);} fixed4 frag8(v2f i):SV_TARGET{return frag_fur(i,0.08);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert9 #pragma fragment frag9 #include "layers.cginc" v2f vert9(appdata v){return vert_fur(v,0.09);} fixed4 frag9(v2f i):SV_TARGET{return frag_fur(i,0.09);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert10 #pragma fragment frag10 #include "layers.cginc" v2f vert10(appdata v){return vert_fur(v,0.10);} fixed4 frag10(v2f i):SV_TARGET{return frag_fur(i,0.1);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert11 #pragma fragment frag11 #include "layers.cginc" v2f vert11(appdata v){return vert_fur(v,0.11);} fixed4 frag11(v2f i):SV_TARGET{return frag_fur(i,0.11);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert12 #pragma fragment frag12 #include "layers.cginc" v2f vert12(appdata v){return vert_fur(v,0.12);} fixed4 frag12(v2f i):SV_TARGET{return frag_fur(i,0.12);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert13 #pragma fragment frag13 #include "layers.cginc" v2f vert13(appdata v){return vert_fur(v,0.13);} fixed4 frag13(v2f i):SV_TARGET{return frag_fur(i,0.13);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert14 #pragma fragment frag14 #include "layers.cginc" v2f vert14(appdata v){return vert_fur(v,0.14);} fixed4 frag14(v2f i):SV_TARGET{return frag_fur(i,0.14);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert15 #pragma fragment frag15 #include "layers.cginc" v2f vert15(appdata v){return vert_fur(v,0.15);} fixed4 frag15(v2f i):SV_TARGET{return frag_fur(i,0.15);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert16 #pragma fragment frag16 #include "layers.cginc" v2f vert16(appdata v){return vert_fur(v,0.16);} fixed4 frag16(v2f i):SV_TARGET{return frag_fur(i,0.16);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert17 #pragma fragment frag17 #include "layers.cginc" v2f vert17(appdata v){return vert_fur(v,0.17);} fixed4 frag17(v2f i):SV_TARGET{return frag_fur(i,0.17);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert18 #pragma fragment frag18 #include "layers.cginc" v2f vert18(appdata v){return vert_fur(v,0.18);} fixed4 frag18(v2f i):SV_TARGET{return frag_fur(i,0.18);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert19 #pragma fragment frag19 #include "layers.cginc" v2f vert19(appdata v){return vert_fur(v,0.19);} fixed4 frag19(v2f i):SV_TARGET{return frag_fur(i,0.19);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert20 #pragma fragment frag20 #include "layers.cginc" v2f vert20(appdata v){return vert_fur(v,0.20);} fixed4 frag20(v2f i):SV_TARGET{return frag_fur(i,0.20);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert21 #pragma fragment frag21 #include "layers.cginc" v2f vert21(appdata v){return vert_fur(v,0.21);} fixed4 frag21(v2f i):SV_TARGET{return frag_fur(i,0.21);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert22 #pragma fragment frag22 #include "layers.cginc" v2f vert22(appdata v){return vert_fur(v,0.22);} fixed4 frag22(v2f i):SV_TARGET{return frag_fur(i,0.22);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert23 #pragma fragment frag23 #include "layers.cginc" v2f vert23(appdata v){return vert_fur(v,0.23);} fixed4 frag23(v2f i):SV_TARGET{return frag_fur(i,0.23);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert24 #pragma fragment frag24 #include "layers.cginc" v2f vert24(appdata v){return vert_fur(v,0.24);} fixed4 frag24(v2f i):SV_TARGET{return frag_fur(i,0.24);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert25 #pragma fragment frag25 #include "layers.cginc" v2f vert25(appdata v){return vert_fur(v,0.25);} fixed4 frag25(v2f i):SV_TARGET{return frag_fur(i,0.25);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert26 #pragma fragment frag26 #include "layers.cginc" v2f vert26(appdata v){return vert_fur(v,0.26);} fixed4 frag26(v2f i):SV_TARGET{return frag_fur(i,0.26);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert27 #pragma fragment frag27 #include "layers.cginc" v2f vert27(appdata v){return vert_fur(v,0.27);} fixed4 frag27(v2f i):SV_TARGET{return frag_fur(i,0.27);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert28 #pragma fragment frag28 #include "layers.cginc" v2f vert28(appdata v){return vert_fur(v,0.28);} fixed4 frag28(v2f i):SV_TARGET{return frag_fur(i,0.28);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert29 #pragma fragment frag29 #include "layers.cginc" v2f vert29(appdata v){return vert_fur(v,0.29);} fixed4 frag29(v2f i):SV_TARGET{return frag_fur(i,0.29);} ENDCG } Pass{ CGPROGRAM #pragma vertex vert30 #pragma fragment frag30 #include "layers.cginc" v2f vert30(appdata v){return vert_fur(v,0.3);} fixed4 frag30(v2f i):SV_TARGET{return frag_fur(i,0.3);} ENDCG } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。