Unity5 使用Projector实现纹理投射

发表于2018-12-04
评论0 8.1k浏览
游戏中,我们经常需要实现将纹理投射到场景中其他物体上的效果,如地上的光环、石块上的logo、水印等。很多情况下我们可以通过灯光或者其他方式达到我们想要的效果,但是Unity已经为我们提供了一种更加便捷高效的实现方式,那就是Projector组件。本篇我们就来看看如何使用Projector实现纹理投射。

最终效果预览

准备工作

首先创建工程,通过Assets->Import Package->Effects导入标准资源库中的特效素材,如下图所示。如果安装Unity时没有安装标准资源库,可以到这里单独下载并安装。

导入资源后,Project中将出现下图中的结构:

接下来就可以在场景中加入必要的元素了。

应用Projector组件

将BlobShadowProjector(Standard Shader Gallery -> Effects -> Projectors -> Prefabs)拖入场景中,Inspector面板如图:

BlobShadowProjector实现的是通过Projector组件在物体上投射一个圆形的阴影。将上图中Cookie改成我们需要的图片(注意图片属性中Alpha from Grayscale需要勾选,Wrap mode选择Clamp,当然你可以尝试不同选择看实际效果),但仍然存在不少问题,如png图片中的透明部分会被渲染成黑色,场景中有不明条纹等。

Projector的原理是为其frustum范围内的物体增加一个Pass,将我们在Projector中定义的材质渲染出来。为了解决上面所说的问题,我们可以创建自己的Shader和材质。

首先,复制Standard Shader Gallery -> Effects -> Projectors -> ProjectorMultiply,另存为ProjectorCustom,修改如下:
Shader "Projector/Custom" {
    Properties{
        _ShadowTex("Cookie", 2D) = "gray" {}
        _FalloffTex("FallOff", 2D) = "white" {}
    }
        Subshader{
        Tags{ "Queue" = "Transparent" }
        Pass{
        ZWrite Off
        ColorMask RGB
        //Blend DstColor Zero
        Blend SrcAlpha OneMinusSrcAlpha
        Offset -1, -1
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #pragma multi_compile_fog
        #include "UnityCG.cginc"
        struct v2f {
            float4 uvShadow : TEXCOORD0;
            float4 uvFalloff : TEXCOORD1;
            UNITY_FOG_COORDS(2)
            float4 pos : SV_POSITION;
        };
        float4x4 _Projector;
        float4x4 _ProjectorClip;
        v2f vert(float4 vertex : POSITION)
        {
            v2f o;
            o.pos = mul(UNITY_MATRIX_MVP, vertex);
            o.uvShadow = mul(_Projector, vertex);
            o.uvFalloff = mul(_ProjectorClip, vertex);
            UNITY_TRANSFER_FOG(o,o.pos);
            return o;
        }
        sampler2D _ShadowTex;
        sampler2D _FalloffTex;
        fixed4 frag(v2f i) : SV_Target
        {
            fixed4 texS = tex2Dproj(_ShadowTex, UNITY_PROJ_COORD(i.uvShadow));
            //texS.a = 1.0-texS.a;
            //fixed4 texF = tex2Dproj(_FalloffTex, UNITY_PROJ_COORD(i.uvFalloff));
            //lerp(fixed4(1, 1, 1, 0), texS, texF.a);
            fixed4 res = texS;
            UNITY_APPLY_FOG_COLOR(i.fogCoord, res, fixed4(1,1,1,1));
            return res;
        }
            ENDCG
        }
    }
}

注释的部分为修改之前的代码

新建一个材质并将Shader选择为Projector/Custom,勾选图片的Alpha is Transparent,将新材质作为Projector组件的Material,并勾选Projector组件的Orthographic复选框,得到如下效果:

我们发现图片不仅投射到地面和方块上,也投射到了人物上,这显然不是我们想要的效果,不过这个问题处理起来很简单,只需要新建一个Player的Layer,将人物的Layer选成Player,然后将Projector的Ignore Layers设置成Player得到了我们的最终效果了。

总结

Projector是一个非常有用的组件,除了我们上面实现的效果,还能用来廉价的实现投影(如我们最开始使用的BlobShadowProjector)、特殊光效(可以用来代替Cookie或者范围光,但是更加高效)等效果,通过尝试不同的设置和不同的Shader,我们还会得到更多有意思的效果。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引