真实感图像渲染系列:颜色,向量与物体

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

颜色

颜色,向量与物体是各种渲染算法的基础。

颜色定义为三个取值在0-1之间的浮点数,分别表示RGB分量。由于分量的值恰好为0-1之间的浮点数,颜色不仅可以理解为每种颜色的强度,还可以理解为每种颜色光线的穿透率。换句话来说,这样定义的颜色同时支持乘法和加法。

class Color
{
	private:
		double r,g,b;
	public:
		Color();
		Color(double r,double g,double b);
		Color operator += (const Color&a);
		void accept(const Json::Value& val);
		double getR()const {return r;}
		double getG()const {return g;}
		double getB()const {return b;}
		friend Color operator +(const Color& a,const Color &b);
		friend Color operator *(const Color& a,double k);
		friend Color operator *(const Color& a,const Color& b);
		Color exp()const;
		std::string description()const;
		Color adjust()const;
};

特别的,对于透明物体的折射,光线穿过物体,存在一定的吸收,该吸收率可以看做是距离的指数函数。即Color_{absorb} = e^{-dist \times Material_{absorb}},如在红光吸收率0.1的物体中穿过2单位距离,则射出的红光应该为原来射入红光强度的e^{-2*0.1}.

向量

向量的定义,也是三个0-1之间的浮点数,表示xyz坐标分量。向量同时具有表征方向和表征位置的功能,坐标本身在某种意义上也是坐标原点O加上某个表示方向的向量。

一个光线,我们就可以用两个向量rayOrayD分别表示他的起始位置以及方向,rayD是一个单位向量,某点P在光线上当且仅当P = rayO + k*rayD,且k>=0

class Vector
{
	double x,y,z;
	public:
		Vector();
		Vector(double x,double y,double z);
		Vector(const Eigen::Vector3d vec);
		double getX() const {return x;}
		double getY() const {return y;}
		double getZ() const {return z;}
		virtual void accept(const Json::Value &sl);
		friend Vector operator * (const Vector &a,const Vector &b);
		friend double operator ^ (const Vector &a,const Vector &b);
		friend Vector operator + (const Vector &a,const Vector &b);
		friend Vector operator - (const Vector &a,const Vector &b);
		friend Vector operator - (const Vector &a);
		friend Vector operator * (double k,const Vector &a);
		friend Vector operator * (const Vector &a,double k);
		friend bool operator == (const Vector &a,const Vector &b);
		friend Vector operator /(const Vector& a,double k);
		friend Vector each_min(const Vector& v1,const Vector& v2);
		friend Vector each_max(const Vector& v1,const Vector& v2);
		Vector unit()const;
		Vector reverse()const;
		double len()const;
		double sqrlen()const;
		bool isUnit()const;
		std::string description()const;
		Eigen::Vector3d eigen()const;
		static Vector randomVectorOnSphere();
};

 

物体

由于C++的多态机制,物体本身是一个抽象类,只需要支持:

  • 判断和某个光线的交点
  • 判断某个位置对应的贴图颜色
  • 提取出诸如漫反射率等表面材质的性质
  • 询问物体hash值(用于抗锯齿等)
struct Material {
	double refl;//reflection ratio
	double diff;//diffusion ratio
	double spec;//high light diffusion
	double refr;//refraction ratio
	double refr_k;
	void accept(const Json::Value& val);
};

class Object {
	protected:
		unsigned hash;
		Material material;
		std::string name;
		Texture* texture;
		Texture* absorb;
	public:
		Object();
		virtual ~Object();
		virtual void accept(const Json::Value& val);
		unsigned getHash()const {return hash;}

		const Material& getMaterial()const {return material;}

		virtual bool collideWith(const Vector& rayO, const Vector& rayD,Collision& coll) = 0;
		virtual Color getColor(const Vector &pos)const = 0;
		std::string getName()const{return name;}
		const Texture& getAbsorb()const;
};

碰撞

碰撞是渲染里面非常核心也很复杂的一个模块,我们使用一个专门的类记录碰撞的信息,实际上,对于碰撞,可以通过碰撞位置C,碰撞法线方向N和如何光线方向I完全表述。有了这三个量,我们可以简单的计算出这个碰撞的反射、折射方向(其中折射方向需要物体折射率)。这里讲一个小的注意点,就是反射,折射光线的起始点不应该都设置为C,反射需要保证光线的起始位置和入社光线位置同侧,而折射恰恰相反,由于精度误差,可能C实际在物体表面的某一侧而我们用C作为新光线的起点是不妥的。解决方案很简单,对于反射,我们使用C_{surface} = C+N*eps,折射则使用C_{backface}=C-N*eps作为光线的其实位置。

class Object;

struct Collision {
	Vector C;//The Center of Collision
	Vector N;//The normal of the plane
	Vector I;//The direction of reflaction
	double dist;
	bool face;
	Object* belongs;
	std::string description()const;
	void refraction(Vector& resO, Vector& resD)const;
	void reflection(Vector& resO, Vector& resD)const;
	void diffusion(Vector& resO, Vector& resD)const;
	void diffusion_hl(Vector& resO, Vector& resD)const;
	Vector getSurfaceC()const;
	Vector getBackfaceC()const;
};

 

 

发表评论

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

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