Cesium中常用的一些数学计算(矩阵、向量)用法

您所在的位置:网站首页 三维垂直向量的公式是什么时候学的 Cesium中常用的一些数学计算(矩阵、向量)用法

Cesium中常用的一些数学计算(矩阵、向量)用法

2024-07-04 17:46| 来源: 网络整理| 查看: 265

刚好本人最近在研究数字孪生模拟相关的专题,涉及到三维空间线代向量、矩阵相关的计算,顺便重温了一下线代,在使用的过程中遇到问题的一些总结和实用技巧在下头阐述,相信这篇文章能够给短时间接触这些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在世界坐标系下的点位置)

multiplyByPoint示意图

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)

如何可视化世界矩阵的局部坐标系?

// 局部坐标系的局部坐标轴 ---核心代码 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, }, }) }

线性代数,可能我们只学了它的计算,但其实更重要的是它的几何含义。计算只是解决问题的工具,而明白其几何含义帮助我们知道解决什么问题要用什么工具,以及如何解读最终结果的含义,学无止境,继续加油吧。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3