0.简介
相机应该都用过吧,手机上面有,数码相机什么的,原理是相机里面有接收光线的元件,就是感光元件,然后将光信号转换成电信号,之后就变成了我们拍摄出来的图像,这里我们来模拟一个相机,只不过我们的相机不是像真实的那样接收光线,而是要从相机发出光线,之后,根据相机发出的光线,追随着这些光线,找到光线能打到的无物体,然后再继续追踪反射,折射的光线,最后将本来是最终打到相机上的一束光线逆向的找到的来的路径,将这沿途的颜色叠加在一起,就得到了屏幕上对应像素点的颜色,每条从相机出发的光线就是与图像上像素点一一对应的,也就是从每一个像素点出发,寻找这个像素点都受到哪些光线影响。
1.相机模型
模拟相机,首先要确定一个相机的基本坐标系,相机有一个自身的坐标系,利用这个坐标系来确定屏幕上像素发出光线的信息。相机类的设计如下。
class Camera
{
public:
Camera();
Camera(vec3 _position,vec3 _front,vec3 _up,float fov/*field of view 视场*/);
//前方
vec3 front;
//上方
vec3 up;
//右方
vec3 right;
//相机位置
vec3 position;
//对应长宽的缩放比例
float scale;
//生成光线
Ray generateRay(float x,float y);
~Camera();
};
相机初始化的函数如下
Camera::Camera(vec3 _position, vec3 _front, vec3 _up, float fov)
{
position = _position;
//保存相机前方向
front = glm::normalize(_front);
//计算相机右方向
right = glm::normalize(glm::cross(front,_up));
//计算相机上方向
up = glm::cross(right, front);
//这里是计算相机投影范围的,暂时考虑的是正方形区域
scale = tan(fov * 0.5 * 3.141592654 / 180) * 2;
}
以相机前方向为主,利用前和上方向,组合出右方向,此时右方向和前方向一定垂直,再用右方向和前方向重新确定上方向,此时,三个方向向量必定互相垂直。scale是相机显示的范围,根据fov角度计算的。
![](https://i-blog.csdnimg.cn/blog_migrate/27fc40a014947064978d22dea64f39dd.jpeg)
因为后面要将图像映射区域坐标从[0,1]范围转换到[-1,1]范围,所以要2倍的scale值。
有了上面那些向量之后,就可以计算某一个像素点发出的光线方向了,对应代码如下。
Ray Camera::generateRay(float x, float y)
{
vec3 u = right * vec1(x-0.5) * vec1(scale);
vec3 v = up * vec1(y - 0.5) * vec1(scale);
return Ray(glm::normalize(front+u+v),position,0,vec3(0,0,0));
}
u,v向量就是偏移向量,原本的front是图像的中心(0,0)坐标,u,v就是对应不同坐标的偏移。
![](https://i-blog.csdnimg.cn/blog_migrate/1c7eed23264495b3f91517b2ec486ab0.jpeg)
上图表示了光线生成函数的过程。
投影区域范围变换到[-1,1],所以要减去0.5,乘以2倍的区域边长。
![](https://i-blog.csdnimg.cn/blog_migrate/8da511c31ec84909fddbb81983e3205b.jpeg)
这样,相机就可以根据图像像素位置来生成对应像素射入的光线了,之后就能根据生成的光线进行反向追踪了。
2.说明
源代码暂时不会公布,因为还没有出第一个效果,并且大部分核心代码都在博客中公布,等能显示第一张图像开始我会将完整代码放在网上供参考学习。