Ray Tracing in One Weekend01无法查看ppm的问题及一个C++字符缓冲传参引发的bug
2021/6/15 22:23:39
本文主要是介绍Ray Tracing in One Weekend01无法查看ppm的问题及一个C++字符缓冲传参引发的bug,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
最近在学习光线追踪的经典教程<<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 *类型就会生成这么个奇怪的图片:
随着课程的深入我会把作者写的源码继续改成svpng兼容的版本再把代码贴出来的,未完待续~
这篇关于Ray Tracing in One Weekend01无法查看ppm的问题及一个C++字符缓冲传参引发的bug的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享