现代图形学入门需要掌握的全部数学知识总结

现代图形学入门需要掌握的全部数学知识总结

  • 1 向量
    • 1. 向量的加法
    • 2. 向量的点乘Dot product
    • 3. 向量的叉乘
      • 1 叉乘在图形学中的用法:
      • 2. 叉乘的属性
      • 3 叉乘的坐标系计算方式
    • 4 向量的规范化
  • 2 矩阵
    • 1 矩阵的乘积
    • 2 矩阵如何和一个向量乘
    • 3 矩阵的转置
    • 4 单位矩阵
    • 5 向量的点乘和叉乘写成矩阵的形式
  • 3 平面与直线相交
    • 1 平面的数学定义
    • 2 求解方法
    • 3 moller Trumbore 方法
  • 4 微积分
  • 5 概率论
    • 1 随机变量
    • 2 概率
    • 3 期望
    • 4 概率密度函数pdf
  • 6 三角函数
    • 1、角
    • 2、三角函数
    • 3、三角函数公式
  • 7 三角形重心坐标
  • 8 几何
    • 1 隐式表示
    • 2 显式表示
    • 3 曲线
      • 贝塞尔曲线
      • B样条
    • 4 贝塞尔曲面
  • 推荐大佬写的计算机图形学中的数学

在刚开始学习图形学的时候,很多网上,某乎,百度的一致说图形学设涉及到的数学很多,让很多对图形学感兴趣,但是数学不好的同学望而却步。其实如果不是为了做科研工作,作为学习图形学,涉及到的数学部分并不是很多,而且也不是很难。用的最多的就是线性代数中很简单的部分。线性代数中难的部分作为学习图形学基本用不着。
在学习图形学的时候也完全没必要害怕。要用到的数学知识有:

  1. 向量的加法,点乘,叉乘,以及向量的规范化。这些向量的数学计算主要是为了模拟光线作用在物体的时候,如何反射,折射,散射。从而计算出每个物体每个顶点的颜色值或者每个像素的颜色值。
  2. 矩阵的乘积,矩阵的转置。这些矩阵的知识主要是为了转化空间和实现物体的各种变形。

在高级图形学中还会用到微积分和概率的部分知识,但是其复杂程度没有达到高数下册后部分。

  1. 微积分:在BRDF中使用。
  2. 概率:在路径追踪中使用
  3. 几何:曲线和曲面
    在光栅化部分用到的数学知识也就是向量和矩阵这两个部分。初步学习完可以不学习微积分和概率部分。

除了数学外与图形学相关的重要的课程还有:
物理:光学,力学
其他涉及到的课程还有:信号处理,数值分析

1 向量

这一块高中学过了。在图形学中也使用的最多。

向量的加法,点乘和叉乘都有几何意义的计算方式和数学坐标系下的计算方式。这两个都需要很熟悉,更重的是要知道在图形学的用法。

1. 向量的加法

向量的加法的结果还是一个向量。
从几何的角度看向量的加法—高中知识
现代图形学入门需要掌握的全部数学知识总结_第1张图片
在坐标系中的向量加法—在以后的图形学中的计算都是用这个来计算向量的加法。这个计算向量的长度是非常方便的。
现代图形学入门需要掌握的全部数学知识总结_第2张图片

2. 向量的点乘Dot product

向量的点乘是一个数.。

向量点乘在图形学中的用法如下:

  • 快速到找到两个向量之间的夹角:后面光照模型都是用点乘来计算光线,视线,物体法线之间的夹角都是用这个来计算的。
  • 一个向量投影到另外一个向量上是什么样子的:分解向量:垂直和水平。
  • 计算两个向量方向的接近程度:根据点乘的结果来判断是接近和远离;比如在高光渲染的时候就要用这个知识
  • 向量点乘还可以给出一个前与后的信息:如果落在了上半圆就是接近,如果落在了下半圆就是远离。根据点乘的符号来判断,如果是正的,结果等于1就是相同,如果是-1是相向;

现代图形学入门需要掌握的全部数学知识总结_第3张图片
下面这张图中着色点的颜色都是利用v,n,l三个向量之间的点乘来计算的,具体可以结合代码看。
现代图形学入门需要掌握的全部数学知识总结_第4张图片

for (auto& light : lights)
    {
        // TODO: For each light source in the code, calculate what the *ambient*, *diffuse*, and *specular* 
        // components are. Then, accumulate that result on the *result_color* object.
          //vector of light and eye.
        Eigen::Vector3f lightDir=light.position-point;
         lightDir=lightDir.normalized();
         Eigen::Vector3f eyeDir=eye_pos-point;
        //  eyeDir=eyeDir.normalized();
         //distance between light with point
         Eigen::Vector3f lightDir_len=light.position-point;
        //  float r= lightDir_len.norm();
         float r= sqrt(pow(lightDir_len[0],2)+pow(lightDir_len[1],2)+pow(lightDir_len[2],2));
        Eigen::Vector3f halfVector=(lightDir+eyeDir).normalized();
       //diffuse
        Eigen::Vector3f diffuse=kd.cwiseProduct((light.intensity/(r*r))*MAX(0,normal.dot(lightDir)));
        //ambient
        Eigen::Vector3f ambient=ka.cwiseProduct(amb_light_intensity);
        //specular
        Eigen::Vector3f specular=ks.cwiseProduct((light.intensity/(r*r))*pow(MAX(0,normal.dot(halfVector)),p));
        if (flag)
        {
            ambient= Eigen::Vector3f(0,0,0);
        }
        
        result_color +=  ambient+diffuse+specular;
        flag=true;

点乘的数学计算如下:

  1. 几何角度:
    现代图形学入门需要掌握的全部数学知识总结_第5张图片

  2. 坐标系角度
    现代图形学入门需要掌握的全部数学知识总结_第6张图片

  3. 点乘的属性
    现代图形学入门需要掌握的全部数学知识总结_第7张图片

3. 向量的叉乘

向量叉乘的结果还是一个向量,其方向用右手螺旋定则来确定。(或者左手定则)
openGL中使用的是左手坐标系。

1 叉乘在图形学中的用法:

  1. 判断一个向量是在另外一个向量的左边还是右边

如下图:判断b在a的左边还是右边
用a叉乘b,得到的结果是正的,说明b在a的左侧
用b叉乘a,得到的结果是负的,说明b在a的右侧

现代图形学入门需要掌握的全部数学知识总结_第8张图片

  1. 判断一个点是否在三角形内部。光栅化的时候判断一个像素点是否在三角形内部,从而判断是否为其着色。
    判断P在三角形ABC的内部?
    ABXAP,结果是正的,说明P在AB的左侧
    BCXBP,结果是正的,说明P在AB的左侧
    CAXPC,结果是正的,说明P在CA的左侧
    所以P在三角形ABC的内部,
    绕的顺序是AB-BC-CA,绕向逆时针和顺时针,也就是三个叉乘结果要嘛都是正的,要嘛都是负的
    这个是三角形光栅化的基础,要知道三角形覆盖了哪些像素,判断像素是否在三角形内部;
    现代图形学入门需要掌握的全部数学知识总结_第9张图片
bool insideTriangle(int x, int y, const Triangle& t)
{   
 
   
    Eigen::Vector2f p(x,y);
    Eigen::Vector2f A(t.v[0].x(),t.v[0].y());
    Eigen::Vector2f B(t.v[1].x(),t.v[1].y());
    Eigen::Vector2f C(t.v[2].x(),t.v[2].y()); 
  
    Eigen::Vector2f Ap(p.x()-A.x(),p.y()-A.y());
    Eigen::Vector2f AB(B.x()-A.x(),B.y()-A.y());
    Eigen::Vector2f Bp(p.x()-B.x(),p.y()-B.y());
    Eigen::Vector2f BC(C.x()-B.x(),C.y()-B.y());
    Eigen::Vector2f Cp(p.x()-C.x(),p.y()-C.y());
    Eigen::Vector2f CA(A.x()-C.x(),A.y()-C.y());
    
    if(cross(AB,Ap)*cross(BC,Bp)*cross(CA,Cp)>=0)//根据叉乘的结果来判断是否(x,y)是否在三角形内部
        return true;

    else
        return false;
    
}

2. 叉乘的属性

下面为右手坐标系

现代图形学入门需要掌握的全部数学知识总结_第10张图片

3 叉乘的坐标系计算方式

现代图形学入门需要掌握的全部数学知识总结_第11张图片

4 向量的规范化

向量规范化,即让向量的长度为1。

向量的规范化在后面的光照模型和光线追踪部分使用也很多,很多计算出来的向量都要进行规范化。
现代图形学入门需要掌握的全部数学知识总结_第12张图片

	//向量的规格化:就是让向量的长度等于1;
	//向量长度 length = sqrt(x² + y² + z²);
	//要让长度=1,那么向量 V(normalize) = V(src)/length=V(src)/sqrt(x² + y² + z²)=V(x/length,y/length,z/length);
	Vector3 normalize(Vector3 const & v)
	{
		//float sqr = v.x*v.x + v.y*v.y + v.z*v.z;
		//return v*inversesqrt(sqr);
 
		float length = sqrt(v.x*v.x + v.y*v.y + v.z*v.z); //向量长度;
		return Vector3(v.x / length, v.y / length, v.z / length); //获取到规格化的向量;
	}

2 矩阵

矩阵主要是在图形学的模型变换,view 变换,投影变换中使用。这些变换的计算都是基于矩阵的相乘进行的。

1 矩阵的乘积

在这里插入图片描述

  1. 相乘计算的简单记忆方式
    现代图形学入门需要掌握的全部数学知识总结_第13张图片

26是两个矩阵乘积的二行四列:
计算方法:找第一个矩阵的第二行(5,2),第二个矩阵的第四列(4,3),把两个向量求个点积就可以了。26=54+26;
61是两个矩阵乘积的二行三列:
计算方法:找第一个矩阵的第二行(5,2)和第二个矩阵的第三列(9,8)求点积就是61;59+28=61=61;
总结归纳这个记忆方法如下:
需要算两个矩阵乘积的第几行第几列的数值,直接在第一个矩阵中找第几行,在第二个矩阵中找第几列,然后将两个找到的向量按照顺序求向量点积。点积的数值就是要求的数值。

  1. 矩阵相乘的特性

没有交换律,有结合律和分配律
现代图形学入门需要掌握的全部数学知识总结_第14张图片

2 矩阵如何和一个向量乘

在这里要始终认为矩阵在左边,向量在右边(Matrix X vector)。
向量永远是一个列向量(mX1)。

这个就是图形学变换的基础。一个点想要变成另外一个点,乘以一个矩阵做变换,这个矩阵就是变换矩阵。

现代图形学入门需要掌握的全部数学知识总结_第15张图片

3 矩阵的转置

现代图形学入门需要掌握的全部数学知识总结_第16张图片

4 单位矩阵

用来定义矩阵的逆。
现代图形学入门需要掌握的全部数学知识总结_第17张图片

5 向量的点乘和叉乘写成矩阵的形式

点乘:
在这里插入图片描述
叉乘:----》》》在图形学旋转的推到中使用这个

在这里插入图片描述

3 平面与直线相交

在Ray traycing中使用这个数学知识。

1 平面的数学定义

平面的一条法线以及平面上的任意一点就可以定义一个平面

平面的一个特性:平面的法线与平面的任意两个点的连线垂直(初中知识)

现代图形学入门需要掌握的全部数学知识总结_第18张图片
p在平面上,根据平面的特性得到如下式子:
在这里插入图片描述

2 求解方法

现代图形学入门需要掌握的全部数学知识总结_第19张图片
上面的算法只是求出了平面与直线的交点,在图形学中需要判断这个交点是否在三角形内部,采用向量叉乘那部分的方法就可以了。
但是这个方法比较麻烦,下面的方法可以直接判断交点是否在三角形内部。

3 moller Trumbore 方法

利用重心坐标来求出三角形内的任何一个点,然后和光线上的点做比较,只要相等就是一个点。需要满足的条件是t>0,三角形三个顶点P0,P1,P2的系数要大于0.

现代图形学入门需要掌握的全部数学知识总结_第20张图片
需要解出t,b1,b2。三个方程和三个未知数,肯定可以求出来。
可以直接使用下面这个就可以解出来了:在这里插入图片描述

4 微积分

在渲染方程中用到了微积分。
也就是BRDF中主要使用的就是微积分的思想。

在这里插入图片描述
现代图形学入门需要掌握的全部数学知识总结_第21张图片

在下面计算dA出收到的irradiance,先算一个方向收到的Radiance,然后再求积分,将各个方向的radiance积分起来,这个地方用的就是微积分思想。

现代图形学入门需要掌握的全部数学知识总结_第22张图片

5 概率论

主要是在蒙特卡洛积分中使用概率论的知识。
蒙特卡洛积分----给你任意一个函数求它的定积分。但是这个函数比较复杂,求不出它的解析式,蒙特卡洛就可以解决这个。
蒙特卡洛是通过随机采样的方法做的。在积分域内不断去采样。最后求和去平均。
p(X)就是概率密度函数pdf.
现代图形学入门需要掌握的全部数学知识总结_第23张图片

1 随机变量

现代图形学入门需要掌握的全部数学知识总结_第24张图片

2 概率

现代图形学入门需要掌握的全部数学知识总结_第25张图片

3 期望

现代图形学入门需要掌握的全部数学知识总结_第26张图片

4 概率密度函数pdf

现代图形学入门需要掌握的全部数学知识总结_第27张图片
现代图形学入门需要掌握的全部数学知识总结_第28张图片

6 三角函数

图形学中的很多情况要用到基本的三角知识,三角知识可以帮我们记忆基本定义。

1、角

以一点出发的两条射线形成一个角。角度定义为这两条射线 在单位圆周上截出的圆弧长度。
一般规定用较短的弧长来表示角度,符号由两条射线的顺序来确定,这时所有弧度值都位于[-π,π].每个角度都是两条射线在单位圆周上切出的圆弧的长度。

2、三角函数

已知一个直角三角形,根据毕达哥拉斯定理有以下等式:
    a²+b²=c²
定义角α的正弦、余弦以及其他三角函数如下
    sinα = b/c
    cscα = c/b
    cosα = a/c
    secα = c/a
    tanα = b/a
    cotα = a/b
注意:在计算机图形学中经常约定逆时针旋转为正方向。
三角函数是周期函数,多个自变量值对应同一个函数值,这 就意味着这些函数在实数域R内是不可逆的。
为了使三角函数可逆,必须对取值范围进行限制。定义域和值域规定为:
    asin:[-1,1]→[-π/2,π/2]
    acos:[-1,1]→[0,π]
    atan:R→[-π/2,π/2]
    atan2:R→[-π,π]
最后一个函数atan2(s,c)是非常有用的。其中s与sinA成正比,c与cosA成正比,且比例因子相同,atan2(s,c)的函数值为A。
假使该比例因子为整数,其中的一种理解方式为,函数返回极坐标下二维笛卡尔点(s,c)的角度。

3、三角函数公式

在此列出各种有用的三角函数公式。
诱导公式:
    sin(-A) = -sinA
    cos(-A) = cosA
    tan(-A) = -tanA
    sin(π/2-A) = cosA
    cos(π/2-A) = sinA
    tan(π/2-A) = cotA
毕达哥拉斯公式:
    sin²A + cos²A = 1
    sec²A - tan²A = 1
    csc²A - cot²A = 1
和差公式:
    sin(A+B) = sinAcosB + cosAsinB
    sin(A-B) = sinAcosB - cosAsinB
    sin(2A) = 2sinAcosA
    cos(A+B) = cosAcosB - sinAsinB
    cos(A-B) = cosAcosB + sinAsinB
    cos(2A) = cos²A - sin²A
    tan(A+B) = (tanA+tanB)/(1-tanAtanB)
    tan(A-B) = (tanA-tanB)/(1+tanAtanB)
    tan(2A) = (2tanA)/(1-tan²A)
半角公式:
    sin²(A/2) = (1-cosA)/2
    cos²(A/2) = (1+cosA)/2
积化和差公式:
    sinAsinB = -(cos(A+B)-cos(A-B))/2
    sinAcosB = (sin(A+B)+sin(A-B))/2
    cosAcosB = (cos(A+B)+cos(A-B))/2
对于变长为a,b,c 对应角分别为A,B,C的任意三角形,下列公式都成立:
    sinA/a = sinB/b = sinC/c(正弦定理)
    c² = a²+b²-2abcosC(余弦定理)
    (a+b)/(a-b) = tan((A+B)/2)/tan((A-b)/2)(正切定理)
三角形的面积同样可以通过三条边长表示出来:
    s = sqrt((a+b+c)(-a+b+c)(a-b+c)(a+b-c))/2

7 三角形重心坐标

重心坐标:数学中,重心坐标是由单形(如三角形或四面体等)顶点定义的坐标。重心坐标是齐次坐标的一种。
在这里插入图片描述
作用:
三角形内的任意点都可以用三角形的三个点的坐标线性表示。如下图所示:
所以只要求出a,β,γ。(a,β,γ)就是重心坐标。

a,β,γ要满足全都大于0的条件。
现代图形学入门需要掌握的全部数学知识总结_第29张图片
a,β,γ计算方式如下:
现代图形学入门需要掌握的全部数学知识总结_第30张图片
代码如下:

static std::tuple<float, float, float> computeBarycentric2D(float x, float y, const Vector4f* v){
    float c1 = (x*(v[1].y() - v[2].y()) + (v[2].x() - v[1].x())*y + v[1].x()*v[2].y() - v[2].x()*v[1].y()) / (v[0].x()*(v[1].y() - v[2].y()) + (v[2].x() - v[1].x())*v[0].y() + v[1].x()*v[2].y() - v[2].x()*v[1].y());
    float c2 = (x*(v[2].y() - v[0].y()) + (v[0].x() - v[2].x())*y + v[2].x()*v[0].y() - v[0].x()*v[2].y()) / (v[1].x()*(v[2].y() - v[0].y()) + (v[0].x() - v[2].x())*v[1].y() + v[2].x()*v[0].y() - v[0].x()*v[2].y());
    float c3 = (x*(v[0].y() - v[1].y()) + (v[1].x() - v[0].x())*y + v[0].x()*v[1].y() - v[1].x()*v[0].y()) / (v[2].x()*(v[0].y() - v[1].y()) + (v[1].x() - v[0].x())*v[2].y() + v[0].x()*v[1].y() - v[1].x()*v[0].y());
    return {c1,c2,c3};//c1,c2,c3=a,β,γ
}

然后就可以利用重心坐标对ABC三个顶点的属性进行插值。下面代码使用的alpha,beta,gamma来源于上面三角形内的点求出来的alpha,beta,gamma
现代图形学入门需要掌握的全部数学知识总结_第31张图片

tatic Eigen::Vector3f interpolate(float alpha, float beta, float gamma, const Eigen::Vector3f& vert1, const Eigen::Vector3f& vert2, const Eigen::Vector3f& vert3, float weight)
{
    return (alpha * vert1 + beta * vert2 + gamma * vert3) / weight;
}

static Eigen::Vector2f interpolate(float alpha, float beta, float gamma, const Eigen::Vector2f& vert1, const Eigen::Vector2f& vert2, const Eigen::Vector2f& vert3, float weight)
{
    auto u = (alpha * vert1[0] + beta * vert2[0] + gamma * vert3[0]);
    auto v = (alpha * vert1[1] + beta * vert2[1] + gamma * vert3[1]);

    u /= weight;
    v /= weight;

    return Eigen::Vector2f(u, v);
}

注意:重心坐标在投影之后坐标会变化,所以插值三维空间的属性,就应该插值三维空间中的重心坐标,然后再对应到二维空间中。

重心坐标在图形学中使用的整个逻辑是:
遍历整个三角形内部的像素坐标,对每个像素坐标求一个重心坐标,然后利用这个重心坐标对三角形三个顶点所带的属性进行插值。
其实就是用了两次重心坐标:第一次已知条件是三角形内部坐标,求出这个已知坐标的重心坐标;第二次是利用这个点的重心坐标对三角形顶点的其他属性,比如所带的颜色,法向量等进行插值计算。这样就求出了了每个像素的法线,颜色以及各种各样的属性。

8 几何

几何部分主要是利用数学来表示几何体的方式分为两种:
隐式表示和显式表示

1 隐式表示

用隐式方程表示,给你一个关系,满足这个关系的点,就是这个几何体上的点。
判断一个点是否在这个面上是非常简单的事情。
现代图形学入门需要掌握的全部数学知识总结_第32张图片

2 显式表示

直接把所有的点或者通过参数映射的表示。
测试一个点在不在几何体内比较难。
现代图形学入门需要掌握的全部数学知识总结_第33张图片

3 曲线

贝塞尔曲线

用一系列的控制点来绘制一条曲线,曲线并不一定通过控制点,只要通过起止点即可。

实现算法是de castekujau 算法
现代图形学入门需要掌握的全部数学知识总结_第34张图片

通过不同的t来生成。

cv::Point2i recursive_bezier(const std::vector<cv::Point2i> &control_points, float t) 
{
    // TODO: Implement de Casteljau's algorithm

    auto &p_0 = control_points[0];
    auto &p_1 = control_points[1];
    auto &p_2 = control_points[2];
    auto &p_3 = control_points[3];
    auto point = std::pow(1 - t, 3) * p_0 + 3 * t * std::pow(1 - t, 2) * p_1 +
                 3 * std::pow(t, 2) * (1 - t) * p_2 + std::pow(t, 3) * p_3;
    return point;
    

}
void bezier(const std::vector<cv::Point2i> &control_points, cv::Mat &window) 
{
   
    for (double t = 0; t <= 1.0; t += 0.001)
    {
        auto point= recursive_bezier(control_points,t);
        window.at<cv::Vec3b>(point.y, point.x)[1] = 255;
    }
    
}

现代图形学入门需要掌握的全部数学知识总结_第35张图片

B样条

几个控制点的基函数加权平均,是对贝塞尔曲线的拓展。
B样条具有局部性,更容易控制,影响范围小
及其复杂。基函数很复杂

4 贝塞尔曲面

在水平方向上做一次贝塞尔曲线,然后再另外一个方向再做一次贝塞尔曲线。需要两个t。
现代图形学入门需要掌握的全部数学知识总结_第36张图片
现代图形学入门需要掌握的全部数学知识总结_第37张图片

推荐大佬写的计算机图形学中的数学

https://www.cc.gatech.edu/~turk/math_gr.html

http://staff.ustc.edu.cn/~lgliu/Resources/CG/Math_for_CG_Turk_CN.htm

你可能感兴趣的:(计算机图形学)