吹水
threejs 学习一段时间了,之前在一直在潜水默默地学习
就在前几天实现平面上飞线效果遇到小小问题,还未解决就阳了,遗憾带阳休息了5天,发烧的两天里满脑袋都是飞线……
三阶贝塞尔曲线
关于贝塞尔曲线看这一篇就够了: 这一篇让你彻底搞懂贝塞尔曲线的原理 - 掘金 (juejin.cn) 这位大佬写得非常好。
参考过的两篇文章
Threejs模仿实现滴滴/github官网首页地球动画 - 掘金 (juejin.cn)
Threejs实现酷炫3D地球技术点汇总 - 知乎 (zhihu.com)
网上的文章基本上都是基于球体上实现的,直接拿来用肯定翻车。
代码
获取两点的中心点
const getVCenter = (v1: THREE.Vector3, v2: THREE.Vector3) => {
const v = v1.add(v2);
return v.divideScalar(2);
}
很简单的算法,两向量相加再除2
获取两向量之间的任意一向量
const getLenVector = (v1: THREE.Vector3, v2: THREE.Vector3, len: number) => {
let v1v2Len = v1.distanceTo(v2);
return v1.lerp(v2, len / v1v2Len);
}
获取两向量之间的任意一向量,具体是哪一点,由lerp的第二个参数决定,范围 0.0 ~ 1.0, 即:
- 0 = 初始点;
- 0.5 = 中间点;
- 1 = 终点;
len与两点的距离归一化为 0.0 ~ 1.0 (理论上)
根据二点生成三阶贝塞尔曲线的两点控制点
// 获取贝塞尔控制点
const getBezierPoint = (v0: THREE.Vector3, v3: THREE.Vector3) => {
// 角度
const angle = v0.angleTo(v3) * 180 / Math.PI; // 0 ~ Math.PI//
// 使用 1.2 和 10 来调整弧度
// 角度值与长度值
const aLen = angle * 1.2, hLen = angle * angle * 10;
// 两点的中心位置
const centerPoint = getVCenter(v0.clone(), v3.clone())
// 法线向量、使用中心点和向上的向量
const rayLine = new THREE.Ray(centerPoint, new THREE.Vector3(0, 1, 0));
// API 更新后,Ray类的 at 方法需要两个参数
const temp = new THREE.Vector3(0, 0, 0);
// 计算位置
const at = hLen / rayLine.at(1,temp).distanceTo(centerPoint);
// 顶点坐标
const vTop = rayLine.at(at, temp);
// 控制点坐标
const v1 = getLenVector(v0.clone(), vTop, aLen);
const v2 = getLenVector(v3.clone(), vTop, aLen);
return [v1, v2]
}
上面的 1.2 和 10 来调整弧度
球体上区别
// 射线的第一个参数(原点)为0点
// 第二个参数(法线向量)为两点的中心点
const centerPoint = getVCenter(v0.clone(), v3.clone())
const rayLine = new THREE.Ray(new THREE.Vector3(), centerPoint);
平面上的区别
// 射线的第一个参数(原点)为两点的中心点
// 第二个参数(法线向量)为向上的向量
const centerPoint = getVCenter(v0.clone(), v3.clone())
const rayLine = new THREE.Ray(centerPoint, new THREE.Vector3(0, 1, 0));
使用
const v0 = new THREE.Vector3(-126, 10, 54);
const v3 = new THREE.Vector3(226, 10, 54);
const [v1, v2] = getBezierPoint(v0, v3);
const curve2 = new THREE.CubicBezierCurve3(
v0, v1, v2, v3
);
const points = curve2.getPoints(50);
const lineGeometry2 = new THREE.BufferGeometry().setFromPoints(points);
const material2 = new THREE.LineBasicMaterial({color: new THREE.Color("#163dff")})
const curveObject = new THREE.Line(lineGeometry2, material2);
scene.add(curveObject)