大家好,我是阿赵。
之前在做钢铁侠线框效果的时候,说到过一种技术,这里单独拿出来再说明一下。
我们经常要做一些模型半透明效果,比如这个钢铁侠的模型,我做了一个Rim边缘光的效果,边缘的地方亮一点,中间的地方暗一点,然后整个模型呈现半透明的状态。
在想象中,这个效果只需要计算一个NdotV,然后赋给alpha通道,应该就可以了吧?然后就应该出现了这样的效果??
但实际上,如果只是单纯的把alpha通道设置为半透明,是会出现这样的效果的:
这是因为,模型内部也是有结构的,当半透明整个模型的时候,这些内部的结构也参与计算,原来由于不透明而被遮挡的部分,也会被看到。
为了解决这个问题,可以加多一个Pass:
Pass
{
Cull off
ZWrite on
ColorMask 0
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 pos:POSITION;
};
struct v2f
{
float4 pos:SV_POSITION;
};
v2f vert(appdata i)
{
v2f o;
o.pos = UnityObjectToClipPos(i.pos);
return o;
}
float4 frag(v2f o):SV_Target
{
return float4(0,0,0,0);
}
ENDCG
}
这个Pass很简单,主要的部分是:
Cull off
ZWrite on
ColorMask 0
开启了ZWrite,让它有一个前后遮挡关系,那么内部的东西就被挡住了。然后ColorMask 0是为了让这个挡住内部的部分,是看不见的。
加完这个Pass之后,就能出现正确的效果了:
加上了Rim边缘光的完整Shader:
Shader "Rim"
{
Properties
{
_color("颜色",Color) = (1,1,1,1)
_emiss("增幅",Float) = 1
_rimPow("边缘强度",Range(0,5)) = 1
_alpha("alpha",Range(0,1)) = 1
}
SubShader
{
Pass
{
Cull off
ZWrite on
ColorMask 0
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 pos:POSITION;
};
struct v2f
{
float4 pos:SV_POSITION;
};
v2f vert(appdata i)
{
v2f o;
o.pos = UnityObjectToClipPos(i.pos);
return o;
}
float4 frag(v2f o):SV_Target
{
return float4(0,0,0,0);
}
ENDCG
}
Pass
{
Blend SrcAlpha OneMinusSrcAlpha
Tags{"Queue" = "Transparent"}
ZWrite off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 pos:POSITION;
float4 normal:NORMAL;
};
struct v2f
{
float4 pos:SV_POSITION;
float3 normal_world:TEXCOORD0;
float3 view_world:TEXCOORD1;
};
float4 _color;
float _emiss;
float _rimPow;
float _alpha;
v2f vert(appdata i)
{
v2f o;
o.pos = UnityObjectToClipPos(i.pos);
float3 normalWorld = mul(i.normal, unity_WorldToObject).xyz;
o.normal_world = normalize(normalWorld);
float4 worldPos = mul(unity_ObjectToWorld, i.pos);
float3 viewWorld = _WorldSpaceCameraPos.xyz - worldPos.xyz;
o.view_world = normalize(viewWorld);
return o;
}
float4 frag(v2f o):SV_Target
{
float NdotV = dot(o.normal_world,o.view_world);
float4 col = _color*_emiss;
float rim = 1-saturate(NdotV);
rim = pow(rim, _rimPow);
col.a = rim*_emiss*_alpha;
return col;
}
ENDCG
}
}
}