如何将光线追踪生成的图像帧输出到SDL窗口?
光线追踪器SDL窗口图像显示问题排查
问题描述
我正在开发课程项目的光线追踪器,程序内置图像帧生成方法,目标是将生成的帧输出到SDL窗口中。当前帧生成器会创建PPM格式图像并存储在vector数组内,生成完成后本该将像素值输出到窗口,但始终无法正常显示。此外排查发现帧生成方法存在内存泄漏,正在修复中。
核心代码
// 帧生成器 std::vector<color> generate_frames(const hittable &world) const { std::vector<color> frames(frame_width * frame_height); for (int j = frame_height - 1; j >= 0; --j) { for (int i = 0; i < frame_width; ++i) { color pixel_color(0, 0, 0); for (int s = 0; s < samples; ++s) { ray ray = get_ray(i, j); pixel_color += ray_color(ray, max_depth, world); } pixel_color /= samples; frames[j * frame_width + i] = pixel_color; } } return frames; } // 渲染器 void render_game(Camera camera, const hittable &world) { std::clog << "Render begin" << std::endl; SDL_SetRenderDrawColor(renderer, 255, 200, 255, 255); std::clog << "Render color set" << std::endl; //! 调试信息 // SDL_RenderClear(renderer); // std::clog << "Renderer cleared" << std::endl; //! 调试信息 std::vector<color> frames = camera.generate_frames(world); // 生成帧 std::clog << "Frames generated" << std::endl; //! 调试信息 void *pixels; // 像素指针 std::clog << "Pixels created" << std::endl; //! 调试信息 int pitch; // 行字节数 std::clog << "Pitch created" << std::endl; //! 调试信息 if (SDL_LockTexture(texture, NULL, &pixels, &pitch) != 0) // 锁定纹理 { std::cerr << "SDL_LockTexture Error: " << SDL_GetError() << std::endl; return; } else { std::clog << "Texture locked" << std::endl; //! 调试信息 } uint32_t *distance = (uint32_t *)pixels; std::clog << "Distance created" << std::endl; for (int j = 0; j < window_height; j++) { for (int i = 0; i < window_width; i++) { color c = frames[j * window_width + i]; uint8_t r = static_cast<uint8_t>(255.999 * clamp(c.x(), 0.0f, 0.999f)); uint8_t g = static_cast<uint8_t>(255.999 * clamp(c.y(), 0.0f, 0.999f)); uint8_t b = static_cast<uint8_t>(255.999 * clamp(c.z(), 0.0f, 0.999f)); distance[j * window_width + i] = (r << 16) | (g << 8) | b; } } std::clog << "Distance set" << std::endl; //! 调试信息 SDL_UnlockTexture(texture); // 解锁纹理 std::clog << "Texture unlocked" << std::endl; //! 调试信息 SDL_RenderClear(renderer); // 清空渲染器 std::clog << "Renderer cleared" << std::endl; //! 调试信息 SDL_RenderCopy(renderer, texture, NULL, NULL); // 复制纹理到渲染器 std::clog << "Texture copied" << std::endl; //! 调试信息 SDL_RenderPresent(renderer); // 显示渲染结果 std::clog << "Renderer presented" << std::endl; //! 调试信息 frames.clear(); // 清空帧数组 std::clog << "Frames cleared" << std::endl; //! 调试信息 std::clog << "Render end" << std::endl; //! 调试信息 std::clog << "Game rendered" << std::endl; //! 调试信息 }
问题分析与修复建议
1. 像素坐标映射错误
generate_frames中是从底部到顶部(j = frame_height - 1到0)遍历像素并存储,但render_game中是从顶部到底部读取,会导致图像上下翻转。同时需确保frame_width/frame_height与window_width/window_height完全一致,否则会出现数组越界访问。
修复方式:在读取帧数据时反转行索引
// 替换render_game中的像素遍历循环 for (int j = 0; j < window_height; j++) { int frame_j = frame_height - 1 - j; // 对应生成时的行顺序 for (int i = 0; i < window_width; i++) { color c = frames[frame_j * frame_width + i]; // ... 后续颜色转换代码 } }
2. SDL纹理像素格式不匹配
代码中直接按RGB888格式(r<<16 | g<<8 | b)赋值,但如果创建SDL纹理时未指定对应格式(如默认可能是RGBA或BGR),会导致颜色错乱或无法显示。
修复方式:创建纹理时明确指定格式
// 初始化纹理时使用对应格式 texture = SDL_CreateTexture( renderer, SDL_PIXELFORMAT_RGB888, // 与代码中像素格式匹配 SDL_TEXTUREACCESS_STREAMING, window_width, window_height );
3. 忽略SDL Pitch的正确使用
SDL的pitch是每行像素的字节数,可能因内存对齐导致与window_width * sizeof(uint32_t)不相等,直接用j * window_width计算偏移会导致像素错位。
修复方式:利用pitch计算每行起始地址
// 替换render_game中的像素赋值逻辑 uint8_t *pixel_bytes = static_cast<uint8_t*>(pixels); for (int j = 0; j < window_height; j++) { int frame_j = frame_height - 1 - j; uint32_t *row = static_cast<uint32_t*>(pixel_bytes + j * pitch); for (int i = 0; i < window_width; i++) { color c = frames[frame_j * frame_width + i]; uint8_t r = static_cast<uint8_t>(255.999 * clamp(c.x(), 0.0f, 0.999f)); uint8_t g = static_cast<uint8_t>(255.999 * clamp(c.y(), 0.0f, 0.999f)); uint8_t b = static_cast<uint8_t>(255.999 * clamp(c.z(), 0.0f, 0.999f)); row[i] = (r << 16) | (g << 8) | b; } }
4. 内存泄漏排查方向
generate_frames中的vector是局部变量,返回时会自动移动构造,本身不会泄漏。需重点排查:
get_ray或ray_color中是否有动态分配的内存(如new创建的对象)未释放hittable派生类中是否存在资源未正确释放的情况- 确保所有智能指针(如
std::unique_ptr)正确管理资源
内容的提问来源于stack exchange,提问作者Tatenda
相关产品推荐
相关产品推荐

