真实感图像渲染系列:使用json初始化场景

这是真实感图像渲染系列的第三篇文章。

场景初始化的必要性

不同于普通的编程作业,图像渲染的场景结构非常复杂,比如同样是物体,一个球体需要读入中心坐标以及半径,而平面则只需要一个定位坐标以及法线方向就能够确定。如何初始化一个场景,为每一个参数赋予正确的初始值是非常重要的。

在参考过往代码发现场景的初始化无非两种方式:一种是将场景作为一个类写在源代码中;另一种是将场景写在文本文件中,对于所有需要初始化的类写一个接口来读取文件。在我的代码中,使用了第二种初始化方式。就编译效率上来说,第二种方式可以防止每次修改模型都重新编译。这在后期可以优化出很多时间。

场景初始化方式

一方面,我使用json格式储存场景,json格式的读取在C++中确实不算简单,需要安装jsoncpp库。jsoncpp库提供了一个数据类型Json::Value ,这个数据类型支持整数下表访问(用于访问列表),以及字符串下表访问(用于访问字典),以及各种转换函数如val.asDouble() 等。最终场景的json文件附在本文末尾。

jsoncpp的简单使用可以参考 通过jsoncpp库的CharReaderBuilder解析字符串

我使用伪·visitor设计模式初始化场景,对于每一个需要初始化的类申明一个成员函数void accept(const Json::Value& val); 接受一个Json::Value 用于初始化自身。

例如,对于vector来说,accept函数如下。

void Vector :: accept(const Json::Value& val) {
	if (!val.isMember("x") || !val.isMember("y") || !val.isMember("z"))
		std::cout<<"The vector not found..."<<std::endl;
	x = val["x"].asDouble();
	y = val["y"].asDouble();
	z = val["z"].asDouble();
}

而一个包含vector的sphere类,可以拥有如下accept函数

void Sphere::accept(const Json::Value& val) {
	Object::accept(val);
	O.accept(val["center"]);
	radius = val["radius"].asDouble();
}

可见,至少在安装了库之后,json的读取是足够简单的。

为场景添加功能

场景本身会被后续不同的渲染算法所使用,为了增加代码复用性,我们可以把渲染算法公共的一些函数放在场景中,例如求一个光线最近碰撞到的物体的函数findCollidedObject 等。最终场景类如下

class Scene {
	protected:
		Camera *camera;
		std::vector<Light*> lights;
		std::vector<Object*> objects;
		Color bg_color;
	public:
		Scene();
		~Scene();
		void accept(const Json::Value& val,int _rx,int _ry);
		const Object* findCollidedObject(const Vector &rayO,const Vector& rayD,Collision& coll);
		const Light* findCollidedLight(const Vector& rayO,const Vector& rayD, Collision& coll);
};

后续的光线追踪等代码,都会直接继承scene来使用scene的这些接口。

源代码

场景json文件

{
 "rx": 512,
 "ry": 1024,
 "_rx": 5,
 "_ry": 10,
 "photon_num": 20000,
 "total_round": 80,
 "total_brightness": 1310.0,
 "round_decay": 0.95,
 "initial_r": 5,
 "r_decay": 0.8,
 "camera": {
  "type": "default",
  "position": {
   "x": 20,
   "y": -10,
   "z": 0
  },
  "dx": {
   "x": -10,
   "y": 0,
   "z": 0
  },
  "dy": {
   "x": 0,
   "y": 20,
   "z": 0
  },
  "origin": {
   "x": 40,
   "y": 0,
   "z": -50
  },
  "fdepth": 0.02
 },
 "lights": [
  {
   "type": "point_light",
   "name": "light1",
   "brightness": 40,
   "position": {
    "x": 12,
    "y": -5,
    "z": 27
   },
   "texture": {
    "type": "pure",
    "r": 1,
    "g": 1,
    "b": 1
   },
   "material": {
    "refl": 0,
    "diff": 0,
    "spec": 0,
    "refr": 0.0,
    "refr_k": 1.0
   }
  },
  {
   "type": "point_light",
   "name": "light1",
   "brightness": 50,
   "position": {
    "x": 37,
    "y": 0.6,
    "z": -45
   },
   "texture": {
    "type": "pure",
    "r": 1,
    "g": 1,
    "b": 1
   },
   "material": {
    "refl": 0,
    "diff": 0,
    "spec": 0,
    "refr": 0.0,
    "refr_k": 1.0
   }
  }
 ],
 "objects": [
  {
   "type": "sphere",
   "name": "marble_ball",
   "center": {
    "x": 3,
    "y": 0,
    "z": 30
   },
   "radius": 1.7,
   "texture": {
    "type": "picture",
    "filename": "materials/marble.bmp",
    "rx": 2,
    "ry": 3.14
   },
   "absorb": {
    "type": "pure",
    "r": 0.5,
    "g": 0.7,
    "b": 0.5
   },
   "material": {
    "refl": 0.3,
    "diff": 0.8,
    "spec": 0.6,
    "refr": 0.0,
    "refr_k": 1.3
   }
  },
  {
   "type": "sphere",
   "name": "marble_ball",
   "center": {
    "x": 3,
    "y": -6,
    "z": 29
   },
   "radius": 1.7,
   "texture": {
    "type": "picture",
    "filename": "materials/marble2.jpg",
    "rx": 2,
    "ry": 3.14
   },
   "absorb": {
    "type": "pure",
    "r": 0.5,
    "g": 0.7,
    "b": 0.5
   },
   "material": {
    "refl": 0.3,
    "diff": 0.8,
    "spec": 0.6,
    "refr": 0.0,
    "refr_k": 1.3
   }
  },
  {
   "type": "sphere",
   "name": "ball",
   "center": {
    "x": 3,
    "y": 0,
    "z": 22
   },
   "radius": 2,
   "texture": {
    "type": "pure",
    "r": 0.7,
    "g": 0,
    "b": 0.7
   },
   "absorb": {
    "type": "pure",
    "r": 0.4,
    "g": 0.1,
    "b": 0.01
   },
   "material": {
    "refl": 0.1,
    "diff": 0.0,
    "spec": 0.6,
    "refr": 0.9,
    "refr_k": 1.3
   }
  },
  {
   "type": "sphere",
   "name": "marble_ball",
   "center": {
    "x": 35,
    "y": 1,
    "z": -40
   },
   "radius": 0.2,
   "texture": {
    "type": "picture",
    "filename": "materials/marble2.jpg",
    "rx": 2,
    "ry": 3.14
   },
   "absorb": {
    "type": "pure",
    "r": 0.5,
    "g": 0.7,
    "b": 0.5
   },
   "material": {
    "refl": 0,
    "diff": 1.0,
    "spec": 0.6,
    "refr": 0,
    "refr_k": 1.3
   }
  },
  {
   "type": "bazier_curves",
   "name": "cup",
   "position": {
    "x": 0,
    "y": 0,
    "z": 30
   },
   "ctrl_pts": [
    [
     [
      0.0,
      1.1,
      1.2,
      2.0
     ],
     [
      0.04,
      0.04,
      -0.0,
      -0.0
     ]
    ],
    [
     [
      2.0,
      2.2,
      2.0,
      1.9
     ],
     [
      -0.0,
      -0.0,
      0.1,
      0.15
     ]
    ],
    [
     [
      1.9,
      1.73,
      0.4,
      0.2
     ],
     [
      0.15,
      0.23,
      -0.2,
      0.4
     ]
    ],
    [
     [
      0.2,
      -0.1,
      3.8,
      3.8
     ],
     [
      0.4,
      1.3,
      1.4,
      2.0
     ]
    ],
    [
     [
      3.8,
      3.8,
      3.6,
      3.6
     ],
     [
      2.0,
      2.2,
      2.2,
      2.0
     ]
    ],
    [
     [
      3.6,
      3.6,
      0.25,
      0.0
     ],
     [
      2.0,
      1.9,
      1.3,
      1.3
     ]
    ]
   ],
   "texture": {
    "type": "pure",
    "r": 0.7,
    "g": 0.7,
    "b": 0.3
   },
   "absorb": {
    "type": "pure",
    "r": 0.1,
    "g": 0.1,
    "b": 0.5
   },
   "material": {
    "refl": 0.0,
    "diff": 0.0,
    "spec": 0.0,
    "refr": 0.9,
    "refr_k": 1.3
   }
  },
  {
   "type": "plane",
   "name": "floor",
   "position": {
    "x": 0,
    "y": -10,
    "z": 25
   },
   "dx": {
    "x": 0,
    "y": 0,
    "z": 30
   },
   "dy": {
    "x": 0,
    "y": 20,
    "z": 0
   },
   "texture": {
    "type": "picture",
    "filename": "materials/floor.jpg",
    "rx": 8,
    "ry": 8
   },
   "material": {
    "refl": 0.4,
    "diff": 0.6,
    "spec": 0.0,
    "refr": 0.0,
    "refr_k": 1.0
   },
   "border": false
  }
 ],
 "bg_color": {
  "type": "pure",
  "r": 0.0,
  "g": 0.0,
  "b": 0.0
 },
 "max_depth": 20,
 "max_jump": 20,
 "start_rows": 0,
 "start_cols": 0
}

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据