赞
踩
Cesium中点由Cartesian3
表示,类似POINT3D点,其形式为包含 (x, y, z)的一维向量
Cesium中默认坐标系以地心为原点,所有未指明的Cartesian3
都基于此坐标系
我们需要进行的平移与旋转基于模型所在点为原点,正东为X,正北为Y的局部坐标系
使用函数Cesium.Transforms.eastNorthUpToFixedFrame(origin)
获取上述局部坐标系中点转换为世界坐标系中的位置的变换矩阵,P世界=M变换矩阵P局部
3Dtiles模型的变换由一个4维矩阵完成,通过不断左乘变换矩阵可以完成一系列的复杂变换
使用vue2,参考官方调整模型高度的案例。
假设模型的原点在世界坐标系下坐标为(xorigin, yorigin, zorigin)
获取坐标系变换矩阵
假设模型需要平移(x, y, z)量,先计算局部坐标系中点(x, y, z)在世界坐标下的位置(xworld, yworld, zworld)
const offset = Cesium.Matrix4.multiplyByPoint(m, tempTranslation, new Cesium.Cartesian3(0, 0, 0));
使用(xworld, yworld, zworld)-(xorigin, yorigin, zorigin)获得世界坐标系中平移向量
使用Cesium.Matrix4.fromTranslation(translation);
获取3Dtiles平移变换矩阵
透明度调整tileset.style = new Cesium.Cesium3DTileStyle({color: "color('rgba(255,255,255," + opacity + ")')"});
- transferModel(tileset, _tx, _ty, _tz,_opacity) {
- if(!this.checkModelLoad()){
- return
- }
- let tx = _tx ? _tx : 0;
- let ty = _ty ? _ty : 0;
- let tz = _tz ? _tz : 0;
- let opacity = _opacity ? _opacity/100 : 1
-
- const origin = tileset.boundingSphere.center;
-
- const m = Cesium.Transforms.eastNorthUpToFixedFrame(origin);//获取到以模型中心为原点,Z轴垂直地表的局部坐标系,以矩阵表示,此矩阵为将局部坐标系变换到世界坐标系的变换矩阵
- //平移
- const tempTranslation = new Cesium.Cartesian3(tx, ty, tz);//平移向量
- const offset = Cesium.Matrix4.multiplyByPoint(m, tempTranslation, new Cesium.Cartesian3(0, 0, 0));//局部坐标中(tx,ty,tz)在世界坐标系中位置
- const translation = Cesium.Cartesian3.subtract(offset, origin, new Cesium.Cartesian3());//终点世界坐标减去原点世界坐标得到世界坐标系下平移向量
- tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
- //透明度
- tileset.style = new Cesium.Cesium3DTileStyle({
- color: "color('rgba(255,255,255," + opacity + ")')",
- });
- },
模型旋转时,由于Cesium默认绕轴旋转是绕世界坐标系轴旋转,因此我们需要做如下操作完成绕局部坐标轴旋转
将模型原点平移回世界坐标系原点(地心),矩阵记为T1
将局部坐标Z轴调整到与世界坐标Z轴重合,矩阵记为R1
将模型绕世界坐标系的某个轴旋转(真正进行旋转的矩阵),此处以Z轴为例,矩阵记为R
将局部坐标Z轴旋转回原来的指向,矩阵记为R2
平移回初始位置,矩阵记为T2
最终模型旋转的矩阵为T2R2RR1T1
将旋转开始前模型的初始变换矩阵左乘此矩阵即可完成旋转变换
- const origin = tileset.boundingSphere.center;
- console.log("初始世界坐标", origin)
- const localToWorldMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(origin);//获取到以模型中心为原点,Z轴垂直地表的局部坐标系的变换矩阵,左乘此矩阵可以将局部坐标变换为世界坐标
- const originMatrix = tileset.modelMatrix//贴地变换矩阵或者初始变换矩阵M0
- console.log("当前坐标变换矩阵", localToWorldMatrix)
- const backToEarthCenter = new Cesium.Cartesian3(-origin.x, -origin.y, -origin.z)//回到地心位移量
- let backToEarthCenterMatrix = Cesium.Matrix4.fromTranslation(backToEarthCenter);//回到地心变换矩阵
- Cesium.Matrix4.multiply(backToEarthCenterMatrix, originMatrix, backToEarthCenterMatrix)//贴地变换矩阵左乘回到地心矩阵 T1M0
- console.log("回到地心变换矩阵", backToEarthCenterMatrix)
先将红线表示的向量(z'轴)绕Z轴顺时针旋转Φ度,再绕Y轴顺时针旋转θ度
1、通过一维向量表示坐标轴,通过左乘变换矩阵完成局部坐标轴在世界坐标系下的表示
- //旋转模型使得Z轴与世界坐标Z轴重合
- let arrowX = new Cesium.Cartesian3(1, 0, 0)
- let arrowY = new Cesium.Cartesian3(0, 1, 0)
- let arrowZ = new Cesium.Cartesian3(0, 0, 1)
- let localArrowX = Cesium.Matrix4.multiplyByPoint(localToWorldMatrix, new Cesium.Cartesian3(1, 0, 0), new Cesium.Cartesian3)
- let localArrowY = Cesium.Matrix4.multiplyByPoint(localToWorldMatrix, new Cesium.Cartesian3(0, 1, 0), new Cesium.Cartesian3)
- let localArrowZ = Cesium.Matrix4.multiplyByPoint(localToWorldMatrix, new Cesium.Cartesian3(0, 0, 1), new Cesium.Cartesian3)
2、先绕世界Z轴旋转局部Z轴到世界XOZ面上,再旋转到Z轴上
Cesium.Cartesian3.angleBetween
可计算两个向量间的弧度
Cesium.Cartesian3.angleBetween(arrowX, new Cesium.Cartesian3(localArrowZ.x, localArrowZ.y, 0))
即为Φ对应弧度
Cesium.Cartesian3.angleBetween(localArrowX, arrowZ)
即为θ对应弧度
Cesium.Matrix3.fromRotationX、Cesium.Matrix3.fromRotationY、Cesium.Matrix3.fromRotationZ
的旋转正方向为逆时针,传入参数为弧度
3、需要注意由于只对齐了Z轴,如需绕X轴,Y轴旋转需要做类似的处理
- let angleToXZ = Cesium.Cartesian3.angleBetween(arrowX, new Cesium.Cartesian3(localArrowZ.x, localArrowZ.y, 0))//局部Z轴在世界坐标系XY平面上投影到X轴角度,即绕Z顺时针旋转这个角度可以到XZ平面上
- let angleToZ = Cesium.Cartesian3.angleBetween(localArrowX, arrowZ)//然后绕Y轴顺时针旋转此角度可使得Z轴与世界坐标系Z轴重合
- const rotationAngleToXZ = Cesium.Matrix3.fromRotationZ(-angleToXZ);//此函数正方向为逆时针
- const rotationAngleToZ = Cesium.Matrix3.fromRotationY(-angleToZ);
- let rotationAngleToZMatrix = Cesium.Matrix3.multiply(rotationAngleToZ, rotationAngleToXZ, new Cesium.Matrix3)
- rotationAngleToZMatrix = Cesium.Matrix4.fromRotationTranslation(rotationAngleToZMatrix)
- Cesium.Matrix4.multiply(rotationAngleToZMatrix, backToEarthCenterMatrix, rotationAngleToZMatrix)//局部轴校正R1T1M0
此处完成真正需要进行的旋转,此处以绕Z轴旋转为例
- // 绕Z轴旋转
- console.log(rz - this.originRz)
- const rotationZ = Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(rz - this.originRz)); // 绕Z轴旋转变换矩阵R
- let rotationMatrix = Cesium.Matrix4.fromRotationTranslation(rotationZ)
- Cesium.Matrix4.multiply(rotationMatrix, rotationAngleToZMatrix, rotationMatrix)//RR1T1M0
将局部Z轴回到原本的指向,即刚刚旋转的角度取负值,此处需要注意变换的顺序,后进行的变换先复位
校正矩阵:Cesium.Matrix3.multiply(rotationAngleToZ, rotationAngleToXZ, new Cesium.Matrix3)
复位矩阵:Cesium.Matrix3.multiply(rotationAngleLeaveXZ, rotationAngleLeaveZ, new Cesium.Matrix3)
- // 旋转模型回到原本朝向
- const rotationAngleLeaveXZ = Cesium.Matrix3.fromRotationZ(angleToXZ);
- const rotationAngleLeaveZ = Cesium.Matrix3.fromRotationY(angleToZ);
- let rotationAngleLeaveZMatrix = Cesium.Matrix3.multiply(rotationAngleLeaveXZ, rotationAngleLeaveZ, new Cesium.Matrix3)
- rotationAngleLeaveZMatrix = Cesium.Matrix4.fromRotationTranslation(rotationAngleLeaveZMatrix)// 局部Z轴回到原本方向
- Cesium.Matrix4.multiply(rotationAngleLeaveZMatrix, rotationMatrix, rotationAngleLeaveZMatrix)//R2RR1T1M0
位移量即为模型原本的世界坐标,直接可获得变换矩阵
- //回到原来位置
- const backToOriginMatrix = Cesium.Matrix4.fromTranslation(origin);//从地心回归原位T2
- rotationModel(tileset,rz) {
-
- if(!this.checkModelLoad()){
- return
- }
- const origin = tileset.boundingSphere.center;
- console.log("初始世界坐标", origin)
- const localToWorldMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(origin);//获取到以模型中心为原点,Z轴垂直地表的局部坐标系的变换矩阵,左乘此矩阵可以将局部坐标变换为世界坐标
- const originMatrix = tileset.modelMatrix//贴地变换矩阵或者初始变换矩阵M0
- console.log("当前坐标变换矩阵", localToWorldMatrix)
- const backToEarthCenter = new Cesium.Cartesian3(-origin.x, -origin.y, -origin.z)//回到地心位移量
- let backToEarthCenterMatrix = Cesium.Matrix4.fromTranslation(backToEarthCenter);//回到地心变换矩阵
- Cesium.Matrix4.multiply(backToEarthCenterMatrix, originMatrix, backToEarthCenterMatrix)//贴地变换矩阵左乘回到地心矩阵 T1M0
- console.log("回到地心变换矩阵", backToEarthCenterMatrix)
- // 旋转
- //旋转模型使得Z轴与世界坐标Z轴重合
- let arrowX = new Cesium.Cartesian3(1, 0, 0)
- let arrowY = new Cesium.Cartesian3(0, 1, 0)
- let arrowZ = new Cesium.Cartesian3(0, 0, 1)
- let localArrowX = Cesium.Matrix4.multiplyByPoint(localToWorldMatrix, new Cesium.Cartesian3(1, 0, 0), new Cesium.Cartesian3)
- let localArrowY = Cesium.Matrix4.multiplyByPoint(localToWorldMatrix, new Cesium.Cartesian3(0, 1, 0), new Cesium.Cartesian3)
- let localArrowZ = Cesium.Matrix4.multiplyByPoint(localToWorldMatrix, new Cesium.Cartesian3(0, 0, 1), new Cesium.Cartesian3)
- let angleToXZ = Cesium.Cartesian3.angleBetween(arrowX, new Cesium.Cartesian3(localArrowZ.x, localArrowZ.y, 0))//局部Z轴在世界坐标系XY平面上投影到X轴角度,即绕Z顺时针旋转这个角度可以到XZ平面上
- let angleToZ = Cesium.Cartesian3.angleBetween(localArrowX, arrowZ)//然后绕Y轴顺时针旋转此角度可使得Z轴与世界坐标系Z轴重合
- const rotationAngleToXZ = Cesium.Matrix3.fromRotationZ(-angleToXZ);//此函数正方向为逆时针
- const rotationAngleToZ = Cesium.Matrix3.fromRotationY(-angleToZ);
- let rotationAngleToZMatrix = Cesium.Matrix3.multiply(rotationAngleToZ, rotationAngleToXZ, new Cesium.Matrix3)
- rotationAngleToZMatrix = Cesium.Matrix4.fromRotationTranslation(rotationAngleToZMatrix)
- Cesium.Matrix4.multiply(rotationAngleToZMatrix, backToEarthCenterMatrix, rotationAngleToZMatrix)//局部轴校正R1T1M0
-
-
- // 绕Z轴旋转
- console.log(rz - this.originRz)
- const rotationZ = Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(rz - this.originRz)); // 绕Z轴旋转变换矩阵R
- let rotationMatrix = Cesium.Matrix4.fromRotationTranslation(rotationZ)
- Cesium.Matrix4.multiply(rotationMatrix, rotationAngleToZMatrix, rotationMatrix)//RR1T1M0
-
- // 旋转模型回到原本朝向
- const rotationAngleLeaveXZ = Cesium.Matrix3.fromRotationZ(angleToXZ);
- const rotationAngleLeaveZ = Cesium.Matrix3.fromRotationY(angleToZ);
- let rotationAngleLeaveZMatrix = Cesium.Matrix3.multiply(rotationAngleLeaveXZ, rotationAngleLeaveZ, new Cesium.Matrix3)
- rotationAngleLeaveZMatrix = Cesium.Matrix4.fromRotationTranslation(rotationAngleLeaveZMatrix)// 局部Z轴回到原本方向
- Cesium.Matrix4.multiply(rotationAngleLeaveZMatrix, rotationMatrix, rotationAngleLeaveZMatrix)//R2RR1T1M0
-
- //回到原来位置
- const backToOriginMatrix = Cesium.Matrix4.fromTranslation(origin);//从地心回归原位T2
- // 应用变换矩阵
-
- const lastMatrix = Cesium.Matrix4.multiply(backToOriginMatrix, rotationAngleLeaveZMatrix, new Cesium.Matrix4)//最终矩阵T2R2RR1T1M0
-
- tileset.modelMatrix = lastMatrix
- console.log("结束世界坐标", tileset.boundingSphere.center)
- this.originRz = rz
-
- },
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。