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

OpenGL中视锥体剔除未完全利用包围球的问题排查

OpenGL视锥体剔除:包围球未完全移出即被误判剔除

在OpenGL实现视锥体剔除时遇到问题:物体的包围球尚未完全移出视锥体,就被判定为需要剔除。程序表现得像是认为包围球的半径比实际更小,但我已反复核对,确认半径计算无误。

目前仅针对包围球顶部是否在视锥体内做检测,修改判断语句会得到完全相反的错误结果。

视锥体检测代码

# 相机到chunk的向量
chunk_vec = chunk.center - self.camera.pos

# chunk在相机坐标系下的y轴距离(含包围球半径)
y_dist = glm.dot(chunk_vec, self.camera.up) + CHUNK_BOUNDING_SPHERE_RADIUS
# chunk在相机坐标系下的z轴距离
z_dist = glm.dot(chunk_vec, self.camera.forward)
HIGHEST_ALLOWED_THETA = VFOV / 2
theta = glm.atan(y_dist / z_dist)
print(glm.degrees(theta), glm.degrees(HIGHEST_ALLOWED_THETA))
if theta <= HIGHEST_ALLOWED_THETA:
    print('render')
else:
    print('cull')

包围球半径计算代码

(确认此处无错误,渲染出的包围球完全贴合物体,且多次核对计算逻辑)

length = glm.sqrt(glm.pow(CHUNK_LENGTH_VOXELS * VOXEL_SIZE / 2, 2) * 2)
height = CHUNK_HEIGHT_VOXELS * VOXEL_SIZE / 2
CHUNK_BOUNDING_SPHERE_RADIUS = glm.sqrt(
    glm.pow(length, 2) + glm.pow(height, 2)
)

问题现象

当代码判定包围球需被剔除时,仍有部分球体处于视锥体内,且该比例不随物体距离或相机位置变化;渲染可见包围球完全贴合物体。

补充:投影与视图矩阵代码

投影矩阵计算

ASPECT_RATIO = 16 / 9
NEAR = 0.1
FAR = 20000
FOV = 70
VFOV = glm.radians(FOV)
HFOV = 2 * glm.atan(glm.tan(VFOV * 0.5) * ASPECT_RATIO)

self.proj_mat = glm.perspective(
  VFOV, ASPECT_RATIO, NEAR, FAR
)

视图矩阵计算(相机类内部)

yaw_change, pitch_change = pg.mouse.get_rel()
self.yaw -= yaw_change * MOUSE_SENSITIVITY
self.pitch -= pitch_change * MOUSE_SENSITIVITY
self.pitch = glm.clamp(self.pitch, -80, 80)

yaw = glm.radians(self.yaw)
pitch = glm.radians(self.pitch)

yaw_sin = glm.sin(yaw)
yaw_cos = glm.cos(yaw)
pitch_sin = glm.sin(pitch)
pitch_cos = glm.cos(pitch)

self.right = glm.normalize(glm.vec3(yaw_cos, 0, -yaw_sin))
self.up = glm.normalize(glm.vec3(yaw_sin * pitch_sin, pitch_cos, yaw_cos * pitch_sin))
self.forward = glm.normalize(glm.vec3(yaw_sin * pitch_cos, -pitch_sin, pitch_cos * yaw_cos))

self.view_mat = glm.mat4(
  glm.vec4(self.right.x, self.up.x, self.forward.x, 0),
  glm.vec4(self.right.y, self.up.y, self.forward.y, 0),
  glm.vec4(self.right.z, self.up.z, self.forward.z, 0),
  glm.vec4(-glm.dot(self.right, self.pos), -glm.dot(self.up, self.pos), -glm.dot(self.forward, self.pos), 1)
)

手动校准半径值可临时解决问题,但并非理想方案,希望找到问题根源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 10:47:04