👏
three.jsで太い線を描画する実験
three.jsで線を描画する場合はTHREE.Line
とTHREE.LineBasicMaterial
を使いますが、linewidth
を指定しても太さが変わりません。
代わりとなるTHREE.MeshLineはメンテされてないみたいです。
ではどうすれば良いかと調べた所、THREE.TubeGeometry
が良さそうなので試してみました。
コードは以下の感じです。
const vertexList = [
-1, 0, 0,
1, 0.5, 0
];
// 通常の線
const lineGeometry = new THREE.BufferGeometry();
const positions = new Float32Array(vertexList);
lineGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
const lineMaterial = new THREE.LineBasicMaterial({ color: 0x0000ff, linewidth: 1 });
const line = new THREE.Line(lineGeometry, lineMaterial);
line.position.set(0, 0, 0.6);
scene.add(line);
// TubeGeometryの線
const tubularSegments = 2;
// 線の太さ
const radius = 0.02;
const radialSegments = 10;
const points: THREE.Vector3[] = [];
for (let i = 0; i < vertexList.length; i += 3) {
points.push(new THREE.Vector3(vertexList[i], vertexList[i + 1], vertexList[i + 2]));
}
const path = new THREE.CatmullRomCurve3(points, true);
const geometry = new THREE.TubeGeometry(path, tubularSegments, radius, radialSegments);
const material = new THREE.MeshBasicMaterial({ color: 0xff0000, side: THREE.DoubleSide });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
青線:THREE.Line、赤線:THREE.TubeGeometry
デメリットは頂点数が増える事ですね。このコード例だと頂点数は99でした。
あとTransformControlsなどで移動した線の始点と終点の座標は以下で取れます。
const tubeGeometry = mesh.geometry as THREE.TubeGeometry;
console.log(tubeGeometry.parameters.path.getPoints(2));
// [{x: -1, y: 0, z: 0}, {x: 1, y: 0.5, z: 0}, {x: -1, y: 0, z: 0}]
// またはtubeGeometry.parameters.path.toJSON()
ただ、このコードだと始点と終点の2点のみの直線の場合しか使えません。
使い勝手が微妙なので以下のようにTHREE.Line
をpositionずらしで複数描画もありかも。
const vertices = new Float32Array([-1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, -1, 0, 1]);
// 通常の線
const sampleGeometry = new THREE.BufferGeometry();
sampleGeometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
const sampleLine = new THREE.LineSegments(sampleGeometry, new THREE.LineBasicMaterial({ color: 0x0000ff }));
sampleLine.position.z = 1.2;
scene.add(sampleLine);
// 太らせる線
const parentGeometry = new THREE.BufferGeometry();
parentGeometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
const parentLine = new THREE.LineSegments(parentGeometry, new THREE.LineBasicMaterial({ color: 0xff0000 }));
scene.add(parentLine);
// FIXME: この値は自分の環境に合わせて調整する
const positions = [0.001, 0.002, 0.003, -0.001, -0.002, -0.003];
for (let i = 0; i < positions.length; i++) {
const childLine = parentLine.clone();
childLine.position.set(positions[i], positions[i], positions[i]);
parentLine.add(childLine);
}
2024/04/09追記
three.js exampleのlines_fatがありました。LineMaterial
で太くできます。
positionについては、以下の頂点を持ってました(どのような線でも変わらない値?)
positionからは始点・終点の座標が取れなさそうですが、instanceStartの方なら取れそうです。
Discussion