您的位置:首页 > 移动开发 > Unity3D

Unity Shader之动态阴影

2017-08-29 11:59 381 查看
动态阴影在Unity中,默认是使用ShadowMap,原理是通过生成投影深度图来比较,但是由于在移动平台对深度浮点值计算的限制,使得ShadowMap技术在移动平台要么效果不理想,要么需要消耗大量的计算。

所以常见的处理移动平台阴影的方式是使用RenderTexture + 投影,如王者荣耀中的实时阴影。

具体的方式是先渲染一张RenderTexture,这张RenderTexture包含了要显示阴影的对象,可以通过Layer设置,来剔除不显示阴影的对象。然后将这张RenderTexture设置给投影和材质。

第一步:

创建一个GameObject,上面添加Projector组件和Camera组件,两个组件和参数设置成一样,最好是使用正交方式。

Camera的clear flag设置为Solid,显示为白色,Camera的Layer mask只设置要生成阴影的那个层级

Projector 的Ignore layers设置来和 Camera的Layer mask一样,目的是投影不要投到了角色身上。

第二步:

创建一张RenderTexture,当然你也可以通过代码来创建,我这里是直接在unity中创建的,大小256*256,如果不够清晰,可以设置到512,格式设置为RGB565,Warp Mode为Clamp,Filter Mode为Bilinear。

将这张RenderTexture设置给上面的Camera

第三步:

创建一个Shader,用于渲染成RenderTexture,最简单的Shader就行

Shader "Unlit/Shadow"
{
Properties
{
_ShadowColor ("Main Color", COLOR) = (0.5, 0.5, 0.5, 1)
}

SubShader
{
Pass
{
Color [_ShadowColor]
}
}
}


再创建一个Shader,用于显示投影

Shader "Projector/Multiply"
{
Properties
{
_ShadowTex ("Cookie", 2D) = "gray" { TexGen ObjectLinear }
_FalloffTex ("FallOff", 2D) = "white" { TexGen ObjectLinear   }
}

Subshader
{
Tags { "RenderType"="Transparent-1" }
Pass
{
ZWrite Off
Fog { Color (1, 1, 1) }
AlphaTest Less 1
ColorMask RGB
Blend DstColor Zero
Offset -1, -1

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"

struct v2f
{
float4 pos : SV_POSITION;
float4 uv_Main : TEXCOORD0;
float4 uv_Clip : TEXCOORD1;
};

sampler2D _ShadowTex;
sampler2D _FalloffTex;
float4x4 unity_Projector;
float4x4 unity_ProjectorClip;

v2f vert(appdata_tan v)
{
v2f o;
o.pos = UnityObjectToClipPos (v.vertex);
o.uv_Main = mul (unity_Projector, v.vertex);
o.uv_Clip = mul (unity_ProjectorClip, v.vertex);
return o;
}

half4 frag (v2f i) : COLOR
{
half4 tex = tex2Dproj(_ShadowTex, i.uv_Main);
half4 falloff = tex2D(_FalloffTex, i.uv_Clip.xy);
tex = lerp(float4(1,1,1,1),tex,falloff.a);
return tex;
}
ENDCG

}
}
}


创建一个材质,给它添加Projector/Multiply这个Shader,然后把这个材质拖到投影的材质处。

最后一步:

编写脚本,主要用于通过自定义的shader来生成一张RenderTexture

public Projector proj;
public Camera projCam;
public Shader shadowShader;

// Use this for initialization
void Start () {
projCam.enabled = false;
}

// Update is called once per frame
void LateUpdate () {
if(proj && projCam){
projCam.aspect = proj.aspectRatio;
projCam.RenderWithShader(shadowShader,null);
}
}

总结:主要步骤,就是通过一个单独的相机渲染一张RenderTexture给投影,投影再将这张RenderTexture投到地面上。

但是有一定的局限,要投影的物品穿过了地面,投影计算也会计算地面以下的,最后显示出来就有错。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  shader