如何不让我的光线投射器用曲线绘制墙壁

问题描述 投票:0回答:1
# define GRID_SIZE 64

// TODO: this comment
# define EPSILON 0.0001

// one degree in radians
# define ONE_DEGREE 0.0174532925

// Screen width
# define SCREEN_WIDTH 720

// Screen Height
# define SCREEN_HEIGHT 480

// Scale Factor for height of walls
# define SCALE_FACTOR 0.05

typedef struct s_ray_data
{
    int     mx;
    int     my;
    int     mp;
    int     dof;
    double  rx;
    double  ry;
    double  ra;
    double  xo;
    double  yo;
    double  a_tan;
    double  n_tan;
    double  hx;
    double  hy;
    double  dist_h;
    double  vx;
    double  vy;
    double  dist_v;
}           t_ray_data;


typedef struct s_ray_result
{
    double  dist;
    double  x;
    double  y;
    int object;
}           t_ray_result;

typedef struct s_ray
{
    int color;
    int direction;
    int object;
    double   distance;
}           t_ray;


double  mes_dist(double ax, double ay, double bx, double by)
{
    return (sqrt((bx - ax) * (bx - ax) + (by - ay) * (by - ay)));
}

void    calculate_horizontal_intercept(t_player_data *p, t_ray_data *rd)
{
    rd->dof = 0;
    rd->a_tan = -1 / tan(rd->ra);
    if (rd->ra > M_PI)
    {
        rd->ry = (((int)p->posy / GRID_SIZE) * GRID_SIZE) - 0.0001;
        rd->rx = (p->posy - rd->ry) * rd->a_tan + p->posx;
        rd->yo = -GRID_SIZE;
        rd->xo = -rd->yo * rd->a_tan;
    }
    if (rd->ra < M_PI)
    {
        rd->ry = (((int)p->posy / GRID_SIZE) * GRID_SIZE) + GRID_SIZE;
        rd->rx = (p->posy - rd->ry) * rd->a_tan + p->posx;
        rd->yo = GRID_SIZE;
        rd->xo = -rd->yo * rd->a_tan;
    }
    if (fabs(rd->ra) < EPSILON || fabs(rd->ra - M_PI) < EPSILON)
    {
        rd->rx = p->posx;
        rd->ry = p->posy;
        rd->dof = 8;
    }
}

void    calculate_vertical_intercept(t_player_data *p, t_ray_data *rd)
{
    rd->dof = 0;
    rd->n_tan = -tan(rd->ra);
    if (rd->ra > M_PI_2 && rd->ra < 3 * M_PI_2)
    {
        rd->rx = (((int)p->posx / GRID_SIZE) * GRID_SIZE) - 0.0001;
        rd->ry = (p->posx - rd->rx) * rd->n_tan + p->posy;
        rd->xo = -GRID_SIZE;
        rd->yo = -rd->xo * rd->n_tan;
    }
    if (rd->ra < M_PI_2 || rd->ra > 3 * M_PI_2)
    {
        rd->rx = (((int)p->posx / GRID_SIZE) * GRID_SIZE) + GRID_SIZE;
        rd->ry = (p->posx - rd->rx) * rd->n_tan + p->posy;
        rd->xo = GRID_SIZE;
        rd->yo = -rd->xo * rd->n_tan;
    }
    if (fabs(rd->ra - M_PI_2) < EPSILON || fabs(rd->ra - 3 * M_PI_2) < EPSILON)
    {
        rd->rx = p->posx;
        rd->ry = p->posy;
        rd->dof = 8;
    }
}

static void calculate_ray_data(t_player_data *p, t_ray_data *rd, t_minimap *m,
        t_ray_result *res)
{
    res->dist = 0.;
    res->x = p->posx;
    res->y = p->posy;
    while (rd->dof < 8)
    {
        rd->mx = (int)(rd->rx) / GRID_SIZE;
        rd->my = (int)(rd->ry) / GRID_SIZE;
        rd->mp = rd->my * m->map_x + rd->mx;
        if (rd->mp > 0 && rd->mx >= 0 && rd->mx < m->map_x && rd->my >= 0
            && rd->my < m->map_y && object_finder(m, rd, res))
        {
            res->x = rd->rx;
            res->y = rd->ry;
            res->dist = mes_dist(p->posx, p->posy, res->x, res->y);
            rd->dof = 8;
        }
        else
        {
            rd->rx += rd->xo;
            rd->ry += rd->yo;
            rd->dof++;
        }
    }
    if (res->dist == 0.)
        res->dist = INFINITY;
}

void    draw_rays(t_player_data *player, t_minimap *map, double angle, t_ray *rs)
{
    t_ray_data      ray_data;
    t_ray_result    result_h;
    t_ray_result    result_v;
    double          ca;

    ray_data.ra = angle;
    ca = player->playerangle - ray_data.ra;
    if (ca < 0)
        ca += 2 * M_PI;
    if (ca > 2 * M_PI)
        ca -= 2 * M_PI;
    calculate_horizontal_intercept(player, &ray_data);
    calculate_ray_data(player, &ray_data, map, &result_h);
    calculate_vertical_intercept(player, &ray_data);
    calculate_ray_data(player, &ray_data, map, &result_v);
    if (result_h.dist < result_v.dist)
    {
        ray_data.rx = result_h.x;
        ray_data.ry = result_h.y;
        rs->object = result_h.object;
        rs->color = 0xFF0000;
        direction_setter(rs, true, &ray_data, player);
    }
    else
    {
        ray_data.rx = result_v.x;
        ray_data.ry = result_v.y;
        rs->object = result_v.object;
        rs->color = 0x800000;
        direction_setter(rs, false, &ray_data, player);
    }
    rs->distance = mes_dist(player->posx, player->posy, ray_data.rx,
            ray_data.ry);
    rs->distance = rs->distance * cos(ca);
}

void    draw_ceiling(int x, int segment_width, int y_start, t_mlx *mlx)
{
    int y;
    int x_current;

    y = 0;
    while (y < y_start)
    {
        x_current = x;
        while (x_current < x + segment_width)
        {
            my_mlx_pixel_put(mlx, x_current, y, rgb_to_hex(mlx->scene.c_clr));
            x_current++;
        }
        y++;
    }
}

void    draw_walls(int x, int y_start, int y_end, t_mlx *mlx)
{
    int y;
    int x_current;
    int segment_width;

    segment_width = SCREEN_WIDTH / mlx->map->player->fov;
    x_current = x;
    while (x_current < x + segment_width)
    {
        y = y_start;
        while (y < y_end)
        {
            my_mlx_pixel_put(mlx, x_current, y, mlx->wall_color);
            y++;
        }
        x_current++;
    }
}

void    draw_floor(int x, int segment_width, int y_end, t_mlx *mlx)
{
    int y;
    int x_current;

    y = y_end;
    while (y < SCREEN_HEIGHT)
    {
        x_current = x;
        while (x_current < x + segment_width)
        {
            my_mlx_pixel_put(mlx, x_current, y, rgb_to_hex(mlx->scene.f_clr));
            x_current++;
        }
        y++;
    }
}


void    draw_wall_segment_to_image(int x, float distance, t_mlx *mlx, int color)
{
    int wall_height;
    int y_start;
    int y_end;
    int segment_width;

    segment_width = SCREEN_WIDTH / mlx->map->player->fov;
    wall_height = (int)(SCREEN_HEIGHT / (distance * SCALE_FACTOR));
    y_start = (SCREEN_HEIGHT - wall_height) / 2;
    y_end = y_start + wall_height;
    mlx->wall_color = color;
    draw_ceiling(x, segment_width, y_start, mlx);
    draw_walls(x, y_start, y_end, mlx);
    draw_floor(x, segment_width, y_end, mlx);
}


void    walls_3d(t_minimap *map, t_player_data *player, t_mlx *mlx)
{
    double  angle;
    int     i;
    int     segment_width;
    t_ray   ray_result;

    segment_width = SCREEN_WIDTH / player->fov;
    i = 0;
    angle = player->playerangle - ONE_DEGREE * (player->fov / 2);
    while (i <= player->fov)
    {
        if (angle < 0)
            angle += 2 * M_PI;
        if (angle > 2 * M_PI)
            angle -= 2 * M_PI;
        draw_rays(player, map, angle, &ray_result);
        draw_wall_segment_to_image(i * segment_width, ray_result.distance, mlx,
            ray_result.color);
        angle += ONE_DEGREE;
        i++;
    }
}


当我靠近一面向我弯曲的墙壁时,我仍然有一些扭曲。如果我站在一堵长墙旁边,看起来它在近距离处向我弯曲,而在远处则弯曲得有点向外。只有当我站在它旁边的某个角度时才会发生这种情况。当我直视它时就没事了。picture of the scenario

我尝试了距离 = 距离 * cos(ca),其中 ca 是玩家角度 - 射线角度。我还尝试使用相机飞机进行一些工作,但无法正常工作。降低视场角似乎也有一点帮助,但我希望人们在设置中拥有一个视场角滑块。

c++ c math graphics raycasting
1个回答
0
投票

你计算了距离的平方吗?

物体的大小取决于(1 / 距离^2)

我猜它在“mes_dist”函数中被取消了

注意:请使用注释线以及曲线的含义,您可以用图片来提问吗

© www.soinside.com 2019 - 2024. All rights reserved.