Threejs变换和坐标系

530 阅读6分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第14天,点击查看活动详情

前言

这些内容主要介绍在空间中的移动对象。在学习3D 空间中移动对象是非常重要的。平时在空间中所有移动对象时,我们可以通过转换的数学运算来实现的。移动对象有三种分别是:平移对象的属性为position、旋转对象的属性为rotation、缩放对象的属性为scale。因此,这些对象属性构成了我们将用来在3D空间中移动对象的三个基本对象属性。

平移、旋转和缩放

(1)平移:position属性

采用相机的位置属性,向Z沿移为10,也可以是用立方体和灯光的位置属性。

camera.position.set(0,0,10) 
//== 等价于
camera.position.x=0;
camera.position.y=0; 
camera.position.z=10;

(2)旋转:rotation属性

在3D空间中通过任何物体或者采用立方体的旋转属性。

cube.rotation.x=20 //向x逆时为20 
cube.rotation.y=-30 //向y顺时为30

(3)缩放:scale属性

在3D空间中通过任何物体的缩放属性。

cube.scale.x=1.25 //向x缩长0.25

世界空间

我们在3D空间中定义了世界空间坐标系,系统的中心是X、Y和Z轴相交的点。

微信截图_20221230151442.png

比如说用position位置属性:
当你移动对象的时:
X轴正值就是把这个对象移动到屏幕右侧。

Y轴正值就是把这个对象向上移动到屏幕顶部。

Z轴正值就是把这个对象出对你的画面。

相反:

X轴负值就是把这个对象移动到屏幕左侧。

Y轴负值就是把这个对象向下移动到屏幕底部。

Z轴负值就是把这个对象出对你的画面,对象越小,该这个对象离你而去。

position和scale可以存储在Vector3类

(1)position存储在Vector3类

我们可以Vector3自己创建实例:

import {Vector3} from 'three'; 
const vector = new Vector3(1,2,3); 
//== 等价于
vector.x; //1 
vector.y; //2 
vector.z; //3

可以直接访问和更新三个.x,.y,.z属性,或者可以.set一次更新三个属性:

//可以直接访问和更新.x属性 
vector.x = 5; 
vector.x; //5 
//更新.set的三个属性 
vector.set(7,7,7); 
vector.x; //7 
vector.y; //7 
vector.z; //7

(2)scale存储在Vector3类

//当创建一个网格 
const mesh = new Mesh(); 
//three.js为我们创建了一个Vector3: 
mesh.scale = new Vector3(1, 1, 1);

注:scale是不支持相机和灯光的缩放,只有可以用网格或立方体的对象

rotation可以存储在Euler类

其实上和.position及.scale属性存储在Vector3类很类似

我们可以用euler创建实例:

import {Euler} from 'three'; 
const euler = new Euler(1, 2, 3); 
// == 等价于
euler.x; // 1
euler.y; // 2 
euler.z; // 3

旋转单位是弧度

在ThreeJS所有其他角度都是使用弧度而不是度数指定的。也就是说代替90度在一个直角,有π/2弧度。

import { MathUtils } from 'three'; 
const rads = MathUtils.degToRad(90); //1.57079... = π/2

其他旋转类:四元数

和euler类的存储很类似,四元数为Quaternion,但是这两个类还是有区别。

//创建一个网格 
const mesh = new Mesh(); 
//... three.js为我们创建一个Euler: 
mesh.rotation = new Euler(); 
// ... 和一个Quaternion: 
mesh.quaternion = new Quaternion();

我们可以互换使用.Quaternion和.Euler,但是.Euler类还是有几个缺点,进行涉及到旋转的数学运算时会变得很明显,尤其是,不能把两个.Euler相加的,而.Quaternion没有这些缺点,但是比.Euler还是难使用的,所以我们一般用.Euler就可以了。

有两种旋转对象的方法:

1.使用欧拉角,使用Euler类表示并存储在.rotation属性中。

2.使用四元数,使用Quaternion类表示并存储在.quaternion属性中。

练习:

简单题

微信截图_20221230152501.png

1.实验展开针对立方体的模块cube.position、cube.scale及cube.rotation

1.1cube.position

/ 平移.position属性   
cube.position.x = 2; 
cube.position.y = 0.1; 
cube.position.z = -0.5; 
// =>  等价于
// cube.position.set(2,0.1,-0.5);

x轴平移向右的值为2个单位;

y轴平移向上的值为0.1个单位;

z轴平移向画面离的值为0.5个单位;

效果图:

微信截图_20221230152648.png

1.2cube.scale

// 缩放.scale属性  
cube.scale.x = 1.5;  
cube.scale.y = 0.6; 
cube.scale.z = 0.3;
// =>  等价于
// cube.scale.set(1.5,0.6,0.3);

X轴缩长了0.5个单位;

Y轴缩小了0.4个单位;

Z轴缩小了0.7个单位;

另外,其实scale.set(1,1,1)就是默认的缩放初始比例

cube.scale.set(1,1,1);

效果图:

微信截图_20221230152811.png

1.3cube.rotation

// 旋转.rotation属性  
cube.rotation.x = MathUtils.degToRad(-40);  
cube.rotation.y = MathUtils.degToRad(-45);  
cube.rotation.z = MathUtils.degToRad(60);

x轴旋转的顺时为40°,顺时就是-,逆时+

y轴旋转的顺时为45°,顺时就是-,逆时+

z轴旋转的逆时为60°,顺时就是-,逆时+

效果图:

微信截图_20221230152917.png

2.实验展开针对灯光的模块light.position

// 把灯向上的值为10   
light.position.set(0100);

把灯光向上的值为10个单位

效果图:

微信截图_20221230153003.png

3.实验展开针对相机的模块camera.position

// 定位相机=相机位置 
camera.position.set(115);

x轴平移向右的值为1个单位

y轴平移向上的值为1个单位

z轴面向屏幕离的值为5个单位

效果图:

微信截图_20221230153045.png

中度题

微信截图_20221230153116.png

1.创建名为第二个网格的cubes

创建了新第二个网格的圆球和材质颜色为绿色

// 创建第二个网格的圆球  
const geometrys = new SphereGeometry(12525); 
const materials = new MeshStandardMaterial({ color'green', }); const cubes = new Mesh(geometrys, materials);

最后,添加第二个网格为第一个网格的子类

cube.add(cubes);

效果图:

微信截图_20221230153236.png

2.两个网格的平移.position属性:两个网格的叠加

// 平移.position属性  
cube.position.set(211); 
cubes.position.set(111);

站在世界空间坐标的角度,父级的X轴移动为2个单位,子级的X轴移动为1个单位,最终子级为X轴移动3个单位。

效果图:

微信截图_20221230153321.png

3.两个网格的旋转.rotation属性:两个网格的叠加

// 旋转.rotation属性  
cube.rotation.x = MathUtils.degToRad(-30);   
cubes.rotation.x = MathUtils.degToRad(-30);

首先父级X轴的旋转为-30°,而子级X轴的旋转为-30°,最终子级为X轴的旋转为-60°

效果图:

微信截图_20221230153411.png

4.两个网格的比例.scale属性:两个网格的乘法

// 缩放.scale属性 
cube.scale.set(211);  
cubes.scale.set(311);

父级网格X轴的缩放为2个单位,而子级网格X轴的缩放为3个单位,那么子级网格X轴的缩放为6个单位,也就是说子级网格X轴的增长到初始大小物体的6倍。

效果图:

微信截图_20221230153552.png

困难题

微信截图_20221230153610.png

1.如果你熟悉弧度,请尝试在没有.degToRad方法的情况下。

//在没有使用degToRad方法的情况下 
cube.rotation.x = Math.PI / 6;

比如Math.PI就是180°,也就是说180°除以6=30°,或者Math.PI/2,就是180°除以2=90°。 效果图:

微信截图_20221230153649.png