源码
flyTo(object, gltfthis) {
if (object === undefined || object === null) {
return;
}
const box3 = new THREE.Box3();
box3.expandByObject(object); // 计算模型包围盒
const size = new THREE.Vector3();
box3.getSize(size); // 计算包围盒尺寸
const center = new THREE.Vector3();
box3.getCenter(center); // 计算一个层级模型对应包围盒的几何体中心坐标
function maxSize(vec3) {
let max;
if (vec3.x > vec3.y) {
max = vec3.x;
} else {
max = vec3.y;
}
if (max < vec3.z) {
max = vec3.z;
}
return max;
}
const max = maxSize(size); // 包围盒长宽高中最大的一个值,用来表征模型的尺寸
var tmp = center.clone().addScalar(max);
var newPos = new THREE.Vector3(tmp.x, tmp.y, tmp.z);
newPos.y = newPos.y + 3.0;
newPos.z = newPos.z + 2.0;
var targetPos = new THREE.Vector3(center.x, center.y, center.z);
targetPos.y = targetPos.y + 1;
let tis = this;
if (object.type == "Group") {
tis = gltfthis;
}
tis.animateCameraFun(
tis.camera.position,
tis.controls.target,
newPos,
targetPos,
2000
);
},
-
参数检查与初始化:
- 首先检查传入的
object
是否为undefined
或null
,如果是则直接返回,不执行后续的操作。
- 首先检查传入的
-
计算包围盒和尺寸:
- 使用
THREE.Box3
来计算传入对象object
的包围盒 (box3
)。 - 通过
box3.getSize(size)
获取包围盒的尺寸size
。 - 使用
box3.getCenter(center)
获取包围盒的中心坐标center
。
- 使用
-
计算模型尺寸的最大值:
- 定义了一个函数
maxSize(vec3)
,用来返回三维向量vec3
中的最大值,即包围盒尺寸的长、宽、高中的最大值。
- 定义了一个函数
-
计算新的相机位置 (
newPos
) 和目标位置 (targetPos
):- 计算出最大尺寸
max
,然后基于包围盒的中心center
和最大尺寸max
计算出新的相机位置newPos
,稍微偏移了一定的距离(y
轴上+3.0,z
轴上+2.0)。 - 计算目标位置
targetPos
,也稍作偏移(y
轴上+1)。
- 计算出最大尺寸
-
动态设置
tis
对象:- 根据传入的
object
的类型,动态选择tis
对象。如果object.type
是"Group"
,则将tis
设置为gltfthis
,否则保持原先的this
。 - 如果是创建mesh不需要这部,因为我gitf模型的处理是用回调去处理添加的gltb模型。so需要手动传入this。
- 根据传入的
-
调用相机动画函数:
- 最后调用
tis.animateCameraFun()
方法,传入相机位置 (tis.camera.position
)、控制器的目标位置 (tis.controls.target
)、新的相机位置 (newPos
)、目标位置 (targetPos
),以及动画持续的时间(2000毫秒)。
- 最后调用
动画源码
/**
*
* @param {*} oldPos 原来相机位置
* @param {*} oldTarget 原来controls
* @param {*} newPos new相机位置
* @param {*} newTarget new controls
* @param {*} time
*/
animateCameraFun(oldPos, oldTarget, newPos, newTarget, time) {
const that = this;
if (time === undefined || time === null) {
time = 1000;
}
// 使用tween动画
var tween = new TWEEN.Tween({
x1: oldPos.x, // 相机x
y1: oldPos.y, // 相机y
z1: oldPos.z, // 相机z
x2: oldTarget.x, // 控制点的中心点x
y2: oldTarget.y, // 控制点的中心点y
z2: oldTarget.z, // 控制点的中心点z
});
tween.to(
{
x1: newPos.x,
y1: newPos.y,
z1: newPos.z,
x2: newTarget.x,
y2: newTarget.y,
z2: newTarget.z,
},
time
);
tween.easing(TWEEN.Easing.Cubic.InOut);
tween.onUpdate(function (pos) {
// that.renderScene2();
that.camera.position.x = pos.x1;
that.camera.position.y = pos.y1;
that.camera.position.z = pos.z1;
that.controls.target.x = pos.x2;
that.controls.target.y = pos.y2;
that.controls.target.z = pos.z2;
that.camera.updateProjectionMatrix(); // 渲染范围改变,注意更新投影矩阵
that.controls.update();
});
tween.onComplete(function () {
that.controls.update();
});
// 开始动画
tween.start();
},
函数定义:animateCameraFun
是一个函数,接受旧的相机位置 (oldPos
) 和目标点 (oldTarget
),以及新的相机位置 (newPos
) 和目标点 (newTarget
),还有一个可选的动画时间参数 (time
)。
Tween 动画设置:使用 tween.js
库创建动画效果,实现平滑过渡。
这里创建了一个 Tween 对象,定义了初始状态(旧的相机位置和目标点)和最终状态(新的相机位置和目标点),以及动画的时间参数。
Tween 设置目标:通过 tween.to()
方法设置 Tween 的目标状态和动画时间。
缓动函数:使用 tween.easing()
方法设置缓动函数,这里使用了 TWEEN.Easing.Cubic.InOut
,表示缓入缓出的三次方缓动效果。
Tween 更新和完成时的操作:
tween.onUpdate()
方法在 Tween 更新时执行,更新相机和控制器的位置和目标点,并更新投影矩阵。tween.onComplete()
方法在 Tween 完成时执行,确保最后一次更新控制器的状态。
启动动画:最后调用 tween.start()
开始动画效果。
关键的地方:在render循环里面记得加 TWEEN.update();
???????????????????