Unity阴影

阴影纹理判断深度那些我们都懂。我的疑惑是对于平行光,如何确定阴影贴图要覆盖的范围。

豆包回答:

左右 / 上下范围 :由 Shadow Distance 和主相机的视场角决定,以主相机为中心,向平行光方向扩展出一个覆盖主相机视锥在 Shadow Distance 内所有区域的立方体,确保主相机能看到的范围内,阴影都能被正确生成。

我感觉就是对场景的所有模型都判断深度,对于一个平行光方向,只用生成一次阴影纹理就能一直使用。如果转动光源,就会看见右下角有Global illumination processing,可能就是在重新生成ShadowMap。

豆包提供了这个脚本,用于标识平行光源阴影视锥。

cs 复制代码
using UnityEngine;
using UnityEditor;

[RequireComponent(typeof(Light))]
public class DirectionalShadowFrustumVisualizer : MonoBehaviour
{
    [Header("可视化设置")]
    [Tooltip("视锥线条颜色")]
    public Color frustumColor = Color.cyan;
    [Tooltip("线条宽度(仅Scene视图生效)")]
    public float lineWidth = 2f;

    private Light _dirLight;
    private Camera _mainCamera;

    // 视锥的8个顶点
    private Vector3[] _frustumCorners = new Vector3[8];

    private void OnEnable()
    {
        _dirLight = GetComponent<Light>();
        // 校验是否为平行光
        if (_dirLight.type != LightType.Directional)
        {
            Debug.LogError("该脚本仅支持平行光!");
            enabled = false;
            return;
        }
        _mainCamera = Camera.main;
    }

    // Scene视图绘制视锥
    private void OnDrawGizmos()
    {
        if (!_dirLight || !_mainCamera) return;

        // 获取全局Shadow Distance
        float shadowDistance = QualitySettings.shadowDistance;
        // 获取平行光的阴影近裁剪面
        float shadowNearPlane = _dirLight.shadowNearPlane;

        // 1. 计算主相机在Shadow Distance范围内的视锥投影边界
        CalculateMainCameraFrustumBounds(shadowDistance, out Vector3 camFrustumMin, out Vector3 camFrustumMax);

        // 2. 计算平行光虚拟相机的正交视锥参数
        Vector3 lightDir = _dirLight.transform.forward;
        // 视锥中心:主相机位置 + 平行光方向 * 阴影距离的一半
        Vector3 frustumCenter = _mainCamera.transform.position + lightDir * shadowDistance * 0.5f;
        // 视锥尺寸:基于主相机视锥的宽度、高度,以及阴影近/远裁剪面的距离
        Vector3 frustumSize = new Vector3(
            camFrustumMax.x - camFrustumMin.x,
            camFrustumMax.y - camFrustumMin.y,
            shadowDistance - shadowNearPlane
        );

        // 3. 计算视锥的8个顶点
        BuildFrustumCorners(frustumCenter, lightDir, frustumSize, shadowNearPlane);

        // 4. 绘制视锥线条
        Gizmos.color = frustumColor;
        Handles.color = frustumColor;
        //Handles.lineThickness = lineWidth;

        // 绘制视锥的12条边
        DrawLine(0, 1);
        DrawLine(1, 3);
        DrawLine(3, 2);
        DrawLine(2, 0);
        DrawLine(4, 5);
        DrawLine(5, 7);
        DrawLine(7, 6);
        DrawLine(6, 4);
        DrawLine(0, 4);
        DrawLine(1, 5);
        DrawLine(2, 6);
        DrawLine(3, 7);
    }

    // 计算主相机在指定距离下的视锥投影边界
    private void CalculateMainCameraFrustumBounds(float distance, out Vector3 min, out Vector3 max)
    {
        float halfFOV = _mainCamera.fieldOfView * 0.5f * Mathf.Deg2Rad;
        float aspect = _mainCamera.aspect;

        float halfHeight = Mathf.Tan(halfFOV) * distance;
        float halfWidth = halfHeight * aspect;

        min = new Vector3(-halfWidth, -halfHeight, distance);
        max = new Vector3(halfWidth, halfHeight, distance);

        // 转换到世界空间
        min = _mainCamera.transform.TransformVector(min);
        max = _mainCamera.transform.TransformVector(max);
    }

    // 构建正交视锥的8个顶点
    private void BuildFrustumCorners(Vector3 center, Vector3 lightDir, Vector3 size, float nearPlane)
    {
        Vector3 halfSize = size * 0.5f;
        Vector3 up = Vector3.up;
        Vector3 right = Vector3.Cross(lightDir, up).normalized;
        up = Vector3.Cross(right, lightDir).normalized;

        // 近裁剪面4个顶点
        _frustumCorners[0] = center - right * halfSize.x - up * halfSize.y - lightDir * (halfSize.z - nearPlane);
        _frustumCorners[1] = center + right * halfSize.x - up * halfSize.y - lightDir * (halfSize.z - nearPlane);
        _frustumCorners[2] = center - right * halfSize.x + up * halfSize.y - lightDir * (halfSize.z - nearPlane);
        _frustumCorners[3] = center + right * halfSize.x + up * halfSize.y - lightDir * (halfSize.z - nearPlane);

        // 远裁剪面4个顶点
        _frustumCorners[4] = center - right * halfSize.x - up * halfSize.y + lightDir * halfSize.z;
        _frustumCorners[5] = center + right * halfSize.x - up * halfSize.y + lightDir * halfSize.z;
        _frustumCorners[6] = center - right * halfSize.x + up * halfSize.y + lightDir * halfSize.z;
        _frustumCorners[7] = center + right * halfSize.x + up * halfSize.y + lightDir * halfSize.z;
    }

    // 绘制单条线段
    private void DrawLine(int indexA, int indexB)
    {
        Handles.DrawLine(_frustumCorners[indexA], _frustumCorners[indexB]);
    }
}

动了一下相机,视锥会跟着变化,规则挺复杂。

相关推荐
魔士于安4 天前
unity 丑陋哥布林 哥布林有humannoid 动画没 带动画
unity·游戏引擎·材质·贴图·模型
小贺儿开发5 天前
Unity 家居视频遥控(细节优化)
科技·unity·程序员·udp·视频·工具·通信
淡海水5 天前
13-04-面试-源码级深度追问链
数据结构·unity·面试·c#·游戏引擎·源码·il2cpp
小小数媒成员6 天前
UGUI 性能优化(详细,全,深入)
开发语言·unity·游戏引擎
林川~016 天前
Unity新输入系统使用笔记
unity·input system
小贺儿开发6 天前
Unity 结合百度AI开放平台 手写文字识别
人工智能·科技·学习·unity·云服务·文字识别·手写文字
goujunwe7 天前
GEO 评估方法:如何自测你的内容,会不会被 AI 引用
搜索引擎·网络安全·游戏引擎·全文检索·中文分词
林川~017 天前
Unity 万能物理检测工具:射线检测 / 范围检测 / 层级过滤 / 编辑器可视化(可直接拿去用)
游戏·unity·c#·射线检测·通用工具
yi碗汤园7 天前
MQTT消息队列遥测传输协议
网络·网络协议·unity
林川~018 天前
Unity 常用 API 与核心类全解:从生命周期到协程,附性能避坑清单(Unity 6 适配)
unity·游戏引擎·常用api