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

Fisheye Raycasting余弦校正不适用时的鱼眼畸变修复问题

Raycasting游戏鱼眼畸变修复方案

问题现状

开发简易光线投射游戏时,基于光线长度、对数公式计算墙体尺寸做渲染,出现鱼眼畸变问题,常规余弦校正无法适配现有项目架构,核心实现代码如下:

void    draw_3d(t_cub3d *this, double len, int num_of_ray, double start)
{
double height;
double width;
double x;
double y;

height = 720 / log10(len + 1);
if (height > 720)
    height = 720;
width = 1280.0 / 640;
y = (720 - height) / 2;
while (y < height)
{
    x = 2 * num_of_ray;
    while(x < 2 + width * num_of_ray)
    {
        my_mlx_pixel_put(this, (int)x, (int)y, 0xfffff);
        x++;
    }
    y++;
  }
}

int raycast(t_cub3d *this)
{
double start = this->raycast->pa - this->raycast->fov;
double end = this->raycast->pa + this->raycast->fov;
double ray_p_x;
double ray_p_y;
double len;
int num_of_ray;

num_of_ray = 0;
while (start <= end)
{
    ray_p_x = this->raycast->px;
    ray_p_y = this->raycast->py;
    while (this->gameinfo->map[(int) ray_p_y / 30][(int) ray_p_x / 30] != '1' && this->gameinfo->map[(int) ray_p_y / 30][(int) ray_p_x / 30] != ' ')
    {
        ray_p_x += cos(start);
        ray_p_y += sin(start);
    }
    len = fabs(this->raycast->px - ray_p_x) / fabs(cos(start));
    len *= cos(this->raycast->pa - start);
    start += this->raycast->fov / 320;
    draw_3d(this, len, num_of_ray, start);
    num_of_ray++;
}
mlx_put_image_to_window(this->mlx_info->mlx, this->mlx_info->mlx_win, this->img->img, 0, 0);
return (0);
}

程序运行时直墙会在视野边缘向外弧形凸起,呈现典型鱼眼畸变效果。

畸变根因

余弦校正失效不是方案本身问题,是现有代码存在3个逻辑错误:

  • 光线长度计算错误:用x轴坐标差反推斜距的方式精度差,当光线接近水平/垂直时容易出现除零、数值溢出问题,算出来的原始长度本身不准
  • 角度差未做归一化:光线角度和玩家朝向角度的差值可能超出余弦函数的有效计算范围,导致校正系数错误
  • 墙体绘制循环边界错误:y轴绘制的终止值设置错误,墙体下半部分无法正常绘制,进一步放大了畸变的视觉表现

适配现有架构的修复步骤

不需要重构现有渲染逻辑,仅修改局部代码即可:

  • 替换光线长度计算逻辑,直接计算玩家到碰撞点的欧氏距离作为原始斜距,替换原有len计算的第一行代码:
// 替换 len = fabs(this->raycast->px - ray_p_x) / fabs(cos(start));
len = sqrt(pow(ray_p_x - this->raycast->px, 2) + pow(ray_p_y - this->raycast->py, 2));
  • 增加角度差归一化逻辑,修正余弦校正系数的计算准确性,替换原有len乘校正系数的代码:
// 替换 len *= cos(this->raycast->pa - start);
double angle_diff = this->raycast->pa - start;
// 归一化角度差到[-π, π]区间,避免cos计算值错误
while (angle_diff > M_PI) angle_diff -= 2 * M_PI;
while (angle_diff < -M_PI) angle_diff += 2 * M_PI;
len *= cos(angle_diff);
  • 修正draw_3d函数中y轴循环的终止条件,原有条件会导致墙体只绘制上半段:
// 把循环条件从 while (y < height) 改为
while (y < (720 + height) / 2)
  • 原有对数计算墙体高度的逻辑完全不需要修改,校正后的len值可以直接传入计算,适配现有架构。

修复后效果

视野内的直墙边缘会保持竖直,不会再出现两侧向外凸起的弧形畸变,和标准光线投射渲染效果一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 12:24:24