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

JavaScript Canvas射线游戏中随墙面角度变化的贴花感知宽度计算问题

射线投射游戏墙体贴花的感知宽度计算方案

现有计算逻辑的问题根源

你之前写的宽度缩放逻辑存在两个硬伤:

  • 直接用玩家方向和贴花朝向的点积当宽度系数,既没有关联贴花在墙面上的实际物理跨度,也没有和墙体本身的透视压缩逻辑对齐
  • 手动加的minPerspective阈值属于经验凑数参数,没有对应真实几何关系,自然会出现小角度下宽度压缩过度、贴花盖不住底层墙体的问题

可直接落地的计算实现(零额外射线投射开销)

完全复用你已经存好的Z-BUFFER、H-BUFFER、GRID_BUFFER数据,不需要重跑射线流程,步骤如下:

  • 初始化阶段:
    • 给每个静态贴花预先定义它在所属网格墙面上的物理边界坐标——也就是贴花本身在墙面上占的横向、纵向物理范围(比如贴花占整面墙横向长度的10%90%、纵向高度的20%80%,直接转换为世界坐标下的两个端点位置)
    • 在射线投射存储GRID_BUFFER时,按网格ID归集每个网格面对应的屏幕x范围,几乎不占额外内存
  • 渲染阶段:
    1. 复用你已经跑通的网格坐标转屏幕坐标的投影公式,分别计算贴花左、右物理端点的屏幕横坐标。这里直接用和墙体投影完全同源的逻辑,不需要重写变换:
      // 完全复用你射线阶段的投影公式,和现有decalScreenX计算逻辑保持一致
      function worldToScreenX(worldPoint) {
        const dx = worldPoint.x - PLAYER.pos.x;
        const dy = worldPoint.y - PLAYER.pos.y;
        // 相机变换矩阵投影,和你现有代码的计算逻辑完全对齐
        const depth = dx * CAMERA.dirX + dy * CAMERA.dirY;
        const offset = dx * CAMERA.planeX + dy * CAMERA.planeY;
        return Math.floor(RAYCAST.SCREEN_WIDTH / 2 * (1 + offset / depth));
      }
      const decalLeftX = worldToScreenX(decal.physicalLeftPoint);
      const decalRightX = worldToScreenX(decal.physicalRightPoint);
      
    2. 贴花的感知宽度直接取两个端点屏幕坐标的绝对值差:decalPerceivedWidth = Math.abs(decalRightX - decalLeftX)
    3. 绘制时直接取贴花所属网格面的x范围作为裁切边界,叠加H-BUFFER计算的高度缩放系数,就能实现和墙体透视完全同步的渲染效果。

为什么这套逻辑能解决之前的所有问题

  • 透视完全对齐:因为投影公式和墙体渲染用的是同一套,贴花在墙面上占多少物理宽度,对应的屏幕宽度就和墙体本身的透视压缩量完全同步,根本不会出现贴花缩得比墙快、漏出底层墙体的问题
  • 无透视死角:哪怕贴花几乎和视线平行,只要在视野范围内,计算出来的投影宽度是严格符合真实几何的,不会被错误归零
  • 运行时开销极低:因为贴花是静态绑定在墙面上的,初始化阶段只需要预先算好物理端点坐标,渲染时只需要两次投影计算,不需要重跑射线,也不需要做复杂的三角函数运算
  • 不需要任何经验阈值:之前手动加的minPerspective、反复调整的FACTOR系数全部可以删除,只需要在宽度计算结果上加1~2像素的偏移,抵消取整带来的绘制缝隙,就能实现贴花完全覆盖目标墙面的效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.26 20:15:01