You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从世界坐标计算归一化设备坐标(NDC)范围异常排查

3D点转归一化设备坐标(NDC)时x值超出[-1,1]范围,投影矩阵是否存在问题?

我尝试实现了一个表示3D点的Vector3对象,用于将世界坐标转换为归一化设备坐标(NDC)。按理解,NDC的x、y、z值应处于[-1, 1]区间,但当前实现的结果并不总是符合该范围。以下是我的代码实现:

import math
import numpy as np

WIN_SIZE: int = 800  # square window
ASPECT_RATIO: float = 1  # square window

FOV: float = math.radians(60)
SCALING_FACTOR: float = 1 / math.tan(FOV / 2)
Z_FAR: float = 100
Z_NEAR: float = 1

class Vector3:
    def __init__(self, x: float, y: float, z: float) -> None:
        self.x: float = x
        self.y: float = y
        self.z: float = z
    
    def xyzw(self) -> np.array:
        return np.array([self.x, self.y, self.z, 1])
    
    def projection_matrix(self) -> np.array:
        m = np.zeros((4, 4))
        m[0, 0] = ASPECT_RATIO * SCALING_FACTOR
        m[1, 1] = SCALING_FACTOR
        m[2, 2] = Z_FAR / (Z_FAR - Z_NEAR)
        m[2, 3] = (-Z_FAR * Z_NEAR) / (Z_FAR - Z_NEAR)
        m[3, 2] = 1
        return m

    def normalized_device_coordinates(self) -> np.array:
        result = np.dot(self.projection_matrix(), self.xyzw())
        x, y, z, w = result

        if w != 0:
            result[0] /= w
            result[1] /= w
            result[2] /= w
        
        return result

测试用例Vector3(6, 0, 10).normalized_device_coordinates()的输出为[ 1.03923048, 0, 0.90909091, 10],其中x值超出了[-1, 1]范围。请问是否是我的投影矩阵实现存在问题?


问题分析与解决

测试点超出视锥体导致x值越界

你的测试点Vector3(6, 0, 10)本身位于视锥体之外,所以NDC x值超出[-1,1]是正常现象:

  • 视锥体在z=10位置的x方向半宽计算公式为:z * tan(FOV/2)
  • 代入数值:10 * tan(30°) ≈ 10 * 0.577 = 5.77
  • 你的测试点x=6,已经超过这个半宽,因此投影后NDC x>1,属于视锥体外的点,后续会被裁剪流程剔除。

投影矩阵的z分量不符合[-1,1]的NDC要求

你当前的投影矩阵生成的z值范围是[0,1],而非你预期的[-1,1]。若要让z也落在[-1,1]区间,需要修改投影矩阵的第3行:

修改前的z行:

m[2, 2] = Z_FAR / (Z_FAR - Z_NEAR)
m[2, 3] = (-Z_FAR * Z_NEAR) / (Z_FAR - Z_NEAR)

修改后的z行(适配NDC z∈[-1,1]):

m[2, 2] = -(Z_FAR + Z_NEAR) / (Z_FAR - Z_NEAR)
m[2, 3] = -2 * Z_FAR * Z_NEAR / (Z_FAR - Z_NEAR)

修改后,视锥体内的点(z∈[Z_NEAR, Z_FAR])的NDC z值会落在[-1,1]区间内。

验证修改效果

以测试点Vector3(5.77, 0, 10)(刚好在视锥边缘)为例:

  • 修改前NDC x≈1.0,z≈0.909
  • 修改后NDC x≈1.0,z≈-0.82(落在[-1,1]范围内)

而原测试点Vector3(6,0,10)即使修改矩阵,NDC x仍会>1,因为它本身就在视锥体外,这是合理的。


内容的提问来源于stack exchange,提问作者Kirk KD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 20:15:15