Unity3D 阴影和深度纹理总结

原创 2017年08月28日 14:43:16

首先介绍一下,阴影的生成,阴影一般是在屏幕空间生成的,利用Unity3D引擎实现阴影的绘制,首先要明白其实现原理,Unity5的Demo已经为我们提供了代码实现,先介绍一下阴影的视线原理:

屏幕空间的阴影实现主要有这么几个步骤:

1、首先得到从当前摄像机处观察到的深度纹理。在延迟渲染里这张深度图本来就有,如果是前向渲染的话就需要把场景整个渲染一遍,把深度渲染

到深度图中。

2、然后再从光源出发得到从该光源处观察到的深度纹理,也被称为这个光源的ShadowMap

3、然后在屏幕空间做一次阴影收集计算(Shadows Collector),这次计算会得到一张屏幕空间阴影纹理,也就是说这张图里面需要有阴影的部分

已经显示在图上了。这个过程概括来说就是把每一个像素根据它在摄像机深度纹理中的深度值得到世界空间坐标,再把它的坐标从世界空间转换到

光源空间中,和光源的ShadowMap里面的深度值对比,如果大于ShadowMap中的深度距离,那么就说明光源无法照到,在阴影内。

4、最后,在正常渲染物体为它计算阴影的时候,只需要按照当前处理的fragment在屏幕空间中的位置对步骤3得到的屏幕空间阴影图采样就可以了。


它的具体实现Shader名字是:

Hidden/Internal-ScreenSpaceShadows(在DefaultResourcesExtra/Internal-ScreenSpaceShadows.shader)。这个Pass在不同的Unity版本

里是不一样的,比如在Unity 5.3里面就是Internal-PrePassCollectShadows(在DefaultResources/Internal-PrePassCollectShadows.shader),看的时候还是要全局搜索确定下。

主要思路就是从摄像机的深度纹理里采样得到该fragment的深度值,然后利用矩阵变换计算得到该点

对应的世界空间的世界坐标(利用CameraToWorld矩阵),然后再变换到光源空间下的坐标(利用WorldToShadow矩阵),最后拿

这个坐标对光源的ShadowMap采样计算阴影。


通常的做法其实都可以满足需求,最重要的是遇到一些特殊情况比如材质是透明或者是半透明的,这个就需要特殊处理了。
在Unity自带的Shader:Standard Shader中计算阴影的Pass:
//  Shadow rendering pass
Pass {
    Name "ShadowCaster"
    Tags { "LightMode" = "ShadowCaster" }

    ZWrite On ZTest LEqual

    CGPROGRAM
    #pragma target 3.0
    // TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
    #pragma exclude_renderers gles

    #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
    #pragma multi_compile_shadowcaster

    #pragma vertex vertShadowCaster
    #pragma fragment fragShadowCaster

    #include "UnityStandardShadow.cginc"

    ENDCG
}

可以发现也是和我们一样定义了LightMode为ShadowCaster的Pass。_ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON这些keyword就是为半透明阴影效果定义的。再看fragShadowCaster的实现(在UnityStandardShadow.cginc中定义):

half4 fragShadowCaster (
    #ifdef UNITY_STANDARD_USE_SHADOW_OUTPUT_STRUCT
    VertexOutputShadowCaster i
    #endif
    #ifdef UNITY_STANDARD_USE_DITHER_MASK
    , UNITY_VPOS_TYPE vpos : VPOS
    #endif
    ) : SV_Target
{
    #if defined(UNITY_STANDARD_USE_SHADOW_UVS)
        half alpha = tex2D(_MainTex, i.tex).a * _Color.a;
        #if defined(_ALPHATEST_ON)
            clip (alpha - _Cutoff);
        #endif
        #if defined(_ALPHABLEND_ON) || defined(_ALPHAPREMULTIPLY_ON)
            #if defined(UNITY_STANDARD_USE_DITHER_MASK)
                // Use dither mask for alpha blended shadows, based on pixel position xy
                // and alpha level. Our dither texture is 4x4x16.
                half alphaRef = tex3D(_DitherMaskLOD, float3(vpos.xy*0.25,alpha*0.9375)).a;
                clip (alphaRef - 0.01);
            #else
                clip (alpha - _Cutoff);
            #endif
        #endif
    #endif // #if defined(UNITY_STANDARD_USE_SHADOW_UVS)

    SHADOW_CASTER_FRAGMENT(i)
}   

代码也很简单,我们需要关注的就是tex3D(_DitherMaskLOD, float3(vpos.xy_0.25,alpha_0.9375)).a这一句。可以看出来,它是对一张

3D的dither纹理采样,这张纹理的z方向对应了透明度值。再使用clip对dither后的结果进行cutout,造成一种半透明阴影的假象。

说得简单点,这种Dither技术其实就是利用人眼的特性,我们看到的其实是有很多细小孔洞的阴影,由于这些空洞的大小和密度变化,

在人眼看来就像是半透明了一样,但实际上真正的阴影颜色是没有变的。总结其实就是,dither texture + cutout。

如果我们要自己在shader中实现这种效果,也可以仿照Standard Shader的做法,对_DitherMaskLOD这张纹理进行采样。例如,

在Shader中添加自定义的ShadowCaster Pass:

Pass{
    Name "ShadowCaster"
    Tags{ "LightMode" = "ShadowCaster" }

    ZWrite On ZTest LEqual

    CGPROGRAM
    #pragma target 3.0

    #pragma vertex vert
    #pragma fragment frag

    #pragma multi_compile_shadowcaster

    #define UNITY_STANDARD_USE_SHADOW_OUTPUT_STRUCT
    #define UNITY_STANDARD_USE_DITHER_MASK
    #define UNITY_STANDARD_USE_SHADOW_UVS

    #include "UnityStandardShadow.cginc"

    fixed _AlphaScale;

    struct VertexOutput
    {
        V2F_SHADOW_CASTER_NOPOS
        float2 tex : TEXCOORD1;
    };

    void vert(VertexInput v, out VertexOutput o, out float4 opos : SV_POSITION)
    {
        TRANSFER_SHADOW_CASTER_NOPOS(o,opos)
        o.tex = v.uv0;
    }

    half4 frag(VertexOutput i, UNITY_VPOS_TYPE vpos : VPOS) : SV_Target
    {
        half alpha = tex2D(_MainTex, i.tex).a * _AlphaScale;

        half alphaRef = tex3D(_DitherMaskLOD, float3(vpos.xy*0.25,alpha*0.9375)).a;
        clip(alphaRef - 0.01);

        SHADOW_CASTER_FRAGMENT(i)
    }

    ENDCG
}

同时禁用其他Fallback,就可以得到“半透明”阴影的效果了。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jxw167/article/details/77648384

Unity 3D中的阴影设置

在Unity 3D中,经常需要用到光照阴影,即Directional Light的Shadow,Shadow分为Hard Shadow和Soft Shadow。区别是Soft Shadow的阴影边缘比...
  • book_longssl
  • book_longssl
  • 2015年01月07日 22:02
  • 4122

Unity3D The Blacksmith 角色阴影技术使用心得

这个demo放出来之后,对其中的角色阴影部分的技术十分感兴趣,我就赶紧下过来研究了一下。官方的技术博客里有对这一部分技术的介绍,链接在这里:独特的角色阴影, 其中写到只要在其他shader里添加 #p...
  • sdqq1234
  • sdqq1234
  • 2017年03月09日 10:28
  • 2376

UnityEffects(2)之ProjectorShadow(手游上的实时阴影方案)

UnityEffects(2)之(2)ProjectorShadow(手游上的实时阴影方案) 上一篇说到了在unity5.x中实现shadowMap的方法(UnityEffects(1)之shado...
  • aceyan0718
  • aceyan0718
  • 2016年08月22日 19:36
  • 8381

Unity3D游戏制作(三)——移动平台上的角色阴影制作

本系列文章由 Amazonzx 编写,欢迎转载,转载请注明出处。 http://blog.csdn.net/amazonzx/article/details/7973740   本文将重点介绍两...
  • Amazonzx
  • Amazonzx
  • 2012年09月13日 10:21
  • 30991

unity移动平台阴影解决方案

unity移动平台角色阴影解决方案Projector Shadow制作思路:主要是利用一个正交的camera去获取阴影模型的体面,赋予给创建的一个rendertexture,然后利用projector...
  • u010943777
  • u010943777
  • 2016年01月15日 13:59
  • 2901

Unity3D【新手问题】阴影效果不显示的原因

Unity 不显示阴影的原因: 模型尺寸太大了,镜头比较远 把模型缩小,镜头一定要拉到最近才能看到 这是我遇到的问题和解决方法,另外一定要设置 Directional light 的 sha...
  • zsjangel
  • zsjangel
  • 2016年06月11日 21:31
  • 7885

Unity局部高效实时阴影的思考和实现

写论文时找到的AR实时阴影制作参考 http://dev.arinchina.com/167wz/ar9113/9113/1   2_53622_8bfbac33...
  • hcud024
  • hcud024
  • 2016年07月05日 20:23
  • 918

unity终极抗锯齿抗白边黑边投影阴影不正常问题解决

unity闪烁 投影问题 边缘锯齿 写这篇时是自己的总结,也是综合了很多其他文章的 因为一般的提问只能解决很少的问题,而且通常不管用,所以自己总结了下 1.首先在edit-project sett...
  • shenmifangke
  • shenmifangke
  • 2016年01月07日 10:34
  • 8426

Unity局部高效实时阴影的思考和实现

无意间看到一篇文章,说是Unity5 demo中为了实现角色的良好阴影,单独给角色设计了一个角色阴影系统。而且使用的是比较老的技术,但效果很好。其实在很多时候,我们需要的并不是万能的阴影光照系统,而是...
  • yxriyin
  • yxriyin
  • 2015年12月03日 18:00
  • 6261

Unity 3D中的阴影设置

在Unity 3D中,经常需要用到光照阴影,即Directional Light的Shadow,Shadow分为Hard Shadow和Soft Shadow。区别是Soft Shadow的阴影边缘比...
  • fang_tang_
  • fang_tang_
  • 2014年12月12日 17:55
  • 1577
收藏助手
不良信息举报
您举报文章:Unity3D 阴影和深度纹理总结
举报原因:
原因补充:

(最多只允许输入30个字)