资源
课程
Lecture 01 Overview of Computer Graphics
What is Computer Graphics?图形学的应用:
-
Viedo Games 游戏
-
Movies 电影特效
-
Animations 动画
-
Design 设计
-
Visualization 可视化
-
Visual Reality 虚拟现实
-
Augmented Reality 增强现实
-
Digital Illustration 数字化描述
-
Simulation 模拟
-
Graphical User Interfaces, GUI 图形用户接口
-
Typography 字体
Why study Computer Graphics?
- Computer Graphics is AWESOME!
Course Topics(mainly 4 parts)
-
Rasterization 光栅化
- Project geometry primitives (3D triangles / polygons) onto the screen 将几何图元(三维三角形/多边形)投影到屏幕上
- Break projected primitives into fragments (pixels) 将投影基元分解为片段(像素)
- Gold standard in Video Games (Real-time Applications) 视频游戏(实时应用)的黄金标准
-
Curves and Meshes 曲线和模型
- How to represent geometry in Computer Graphics 如何在计算机图形学中表示几何图形
-
Ray Tracing 光线追踪
- Shoot rays from the camera though each pixel 通过每个像素从相机拍摄光线
- Calculate intersection and shading 计算交点和着色
- Continue to bounce the rays till they hit light sources 继续反射光线,直到光线碰到光源
- Gold standard in Animations / Movies (Offline Applications) 动画/电影黄金标准(离线应用程序)
- Shoot rays from the camera though each pixel 通过每个像素从相机拍摄光线
-
Animation / Simulation 动画 / 模拟
- Key frame Animation 关键帧动画
- Mass-spring System 质量弹簧系统
计算机图形学、计算机视觉、数字图像处理的区别:
Lecture 02 Review of Linear Algebra
A Swift and Brutal Introduction to Linear Algebra! 一份对线性代数的迅速且直接的介绍!
Graphics’ Dependencies 图形相关的依赖项
-
Basic mathematics 基础数学
- Linear algebra, calculus, statistics 线性代数、微积分、统计学
-
Basic physics 基础物理学
- Optics, Mechanics 光学、力学
-
Misc 杂项
-
Signal processing 信号处理
-
Numerical analysis 数值分析
-
-
And a bit of aesthetics 还有一点美学
This Course
- More dependent on Linear Algebra 更多依赖于线性代数
- Vectors (dot products, cross products, …) 向量(点积、叉积等)
- Matrices (matrix-matrix, matrix-vector mult., …) 矩阵(矩阵相乘、矩阵与向量相乘等)
- For example,
- A point is a vector? 一个点是一个向量吗?
- An operation like translating or rotating objects can be matrix-vector multiplication 类似平移或旋转物体的操作可以通过矩阵与向量相乘实现
Vectors
-
通常被写作 或
-
向量的长度被写作
-
向量的归一化,方向不变,长度设为 1:
Cartesian Coordinates 笛卡尔坐标系
Dot (scalar) Product 向量点乘
对于 Unit Vectors 单位向量:
性质:
交换律:
分配律:
结合律:
Dot Product in Cartesian Coordinates 笛卡尔坐标系下的向量点乘
Component-wise multiplication, then adding up 分量逐个相乘,然后求和
-
In 2D
-
In 3D
Dot Product in Graphics 向量点乘在图形学中的应用
-
Find angle between two vectors (e.g. cosine of angle between light source and surface) 寻找两个向量之间的夹角,例如光源和表面之间的夹角的余弦值。
-
Finding projection of one vector on another 找到一个向量在另一个向量上的投影。
- : 在 方向的投影。
- 必须与 或 平行。
- 必须与 或 平行。
- : 在 方向的投影。
-
Measure how close two directions are 测量两个方向之间的接近程度
-
Decompose a vector 分解一个向量
-
Determine forward / backward 确定正向/反向
Cross (vector) Product 矢量积
- Cross product is orthogonal to two initial vectors 叉乘结果与两个初始向量垂直
- Direction determined by right-hand rule 方向由右手定则确定
- Useful in constructing coordinate systems (later) 在构建坐标系时非常有用
性质:
对于右手坐标系:
不满足交换律:
跟自身叉乘为零向量:
满足分配律:
Cross Product: Cartesian Formula? 矢量积在笛卡尔坐标系中
是 的伴随矩阵(伴随矩阵 - 维基百科,自由的百科全书 (wikipedia.org))
Cross Product in Graphics 矢量积在图形学中的应用
- Determine left / right 判别左右
- Determine inside / outside 判别内外
Orthonormal Bases / Coordinate Frames 正交基 / 坐标系
构建右手坐标系:
Matrix 矩阵
Matrix-Matrix Multiplication 矩阵乘法
一般不满足交换律(一般不满足 )
满足结合律和分配律:
Identity Matrix 单位矩阵
Vector multiplication in Matrix form 向量与矩阵相乘
- Dot product 点乘
- Cross product 叉乘
Lecture 03 Transformation
2D Transform 二维变换
Scale Transform 缩放
等比缩放:
用矩阵乘法表示:
Scale (Non-Uniform) 任意缩放
Reflection Matrix 镜像
Horizontal reflection 水平镜像:
用矩阵乘法表示:
Shear Matrix 斜切:
Hints:
- Horizontal shift is at
- Horizontal shift is at
- Vertical shift is always
Rotation Matrix 旋转
旋转相反的角等于矩阵的逆,等于矩阵的转置:
旋转矩阵是正交矩阵。
Linear Transforms = Matrices 线性变换 = 矩阵
简写为:
Translation 平移
Why Homogeneous Coordinates 为什么引入齐次坐标
- Translation cannot be represented in matrix form 平移变换不能用矩阵来表示
因此,平移变换不是线性变换!
-
But we don’t want translation to be a special case 但我们不希望平移变换成为特例
-
Is there a unified way to represent all transformations? (and what’s the cost?) 用统一的方式描述所有变换?(代价是什么?)
Solution: Homogenous Coordinates 解决办法:齐次坐标
Add a third coordinate (w-coordinate) 增加一个维度
- 2D point =
- 2D vector =
Matrix representation of translations 用矩阵描述所有变换
Valid operation if w-coordinate of result is 1 or 0 所增加维度的值不是 1 就是 0,这是因为:
- vector + vector = vector
- point – point = vector
- point + vector = point
- point + point = 它们的中点
因此定义,在齐次坐标中:
Affine Transformation 仿射变换
Affine map = linear map + translation 仿射变换 = 线性变换 + 平移
Using homogenous coordinates: 使用齐次坐标
2D Transformations 2D 变换
Scale 缩放
Rotation 旋转
Translation 平移
Inverse Transform 逆变换
Composing Transforms 复合变换
Sequence of affine transforms 对于仿射变换序列
- Compose by matrix multiplication 通过矩阵乘法进行合成
- Very important for performance! 对性能非常重要!
预乘 个矩阵以获得表示组合变换的单个矩阵。
Decomposing Complex Transforms 分解复合变换
How to rotate around a given point ? 如何绕空间任意一点 旋转?
- Translate center to origin 平移回原点
- Rotate 旋转
- Translate back 平移回去
3D Transforms
Use homogeneous coordinates again 再次使用齐次坐标:
- 3D point =
- 3D vector =
In general, is the 3D point:
3D Transformations 3D 变换
Use matrices for affine transformations 使用 齐次坐标表示:
先应用线性变换,再平移。
Lecture 04 Transformation Cont.
Viewing (观测) transformation
- View (视图) / Camera transformation
- Projection (投影) transformation
- Orthographic (正交) projection
- Perspective (透视) projection
3D Transformations 3D 变换
Rotation around -, -, or -axis 沿 、、 轴旋转:
Compose any 3D rotation from , , ? 让 , , 构成任意三维旋转?
- So-called Euler angles 所谓的欧拉角
- Often used in flight simulators: roll, pitch, yaw 常用于飞行模拟器:滚转、俯仰、偏航
Rodrigues’ Rotation Formula 罗德里格斯轮换公式
绕轴 旋转角度 :
View / Camera Transformation 视图变换
- What is view transformation? 什么是视图变换?
- Think about how to take a photo 考虑拍照
- Find a good place and arrange people (model transformation) 摆好场景:模型变换
- Find a good “angle” to put the camera (view transformation) 选好视角:视图变换
- Cheese! (projection transformation) 拍照:投影变换
- How to perform view transformation? 如何进行视图变换?
- Define the camera first 首先定义一个相机
- Position 位置
- Look-at / gaze direction 注视/凝视方向
- Up direction 上方向
- Define the camera first 首先定义一个相机
-
Key observation 重点观察
- If the camera and all objects move together, the “photo” will be the same 如果相机和所有物体一起移动,“照片”将是相同的
-
How about that we always transform the camera to 不如我们总是把相机变成
- The origin, up at , look at 处于原点,上方为 轴,看着 轴方向
- And transform the objects along with the camera 并随相机变换对象
-
Transform the camera by
-
So it’s located at the origin, up at , look at 所以它位于原点,向上看 ,看
-
in math?
-
Translates to origin
-
Rotates to 、Rotates to 、Rotates () To
-
Difficult to write! 将 旋转到 轴、将 旋转到 轴、将 () 旋转到 轴,描述成矩阵是很复杂的!
-
考虑求其逆变换
-
由于旋转矩阵是正交矩阵,其逆为它的转置,因此易求得
-
-
-
Summary 总结
- Transform objects together with the camera 与摄影机一起变换对象
- Until camera’s at the origin, up at , look at 直到相机移动到原点,以 轴为上方,视点在 轴方向。
-
Also known as ModelView Transformation 也称为 ModelView 变换
Projection Transformation 投影变换
- Projection in Computer Graphics 投影在计算机图形学
- 3D to 2D
- Orthographic projection 正交投影
- Perspective projection 透视投影
Orthographic Projection 正交投影
-
A simple way of understanding 简单的理解方法
- Camera located at origin, looking at , up at (looks familiar?) 相机移动到原点,以 轴为上方,视点在 轴方向
- Drop coordinate 删除 坐标
- Translate and scale the resulting rectangle to 将生成的矩形平移并缩放到
-
In General
-
We want to map a cuboid to the “canonical” cube
我们想把长方体 映射到“规范(正则、规范、标准)” 的立方体
-
-
Slightly different orders (to the “simple way”)
- Center cuboid by translating 通过平移使长方体居中
- Scale into “canonical” cube 缩放为“规范”多维数据集
的定义如下所示:
轴坐标范围:
轴坐标范围:
轴坐标范围:
-
Transformation matrix?
-
Translate (center to origin) first, then scale (length/width/height to 2) 首先平移(中心到原点)然后缩放(长度/宽度/高度到 2)
-
-
Caveat 警告
- Looking at / along is making near and far not intuitive () 观察/沿着 轴使远近不直观()
- 和 是负的,。
- FYI: that’s why OpenGL (a Graphics API) uses left hand coords. 仅供参考:这就是 OpenGL(图形 API)使用左手坐标的原因。
- Looking at / along is making near and far not intuitive () 观察/沿着 轴使远近不直观()
Perspective Projection 透视投影
- Most common in Computer Graphics, art, visual system 最常见于计算机图形学、艺术、视觉系统
- Further objects are smaller 其他物体较小
- Parallel lines not parallel; converge to single point 平行线不平行;收敛到单点
-
How to do perspective projection 如何进行透视投影
-
First “squish” the frustum into a cuboid (, ) ()
首先将截头体“压扁”成长方体(,)()
-
Do orthographic projection (, already known!) 做正交投影(,已经知道了!)
-
-
In order to find a transformation 为了找到变换(推导出矩阵 )
-
Recall the key idea: Find the relationship between transformed points and the original points
回想关键思想:找到转换之间的关系点 和原始点
-
-
In homogeneous coordinates, 齐次坐标下,
-
So the “squish” (persp to ortho) projection does this 所以“挤压”(透视到正交)投影可以做到这一点
-
Already good enough to figure out part of 可以求得 的一部分:
-
Observation: the third row is responsible for 观察:第三排负责
-
Any point on the near plane will not change 近平面上的任何点都不会改变
-
Any point’s z on the far plane will not change 远平面上的任何点的 都不会改变
-
-
Any point on the near plane will not change 近平面上的任何点都不会改变
-
So the third row must be of the form 所以第三行的形式必须是
-
What do we have now?
-
Any point’s z on the far plane will not change 近平面上的任何点都不会改变
-
Solve for and
-
Finally, every entry in is known!
-
What’s next?
- 完成正交投影()
HW0
环境配置
WSL2 下:
sudo apt-get install xfce4-terminal
sudo apt-get install xfce4配置环境变量:
echo "export DISPLAY=localhost:0">> ~/.bashrcMobaXterm 下配置 wsl2:
开跑!
安装库:
sudo apt update
sudo apt install g++ gdb cmake
sudo apt install libopencv-dev libeigen3-dev
sudo apt install libglu1-mesa-dev freeglut3-dev mesa-common-dev xorg-devWindows 下的 VSCode,安装 wsl 插件,点击左下角,连接 wsl。
打开作业模板,有如下命令:
mkdir build: 创建名为 build 的文件夹。cd build: 移动到 build 文件夹下。cmake ..: 注意其中 ’..’ 表示上一级目录,若为 ’.’ 则表示当前目录。make: 编译程序,错误提示会显示在终端中。./Transformation:若上一步无错误,则可运行程序(这里 Transformation 为可执行文件名,可参照 CMakeLists.txt 中修改)。
写一个 compile.sh 便于编译:
rm -rf build
mkdir build
cd build
cmake ..
make
./Transformation
cd ../修改权限:
chmod a+x compile.sh开跑!
sh compile.sh作业
写一个用于的 sh:
rm -rf build
mkdir build
cd build
cmake ..
make -j4
cd ../示例代码
#include<cmath>
#include<eigen3/Eigen/Core>
#include<eigen3/Eigen/Dense>
#include<iostream>
int main(){
// Basic Example of cpp
std::cout << "Example of cpp \n";
float a = 1.0, b = 2.0;
std::cout << a << std::endl;
std::cout << a/b << std::endl;
std::cout << std::sqrt(b) << std::endl;
std::cout << std::acos(-1) << std::endl;
std::cout << std::sin(30.0/180.0*acos(-1)) << std::endl;
// Example of vector
std::cout << "Example of vector \n";
// vector definition
Eigen::Vector3f v(1.0f,2.0f,3.0f);
Eigen::Vector3f w(1.0f,0.0f,0.0f);
// vector output
std::cout << "Example of output \n";
std::cout << v << std::endl;
// vector add
std::cout << "Example of add \n";
std::cout << v + w << std::endl;
// vector scalar multiply
std::cout << "Example of scalar multiply \n";
std::cout << v * 3.0f << std::endl;
std::cout << 2.0f * v << std::endl;
// Example of matrix
std::cout << "Example of matrix \n";
// matrix definition
Eigen::Matrix3f i,j;
i << 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0;
j << 2.0, 3.0, 1.0, 4.0, 6.0, 5.0, 9.0, 7.0, 8.0;
// matrix output
std::cout << "Example of output \n";
std::cout << i << std::endl;
// matrix add i + j
// matrix scalar multiply i * 2.0
// matrix multiply i * j
// matrix multiply vector i * v
return 0;
}题目
给定一个点 , 将该点绕原点先逆时针旋转 ,再平移 ,计算出变换后点的坐标(要求用齐次坐标进行计算)。
以齐次坐标的表示形式为
旋转矩阵为
平移矩阵
最终坐标为 。
#include<cmath>
#include<eigen3/Eigen/Core>
#include<eigen3/Eigen/Dense>
#include<iostream>
#define PI 3.1415926535
using namespace std;
using namespace Eigen;
int main()
{
float theta = PI / 4.0f;
Vector3f P(2.0f, 1.0f, 1.0f);
Matrix3f R, T;
R <<
cos(theta), -sin(theta), 0,
sin(theta), cos(theta), 0,
0, 0, 1;
T <<
1, 0, 1,
0, 1, 2,
0, 0, 1;
cout << T * R * P << endl;
return 0;
}1.70711
4.12132
1
HW1
本次作业的任务是填写一个旋转矩阵和一个透视投影矩阵。给定三维下三个点 , , , 你需要将这三个点的坐标变换为屏幕坐标并在屏幕上绘制出对应的线框三角形(在代码框架中,我们已经提供了draw_triangle 函数,所以你只需要去构建变换矩阵即可)。
get_model_matrix(float rotation_angle): 逐个元素地构建模型变换矩阵并返回该矩阵。
代公式:
Eigen::Matrix4f get_model_matrix(float rotation_angle)
{
Eigen::Matrix4f model = Eigen::Matrix4f::Identity();
// TODO: Implement this function
// Create the model matrix for rotating the triangle around the Z axis.
// Then return it.
float angle = rotation_angle * MY_PI / 180.0f;
Eigen::Matrix4f translate;
translate << std::cos(angle), -std::sin(angle), 0, 0,
std::sin(angle), std::cos(angle), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1;
model = translate * model;
return model;
}get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar): 使用给定的参数逐个元素地构建透视投影矩阵并返回该矩阵。
代公式:
其中:
,映射到“规范(正则、规范、标准)” 的立方体 ,因此:
具体地,如上图,zNear 即为 ,zFar 即为 ,。
由于右手坐标系 和 为负,因此:
float angle = eye_fov * MY_PI / 180.0f;
float n = -zNear;
float f = -zFar;
float t = std::tan(angle / 2) * n;
float b = -t;
float r = t * aspect_ratio;
float l = -r;最后 即为所求。
完整代码:
Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,
float zNear, float zFar)
{
// Students will implement this function
Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();
// TODO: Implement this function
// Create the projection matrix for the given parameters.
// Then return it.
Eigen::Matrix4f M_P;
M_P << zNear, 0, 0, 0,
0, zNear, 0, 0,
0, 0, zNear + zFar, -(zNear * zFar),
0, 0, 1, 0;
float angle = eye_fov * MY_PI / 180.0f;
float n = -zNear;
float f = -zFar;
float t = std::tan(angle / 2) * n;
float b = -t;
float r = t * aspect_ratio;
float l = -r;
Eigen::Matrix4f M_T;
M_T << 1, 0, 0, -(r + l) / 2,
0, 1, 0, -(t + b) / 2,
0, 0, 1, -(n + f) / 2,
0, 0, 0, 1;
Eigen::Matrix4f M_S;
M_S << 2 / (r - l), 0, 0, 0,
0, 2 / (t - b), 0, 0,
0, 0, 2 / (f - n), 0,
0, 0, 0, 1;
projection = M_T * M_S * M_P * projection;
return projection;
}运行时:
- n = -0.1
- f = -50
- t = -0.0414214
- b = 0.0414214
- r = -0.0414214
- l = 0.0414214
提高项:在 main.cpp 中构造一个函数,该函数的作用是得到绕任意
过原点的轴的旋转变换矩阵。Eigen::Matrix4f get_rotation(Vector3f axis, float angle)
代公式:
Eigen::Matrix4f get_rotation(Vector3f axis, float angle)
{
Eigen::Matrix4f model = Eigen::Matrix4f::Identity();
float alpha = angle * MY_PI / 180.0f;
float nx = axis[0];
float ny = axis[1];
float nz = axis[2];
Eigen::Matrix3f M;
M <<
0, -nz, ny,
nz, 0, -nx,
-ny, nx, 0;
Eigen::Matrix3f R = std::cos(alpha) * Eigen::Matrix3f::Identity() + (1 - std::cos(alpha)) * axis * axis.transpose() + std::sin(alpha) * M;
Eigen::Matrix4f translate = Eigen::Matrix4f::Identity();
translate.block<3, 3>(0, 0) = R;
model = translate * model;
return model;
}