向量点乘
两个向量点乘(x1,y1,z1).(x2,y2,z2),结果是一个数值
//向量点乘
inline float vec3_dot(Vec3& v1,Vec3& v2){
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
点乘的几何意义
计算两个向量正交性
当结果为0,表示两个向量垂直
当结果>0,表示两个向量方向相同,夹角在0~90度
当结果<0,表示两个向量方向相反,夹角在90~180度
- 两个向量夹角0~90度
(0.5,0.5,0),(0.5,0,0)计算这两个点的点乘结果
0.50.5+0.50+0*0 = 0.25
image.png- 两个向量垂直
(0,0.5,0),(0.5,0,0)
00.5+0.50+0*0 = 0
image.png- 两个向量夹角90~180度
(0.5,0.5,0),(-0.5,0,0)
0.5*-0.5+0.50+00 = -0.25
image.png计算两个向量的夹角
cos(θ) = (A·B) / (||A|| * ||B||)
其中:||A|| = √(A₁² + A₂² + ... + Aₙ²),||B|| = √(B₁² + B₂² + ... + Bₙ²)
向量叉乘
公式
两个三维向量 𝐀 = [𝐀₁, 𝐀₂, 𝐀₃] 和 𝐁 = [𝐁₁, 𝐁₂, 𝐁₃]
AxB叉乘结果是一个向量,通俗的讲法就是法向量,该向量垂直于 A ,B 向量构成的平面。
两个向量的叉乘公式如下:
<aside>
💡 𝐀 × 𝐁 = [𝐴₂𝐁₃ - 𝐴₃𝐁₂, 𝐴₃𝐁₁ - 𝐴₁𝐁₃, 𝐴₁𝐁₂ - 𝐴₂𝐁₁]
</aside>
inline Vec3 vec3_cross(Vec3& v1,Vec3& v2){
Vec3 v;
v.x = v1.y * v2.z - v1.z * v2.y;
v.y = v1.z * v2.x - v1.x * v2.z;
v.z = v1.x * v2.y - v1.y * v2.x;
return v;
}
叉乘的几何意义
计算法向量
向量C = AxB
方向的判断
根据右手法则,axb表示红色法向量,表示大拇指的方向,四指从a指向b。
bxa或者-axb表示黄色法向量,表示大拇指的方向,四指方向从b指向a
image.png向量 A 和向量B 构成的平行四边形面积
根据向量叉乘的性质,两个向量的叉乘结果的模长等于这两个向量所在平行四边形的面积。|𝐀 × 𝐁| = |𝐀| × |𝐁| × sin(θ),|𝐀| 表示向量 𝐀 的模长,|𝐁| 表示向量 𝐁 的模长,θ 表示向量 𝐀 和 𝐁 之间的夹角
面积的计算方式:
面积 = || 𝐴 × 𝐵 ||表示向量 𝐴 叉乘向量 𝐵 的模,也就是叉积的大小。
image.png image.png平行四边形面积:s = a*h
|A| = |A| = √(a₁² + a₂² + ... + aₙ²)
计算两个向量 A B的所形成的平行四边形的面积
image.png矩阵运算
矩阵加法/减法
前提:同型矩阵。也就是两个矩阵的行列都要一样,结果还是一个矩阵
矩阵数乘
一个数值与矩阵相乘就叫做矩阵的数乘,结果还是一个矩阵
image.png矩阵转置
把矩阵 A 的行和列相互交互所产生的矩阵称为 A 的转置矩阵,结果还是一个矩阵
mxn → nxm
image.png//交换两个数
inline void swapf(float &a,float &b){
float tmp = a;
a = b;
b = tmp;
}
//矩阵转置
inline Mat3x3 mat3x3_transpose(Mat3x3 &matrix){
Mat3x3 result = matrix;
swapf(result.r0.y,result.r1.x);
swapf(result.r0.z,result.r2.x);
swapf(result.r1.z,result.r2.y);
return result;
}
矩阵相乘
前提:矩阵 A 的列数等于矩阵 B 的行数,A 矩阵mxn B 矩阵 nxp,因此矩阵的乘法不满足交换律
矩阵 C = A x B = mxp
矩阵行列式
一个矩阵的行列式的结果是一个数,它的几何意义是矩阵的行列式结果不为 0,表示该矩阵是可逆的。
image.png
inline float mat3x3_determinant(Mat3x3& matrix){
return matrix.r0.x * (matrix.r1.y * matrix.r2.z -matrix.r1.z * matrix.r2.y)
-matrix.r0.y * (matrix.r1.x * matrix.r2.z -matrix.r1.z * matrix.r2.x)
+matrix.r0.z * (matrix.r1.x * matrix.r2.y -matrix.r1.y * matrix.r2.x);
}
伴随矩阵
矩阵 A 的伴随矩阵使用 A* 表示
inline Mat3x3 companion_mat3x3(Mat3x3& matrix){
Mat3x3 inv;
Vec3 v1 = matrix.r0;
Vec3 v2 = matrix.r1;
Vec3 v3 = matrix.r2;
float a11 = 1 * (v2.y * v3.z - v2.z * v3.y);
float a12 = -1 * (v2.x * v3.z - v3.x * v2.z);
float a13 = 1 * (v2.x * v3.y - v2.y * v3.x);
float a21 = -1 * (v1.y * v3.z - v1.z * v3.y);
float a22 = 1 * (v1.x * v3.z - v1.z * v3.x);
float a23 = -1* (v1.x * v3.y - v1.y * v3.x);
float a31 = 1 * (v1.y * v2.z - v1.z * v2.y);
float a32 = -1 * (v1.x * v2.z - v1.z * v2.x);
float a33 = 1 * (v1.x * v2.y - v1.y * v2.x);
inv.r0.x = a11;
inv.r0.y = a12;
inv.r0.z = a13;
inv.r1.x = a21;
inv.r1.y = a22;
inv.r1.z = a23;
inv.r2.x = a31;
inv.r2.y = a32;
inv.r2.z = a33;
//转置矩阵
mat3x3_transpose(inv);
// inv.r0.x = a11;
// inv.r0.y = a21;
// inv.r0.z = a31;
// inv.r1.x = a12;
// inv.r1.y = a22;
// inv.r1.z = a32;
// inv.r2.x = a13;
// inv.r2.y = a23;
// inv.r2.z = a33;
return inv;
}
矩阵 A 的伴随矩阵的计算过程如下所示
image.png逆矩阵
矩阵 A 的逆矩阵 = 矩阵A的伴随矩阵/矩阵A的行列式
image.png|A| 矩阵A的行列式如果不为0,则表示该矩阵是可腻的。
inline void vec3_div(Vec3& vec3,float div){
vec3.x = vec3.x/div;
vec3.y = vec3.y /div;
vec3.z = vec3.z/div;
}
inline void mat3x3_div(Mat3x3& m,float div){
vec3_div(m.r0,div);
vec3_div(m.r1,div);
vec3_div(m.r2,div);
}
inline Mat3x3 mat3x3_reverse(Mat3x3& matrix){
float determinant = mat3x3_determinant(matrix);
Mat3x3 compain_matrix = companion_mat3x3(matrix);
mat3x3_div(compain_matrix,determinant);
return compain_matrix;
}
下面是通过这个公式来推导出矩阵 A 的逆矩阵
image.png
参考
线性代数课程
本文是笔者学习之后的总结,方便日后查看学习,有任何不对的地方请指正。
记录于2023年11月21日
网友评论