阴影贴图

简介

阴影贴图是一种为 3D 场景提供实时阴影的常用技术。它的工作原理是从光源的角度渲染深度图纹理。然后,在为三维模型的像素着色时,将其深度值与深度图进行比较,如果该像素处于阴影中,则其阴影会变暗;如果该像素被光线照亮,则其阴影会变亮。

阴影增加了场景的真实感,使人们更容易判断物体的相对位置。

请注意,在图像的左侧场景中,我们无法判断物体离平面有多远,但在右侧场景中,阴影却能让我们轻松判断。

Qt XML 为所有三种光线类型(DirectionalLightPointLightSpotLight )提供阴影映射支持。要在场景中激活阴影,首先需要通过将castsShadow 设置为true 来设置灯光投射阴影。然后,您可以通过将castsShadowsreceivesShadows 设置为truefalse 来控制哪些模型将投射和接收阴影。

定向灯

定向光从无限远处的一个无法识别的光源向一个方向发射光线。这与现实生活中阳光的作用方式类似。定向光的范围是无限的,并且不会减弱。

级联阴影贴图

DirectionalLight 的一个问题是,它从光线的角度渲染整个场景。如果阴影贴图的大小不够,就会导致阴影看起来很模糊。要获得更好的渲染质量,一种方法是使用级联阴影贴图(CSM)。Qt 支持一种名为 Parallell Split Shadow Maps(PSSM)的 CSM 版本。PSSM 的工作原理是将视图圆锥体分割成几个部分,并为每个部分渲染阴影贴图。

这张图显示的是带有 PSSM 分割的视场半球的抽象图像。它有两个分割,最后形成三个级联。

通过这种方式,您可以在靠近摄像机的地方获得更高的阴影贴图分辨率,视觉质量会更明显,而在远离摄像机的地方获得较低的分辨率,视觉质量会更不明显。

上图显示的是没有任何分割的阴影贴图(左)和有 3 个分割的阴影贴图(右)。

您可以通过csmNumSplits 属性控制级联分割的数量,并通过csmSplit1csmSplit2csmSplit3 属性控制分割的位置。为了使分割之间的过渡效果更美观,可以使用csmBlendRatio 属性指定分割之间一定的混合程度。

上图显示的是级联接缝的放大视图,没有使用任何混合效果。

请注意,每添加一个分割点,应用程序就必须渲染另一个阴影贴图,这将对性能产生负面影响。混合区域的大小也会影响性能,因此要尽可能缩小。

点光源

PointLight 可以被描述为一个球体,从光源中心到给定半径的所有方向都会发出强度相同的光。这与灯泡的发光方式类似。

PointLight 会将阴影贴图渲染为立方体贴图,这意味着需要进行六次渲染。这在计算上可能相当昂贵。

聚光灯

SpotLight 以圆锥形向一个方向发光,圆锥形由coneAngle 属性定义。当接近coneAngle 时,光强会减弱。光强开始减弱的角度由innerConeAngle 定义。这与手电筒或聚光灯的发光原理类似。

PointLight 不同,SpotLight 将其阴影贴图渲染为单一深度贴图。

性能和场景调整

虽然 Qt 尝试为与阴影贴图相关的属性提供合理的默认值,但通常需要对它们进行调整以适应特定场景。尤其是当场景比预期的要小或大得多时。下文将详细介绍如何调整这些值,使阴影贴图既美观又尽可能保持良好的性能。

阴影偏置

Shadow bias 是一种消除所谓阴影痤疮的方法,这种痤疮是通常出现在某些图案中的虚假阴影。阴影偏置会偏移阴影贴图的深度纹理,使阴影显示在离阴影物体更远的地方,这通常可以解决阴影痤疮问题。但缺点是,如果阴影偏置过多,就会产生一种称为 "彼得平移 "的效果,即阴影离阴影物体太远。也可以通过提高阴影贴图的分辨率来减少阴影痤疮。

上图显示了 0 阴影偏置(左)与 10 阴影偏置(右)的场景对比。左侧场景的圆锥体和圆柱体顶部有一些虚假阴影。

阴影贴图分辨率

阴影贴图的分辨率/质量由shadowMapQuality 属性控制。阴影贴图的质量越高,阴影的遮挡就越少,但渲染成本也就越高,因此在保持所需的视觉质量的前提下,尽可能将分辨率设得低一些。

上图显示的是阴影贴图分辨率较低的场景与阴影贴图分辨率较高的场景。

软阴影质量

软阴影是一种近似于现实生活中阴影效果的方式,即阴影的边缘由硬变软。柔和阴影的质量由softShadowQuality 属性控制。它支持无柔和度的硬阴影以及不同质量的百分比闭合过滤 (PCF) 柔和阴影。硬阴影的渲染成本最低,而 PCF 质量越高,成本越高。要控制柔和阴影的半径,请使用pcfFactor 属性。pcfFactor 的值不会影响渲染速度,但它越高,软阴影的质量就越高,看起来才会更美观。

上图左侧显示的是带有softShadowQuality Light.Hard 阴影的场景,右侧显示的是带有softShadowQuality Light.PCF32pcfFactor 10 阴影的场景。

阴影贴图远景

shadowMapFar 属性可用于控制阴影贴图的最大距离。该属性对PointLightSpotLightDirectionalLight 的作用略有不同。

对于PointLight/SpotLight ,它决定了渲染阴影的边界框应有多大,但对于DirectionalLight ,它定义了阴影贴图在场景中应覆盖距离场景摄像机多远的范围。

上图显示的是同一场景,光照方向相同,但shadowMapFar 的值不同。

阴影贴图位深度

在某些情况下,如果场景非常大,会导致阴影贴图在深度轴上覆盖很大的区域。例如,如果有许多物体远离摄像机视角,但仍然投射阴影,并且需要成为阴影贴图边界的一部分。在这种情况下,即使使用较高的{Light::}{shadowBias},场景仍然会出现带状伪影。解决方法之一是在阴影贴图上使用 32 位深度。将{Light::}{use32BitShadowmap}属性设置为true 将在特定灯光上启用此功能。

上图显示了具有相同方向光线的相同场景,但一个使用 32 位阴影贴图,另一个使用 16 位阴影贴图。

另请参阅 "使用基于图像的照明"、"光照贴图和全局照明 "Qt Quick 3D - 层叠阴影贴图示例

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.