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;
}

矩阵推导

当设置相机位置之后,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");
    }