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

OpenGL相机碰撞检测:实现仅限制碰撞方向移动的解决方案求助

解决OpenGL相机碰撞仅限制碰撞方向移动的问题

核心思路是把每个轴的移动单独拆分处理,先预判移动后的位置,再根据碰撞结果决定是否应用该方向的移动,而不是碰撞后直接停止所有方向的移动。这样就能实现仅限制碰撞轴、其他方向正常通行的效果。

第一步:重构碰撞检测逻辑(新增预判位置检测函数)

我们需要一个辅助函数,用来判断相机移动到某个目标位置时是否会和AABB碰撞,而不是检测当前位置:

// 判断相机在目标位置是否与指定AABB碰撞
fun isCameraPositionColliding(targetPos: Vector3f, quad: Renderable?): Boolean {
    val quadPos = quad?.getPosition() ?: return false
    val collisionX = targetPos.x <= quadPos.x + maxX && targetPos.x >= quadPos.x + minX
    val collisionY = targetPos.y <= quadPos.y + maxY && targetPos.y >= quadPos.y + minY
    val collisionZ = targetPos.z <= quadPos.z + maxZ && targetPos.z >= quadPos.z + minZ
    return collisionX && collisionY && collisionZ
}

// 如果需要检测多个碰撞体,可用这个版本
fun isCameraPositionColliding(targetPos: Vector3f, colliders: List<Renderable>): Boolean {
    for (quad in colliders) {
        val quadPos = quad.getPosition() ?: continue
        val collisionX = targetPos.x <= quadPos.x + maxX && targetPos.x >= quadPos.x + minX
        val collisionY = targetPos.y <= quadPos.y + maxY && targetPos.y >= quadPos.y + minY
        val collisionZ = targetPos.z <= quadPos.z + maxZ && targetPos.z >= quadPos.z + minZ
        if (collisionX && collisionY && collisionZ) {
            return true
        }
    }
    return false
}

第二步:修改相机移动函数,实现分轴控制

把原来的直接移动逻辑拆分成每个轴独立处理,先计算移动后的位置,检测无碰撞后再应用移动:

fun moveCamera(dt: Float, t: Float) {
    this.dt = t - lastFrame
    lastFrame = t.toFloat()
    val s = 2.0f
    val cameraSpeed = dt * s
    camera.parent = null

    // 获取相机当前位置,作为目标位置的初始值
    val currentPos = camera.getPosition()
    var targetPos = Vector3f(currentPos.x, currentPos.y, currentPos.z)

    // 处理X轴移动(J左移)
    if (window.getKeyState(GLFW.GLFW_KEY_J)) {
        targetPos.x -= cameraSpeed
        // 预判移动后是否碰撞,碰撞则回滚X轴位置
        if (isCameraPositionColliding(targetPos, wallModule1x1Renderable)) {
            targetPos.x = currentPos.x
        }
    } 
    // 处理X轴移动(L右移)
    else if (window.getKeyState(GLFW.GLFW_KEY_L)) {
        targetPos.x += cameraSpeed
        if (isCameraPositionColliding(targetPos, wallModule1x1Renderable)) {
            targetPos.x = currentPos.x
        }
    }

    // 处理Z轴移动(K向前/向后,保持你原来的逻辑)
    if (window.getKeyState(GLFW.GLFW_KEY_K)) {
        targetPos.z -= cameraSpeed
        if (isCameraPositionColliding(targetPos, wallModule1x1Renderable)) {
            targetPos.z = currentPos.z
        }
    }

    // 最后将验证后的目标位置应用到相机
    camera.setPosition(targetPos)
}

逻辑说明

  1. 每个轴的移动独立计算,互不干扰:比如X轴碰撞时,Z轴的移动依然可以正常执行
  2. 采用预判位置检测,避免相机已经穿入碰撞体后再修正的卡顿问题
  3. 如果需要支持多个碰撞墙,只需把wallModule1x1Renderable换成碰撞体列表,调用多碰撞体版本的检测函数即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 02:44:04