首页 > 解决方案 > 如何制作一个完整弧线的视野?尝试创建射线弧

问题描述

我正在尝试使用玩家(实心圆圈)创建 2d 地图,并且开始创建光线投射。在进行光线投射之前,我正在尝试绘制一个简单的 FOV(视野),它应该是一个带有纯红色的弧形填充,如下所示:

在此处输入图像描述

(该图像只是为了说明填充的实心红色弧线)

为了计算绘图的弧线,我得到了弧线的第一个位置:

rayAngle = rotationAngle - (FOV_ANGLE /2)

rotationAngle 是玩家的起始位置,以弧度表示:

90d - PI/2
270d = 3 * PI/2
180d = PI
360d = 2 * PI

FOV_ANGLE 是 60d 的弧度,我用这个函数做了:

60 * (PI /180)

对于其他光线,我使用这些计算:

ray_angle += fov_angle / num_ray;

num_ray 只是窗口的宽度,在这种情况下考虑它是 (11 * 32)

有了这个功能。我计算每条光线并保存在一个数组中

t_point *rays

对于 struct t_point 我有这个:

typedef struct s_point
{
    int x;
    int y;
    int color;
} t_point;

之后,我得到数组的每个索引并使用 dda 算法画一条线:

#define ROUND(a) ((int)(a + 0.5))

void ft_line_dda(t_data *img, t_point start, t_point end)
{
    int dx = end.x - start.x;
    int dy = end.y - start.y;
    int steps;
    int k;
    long double xincrement;
    long double yincrement;
    long double x = start.x;
    long double y = start.y;

    if (abs(dx) > abs(dy))
        steps = abs(dx);
    else
        steps = abs(dy);

    xincrement = abs(dx) / (long double)steps;
    yincrement = abs(dy) / (long double)steps;
    my_mlx_pixel_put(img, ROUND(x), ROUND(y), get_color(ft_create_point(ROUND(x), ROUND(y), 0), start, end));
    for (k = 0; k < steps; k++)
    {
        if (start.x <= end.x)
            x += xincrement;
        else
            x -= xincrement;
        if (start.y <= end.y)
            y += yincrement;
        else
            y -= yincrement;
        // my_mlx_pixel_put(img, ROUND(x), ROUND(y), start.color);
        my_mlx_pixel_put(img, ROUND(x), ROUND(y), get_color(ft_create_point(ROUND(x), ROUND(y), 0), start, end));
    }
}

但问题是我不断得到这张图片,有一些点和空格:

在此处输入图像描述

(大小还可以。问题是空白和点)

请在下面找到与我正在尝试做的弧(伪射线投射)相关的代码:

void ft_create_rays(t_vars *vars)
{
    long double fov_angle;
    long double ray_angle;
    long double num_ray;
    t_point *rays;
    int i;

    i = 0;
    fov_angle = ft_degtorad(FOV_ANGLE);
    num_ray = vars->win_width / WALL_STRIP_WIDTH;
    ray_angle = vars->player->rotation_angle - (fov_angle / 2);
    rays = malloc(num_ray * sizeof(t_point));
    while (i < num_ray)
    {
        rays[i] = ft_create_point(vars->player->x + cos(ray_angle) * 100,
                                  vars->player->y + sin(ray_angle) * 100, 0x00ff0000);
        ray_angle += fov_angle / num_ray;
        i++;
    }
    if (vars->rays != NULL)
        free(vars->rays);
    vars->rays = rays;
}

void ft_raycast_render(t_vars *vars, t_data *img)
{
    int i;
    t_point central;

    i = 0;
    central = ft_create_point(vars->player->x, vars->player->y, 0x00ff0000);
    while (i < (vars->win_width / WALL_STRIP_WIDTH))
    {
        ft_line_dda(img, central, vars->rays[i]);
        i++;
    }
}

void ft_raycast(t_vars *vars, t_data *img)
{
    ft_create_rays(vars);
    ft_raycast_render(vars, img);
}

我想我展示了帮助我调试它所需的所有代码。无论如何,我会让链接到 github 存储库:

https://github.com/wblech/cub3d

PS我认为问题可能是终点在错误的位置并且线路转到不同的位置。但我不知道是否是这样,如果是,我不知道如何解决。

标签: cmathgraphicsraycasting

解决方案


空间在那里,因为你的观点真的有洞......

你知道,如果你n以某个角度投射阵列,FOV那么在所有距离上你只会n在弧周上得到点,所以你看起来越远,洞就越大。如果您想避免这种情况,请限制您的视距......并从周边弧长计算光线数量。

所以让我们举个例子:


l=128是以 [像素]
FOV=60*deg=1.0471975511965977461542144610932 rad为单位的视距(或地图大小)是以 [rad]
n=?为单位的视场是 FOV 中没有孔的最小光线数

n >= FOV*l
n >= 134.04128655316451150773945101993
n = 135

如果您想要一些灵感,请查看:


推荐阅读