three.js线转面
项目中有遇到这个问题,在这里记录一下
threejs没有提供类似函数,可以使用第三方库 three-line-2d
,three.meshline
。这库怎么使用我也没试过,后来才找到的。当时使用自己的方法处理了, 怎么使用可以看npm官网。
https://www.npmjs.com/package/three-line-2d
https://www.npmjs.com/package/three.meshline
线转面,只需要计算出线上的点在扩散后的位置即可,每个点会生成2个点,再将点连起来形成Shape。
只是简单处理了一下,不能拐弯处实现圆滑效果,直接上代码。
/**
* 线拉伸成平面
* @param { {x: number, y: number}[] } points 点
* @param { number } radius 拉伸半径(宽度)
* @returns { THREE.Vector2[] }
*/
export function createShapeFromPoints(points, radius = 1) {
let left = [];
let right = [];
for (let i = 0, len = points.length; i < len; i++) {
let prev = points[i - 1] || {};
let curr = points[i];
let next = points[i + 1] || {};
let v1 = [curr.x - prev.x, curr.y - prev.y];
let v2 = [next.x - curr.x, next.y - curr.y];
if (!prev.x && prev.x !== 0) {
v1 = [...v2];
} else if (!next.x && next.x !== 0) {
v2 = [...v1];
}
let modelV1 = Math.sqrt(v1[0] ** 2 + v1[1] ** 2);
let modelV2 = Math.sqrt(v2[0] ** 2 + v2[1] ** 2);
// 单位向量
v1 = [v1[0] / modelV1, v1[1] / modelV1];
v2 = [v2[0] / modelV2, v2[1] / modelV2];
// 方向和的单位向量
let vector = [v1[0] + v2[0], v1[1] + v2[1]];
let modelVector = Math.sqrt(vector[0] ** 2 + vector[1] ** 2);
vector = [vector[0] / modelVector, vector[1] / modelVector];
// 扩散点的方向和转角处的角度偏移
let Lvector = rotateVector(vector, -Math.PI / 2);
let Rvector = rotateVector(vector, Math.PI / 2);
let deflection = vectorAngleCosHalf(v1, v2);
left.push(
new THREE.Vector2(
curr.x + Lvector[0] * (radius / deflection),
curr.y + Lvector[1] * (radius / deflection)
)
);
right.unshift(
new THREE.Vector2(
curr.x + Rvector[0] * (radius / deflection),
curr.y + Rvector[1] * (radius / deflection)
)
);
prev = curr;
}
return left.concat(right);
}
/**
* 向量夹角的cos值
* @param { [number, number] } a
* @param { [number, number] } b
* @returns
*/
export function vectorAngleCos(a, b) {
return (
(a[0] * b[0] + a[1] * b[1]) /
(Math.sqrt(a[0] ** 2 + a[1] ** 2) * Math.sqrt(b[0] ** 2 + b[1] ** 2))
);
}
/**
* 向量夹角的一半的cos值
* @param { [number, number] } a
* @param { [number, number] } b
* @returns
*/
export function vectorAngleCosHalf(a, b) {
return Math.sqrt((1 + vectorAngleCos(a, b)) / 2);
}
/**
* 将点绕原点旋转
* @param { [number, number] } param0
* @param { number } angle
* @returns { [number, number] }
*/
export function rotateVector([x1, y1], angle) {
let x2 = x1 * Math.cos(angle) - y1 * Math.sin(angle);
let y2 = y1 * Math.cos(angle) + x1 * Math.sin(angle);
return [x2, y2];
}
使用
let line = [
{ x: 0, y: 0 },
{ x: 20, y: 40 },
{ x: 40, y: 10 },
{ x: 100, y: 100 },
];
let points = createShapeFromPoints(line, 2);
let shape = new THREE.Shape(points);
let geometry = new THREE.ShapeGeometry(shape);
let material = new THREE.LineBasicMaterial({
color: 0x7d5fff,
transparent: true,
opacity: 0.9,
});
let line = new THREE.Mesh(geometry, material);
ok, 这样就得到line的Mesh了。
蓝色为原来的线,黑色是计算后的到的多边形points