5.0 Lession 5 相机视角
[TOC]
矩阵
Matrix lookAt(Vec3f eye, Vec3f center, Vec3f up) {
Vec3f z = (eye-center).normalize();
Vec3f x = (up^z).normalize();
Vec3f y = (z^x).normalize();
Matrix res = Matrix::identity(4);
for (int i=0; i<3; i++) {
res[0][i] = x[i];
res[1][i] = y[i];
res[2][i] = z[i];
res[i][3] = -center[i];
}
return res;
}
矩阵推导
- 一个英文课件对相机转换矩阵的推导
- TinyRenderer-Lesson 5 Moving the camera
- Online Graphics Transforms 2: GluLookAt-Youtube
当设置相机位置之后,Origin原点变成了eye的位置,将物体的坐标位置从世界坐标系(World Frame)变成 相机坐标系(Camera Frame)的过程使用model-view matrx(这里可以参考 【计算机图形学/OpenGL/4.1 坐标空间和转换.md】)
我们移动相机可以通过 先旋转再平移
Model‐view matrix C = TR
首先我们定义相机坐标系UVN
OpenGL使用右手坐标系,所以相机是看向-n的
Step1求导n
因为我们的n是朝向外的,那么N = eye - center
求n的基向量 n = N / |N|
Step2求导v、u
至此,我们求解了相机坐标系vnu的基向量
那么我们又该如何推导矩阵呢?
原坐标P,在相机坐标系下P`通过乘以Matrix获得
P’ = Mw2e x P
之前我们讲过相机实际上是旋转后平移获得的。
那么我们可以得到
例子
{
int width = 1000;
int height = 1000;
int depth = 255;
TGAImage image(width, height, TGAImage::RGB);
Model model("../obj/african_head.obj");
Vec3f lightDir(0, 0, -1);
Vec3f eye(2,2,-2);
Vec3f center(0,0,0);
Matrix modelView = lookAt(eye, center, Vec3f(0,1,0));
Matrix viewportMatrix = viewPort(width / 4, height / 4, width * 3.f / 4, height* 3.f / 4, depth);
int zbuffer[width * height];
for (int i = 0; i < width * height; i++) {
zbuffer[i] = std::numeric_limits<int>::min();
}
for (int face = 0; face < model.nfaces(); face++) {
Vec3i screenCordinates[3];
Vec3f worldCordinates[3];
Vec2i uv[3];
for (int j = 0; j < 3; j++) {
Vec3f v = model.vert(face, j);
uv[j] = model.uv(face, j);
Vec3f tmp = m2v(viewportMatrix * modelView * v);
screenCordinates[j] = Vec3i (tmp[0], tmp[1], tmp[2]);
worldCordinates[j] = v;
}
//注意,这里面剔除因为顶点坐标发生过了变化,所以使用最新的screen坐标进行计算
Vec3f norm = (Vec3f (screenCordinates[2].x, screenCordinates[2].y, screenCordinates[2].z) - Vec3f (screenCordinates[0].x, screenCordinates[0].y, screenCordinates[0].z))
^ (Vec3f (screenCordinates[1].x, screenCordinates[1].y, screenCordinates[1].z) - Vec3f (screenCordinates[0].x, screenCordinates[0].y, screenCordinates[0].z));
norm.normalize();
float intensity = norm.dotProduct(lightDir);
if (intensity > 0) {
triangle_line_sweeping_texture_3d(screenCordinates[0], screenCordinates[1], screenCordinates[2], uv[0],
uv[1], uv[2], &model, intensity, image, zbuffer);
}
}
image.flip_vertically();
image.write_tga_file("l4_5_lookat.tga");
}