刚好本人最近在研究数字孪生模拟相关的专题,涉及到三维空间线代向量、矩阵相关的计算,顺便重温了一下线代,在使用的过程中遇到问题的一些总结和实用技巧在下头阐述,相信这篇文章能够给短时间接触这些API的人一些启发。
在三维中可以把矩阵的列看出变换后的基向量:
通常而言,表示坐标系的i、j向量为(1,0)、(0,1),当我们把坐标轴逆时针旋转90°后,坐标系的基向量发生成了变化,i–>(0,1)、(-1, 0);
矩阵乘以一个向量有什么几何意义
矩阵乘向量就是把这个向量旋转,而且向量的大小也会改变,可以看出某空间下的向量到另一个空间的映射,其实就是向量空间的线性变换。
对于这一块理解比较模糊的同学推荐看一下国外的Blue1Brown视频->线性代数的本质
来看一下一些常见的用法:
特别的仿射四维矩阵:
左上角是旋转矩阵、右上角是平移矩阵,旋转矩阵的最后一维是0,平移矩阵的最后一维是1。
总结一下Cesium 中Matrix4的一些常见用法:
Cesium.Matrix4,4x4矩阵,一般用于描述旋转加平移变换。
在计算机图形学中,Cesium.Matrix3,3x3矩阵,一般用于描述旋转变换。
矩阵和标量相乘
Cesium.Matrix4.multiplyByScalar (matrix, scalar, new Cesium.Matrix4())
矩阵的缩放倍数
result[0] = matrix[0] * scalar;
result[1] = matrix[1] * scalar;
result[2] = matrix[2] * scalar;
result[3] = matrix[3] * scalar;
result[4] = matrix[4] * scalar;
result[5] = matrix[5] * scalar;
result[6] = matrix[6] * scalar;
result[7] = matrix[7] * scalar;
result[8] = matrix[8] * scalar;
result[9] = matrix[9] * scalar;
result[10] = matrix[10] * scalar;
result[11] = matrix[11] * scalar;
result[12] = matrix[12] * scalar;
result[13] = matrix[13] * scalar;
result[14] = matrix[14] * scalar;
result[15] = matrix[15] * scalar;
return result;
* // m = [10.0, 11.0, 12.0, 13.0]
* // [14.0, 15.0, 16.0, 17.0]
* // [18.0, 19.0, 20.0, 21.0]
* // [22.0, 23.0, 24.0, 25.0]
*
* const a = Cesium.Matrix4.multiplyByScalar(m, -2, new Cesium.Matrix4());
*
* // m remains the same
* // a = [-20.0, -22.0, -24.0, -26.0]
* // [-28.0, -30.0, -32.0, -34.0]
* // [-36.0, -38.0, -40.0, -42.0]
* // [-44.0, -46.0, -48.0, -50.0]
*/
矩阵和向量相乘部分
Cesium.Matrix4.multiplyByScale (matrix, scale, new Cesium.Matrix4())
对矩阵空间中的列向量进行成比例缩放,缩放了空间基向量的长度
const scaleX = scale.x;
const scaleY = scale.y;
const scaleZ = scale.z;
// Faster than Cartesian3.equals
if (scaleX === 1.0 && scaleY === 1.0 && scaleZ === 1.0) {
return Matrix4.clone(matrix, result);
}
result[0] = scaleX * matrix[0];
result[1] = scaleX * matrix[1];
result[2] = scaleX * matrix[2];
result[3] = matrix[3];
result[4] = scaleY * matrix[4];
result[5] = scaleY * matrix[5];
result[6] = scaleY * matrix[6];
result[7] = matrix[7];
result[8] = scaleZ * matrix[8];
result[9] = scaleZ * matrix[9];
result[10] = scaleZ * matrix[10];
result[11] = matrix[11];
result[12] = matrix[12];
result[13] = matrix[13];
result[14] = matrix[14];
result[15] = matrix[15];
return result;
Cesium.Matrix4.multiplyByTranslation (matrix, translation, new Cesium.Matrix4())
const x = translation.x;
const y = translation.y;
const z = translation.z;
const tx = x * matrix[0] + y * matrix[4] + z * matrix[8] + matrix[12];
const ty = x * matrix[1] + y * matrix[5] + z * matrix[9] + matrix[13];
const tz = x * matrix[2] + y * matrix[6] + z * matrix[10] + matrix[14];
result[0] = matrix[0];
result[1] = matrix[1];
result[2] = matrix[2];
result[3] = matrix[3];
result[4] = matrix[4];
result[5] = matrix[5];
result[6] = matrix[6];
result[7] = matrix[7];
result[8] = matrix[8];
result[9] = matrix[9];
result[10] = matrix[10];
result[11] = matrix[11];
result[12] = tx;
result[13] = ty;
result[14] = tz;
result[15] = matrix[15];
Cesium.Matrix4.multiplyByVector(matrix, cartesian, new Cesium.Cartesian3())
将一个3D向量进行线性变换,使其沿着矩阵的行方向进行缩放、旋转和平移
cartesian的w分量为0,表示这个结果是一个向量,而不是一个点,你可以用这个函数获取一个向量。
// 源码
const vX = cartesian.x;
const vY = cartesian.y;
const vZ = cartesian.z;
const vW = cartesian.w;
const x = matrix[0] * vX + matrix[4] * vY + matrix[8] * vZ + matrix[12] * vW;
const y = matrix[1] * vX + matrix[5] * vY + matrix[9] * vZ + matrix[13] * vW;
const z = matrix[2] * vX + matrix[6] * vY + matrix[10] * vZ + matrix[14] * vW;
const w = matrix[3] * vX + matrix[7] * vY + matrix[11] * vZ + matrix[15] * vW;
result.x = x;
result.y = y;
result.z = z;
result.w = w;
将这个向量乘以矩阵,得到一个新的向量,即将原向量进行变换后得到新向量。
Cesium.Matrix4.multiplyByPoint(matrix, cartesian, new Cesium.Cartesian3())
cartesian的w分量为1,表示这个结果是一个点,不是一个向量,你可以用这个函数获取一个坐标点。
// 源码
const vX = cartesian.x;
const vY = cartesian.y;
const vZ = cartesian.z;
const x = matrix[0] * vX + matrix[4] * vY + matrix[8] * vZ + matrix[12];
const y = matrix[1] * vX + matrix[5] * vY + matrix[9] * vZ + matrix[13];
const z = matrix[2] * vX + matrix[6] * vY + matrix[10] * vZ + matrix[14];
result.x = x;
result.y = y;
result.z = z;
常用于,将模型从局部空间转换到世界空间,或者相机空间等。任何位移,旋转,缩放的组合都可以用一个4x4矩阵来表示,这样就可以简单地使用矩阵乘法来变换点和向量。
通俗一点,即将局部坐标系下的点坐标转化为世界坐标的点。以下点A通过矩阵变换:
Cesium.Matrix4.multiplyByPoint(局部坐标系, A在局部坐标的位置, A在世界坐标系下的点位置)
Cesium.Matrix4.multiplyByPointAsVector(matrix, new Cesium.Cartesian3(x, y, z), new Cesium.Cartesian3());
w分量为0,等效于调用 Matrix4.multiplyByVector,但是multiplyByPointAsVector方法返回的是一个Cartesian4对象,表示这个结果是一个向量,而不是一个点
// 源码
const vX = cartesian.x;
const vY = cartesian.y;
const vZ = cartesian.z;
const x = matrix[0] * vX + matrix[4] * vY + matrix[8] * vZ;
const y = matrix[1] * vX + matrix[5] * vY + matrix[9] * vZ;
const z = matrix[2] * vX + matrix[6] * vY + matrix[10] * vZ;
result.x = x;
result.y = y;
result.z = z;
Cesium.Matrix4.setTranslation (matrix, translation, new Cesium.Matrix4())
设置平移矩阵
result[0] = matrix[0];
result[1] = matrix[1];
result[2] = matrix[2];
result[3] = matrix[3];
result[4] = matrix[4];
result[5] = matrix[5];
result[6] = matrix[6];
result[7] = matrix[7];
result[8] = matrix[8];
result[9] = matrix[9];
result[10] = matrix[10];
result[11] = matrix[11];
result[12] = translation.x;
result[13] = translation.y;
result[14] = translation.z;
result[15] = matrix[15];
Cesium.Matrix4.setScale (matrix, scale, new Cesium.Matrix4())
设置矩阵的比例缩放。
const existingScale = Matrix4.getScale(matrix, scaleScratch1);
const scaleRatioX = scale.x / existingScale.x;
const scaleRatioY = scale.y / existingScale.y;
const scaleRatioZ = scale.z / existingScale.z;
result[0] = matrix[0] * scaleRatioX;
result[1] = matrix[1] * scaleRatioX;
result[2] = matrix[2] * scaleRatioX;
result[3] = matrix[3];
result[4] = matrix[4] * scaleRatioY;
result[5] = matrix[5] * scaleRatioY;
result[6] = matrix[6] * scaleRatioY;
result[7] = matrix[7];
result[8] = matrix[8] * scaleRatioZ;
result[9] = matrix[9] * scaleRatioZ;
result[10] = matrix[10] * scaleRatioZ;
result[11] = matrix[11];
result[12] = matrix[12];
result[13] = matrix[13];
result[14] = matrix[14];
result[15] = matrix[15];
矩阵和矩阵相乘部分
Cesium.Matrix4.multiplyByMatrix3 (matrix, rotation, new Cesium.Matrix4())
乘以一个转换矩阵(3x3旋转矩阵),优化 Matrix4.multiply(m,Matrix4.fromRotationTranslation(rotation),m)的计算,使得分配和运算量较少。
Cesium.Matrix4.multiply(left, right, new Cesium.Matrix4());
四维矩阵相乘。
A * B B左乘A, 可以把A看做坐标系,A的行向量是坐标系的基向量。把B看做列向量集合。 A * B就是把B中的列向量投影到A的所有基向量上。计算过程就是设b为B中的一个列向量。b点乘A中的所有基向量得到b在A的所有基向量上的投影,得到b向量在A坐标系中的表示方法。所以B做成A就是,将B中的所有向量转换为在A坐标空间中的表示方法。
Cesium.Matrix4.multiplyTransformation(left, right, new Cesium.Matrix4()) ;
当两个矩阵都是左上角旋转矩阵+右上角平移矩阵+底为[0,0,0,1]的这种形式的,用这种方法计算比一般用Matrix4.multiply 的速度更快。
// 源码
const column0Row0 = left0 * right0 + left4 * right1 + left8 * right2;
const column0Row1 = left1 * right0 + left5 * right1 + left9 * right2;
const column0Row2 = left2 * right0 + left6 * right1 + left10 * right2;
const column1Row0 = left0 * right4 + left4 * right5 + left8 * right6;
const column1Row1 = left1 * right4 + left5 * right5 + left9 * right6;
const column1Row2 = left2 * right4 + left6 * right5 + left10 * right6;
const column2Row0 = left0 * right8 + left4 * right9 + left8 * right10;
const column2Row1 = left1 * right8 + left5 * right9 + left9 * right10;
const column2Row2 = left2 * right8 + left6 * right9 + left10 * right10;
const column3Row0 =
left0 * right12 + left4 * right13 + left8 * right14 + left12;
const column3Row1 =
left1 * right12 + left5 * right13 + left9 * right14 + left13;
const column3Row2 =
left2 * right12 + left6 * right13 + left10 * right14 + left14;
result[0] = column0Row0;
result[1] = column0Row1;
result[2] = column0Row2;
result[3] = 0.0;
result[4] = column1Row0;
result[5] = column1Row1;
result[6] = column1Row2;
result[7] = 0.0;
result[8] = column2Row0;
result[9] = column2Row1;
result[10] = column2Row2;
result[11] = 0.0;
result[12] = column3Row0;
result[13] = column3Row1;
result[14] = column3Row2;
result[15] = 1.0;
矩阵的常见用法
Cesium.Matrix4.subtract (left, right, new Cesium.Matrix4())
矩阵求差
Cesium.Matrix4.add (left, right, new Cesium.Matrix4())
矩阵求和
Cesium.Matrix4.abs (matrix, new Cesium.Matrix4())
求矩阵绝对值
Cesium.Matrix4.clone (matrix, new Cesium.Matrix4())
克隆当前矩阵实例
Cesium.Matrix4.equals(left, right)
对比矩阵的每个元素值是否相等
逆矩阵部分
Cesium.Matrix4.inverse(matrix, new Cesium.Matrix4()) ;
逆矩阵是和这个矩阵相乘以后成为单位矩阵的矩阵。 当行列式不为0,矩阵才有逆矩阵。如果输入矩阵不可逆,则会返回一个全零并且平移为负的矩阵。计算矩阵的逆矩阵,从世界坐标系到局部坐标系的变换矩阵。
Cesium.Matrix4.inverseTransformation(matrix, new Cesium.Matrix4());
当其中左上3x3元素是旋转矩阵,第四列中的上三个元素是平移矩阵,最下面的一行是[0,0,0,1]时求矩阵的逆矩阵,用inverseTransformation这种方法比计算一般4x4矩阵使用 Matrix4.multiply的速度更快
const matrix0 = matrix[0];
const matrix1 = matrix[1];
const matrix2 = matrix[2];
const matrix4 = matrix[4];
const matrix5 = matrix[5];
const matrix6 = matrix[6];
const matrix8 = matrix[8];
const matrix9 = matrix[9];
const matrix10 = matrix[10];
const vX = matrix[12];
const vY = matrix[13];
const vZ = matrix[14];
const x = -matrix0 * vX - matrix1 * vY - matrix2 * vZ;
const y = -matrix4 * vX - matrix5 * vY - matrix6 * vZ;
const z = -matrix8 * vX - matrix9 * vY - matrix10 * vZ;
result[0] = matrix0;
result[1] = matrix4;
result[2] = matrix8;
result[3] = 0.0;
result[4] = matrix1;
result[5] = matrix5;
result[6] = matrix9;
result[7] = 0.0;
result[8] = matrix2;
result[9] = matrix6;
result[10] = matrix10;
result[11] = 0.0;
result[12] = x;
result[13] = y;
result[14] = z;
result[15] = 1.0;
return result;
inverse方法仅计算输入矩阵的逆矩阵,而inverseTransformation方法计算输入矩阵的逆矩阵和平移向量的相反数。在不同的场景下,选择不同的方法可以更方便地实现所需的功能。
Cesium.Matrix4.transpose (matrix, new Cesium.Matrix4())
矩阵的转置,将矩阵的行列互换得到的新矩阵称为转置矩阵,转置矩阵的行列式不变。
//returns transpose of a Matrix4
// m = [10.0, 11.0, 12.0, 13.0]
// [14.0, 15.0, 16.0, 17.0]
// [18.0, 19.0, 20.0, 21.0]
// [22.0, 23.0, 24.0, 25.0]
var a = Cesium.Matrix4.transpose(m, new Cesium.Matrix4());
// m remains the same
// a = [10.0, 14.0, 18.0, 22.0]
// [11.0, 15.0, 19.0, 23.0]
// [12.0, 16.0, 20.0, 24.0]
// [13.0, 17.0, 21.0, 25.0]
转置的作用相当于对矩阵进行旋转,使得行变成列,列变成列。
Cesium.Matrix4.inverseTranspose(matrix,result)
求逆转置
// 源码
return Matrix4.inverse(
Matrix4.transpose(matrix, scratchTransposeMatrix),
result
);
在模型视图变换时,顶点乘模型视图变换矩阵,而顶点对应的顶点法线向量(或其他的法线向量)则要乘模型视图矩阵的逆转置矩阵。
https://blog.51cto.com/u_15127690/4750355
Cesium.Matrix4.negate (matrix, result)
对矩阵每一个元素取相反数
// 实现逻辑
//create a new Matrix4 instance which is a negation of a Matrix4
// m = [10.0, 11.0, 12.0, 13.0]
// [14.0, 15.0, 16.0, 17.0]
// [18.0, 19.0, 20.0, 21.0]
// [22.0, 23.0, 24.0, 25.0]
var a = Cesium.Matrix4.negate(m, new Cesium.Matrix4());
// m remains the same
// a = [-10.0, -11.0, -12.0, -13.0]
// [-14.0, -15.0, -16.0, -17.0]
// [-18.0, -19.0, -20.0, -21.0]
// [-22.0, -23.0, -24.0, -25.0]
用Matrix4类的API生成四维矩阵
Cesium.Matrix4.fromTranslation(translation, new Cesium.Matrix4());
if (!defined(result)) {
return new Matrix4(
1.0,
0.0,
0.0,
translation.x,
0.0,
1.0,
0.0,
translation.y,
0.0,
0.0,
1.0,
translation.z,
0.0,
0.0,
0.0,
1.0
);
}
Cesium.Matrix4.getTranslation(matrix, new Cesium.Cartesian3())
从矩阵获取平移向量, 用于获取一个4x4矩阵的平移部分,返回的是矩阵的平移部分,也就是矩阵的第4列的前3个元素。这个结果是一个Cartesian3对象,表示3D空间中的一个点,这个点的坐标就是矩阵所表示的变换中的平移部分。
通常,一个4x4的矩阵可以分解为三个部分:平移部分、旋转部分和缩放部分。
同理, Cesium.Matrix4.getScale(matrix, new Cesium.Cartesian3()), Cesium.Matrix4.getRotation(matrix, new Cesium. Matrix3()) ,分别用于获取缩放比例和旋转部分。
Cesium.Matrix4.fromRotationTranslation(rotation, translation, result)
Cesium.Matrix4.fromScale(scale, result)
Cesium.Matrix4.fromTranslationQuaternionRotationScale(translation, rotation, scale, result)
Cesium.Matrix4.fromTranslationRotationScale(translationRotationScale, result)
如何可视化世界矩阵的局部坐标系?文章来源:https://www.toymoban.com/news/detail-695734.html
// 局部坐标系的局部坐标轴 ---核心代码
addlocalAxis(parentMatrix, color) {
let parentPosition = Cesium.Matrix4.getTranslation(parentMatrix, new Cesium.Cartesian3());
this.addEntity(parentPosition, Cesium.Color.RED);
// 求矩阵的x轴基向量
// Cesium.Cartesian3.UNIT_X <=> new Cesium.Cartesian3(1, 0, 0)
const localAxisX = Cesium.Matrix4.multiplyByPointAsVector(parentMatrix, new Cesium.Cartesian3(1, 0, 0), new Cesium.Cartesian3());
// 求矩阵的y轴基向量
// Cesium.Cartesian3.UNIT_Y <=> new Cesium.Cartesian3(0, 1, 0)
const localAxisY = Cesium.Matrix4.multiplyByPointAsVector(parentMatrix, new Cesium.Cartesian3(0, 1, 0), new Cesium.Cartesian3());
// 求矩阵的z轴基向量
// Cesium.Cartesian3.UNIT_Z <=> new Cesium.Cartesian3(0, 0, 1)
const localAxisZ = Cesium.Matrix4.multiplyByPointAsVector(parentMatrix, new Cesium.Cartesian3(0, 0, 1), new Cesium.Cartesian3());
this.addPolyline(parentPosition, localAxisX, color);
this.addPolyline(parentPosition, localAxisY, color);
this.addPolyline(parentPosition, localAxisZ, color);
}
addPolyline(position, vector, color) {
return this.viewer.entities.add({
polyline: {
width: 10,
positions: [position, Cesium.Cartesian3.add(position, vector, new Cesium.Cartesian3())],
material: new Cesium.PolylineArrowMaterialProperty(
color
),
},
});
}
// 添加entity点
addEntity(position, color) {
return this.viewer.entities.add({
position: position,
point: {
color: color,
pixelSize: 10,
},
})
}
线性代数,可能我们只学了它的计算,但其实更重要的是它的几何含义。计算只是解决问题的工具,而明白其几何含义帮助我们知道解决什么问题要用什么工具,以及如何解读最终结果的含义,学无止境,继续加油吧。文章来源地址https://www.toymoban.com/news/detail-695734.html
到了这里,关于Cesium中常用的一些数学计算(矩阵、向量)用法——矩阵的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!