矩阵变换基础知识补充:

矩阵变换是图形学中的知识,在Cesium开发中理解它的概念和实践也同样重要。学会了矩阵变换可以轻松完成对模型的平移、旋转、缩放操作;感兴趣的同学可移步games101B站视频课补充相关知识;

1.平移、旋转、缩放都可以在线性代数中用一个变换矩阵表示;

2.对一个图形进行变换,只需要将图形的每一个坐标点左乘一个变换矩阵,即可计算出这个图形变换后的每一个新坐标点;

3.矩阵的乘法运算不符合交换律,左乘和右乘结果不一样;

实现思路:

模型平移:

假设在三维空间中有一个模型,可以建立一个三维空间坐标系来描述模型的位置,对模型实现平移操作只需要对模型的x,y,z坐标进行加减即可;但是在Cesium中,默认三维坐标系是以球心为原点的ENU坐标,使用此坐标直接进行模型平移运算较为困难,我们还需要建立一个以模型中心为原点的局部ENU坐标,以简化对模型的坐标计算。

模型旋转、缩放:

对模型旋转和缩放原理与平移差不多,但需要注意应用一个旋转、缩放矩阵时,需要将旋转、缩放参考点先平移到坐标原点;

关键源码封装:

!未考虑执行效率,有精力可继续优化;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// 修改3DTiles的位置
export function update3dtiles(tileSet: Cesium.Cesium3DTileset, options: any) {
const { tx = 0, ty = 0, tz = 0, rx = 0, ry = 0, rz = 0, scale = 1,sx =1,sy =1,sz =1 } = options
console.log(tx,ty,tz,rx,ry,rz,scale,'模型变换参数')
const center = tileSet.boundingSphere.center

//定义以模型中心为原点的局部坐标转换
const m = Cesium.Transforms.eastNorthUpToFixedFrame(center)

//构建平移向量
const tempTranslation = new Cesium.Cartesian3(tx, ty, tz)

//平移向量转换到世界坐标;
const offset = Cesium.Matrix4.multiplyByPoint(
m,
tempTranslation,
new Cesium.Cartesian3(0, 0, 0)
)

//计算世界坐标下的平移向量
const translation = Cesium.Cartesian3.subtract(
offset,
center,
new Cesium.Cartesian3()
)
//平移向量应用到模型
tileSet.modelMatrix = Cesium.Matrix4.multiply(
Cesium.Matrix4.fromTranslation(translation),
tileSet.modelMatrix,
new Cesium.Matrix4()
)

//旋转及缩放
if (rx || ry || rz || scale) {
//保存原始位置
const initialCenter = Cesium.Cartesian3.clone(tileSet.boundingSphere.center)

// 构建模型平移到原点矩阵
const translationMatrix = Cesium.Matrix4.fromTranslation(
Cesium.Cartesian3.negate(
tileSet.boundingSphere.center,
new Cesium.Cartesian3()
)
)

// 定义旋转角度(单位:弧度)
const radiansX = Cesium.Math.toRadians(rx)
const radiansY = Cesium.Math.toRadians(ry)
const radiansZ = Cesium.Math.toRadians(rz)

// 创建旋转矩阵
const rotationX = Cesium.Matrix3.fromRotationX(radiansX)
const rotationY = Cesium.Matrix3.fromRotationY(radiansY)
const rotationZ = Cesium.Matrix3.fromRotationZ(radiansZ)

// 组合旋转矩阵
const combinedRotation = Cesium.Matrix3.multiply(
rotationX,
rotationY,
new Cesium.Matrix3()
)
Cesium.Matrix3.multiply(combinedRotation, rotationZ, combinedRotation)

// 将 3x3 旋转矩阵转换为 4x4 矩阵
const rotationMatrix4 = Cesium.Matrix4.fromRotation(combinedRotation)

//构建缩放矩阵
let scaleTempParam = new Cesium.Cartesian3(scale, scale, scale)
if(sx!=1 || sy!=1 || sz!=1){
scaleTempParam = new Cesium.Cartesian3(sx, sy, sz)
}
const scaleMatrix4 = Cesium.Matrix4.fromScale(
scaleTempParam,
new Cesium.Matrix4()
)

//构建平移复位矩阵
const translationBack = Cesium.Matrix4.fromTranslation(initialCenter)

//组合矩阵
let tempMatrix = tileSet.modelMatrix
//1.应用移到原点
tempMatrix = Cesium.Matrix4.multiply(
translationMatrix,
tempMatrix,
new Cesium.Matrix4()
)
//2.应用旋转矩阵
tempMatrix = Cesium.Matrix4.multiply(
rotationMatrix4,
tempMatrix,
new Cesium.Matrix4()
)
//3.应用缩放矩阵
tempMatrix = Cesium.Matrix4.multiply(
scaleMatrix4,
tempMatrix,
new Cesium.Matrix4()
)
//4.应用复位矩阵
tempMatrix = Cesium.Matrix4.multiply(
translationBack,
tempMatrix,
new Cesium.Matrix4()
)
tileSet.modelMatrix = tempMatrix
}

return tileSet
}

使用示例:

1
2
//对一个3dtileset沿x轴平移100,沿z轴平移200,绕z轴旋转10度
update3dtiles(3dtileset, {tx:100,tz:200, rz: 10 })

效果展示:

参考链接:

岭南灯火大佬的文章,写的很好讲的深入浅出,配了很多图片:https://www.cnblogs.com/onsummer/p/14059220.html