You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将光线追踪生成的图像帧输出到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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 07:22:03