开启掘金成长之旅!这是我参与「掘金日新计划 · 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轴相交的点。
比如说用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属性中。
练习:
简单题
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个单位;
效果图:
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);
效果图:
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°,顺时就是-,逆时+
效果图:
2.实验展开针对灯光的模块light.position
// 把灯向上的值为10
light.position.set(0, 10, 0);
把灯光向上的值为10个单位
效果图:
3.实验展开针对相机的模块camera.position
// 定位相机=相机位置
camera.position.set(1, 1, 5);
x轴平移向右的值为1个单位
y轴平移向上的值为1个单位
z轴面向屏幕离的值为5个单位
效果图:
中度题
1.创建名为第二个网格的cubes
创建了新第二个网格的圆球和材质颜色为绿色
// 创建第二个网格的圆球
const geometrys = new SphereGeometry(1, 25, 25);
const materials = new MeshStandardMaterial({ color: 'green', }); const cubes = new Mesh(geometrys, materials);
最后,添加第二个网格为第一个网格的子类
cube.add(cubes);
效果图:
2.两个网格的平移.position属性:两个网格的叠加
// 平移.position属性
cube.position.set(2, 1, 1);
cubes.position.set(1, 1, 1);
站在世界空间坐标的角度,父级的X轴移动为2个单位,子级的X轴移动为1个单位,最终子级为X轴移动3个单位。
效果图:
3.两个网格的旋转.rotation属性:两个网格的叠加
// 旋转.rotation属性
cube.rotation.x = MathUtils.degToRad(-30);
cubes.rotation.x = MathUtils.degToRad(-30);
首先父级X轴的旋转为-30°,而子级X轴的旋转为-30°,最终子级为X轴的旋转为-60°
效果图:
4.两个网格的比例.scale属性:两个网格的乘法
// 缩放.scale属性
cube.scale.set(2, 1, 1);
cubes.scale.set(3, 1, 1);
父级网格X轴的缩放为2个单位,而子级网格X轴的缩放为3个单位,那么子级网格X轴的缩放为6个单位,也就是说子级网格X轴的增长到初始大小物体的6倍。
效果图:
困难题
1.如果你熟悉弧度,请尝试在没有.degToRad方法的情况下。
//在没有使用degToRad方法的情况下
cube.rotation.x = Math.PI / 6;
比如Math.PI就是180°,也就是说180°除以6=30°,或者Math.PI/2,就是180°除以2=90°。 效果图: