1-用位移矩阵做实验
1-1-示例
已知:
-
宇宙universe
-
宇宙的本地坐标系是[O1;i1,j1,k1]
- O1(0,0,0)
- i1(1,0,0)
- j1(0,1,0)
- k1(0,0,1)
-
宇宙包含万物,其本地坐标系就是万物的世界坐标系
-
银河系galaxy
-
银河系的本地坐标系是[O2;i2,j2,k2]
- O2(1,2,3)
- i2(1,0,0)
- j2(0,1,0)
- k2(0,0,1)
-
太阳sun
-
太阳在银河系内的本地坐标位是P2(4,5,6)
-
太阳∈银河系∈宇宙
求:太阳的世界位P1
解:
由宇宙坐标系[O1;i1,j1,k1]解矩阵m1:
[ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]
由银河系[O2;i2,j2,k2]解矩阵m2:
[ 1,0,0,0, 0,1,0,0, 0,0,1,0, 1,2,3,1]
点P的世界坐标位是:
P1=m1*m2*(4,5,6)
P1=(1+4,2+5,3+6)
P1=(5,7,9)
接下来我们拿three.js验证一下
1-2-验证
1.从three.js 中引入我们要用到的方法
import { Group, Matrix4, Object3D,Scene, Vector3, } from 'https://unpkg.com/three/build/three.module.js';
2.基于世界坐标系和本地坐标系构建矩阵
//世界坐标系-宇宙
const m1 = new Matrix4()
m1.elements = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
]
//本地坐标系-银河系
const m2 = new Matrix4()
m2.elements = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
1, 2, 3, 1
]
3.声明太阳在银河系内本地坐标P2
//本地坐标位-太阳
const P2 = new Vector3(4, 5, 6)
4.创造一个宇宙
const universe = new Scene()
universe.applyMatrix4(m1)
applyMatrix4() 通过四维矩阵赋予对象坐标系
5.同理,创造银河系
//银河系
const galaxy = new Group()
galaxy.applyMatrix4(m2)
6.创造太阳
const sun = new Object3D()
sun.position.copy(P2)
太阳的position属性便是其在银河系中的相对位
7.宇宙、银河系和太阳的包含关系:太阳∈银河系∈宇宙
galaxy.add(sun)
universe.add(galaxy)
8.计算太阳的在宇宙中的世界位
const P1 = new Vector3()
sun.getWorldPosition(P1)
console.log(P1);
//{x:5,y:7,z:9}
这个结果和我们之前推理的是一样的。
接下来咱们借此深度探究一下位移的法则。
2-位移法则
如果我们不想求太阳的位置,而是想求太阳系内的地球的位置,那是否还可以按照我们之前的思路来求解?
答案是肯定的。
2-1-示例
调整一下之前的已知条件。
-
把太阳改成太阳系solar
-
太阳系的本地坐标系是[O3;i3,j3,k3]
- O3(4,5,6)
- i3(1,0,0)
- j3(0,1,0)
- k3(0,0,1)
-
地球earth
-
地球在太阳系内的本地坐标位是P3(7,8,9)
-
地球∈太阳系∈银河系∈宇宙
求:地球的世界坐标位P1
解:
由太阳系的本地坐标系可得矩阵m3:
[ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 4, 5, 6, 1]
求地球的世界坐标位P1:
P1=m1*m2*m3*(7,8,9)
P1=(1+4+7,2+5+8,3+6+9)
P1=(12,15,18)
2-2-验证
按照之前的原理用three.js验证一番:
import { Group, Matrix4, Object3D, Scene, Vector3, } from 'https://unpkg.com/three/build/three.module.js';
//世界坐标系-宇宙
const m1 = new Matrix4()
m1.elements = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
]
//本地坐标系-银河系
const m2 = new Matrix4()
m2.elements = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
1, 2, 3, 1
]
//本地坐标系-太阳系
const m3 = new Matrix4()
m3.elements = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
4, 5, 6, 1
]
//本地坐标位-地球
const P3 = new Vector3(7, 8, 9)
//宇宙(世界坐标系是宇宙的本地坐标系)
const universe = new Scene()
universe.applyMatrix4(m1)
console.log(universe.position)
console.log(universe.matrix)
//银河系
const galaxy = new Group()
galaxy.applyMatrix4(m2)
//太阳系
const solar = new Group()
solar.applyMatrix4(m3)
//地球
const earth = new Object3D()
earth.position.copy(P3)
//包含关系
solar.add(earth)
galaxy.add(solar)
universe.add(galaxy)
//点P的世界位
const P1 = new Vector3()
earth.getWorldPosition(P1)
console.log(P1);
//{x: 12, y: 15, z: 18}
2-3-推理
我们可以从上面的结论中得到一个规律:
当一点P和宇宙之间存在n层嵌套
点P的本地坐标位是Pn
第n层世界的本地坐标系所对应的矩阵是mn
则点P的世界位P1是:
P1=m1*m2*……*mn*pn
上面的公式,我们就暂且叫它“本地坐标转世界坐标公式”了,我不知其有没有学名,就先这么叫着了。
接下来,我们再思考一个问题。
之前我们对所有坐标系只是进行了位移操作,那如果我们对其做了缩放和旋转操作,上式是否成立呢?
3-缩放法则
3-1-示例
修改之前已知条件:
-
在银河系的本地坐标系[O2;i2,j2,k2]中,让j2是单位向量的2倍:
- O2(1,2,3)
- i2(1,0,0)
- j2(0,2,0)
- k2(0,0,1)
-
在太阳系的本地坐标系[O3;i3,j3,k3],让k3是单位向量的3倍:
- O3(4,5,6)
- i3(1,0,0)
- j3(0,1,0)
- k3(0,0,3)
求:地球的世界坐标位P1
解:
由银河系的本地坐标系可得矩阵m2:
[ 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 1, 2, 3, 1]
由太阳系的本地坐标系可得矩阵m3:
[ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 3, 0, 4, 5, 6, 1]
求地球的世界坐标位P1:
P1=m1*m2*m3*(7,8,9)
m1*m2*m3=[
1, 0, 0, 0,
0, 2, 0, 0
0, 0, 3, 0
4+1,2*5+2,6+3,1
]
m1*m2*m3=[
1,0, 0,0,
0,2, 0,0,
0,0, 3,0,
5,12,9,1
]
P1=(7+5,16+12,27+9)
P1=(12,28,36)
3-2-测试
基于“位移法则”的three.js代码改改:
//本地坐标系-银河系
const m2 = new Matrix4()
m2.elements = [
1, 0, 0, 0,
0, 2, 0, 0,
0, 0, 1, 0,
1, 2, 3, 1
]
//本地坐标系-太阳系
const m3 = new Matrix4()
m3.elements = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 3, 0,
4, 5, 6, 1
]
运行代码,可得到和我们刚才计算的一样的结果。
由此可见,当坐标系发生缩放时,本地坐标转世界坐标公式依旧成立
接下咱们再说旋转。
4-旋转法则
4-1-示例
修改之前已知条件:
-
让银河系的本地坐标系[O2;i2,j2,k2]绕j2轴逆时针旋转20°。
设:c2=cos(-20°),s2=sin(-20°)
则:
- O2(1,2,3)
- i2(c2,0,-s2)
- j2(0,1,0)
- k2(s2,0,c2)
-
让太阳系的本地坐标系[O3;i3,j3,k3]绕k3轴逆时针旋转30°
设:c3=cos(30°),s3=sin(30°)
则:
- O3(4,5,6)
- i3(c3,-s3,0)
- j3(s3,c3,0)
- k3(0,0,1)
求:地球的世界坐标位P1
解:
由银河系的本地坐标系可得矩阵m2:
[ c2, 0, s2, 0, 0, 1, 0, 0, -s2,0, c2, 0, 1, 2, 3, 1]
由太阳系的本地坐标系可得矩阵m3:
[ c3, s3, 0, 0, -s3, c3, 0, 0, 0, 0, 1, 0, 4, 5, 6, 1]
求地球的世界坐标位P1:
P1=m1*m2*m3*(7,8,9)
m1*m2*m3=[
c2*c3, s3, s2*c3, 0,
-c2*s3, c3, -s2*s3, 0,
-s2, 0, c2, 0,
c2*4-s2*6+1,5+2,s2*4+c2*6+3,1
]
P1=(11.826885919330648,17.428203230275507,15.02200238270646)
注,上式很难像之前那样心算,可以直接用计算机算:
//让银河系的本地坐标系[O2;i2,j2,k2]绕j2轴逆时针旋转20°
const ang2 = -20 * Math.PI / 180
const c2 = Math.cos(ang2)
const s2 = Math.sin(ang2)
//让太阳系的本地坐标系[O3;i3,j3,k3]绕k3轴逆时针旋转30°
const ang3 = 30 * Math.PI / 180
const c3 = Math.cos(ang3)
const s3 = Math.sin(ang3)
const m=new Matrix4()
m.elements = [
c2 * c3, s3, s2 * c3, 0,
-c2 * s3, c3, -s2 * s3, 0,
-s2, 0, c2, 0,
c2 * 4 - s2 * 6 + 1, 5 + 2, s2 * 4 + c2 * 6 + 3, 1
]
const P1 = P3.applyMatrix4(m)
console.log(P1);
4-2-验证
基于“位移法则”的three.js代码改改:
//本地坐标系-银河系
const ang2 = 20 * Math.PI / 180
const m2 = new Matrix4()
m2.makeRotationY(ang2)
m2.setPosition(1, 2, 3)
//本地坐标系-太阳系
const ang3 = 30 * Math.PI / 180
const m3 = new Matrix4()
m3.makeRotationZ(ang3)
m3.setPosition(4, 5, 6)
运行代码,可得到和我们刚才计算的一样的结果。
由此可见,当坐标系发生旋转时,本地坐标转世界坐标公式依旧成立
然而,细心的同学可能会发现一个问题:
我在旋转矩阵的时候,只是在让矩阵绕xyz轴的某一个坐标向量进行旋转。
那我能不能让矩阵绕任意向量旋转呢?
亦或者,能不能先绕x旋转angX度,再绕y轴旋转angY度?
这肯定是可以的,接下来我们就对旋转法则进行深度探索。