好了,终于到了可以看到图片的环节了。之前的类,你一定要实现好了。所有关于World类的报错,现在我们一个一个解决来了。
先看看World类的声明:
#pragma once #ifndef __WORLD_HEADER__ #define __WORLD_HEADER__ #include "geometry.h" #include "viewplane.h" #include "../objects/primitive/sphere.h" #include "../tracers/tracer.h" class World { public: World(); World(const World& wr); ~World(); void build();//初始化数据 void render();//渲染 void add_object(Geometrics* obj);//添加几何对象 void remove_object(Geometrics* obj);//删除几何对象 integer get_object_size() const;//几何对象个数,这个在SingleSphere类中用到了哈 ShadeRec hit_bare_bones_objects(const Ray& ray); private: void open_window(const integer hres, const integer vres);//初始化视窗,有条件的可以用DirectX或者OpenGL显示,我这里用ppm文件显示 void display_pixel(const integer row, const integer column, const RGBColor& color);//写入像素 std::stringstream ss;//缓存 std::vector<Geometrics*> objects; ViewPlane vp;//视窗类 RGBColor backgrd_color;//背景色 Tracer* tracer_ptr;//光线和几何对象的碰撞 }; #endif
类实现:
#include "pch.h" #include "world.h" #include "../tracers/singlesphere.h" World::World():tracer_ptr(nullptr) {} World::~World() {//写入到ppm文件 std::ofstream fout; fout.open("test.ppm", std::ios::out); fout.write(ss.str().c_str(), ss.str().size()); fout.close(); } World::World(const World& wr) : vp(wr.vp), backgrd_color(wr.backgrd_color), tracer_ptr(wr.tracer_ptr) { objects.clear(); } void World::build() { vp.set_hres(200); vp.set_vres(100);//200*100像素图片 tracer_ptr = new SingleSphere(this); Geometrics* obj = new Sphere(0, 0.5); obj->set_color(RGBColor(1, 0, 0));//球体颜色是红色 add_object(obj); } void World::render() { Ray ray; ldouble x, y; open_window(vp.hres, vp.vres); Point3 sp; ray.o = Point3(0, 0, 1);//光线源位置 for (integer r = vp.vres - 1; r >= 0; r--)//render from left-corner to right-corner, 书上是错误的,必须这样渲染,不然图像是颠倒的 for (integer c = 0; c < vp.hres; c++) { RGBColor color; x = vp.s * (c - 0.5 * vp.hres); y = vp.s * (r - 0.5 * vp.vres); ray.d = Point3(x, y, -1);//只需要改变光线的方向 color = tracer_ptr->trace_ray(ray); display_pixel(r, c, color); } } void World::add_object(Geometrics* obj) { objects.push_back(obj); } void World::remove_object(Geometrics* obj) { for (auto it = objects.begin(); it != objects.end(); it++) if ((*it) == obj) objects.erase(it); } integer World::get_object_size() const { return objects.size(); } ShadeRec World::hit_bare_bones_objects(const Ray& ray) {//这个就是经常出现在SingleSphere和MultiSphere类中的函数了 ShadeRec sr(*this); ldouble t, tmin= std::numeric_limits<ldouble>::max(); for (auto obj : objects) if (obj->hit(ray, t, sr) && t < tmin) { sr.hit_an_object = true; tmin = t; sr.color = obj->get_color();//保存碰撞后的颜色 } return sr; } void World::open_window(const integer hres, const integer vres) { ss.clear(); ss << "P3 " << hres << " " << vres << " 255 ";//ppm文件头 } void World::display_pixel(const integer row, const integer column, const RGBColor& color) { RGBColor c = color; if (vp.g != 1.0) c = color.powc(vp.g); integer ir = (integer)(255.99 * c.r), ig = (integer)(255.99 * c.g), ib = (integer)(255.99 * c.b); ss << ir << " " << ig << " " << ib << " ";//写入颜色值 }
好了,现在我们看下main函数的调用吧(以后main函数的调用都是一样的,所以不再重复了)
#include "../Common/RayTracingGroundUp/utilities/world.h" int main() { World w; w.build(); w.render(); return 0; }
得到的图像如下(因为我是mac电脑下开的win7虚拟机,所以mac自带读取ppm文件,如果你的win7不能打开,请用photoshop等作图软件打开就行了),终于成功了: