three.js中Meshline的使用
- 库的地址
- 为什么要使用MeshLine,three.js内置的线不好用吗?
- MeshLine入门
- MeshLine的深入思考
- 样条曲线
- 一个问题
库的地址
https://github.com/spite/THREE.MeshLine?tab=readme-ov-file
为什么要使用MeshLine,three.js内置的线不好用吗?
确实不好用,比如three.js内置的线无法设置粗细,MeshLine就可以
MeshLine入门
- 先安装库文件
npm i three.meshline
- 然后再demo中引入库文件
import { MeshLine, MeshLineMaterial, MeshLineRaycast } from 'three.meshline/src/THREE.MeshLine.js';
- MeshLine的简单使用
var scene, camera, renderer, amountToAdd = 0.01;
var points, line;
function init() {
scene = new THREE.Scene();//设置场景
camera = new THREE.PerspectiveCamera(75, 640 / 480, 0.1, 1000);//设置相机
renderer = new THREE.WebGLRenderer();//设置渲染器
renderer.setSize(640, 480);//设置窗口大小
document.body.appendChild(renderer.domElement);
camera.position.z = 9;
//设置点集
points = [];
for (var i = -10; i < 10.1; i += 0.1) {
points.push([i, Math.sin(i), 0]);
}
//创建线的几何体
line = new MeshLine();
//设置构成这条线需要的几个点
line.setPoints(points.flat());
//设置线段需要的材质
var material = new MeshLineMaterial({
color: new THREE.Color(0x00FFFF),
lineWidth: 0.1,
//dashArray和dashRatio都是构成虚线的影响因素
// dashArray: 0.01,
// dashRatio: 0.2,
});
// material.transparent = true;//虚线功能//只要开启虚线功能后,dashArray和dashRatio才会生效
var mesh = new THREE.Mesh(line, material);//网格=几何体+材质
scene.add(mesh);
//每2000毫秒边执行一次,来实现曲线上下移动的效果
setInterval(() => { amountToAdd *= -1 }, 2000);
animate();
}
//事件循环
function animate() {
points = points.map((point) => [point[0], point[1] * (1 + amountToAdd), point[2]]);
line.setPoints(points.flat());
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
init();//执行函数
- 效果
MeshLine的深入思考
因为,three.js的原配线段有很多与浏览器不合的部分,为了让用户有更好的效果,所以不得不采用MeshLine来替代three.js原来的内置线段
有一点很重要,MeshLine最主要是生成直线的,如果非要实现曲线的效果,那就需要足够的点,最终实现化直为曲的效果.
举个类似的例子,three.js的球体,其实是无数个三角形构成的,三角形越多,球体就越圆.同样的道理:直线段分的段数越多,曲线就越圆滑,而构成直线段的要素是俩个点,也就是说:点越多,曲线就越圆.
所以,我们需要很多很多的点!
样条曲线
由于我们需要很多很多的点,我们便顺理成章的引入样条曲线的概念:样条曲线可以由几个关键的点生成一个点集,这样我们就可以用Meshline来生成一条曲线了
一个问题
也就是说,我们需要用Vector3保存最开始的点,
然后用样条曲线有限的点集生成更多的点集,
最用将生成的点集转化为[x,y,z]的格式
var init_points, tmpPoints, final_points, line;
function init() {
init_points = [];
final_points = [];
//1.先计算几个关键点,键关键点放在init_points(Vector3的格式)中
for (var i = 0; i < Dental_arch_line.length; i += 1) {
Dental_arch_line[i].y += 10;
var vec = new THREE.Vector3(Dental_arch_line[i].x, Dental_arch_line[i].y, Dental_arch_line[i].z);
init_points.push(vec);
}
//2.使用样条曲线,使用init_points点集生成更多的点集tmpPoints(Vector3的格式)
// 假设 points 是一个包含 THREE.Vector3 对象的数组
var curve = new THREE.CatmullRomCurve3(init_points);
// 获取曲线上的点(您可以根据需要调整分段数量)
tmpPoints = curve.getPoints(100); // 这里的 100 表示曲线将被分成100段
console.log('tmpPoints:', tmpPoints);//此时,将牙弓线变成了100个点
//3.将生成的点集tmpPoints(Vector3的格式)转换成final_points([x,y,z]的格式)
//还需要进一步转换,将Vector3的类型变成[x,y,z]的格式
for (var i = 0; i < tmpPoints.length; i += 1) {
final_points.push([tmpPoints[i].x, tmpPoints[i].y, tmpPoints[i].z]);
}
//4.然后MeshLine就可以用了final_points这种格式了
line = new MeshLine();
line.setPoints(final_points.flat());
var material = new MeshLineMaterial({
color: new THREE.Color(0x00FFFF),
lineWidth: 1,
});
var mesh = new THREE.Mesh(line, material);
scene.add(mesh);
}
- 补充: