Games 101 作业1

1 坐标系

关于坐标系,坐标系其实就是空间信息。有了坐标系我们可以非常详细的描述这个世界,为了方便一般为一个观测者生成一个坐标系。

坐标系以观测者所在的位置为原点。就像我们常说的前面三米,我们对世界的描述通常是以自己为基础的。

而这个世界可能存在许多观测者,所以这个世界有点混乱。
每个人都在描述这个世界,说一些坐标,eg.一个飞机
A:飞机在我前面3m
B:飞机在我后面3m
C:飞机在我左边3m

那么飞机到底在哪里呢?如果这时另外一个观测者(World)用全局的眼光看这个飞机,这是显而易见的,飞机只有一个,只在一个地方,只有一个坐标。

所以一个个人坐标系的描述如何转化为世界坐标系就是所有人都认可的一个公共坐标系就是非常重要的。

ref1:5th 7.5 Coordinate Transormation

When managing multiple coordinate systems, it’s easy to get confused and wind up with objects in the wrong coordinates, causing them to show up in unexpected places. But with systematic thinking about transformations between coordinate systems, you can reliably get the transformations right.

Geometrically, a coordinate system, or coordinate frame, consists of an origin and a basis—a set of three vectors. Orthonormal bases are so convenient that In 2D, of course, there are two basis vectors.

we’ll normally assume frames are orthonormal unless otherwise specified. In a frame with origin p and basis {\(\mathbf{u}\), \(\mathbf{v}\), \(\mathbf{w}\)}, the coordinates (u, v, w) describe the point

\[\mathbf{p} + u \mathbf{u} + v\mathbf{v} + w\mathbf{w} \]

When we store these vectors in the computer, they need to be represented in terms of some coordinate system. To get things started, we have to designate some canonical coordinate system, often called “global” or “world” coordinates, which is used to describe all other systems. In the city example, we might adopt the street grid and use the convention that the x-axis points along Main Street, the y-axis points up, and the z-axis points along Central Avenue. Then, when we write the origin and basis of the car frame in terms of these coordinates, it is clear what we mean.

In 2D our convention, it is to use the point o for the origin, and x and y for the right-handed orthonormal basis vectors x and y (Figure 7.20)

1.2 向量

向量的定义:就是只有大小与方向。我们对于向量的很多认识都是从原点开始进行一个方向的指向。

不过起点放在哪里对某一向量完全没有任何影响。

也就是说一旦我们在世界坐标系下定义了一个向量 \(\mathbf{a}\)。只要在不改变其大小方向的情况下,我们可以拿着他随便乱跑 \(\mathbf{a}\) 还是 \(\mathbf{a}\)

local-to-world(Frame-to-canonical):

这里的 \(\mathbf{o}, \mathbf{e}, \mathbf{u}, \mathbf{v}\)均是以世界坐标系为基础的向量。

ref2 5th 7.5 Coordinate Transormation

image

ref3 5th 7.5 Coordinate Transormation

世界坐标系到局部坐标系以及其逆转换。
image

Hw1 作业片段 main.cpp

意思很明确,camrea coordinate 的坐标原点为 e, 基向量与世界坐标系无异。

所以相机向着着 z轴 负方向看着这个世界。

Eigen::Vector3f eye_pos = {0, 0, 5};

Eigen::Matrix4f get_view_matrix(Eigen::Vector3f eye_pos)
{
    Eigen::Matrix4f view = Eigen::Matrix4f::Identity();

    Eigen::Matrix4f translate;
    translate << 1, 0, 0, -eye_pos[0], 0, 1, 0, -eye_pos[1], 0, 0, 1,
        -eye_pos[2], 0, 0, 0, 1;

    view = translate * view;

    return view;
}

课件矩阵

image

这个矩阵只要注意可以将 任意向量 分解为 垂直于旋转轴和平行于旋转轴的两个向量。平行于旋转轴的分量不会改变。只需要关注垂直于旋转轴的那个分量即可。
image

关于画出三角形为倒置的情况。

假设:

  1. 老师讲的p2o矩阵完全适配代码,以及其他所有的知识完全正确(Fov aspect)。
  2. 世界坐标系 x y 与地面平行且重合, z 指向天空。我们是这个世界坐标系的观测者,右手系下 x →, y ↑。
  3. get_view_matrix() 完全正确
  4. 我们按照老师的 z 轴负向 正确实现了透视投影所需矩阵。

推出:
代码给出的三角形是一个等腰三角形,有一致的z轴坐标,三角形所在平面与地面平行。深入地下2m。

给出的相机坐标放在离地面5m 的地方,基础向量与 x y z 一致,所以看向地面即 -z 方向。相机即画面的竖直方向为 y 水平方向为 x。这时候如果把你放在那看,就已经是一个正三角型了。

可以得出在相机坐标系三角形 z 坐标都为 -7m。

很多人的问题是,程序自带的(zNear=0.1 zFar=50),以及相关参数规定了一个处于 z 轴正半轴的视锥,即可视空间。而三角形明明在 z 负半轴 为什么还可以画出三角形,并且三角形向下?

首先我要说明,老师给的所有透视投影矩阵 p2o otho 所有的参数都是基于 n f 为 负数的情况。

所谓透视投影,就是近大远小。所以远处(z 负方向)的物体要乘以一个比例 \(y'=(n/z)*y\),我们很清楚的看到由于除法的关系 (n/z) 是一个正数, 缩小的同时,不会改变原来的位置关系,在上面永远在上面。在下面永远在下面。透视投影(老师所给)变换后,z' = n+f - nf/z 坐标还是在负半轴。并且保持原来的远近关系。

程序自带(zNear=0.1 zFar=50)把这个 y'=(n/z)*y 由于除法的关系 (n/z) 是一个负数,缩小之后还要进行上下的颠倒。这就是症结所在。我们再看 z' = n+f - nf/z, 当 z属于[-0.1,-50]时,即三角形所在的视锥里(三角形 z=-49.38) 被变化到 z'属于[0.1+50-5/(-0.1)=100.1 ,0.1+50-5/(-50)=50.2](三角形 z=50.81)。即正半轴了。

而othor矩阵接受正数(zNear=0.1 zFar=50),刚好不会把三角形变化到正方体里。所以这里也是问题,按三角形缩小反转了并且被放到了 z 正轴。但不在正方体里,我们为什么还可以看见?

是因为在othor之后还应该有一步操作Clipping,就是将不在视锥中的东西切掉。

Clipping in Homogeneous Coordinates (Option 2)
Surprisingly, the option usually implemented is that of clipping in homogeneous
coordinates before the divide.
5th P191

而代码中没有这么做,直接进行齐次坐标化简后 vert /= vert.w(), 然后进行了视口变化。视口变化主要对 x y 坐标 进行,但是代码中还给出 z 的变换,这里没有太懂。视口变化可以看作是先不考虑 z 坐标,然后把图像挤在屏幕上,考虑遮挡关系的时候需要考虑 z 坐标。

所以还是可以看到三角形,而且是倒着的。

因此结论是在假设成立的情况下,将(zNear=0.1 zFar=50)变为负号即可。

关于 opencv Mat 显示问题

mat的显示其实就是二维数组,左上角为(0,0) 右下角为(n-1,n-1)。

而我们人眼比较喜欢左下角为(0,0)。

所以我们看到

void rst::rasterizer::set_pixel(const Eigen::Vector3f& point, const Eigen::Vector3f& color)
{
    //old index: auto ind = point.y() + point.x() * width;
	// up left = (0,0)
    if (point.x() < 0 || point.x() >= width ||
        point.y() < 0 || point.y() >= height) return;
	// down left = (0, 0)
    auto ind = (height-point.y())*width + point.x();
    frame_buf[ind] = color;
}

image

image

将c点 c.x += 50
image
将c点 c.x=c.y=0
image

但是这个算法有问题,我真的是服辣。很容易就数组越界。

eg.x=0 y=0 则 ind=49000, 但是整个 frame_buf.size()=49000。下标取值范围[0,49000)。49000是越界的。但是vector越界不会报错,我真的是服辣。

image

对这个算法进行修改。

auto ind = (height-1-point.y())*width + point.x();

image

3.5 今天一天都在看这个代码框架。

3.6 今天看作业二,这个溢出问题已经修改了。视口变化的代码中还给出 z 的变换,这是为了 z-buffer算法 将 z 变化到了正半轴。

posted @ 2023-03-07 08:51  Dba_sys  阅读(194)  评论(0编辑  收藏  举报