基于SDL2的Raycasting项目消除鱼眼效果技术咨询
Raycasting项目鱼眼效果修复求助
我正在使用SDL2开发一个Raycasting项目,已成功实现射线投射功能,但3D预览环节仍存在鱼眼效果,无法达到预期的3D呈现效果。以下是当前实现代码,恳请提供解决思路:
#include "include/maze.h" #include "include/colors.h" void drawRays(SDL_Renderer *renderer, SDL_Renderer *renderer2, Player *player, SDL_Point walls[200][2], int wallCount) { SDL_Point target; SDL_Point closest; SDL_Rect rect; SDL_Surface *surface = createPlusTexture(0,0); SDL_Texture *t = SDL_CreateTextureFromSurface(renderer2, surface);//creates brown texture // The thickness the bars can be based on the window width int rayPreviewrenstep = windowW * 1.15 / fov; int rayCount = 0; int closestDistance; rect.w = rayPreviewrenstep; // We can pre calculate the width as this is a constant // Loop for each ray in fov at 1 degree step for (int a = player->angle - fov / 2; a < player->angle + fov / 2; a++) { rayCount++; target = CreateTarget(player->pos.p1.x, player->pos.p1.y, a, viewRange); // Find the point at which the ray is out of view distance closest = target; closestDistance = viewRange; // Loop over each wall for (int i = 0; i < wallCount; i++) { // Find the intersection point float a1 = target.y - player->pos.p1.y; float b1 = player->pos.p1.x - target.x; float c1 = a1 * player->pos.p1.x + b1 * player->pos.p1.y; float a2 = walls[i][1].y - walls[i][0].y; float b2 = walls[i][0].x - walls[i][1].x; float c2 = a2 * walls[i][0].x + b2 * walls[i][0].y; float det = a1 * b2 - a2 * b1; // If its not parallel if (det != 0) { int x = (b2 * c1 - b1 * c2) / det; int y = (a1 * c2 - a2 * c1) / det; // If the point falls inside the wall and the ray if (PointOnLine(player->pos.p1.x, player->pos.p1.y, target.x, target.y, x, y) && PointOnLine(walls[i][0].x, walls[i][0].y, walls[i][1].x, walls[i][1].y, x, y)) { // Calculate the distance to the point int dist = PointDistance(player->pos.p1.x, player->pos.p1.y, x, y); // If its the closest wall, store it if (dist < closestDistance) { closest.x = x; closest.y = y; closestDistance = dist; } } } } // If the ray hit something if (closestDistance != viewRange) { // Draw the ray SDL_SetRenderDrawColor(renderer, COLOR_DARK_GRAY.r, COLOR_DARK_GRAY.g, COLOR_DARK_GRAY.b, COLOR_DARK_GRAY.a); SDL_RenderDrawLine(renderer, player->pos.p1.x, player->pos.p1.y, closest.x, closest.y); // Draw the 3d preview // correct vision rect.x = rayPreviewrenstep * rayCount + (windowW - 900) / 3; rect.y = closestDistance / 2; rect.h = windowH - rect.y *2; int brightness = 255 - closestDistance / 2; SDL_SetRenderDrawColor(renderer2, brightness, brightness, brightness, 255); SDL_RenderFillRect(renderer2, &rect); // SDL_RenderCopy(renderer2, t, NULL, &rect); SDL_SetRenderDrawColor(renderer2, COLOR_BLACK.r, COLOR_BLACK.g, COLOR_BLACK.b, COLOR_BLACK.a); } } } SDL_Point CreateTarget(int x, int y, int dir, int dist) { // Create a point dist pixels away in dir direction from x and y SDL_Point target; double translated = DEG2RAD(dir); // Convert to radians target.x = round(x + dist * cos(translated)); target.y = round(y + dist * sin(translated)); return target; } int PointOnLine(int x1, int y1, int x2, int y2, int tx, int ty) { // Check if a point is on a line segment if (fmin(x1, x2) <= tx && tx <= fmax(x1, x2) && fmin(y1, y2) <= ty && ty <= fmax(y1, y2)) { return true; } return false; } int PointDistance(int x1, int y1, int x2, int y2) { // Find the distance between two points int out = sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2)); return out; }
解决思路
鱼眼效果的核心原因是直接使用射线的欧几里得距离(PointDistance计算的直线距离)计算墙高,实际需要的是垂直于玩家视角的投影距离。
具体修复步骤:
- 计算角度差:对每条射线,计算其角度与玩家当前朝向(
player->angle)的差值,转换为弧度。 - 修正距离:用欧几里得距离乘以
cos(角度差),得到消除鱼眼的投影距离——正前方射线角度差为0,cos值为1无修正;边缘射线角度差大,cos值小,修正幅度大。
代码修改点:
- 在获取
closestDistance后添加距离修正逻辑:
// 转换为弧度计算角度差 double rayAngleRad = DEG2RAD(a); double playerAngleRad = DEG2RAD(player->angle); double angleDiff = rayAngleRad - playerAngleRad; // 修正距离,消除鱼眼 float correctedDist = closestDistance * cos(angleDiff);
- 绘制3D墙时用
correctedDist替代closestDistance:
rect.y = correctedDist / 2; rect.h = windowH - rect.y * 2; int brightness = 255 - correctedDist / 2;
额外优化建议:
- 将
closestDistance类型从int改为float/double,避免整数截断损失精度。 - 修改
PointDistance函数返回值为浮点数,进一步提升计算精度。
内容的提问来源于stack exchange,提问作者AlvinV
相关产品推荐
相关产品推荐

