实时阴影具有相当高的渲染开销;任何可能投射阴影的游戏对象都必须首先渲染到阴影贴图中,然后该贴图将用于渲染可能接受阴影的对象。
柔和阴影比生硬阴影具有更大的渲染开销,但这仅影响 GPU,不会导致额外的 CPU 工作。
If rendering real-time shadows for complex geometry is prohibitively expensive, consider using low LOD meshes or even primitives to cast shadows.
If this is too resource-intensive, you can fake shadows using a blurred texture applied to a simple mesh or quad underneath your characters, or can create blob shadows with custom shaders.
直接获得光照的表面有时看起来部分处于阴影中。之所以出现这种情况,是因为应该精确位于阴影贴图中指定距离处的像素有时被计算为更远距离(这是对阴影贴图使用阴影过滤或低分辨率图像的结果)。造成的结果是阴影中出现任意像素图案(这些像素其实应当获得光照),带来称为“阴影暗斑”(shadow acne) 的视觉效果。
为防止阴影暗斑,可以调整 light bias 设置。
可以向阴影贴图中的距离添加偏差,以确保边界线上的像素通过比较,也可以沿其法线将几何体稍微嵌入一点。
在内置渲染管线中,启用阴影后,可以通过 Light Inspector 窗口中的 Bias 和 Normal Bias 属性设置这些值。
不要将 Bias 值设置得太高,因为游戏对象附近的阴影周围区域有时会被错误地照亮。这会导致阴影脱离游戏对象,使游戏对象看起来好像飘在地面上方。
同样,将 Normal Bias 值设置得太高会使阴影对于游戏对象来说太窄:
在某些情况下,Normal Bias 会导致称为“光渗”(light bleeding) 的不良效果,这种情况下,光线从附近的几何体渗透到应该产生阴影的区域。一种可能的解决方案是打开游戏对象的网格渲染器,并将 Cast Shadows 属性更改为 Two Sided。这种做法有时会有所帮助,但可能会占用更多资源,并在渲染场景时增加性能开销。
光源的 Bias 值可能需要适当调整以免产生不想要的效果。通常用眼睛衡量正确值会更简单,而不是试图计算该值。
为了进一步防止阴影暗斑,我们采用一种称为阴影平坠的技术。该技术旨在减少沿光照方向渲染阴影贴图时使用的光照空间范围。这可以提高阴影贴图的精度,减少阴影暗斑。
在上图中:
将这些阴影投射物钳制在优化空间的近裁剪面(在顶点着色器中)。请注意,虽然这通常很有效,但对于穿过近裁剪面的大型三角形,这会带来瑕疵:
在此情况下,只有蓝色三角形的一个顶点位于近裁剪面背后并被钳制到此处。但是,这会改变三角形的形状,并可能产生不正确的阴影。
您可以从 Quality 窗口中调整 Shadow Near Plane Offset 属性以避免发生此问题。这将拉回近裁剪面。但是,如果将此值设置得非常高,最终会引入阴影暗斑,因为它会提高阴影贴图需要在光照方向上覆盖的范围。或者,您也可以细分有问题的阴影投射三角形。
如果您发现一个或多个对象未投射阴影,则应检查以下几点:
可在 Quality 窗口中彻底禁用实时阴影。确保启用了正确的质量级别并为该设置启用了阴影。
场景中的所有网格渲染器都必须正确设置相应的 Receive Shadows 和 Cast Shadows。默认情况下两者都已启用,但请检查确保未意外禁用它们。
只有不透明对象才投射和接受阴影,因此使用内置透明着色器或粒子着色器的对象既不会投射也不会接受阴影。通常,您可以使用透明镂空着色器代替具有“间隙”的对象,例如栅栏、植被等。自定义着色器必须采用像素光照并使用几何渲染队列。
使用顶点光照 (VertexLit) 着色器的对象不能接受阴影,但可投射阴影。
如果游戏对象的材质具有“无光照”类型的着色器,Unity 无法为这些游戏对象计算阴影。只有材质的着色器支持光照时,Unity 才能为材质计算阴影。
In the Built-in Render Pipeline, using the Forward rendering path, some shaders allow only the brightest directional light to cast shadows (in particular, this happens with Unity’s built-in shaders from 4.x versions). If you want to have more than one shadow-casting light then you should use the Deferred Shading rendering path instead. You can enable your own shaders to support “full shadows” by using the fullforwardshadows
surface shader directive.