揭秘视锥体:6个平面如何决定你的视野


一、什么是视锥体?——形象比喻

想象你用手做了一个“望远镜”或者“漏斗”,
你眼睛看到的空间,就是一个锥形的区域
这个区域叫做视锥体(View Frustum)

  • 摄像机就像你的眼睛
  • 视锥体就是你能看到的“空间范围”

视锥体有6个面:上、下、左、右、前、后,
就像一个被切掉头尾的金字塔。


二、视锥体的6个平面和法向量朝向

1. 6个平面

  • 左平面(Left)
  • 右平面(Right)
  • 上平面(Top)
  • 下平面(Bottom)
  • 近裁剪面(Near)(靠近摄像机的那一面)
  • 远裁剪面(Far)(远离摄像机的那一面)

2. 法向量的朝向

法向量就像每个平面上竖着的一根“箭头”,
都指向视锥体的内部,也就是摄像机能看到的空间。

  • 左、右、上、下平面的法向量都“斜着”指向视锥体内部
  • 近裁剪面法向量指向视锥体内部(远离摄像机)
  • 远裁剪面法向量指向视锥体内部(朝向摄像机)

3. 形象图示

         /\
        /  \
       /    \
      /------\
     / |    | \
    /  |    |  \
   /   |    |   \
  /----|----|----\
      Near   Far

(俯视图,摄像机在左,视锥体向右展开)
  • 每个斜面(左、右、上、下)都像一面“墙”,法向量都朝向视锥体内部
  • Near面法向量指向视锥体内部(远离摄像机)
  • Far面法向量指向视锥体内部(朝向摄像机)

三、计算6个平面的法向量和方程

1. 已知条件

在这里插入图片描述

2. 计算视锥体8个顶点

  • 先计算Near面和Far面中心点
  • 再根据FOV和宽高比,算出Near面和Far面的宽高
  • 得到8个顶点(Near面4个,Far面4个)

3. 计算每个平面的法向量

以左平面为例:
  • 取摄像机位置、Near面左上角、Far面左上角三个点
  • 用向量叉乘得到法向量

具体步骤:

在这里插入图片描述

其他平面同理:

4. 平面方程

在这里插入图片描述


四、方向图形(示意)

         摄像机
            |
            v
         Near面
        /      \
       /        \
左平面/          \右平面
     /            \
    /              \
   /                \
  /                  \
 上平面             下平面
  \                  /
   \                /
    \              /
     \            /
      \          /
       \        /
        Far面

每个平面的法向量都指向视锥体内部

五、总结口诀

“六面包围视野锥,法向量都朝里推;
叉乘三点得法线,判断可见靠它归。”


六、实际应用

  • 视锥体裁剪:判断物体是否在摄像机视野内
  • 碰撞检测:判断射线/物体是否穿过视锥体
  • 光照/阴影:判断光源照射范围

七、简要伪代码

# 以左平面为例
left_normal = cross(NearTopLeft - CameraPos, FarTopLeft - CameraPos)
left_normal = normalize(left_normal)
left_plane = (left_normal, NearTopLeft)  # 法向量+平面上一点

# 其他平面同理

继续研究用视锥体的6个平面做物体可见性判断,在游戏开发和3D渲染中叫做“视锥体裁剪(Frustum Culling)”。它的作用是:只渲染玩家摄像机能看到的物体,节省大量计算资源

下面用生动形象的方式详细讲解:


一、形象比喻

想象你拿着一个漏斗(视锥体),眼睛贴在漏斗小口(摄像机)往外看。
只有在漏斗范围内的东西你才能看到,漏斗外的东西你看不到。
我们要做的,就是判断一个物体(比如一个箱子)是不是在漏斗里面。


二、基本原理

  1. 视锥体由6个平面包围(上、下、左、右、近、远)。
  2. 每个平面都有一个“朝向视锥体内部”的法向量和方程 (Ax+By+Cz+D=0)。
  3. 物体通常用“包围盒”(AABB)或“包围球”来近似表示。

三、判断流程

1. 以包围盒为例

  • 包围盒有8个顶点(立方体的8个角)。

2. 对每个平面做判断

  • 对于每个平面,把包围盒的8个顶点都代入平面方程。
  • 计算 (Ax+By+Cz+D) 的值。

3. 判断结果

  • 如果8个点都在平面“外侧”(即 (Ax+By+Cz+D < 0)),说明物体完全在视锥体外部,可以直接丢弃,不渲染。
  • 如果有点在平面“内侧”(即 (Ax+By+Cz+D \geq 0)),说明物体有一部分在视锥体内,需要渲染。

4. 对6个平面都做一次

  • 只要有一个平面“全部在外”,就可以丢弃。
  • 只有所有平面都“不是全部在外”,物体才可能被看到。

四、图示说明

视锥体(漏斗)         包围盒(箱子)
   /------\                +------+
  /        \              /      /|
 /          \            +------+ |
/------------\           |      | +
|            |           |      |/
\------------/           +------+
  • 箱子在漏斗内:可见
  • 箱子在漏斗外:不可见
  • 箱子部分在漏斗内:可见

五、伪代码示例

def is_box_in_frustum(box_vertices, frustum_planes):
    for plane in frustum_planes:
        # 检查包围盒的8个顶点是否都在平面外侧
        if all(plane.A * v.x + plane.B * v.y + plane.C * v.z + plane.D < 0 for v in box_vertices):
            return False  # 物体完全在视锥体外
    return True  # 物体有一部分在视锥体内

六、包围球的判断(更快)

  • 计算球心到平面的距离 (d = A x_0 + B y_0 + C z_0 + D)
  • 如果 (d < -r)(r为半径),球完全在平面外侧,可丢弃
  • 如果 (d \geq -r),球有一部分在视锥体内

七、口诀总结

“六面包围视野锥,八点代入看内外;
全外丢弃节性能,部分可见才渲染。”


八、实际应用

  • 游戏场景中,成千上万个物体,只有视锥体内的才会被渲染
  • 大大提升帧率和性能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你一身傲骨怎能输

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值