在我的 raycaster 中透视扭曲的原因是什么?

问题描述

我正在尝试使用 SDL 编写光线投射器。不幸的是,很多时候这种观点是扭曲的。我正在调用 SDL_RenderFillRect 来填充每个垂直矩形,但有时该矩形未被填充。此外,当我使用向上箭头键前进时,这面墙会缩小而不是增长。我不明白为什么会这样。控制方式如下:上键前进,下键后退,左键左转,右键右转。我是编写 raycasters 的新手,所以如果可能的话,请给我关于如何改进它的建议。谢谢。

我正在像这样编译我的代码(在 Mac 上): gcc -Wall -Wformat -O3 `pkg-config --cflags --libs sdl2` raycaster.c

const int
    screen_width = 600,screen_height = 300,map_width = 10,map_height = 6;

const float width_ratio = (float) screen_width / map_width,height_ratio = (float) screen_height / map_height;

const unsigned char map[map_height][map_width] = {
    {1,1,1},{1,1}
};

typedef struct {
    float angle,fov;
} Camera;

typedef struct {
    float x,y;
    Camera camera;
} Player;

#define SET_COLOR(rend,r,g,b) SDL_SetRenderDrawColor(rend,b,SDL_ALPHA_OPAQUE)

#include <SDL2/SDL.h>
#include <math.h>

SDL_Window* window;
SDL_Renderer* renderer;

void render(Player player) {
    int rel_x = player.x * width_ratio,rel_y = player.y * height_ratio;
    Camera cam = player.camera;
    float half_fov = cam.fov / 2,width_fov_ratio = screen_width / cam.fov;
    
    for (float theta = cam.angle - half_fov,vline_x = 0;
        theta < cam.angle + half_fov;
        theta += 0.5,vline_x += width_fov_ratio) {

        float radian_theta = theta * (M_PI / 180);
        float cos_theta = cos(radian_theta),sin_theta = sin(radian_theta);

        float d = 0,new_x,new_y;
        while (d += 0.5) {
            new_y = sin_theta * d + rel_y,new_x = cos_theta * d + rel_x;

            int scaled_down_y = round(new_y / height_ratio),scaled_down_x = round(new_x / width_ratio);

            if (map[scaled_down_y][scaled_down_x]) {
                float dist_to_wall = sqrt(pow(new_x - rel_x,2) + pow(new_y - rel_y,2));

                SDL_Rect r;
                r.x = vline_x;
                r.y = dist_to_wall;
                r.w = width_fov_ratio * 2;
                r.h = screen_height - dist_to_wall * 2;

                SET_COLOR(renderer,191,255);
                SDL_RenderFillRect(renderer,&r);
                SDL_RenderDrawRect(renderer,&r);
                break;
            }
        }
    }
}

int main() {
    SDL_CreateWindowAndRenderer(screen_width,screen_height,&window,&renderer);
    SDL_SetwindowTitle(window,"Raycaster");
    Player player = {2,2,{45,90}};

    while (1) {
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
                case SDL_QUIT:
                    SDL_DestroyWindow(window),SDL_DestroyRenderer(renderer);
                    return 0;
                case SDL_KEYDOWN: {
                    float radian_angle = player.camera.angle * (M_PI / 180);
                    float move_x = cos(radian_angle) * 0.1,move_y = sin(radian_angle) * 0.1;
                    switch (event.key.keysym.sym) {
                        case SDLK_UP: player.x += move_x,player.y += move_y; break;
                        case SDLK_DOWN: player.x -= move_x,player.y -= move_y; break;
                        case SDLK_LEFT: player.camera.angle -= 2; break;
                        case SDLK_RIGHT: player.camera.angle += 2; break;
                    }
                    if (player.x < 0) player.x = 0;
                    else if (player.x > screen_width) player.x = screen_width;

                    if (player.y < 0) player.y = 0;
                    else if (player.y > screen_height) player.y = screen_height;

                    if (player.camera.angle > 360) player.camera.angle = 0;
                    else if (player.camera.angle < 0) player.camera.angle = 360;
                }
            }
        }
        SET_COLOR(renderer,0);
        SDL_RenderClear(renderer);
        render(player);
        SDL_RenderPresent(renderer);
        SDL_UpdateWindowSurface(window);
    }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)