Ray Tracing in One Weekend01无法查看ppm的问题及一个C++字符缓冲传参引发的bug

2023-11-19

最近在学习光线追踪的经典教程<<Ray Tracing in One Weekend—The Book Series>>,在这个系列中作者的程序运行后生成ppm格式的图片无奈本地的图片查看器包括Photoshop都无法查看作者生成的PPM格式,令人疑惑的是在闫令琪大佬的GAMES101-现代计算机图形学课程中生成的ppm格式文件文件用Photoshop打开就完全没问题,比如说这张斯坦福兔的图片:
在这里插入图片描述
无奈只好换一个方向,在Github上找到了将RGB/RGBA 格式的数据压缩为PNG格式的repo,就下载过来试一下,还真的很好用----svpng
下载过来后将里面的附件svpng.inc放在和主程序同一级目录下.
这样作者原先写的代码就可以修改为

#include <iostream>
#include "svpng.inc"
int main() {

    // Image
    FILE *fp = fopen("firstppm.png", "wb");
    unsigned char rgb[256 * 256 * 3], *p = rgb;
    const int image_width = 256;
    const int image_height = 256;

    // Render

    for (int j = image_height-1; j >= 0; --j) {
        for (int i = 0; i < image_width; ++i) {
            auto r = double(i) / (image_width-1);
            auto g = double(j) / (image_height-1);
            auto b = 0.25;

            *p++ = (unsigned char)static_cast<int>(255.999 * r);
            *p++ = (unsigned char)static_cast<int>(255.999 * g);
            *p++ = (unsigned char)static_cast<int>(255.999 * b);
        }
    }
    svpng(fp, 256, 256, rgb, 0);
    fclose(fp);
    return 0;
}

编译完成后直接运行可执行文件就可以生成firstppm.png,像这样:
在这里插入图片描述
后续的vec3.h和color.h也要按照作者源码做对应修改:
vec3.h:

#ifndef VEC3_H
#define VEC3_H

#include<cmath>
#include<iostream>

using std::sqrt;

class vec3
{
    public:
        vec3(): e{0,0,0}{}
        vec3(double e0, double e1, double e2) : e{e0, e1, e2} {}

        double x() const { return e[0]; }
        double y() const { return e[1]; }
        double z() const { return e[2]; }

        vec3 operator-() const { return vec3(-e[0], e[1], -e[2]); }
        double operator[](int i) const { return e[i]; }
        double &operator[](int i) { return e[i]; }

        vec3& operator+=(const vec3 &v)
        {
            e[0] += v.e[0];
            e[1] += v.e[1];
            e[2] += v.e[2];
            return *this;
        }

        vec3& operator*=(const double t){
            e[0] *= t;
            e[1] *= t;
            e[2] *= t;
            return *this;
        }

        vec3& operator/= (const double t){
            return *this *= 1 / t;
        }

        double length() const {
            return sqrt(length_squared());
        }

        double length_squared() const
        {
            return e[0] * e[0] + e[1] * e[1] + e[2] * e[2];
        }
    public:
        double e[3];
};

//Type aliases for vec3
using point3 = vec3;//3D point
using color = vec3; //RGB color

//vec3 Utility Functions
inline void operator<<(unsigned char *&out,const vec3 &v)
{
    *out++ = (unsigned char)(v.e[0]);
    *out++ = (unsigned char)(v.e[1]);
    *out++ = (unsigned char)(v.e[2]);
    return;
}

inline vec3 operator+(const vec3 &u,const vec3 &v)
{
    return vec3(u.e[0] + v.e[0], u.e[1] + v.e[1], u.e[2] + v.e[2]);
}

inline vec3 operator-(const vec3 &u,const vec3 &v)
{
    return vec3(u.e[0] - v.e[0], u.e[1] - v.e[1], u.e[2] - v.e[2]);
}

inline vec3 operator*(const vec3 &u,const vec3 &v)
{
    return vec3(u.e[0] * v.e[0], u.e[1] * v.e[1], u.e[2] * v.e[2]);
}

inline vec3 operator*(double t,const vec3 &v)
{
    return vec3(t*v.e[0], t*v.e[1],t*v.e[2]);
}

inline vec3 operator*(const vec3 &v, double t) {
    return t * v;
}

inline vec3 operator/(vec3 v, double t) {
    return (1/t) * v;
}

inline double dot(const vec3 &u,const vec3 &v)
{
    return u.e[0] * v.e[0] + u.e[1] * v.e[1] + u.e[2] * v.e[2];
}

inline vec3 cross(const vec3 &u, const vec3 &v) {
    return vec3(u.e[1] * v.e[2] - u.e[2] * v.e[1],
                u.e[2] * v.e[0] - u.e[0] * v.e[2],
                u.e[0] * v.e[1] - u.e[1] * v.e[0]);
}

inline vec3 unit_vector(vec3 v) {
    return v / v.length();
}

#endif

color.h:

#ifndef COLOR_H
#define COLOR_H

#include "vec3.h"

#include <iostream>

void write_color(unsigned char *&out, color pixel_color) {
    // Write the translated [0,255] value of each color component.
    *out++ = (unsigned char)static_cast<int>(255.999 * pixel_color.x());
    *out++ = (unsigned char)static_cast<int>(255.999 * pixel_color.y());
    *out++ = (unsigned char)static_cast<int>(255.999 * pixel_color.z());
    return;
}

#endif

源程序也就变成这样了,注意svpng的引用路径变了:

#include"color.h"
#include "vec3.h"
#include <iostream>
#include "../svpng.inc"
int main() {

    // Image
    FILE *fp = fopen("firstppm.png", "wb");
    const int image_width = 256;
    const int image_height = 256;
    unsigned char rgb[image_width * image_height * 3], *p = rgb;
    // Render

    for (int j = image_height-1; j >= 0; --j) {
        for (int i = 0; i < image_width; ++i) {
            color pixel_color(double(i)/(image_width-1), double(j)/(image_height-1), 0.25);
            write_color(p, pixel_color);
        }
    }
    svpng(fp, 256, 256, rgb, 0);
    fclose(fp);
    return 0;
}

注意:在vec3.h中的重载运算符函数operator<<(unsigned char *&out,const vec3 &v),和color.h中定义的write_color(unsigned char *&out, color pixel_color) 一定要传入字符缓冲的引用,也就是unsigned char *&out,因为颜色的写入操作直接对应字符缓冲rgb的地址,不应有中间拷贝。
如果传入的是unsigned char *类型就会生成这么个奇怪的图片:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Ray Tracing in One Weekend01无法查看ppm的问题及一个C++字符缓冲传参引发的bug 的相关文章

  • 是否有与 posix_memalign 对应的 C++ 版本?

    当我打电话时posix memalign http man7 org linux man pages man3 posix memalign 3 html为类型的对象分配对齐的内存Foo在我的 C 代码中 我需要做一个reinterpret
  • C++ 维护子类对象的混合集合

    如果我在这里错过了一个相当基本的概念 我很抱歉 但我正在尝试弄清楚如何维护多个类类型的集合 所有类类型都派生自同一个父类 并且在检索它们时仍然可以访问它们的特定于子类的方法从集合中 作为上下文 我有一个基类 BaseClass 和许多类 例
  • CLR 2.0 与 4.0 性能比较?

    如果在 CLR 4 0 下运行 为 CLR 2 0 编译的 NET 程序会运行得更快吗 应用程序配置
  • 使用 C# 登录《我的世界》

    我正在尝试为自己和一些朋友创建一个简单的自定义 Minecraft 启动器 我不需要启动 Minecraft 的代码 只需要登录的实际代码行 例如 据我所知 您过去可以使用 string netResponse httpGET https
  • 如何在多线程C++ 17程序中交换两个指针?

    我有两个指针 pA 和 pB 它们指向两个大的哈希映射对象 当pB指向的哈希图完全更新后 我想交换pB和pA 在C 17中 如何快速且线程安全地交换它们 原子 我是 c 17 的新手 2个指针的原子无等待交换可以通过以下方式实现 inclu
  • GetType() 在 Type 实例上返回什么?

    我在一些调试过程中遇到了这段代码 private bool HasBaseType Type type out Type baseType Type originalType type GetType baseType GetBaseTyp
  • C++ 是否可以在 MacOS 上与 OpenMP 和 boost 兼容?

    我现在已经尝试了很多事情并得出了一些结论 也许 我监督了一些事情 但似乎我无法完成我想要的事情 问题是 是否有可能使用 OpenMP 和 boost 在 MacOS High Sierra 上编译 C 一些发现 如果我错了请纠正我 Open
  • 如何在C(Linux)中的while循环中准确地睡眠?

    在 C 代码 Linux 操作系统 中 我需要在 while 循环内准确地休眠 比如说 10000 微秒 1000 次 我尝试过usleep nanosleep select pselect和其他一些方法 但没有成功 一旦大约 50 次 它
  • C# 数据表更新多行

    我如何使用数据表进行多次更新 我找到了这个更新 1 行 http support microsoft com kb 307587 my code public void ExportCSV string SQLSyntax string L
  • 使用可变参数包类型扩展的 C++ 函数调用者包装器

    我绑定了一些 API 并且绑定了一些函数签名 如下所示 static bool WrapperFunction JSContext cx unsigned argc JS Value vp 我尝试将对象和函数包装在 SpiderMonkey
  • 在Linux中,找不到框架“.NETFramework,Version=v4.5”的参考程序集

    我已经设置了 Visual studio 来在我的 Ubuntu 机器上编译 C 代码 我将工作区 我的代码加载到 VS 我可以看到以下错误 The reference assemblies for framework NETFramewo
  • 打破 ReadFile() 阻塞 - 命名管道 (Windows API)

    为了简化 这是一种命名管道服务器正在等待命名管道客户端写入管道的情况 使用 WriteFile 阻塞的 Windows API 是 ReadFile 服务器已创建启用阻塞的同步管道 无重叠 I O 客户端已连接 现在服务器正在等待一些数据
  • 在视口中查找 WPF 控件

    Updated 这可能是一个简单或复杂的问题 但在 wpf 中 我有一个列表框 我用一个填充数据模板从列表中 有没有办法找出特定的数据模板项位于视口中 即我已滚动到其位置并且可以查看 目前我连接到了 listbox ScrollChange
  • WPF DataGridTemplateColumn 组合框更新所有行

    我有这个 XAML 它从 ItemSource 是枚举的组合框中选择一个值 我使用的教程是 http www c sharpcorner com uploadfile dpatra combobox in datagrid in wpf h
  • 打印大型 WPF 用户控件

    我有一个巨大的数据 我想使用 WPF 打印 我发现WPF提供了一个PrintDialog PrintVisual用于打印派生的任何 WPF 控件的方法Visual class PrintVisual只会打印一页 因此我需要缩放控件以适合页面
  • C++ new * char 不为空

    我有一个问题 我在 ASIO 中开发服务器 数据包采用尖头字符 当我创建新字符时 例如char buffer new char 128 我必须手动将其清理为空 By for int i 0 i lt 128 i buffer i 0x00
  • 在 Windows Phone silverlight 8.1 上接收 WNS 推送通知

    我有 Windows Phone 8 1 silverlight 应用程序 我想使用新框架 WNS 接收通知 我在 package appxmanifest 中有
  • 可访问性不一致:参数类型的可访问性低于方法

    我试图在两个表单之间传递一个对象 基本上是对当前登录用户的引用 目前 我在登录表单中有一些类似的内容 private ACTInterface oActInterface public void button1 Click object s
  • 如何在richtextbox中使用多颜色[重复]

    这个问题在这里已经有答案了 我使用 C windows 窗体 并且有 richtextbox 我想将一些文本设置为红色 一些设置为绿色 一些设置为黑色 怎么办呢 附图片 System Windows Forms RichTextBox有一个
  • OpenCV SIFT 描述符关键点半径

    我正在深入研究OpenCV的SIFT描述符提取的实现 https github com Itseez opencv blob master modules nonfree src sift cpp 我发现了一些令人费解的代码来获取兴趣点邻域

随机推荐