九、threejs学习笔记-生成曲线、几何体

友情链接:threejs 中文文档

1. 几何体方法.setFromPoints()

三维向量Vector3表示顶点坐标

用三维向量Vector3表示顶点的x、y、z坐标,作为数组元素创建一组顶点坐标

const pointsArr = [
    // 三维向量Vector3表示的坐标值
    new THREE.Vector3(0,0,0),
    new THREE.Vector3(0,100,0),
    new THREE.Vector3(0,100,100),
    new THREE.Vector3(0,0,100),
];

.setFromPoints() 方法

.setFromPoints()是几何体BufferGeometry的一个方法,通过该方法可以把数组pointsArr中坐标数据提取出来赋值给几何体。具体说就是把pointsArr里面坐标数据提取出来,赋值给geometry.attributes.position属性

// 把数组pointsArr里面的坐标数据提取出来,赋值给`geometry.attributes.position`属性
geometry.setFromPoints(pointsArr);
console.log('几何体变化',geometry.attributes.position);

2. 曲线Curve

threejs提供了很多常用的曲线或直线API,可以直接使用。这些API曲线都有一个共同的父类Curve

曲线Curve方法.getPoints()

椭圆弧线EllipseCurve的父类是曲线Curve,自然会继承父类曲线.getPoints()方法,通过.getPoints()可以从曲线上获取顶点数据。

通过方法.getPoints()可以从曲线上按照一定的细分精度返回沿着曲线分布的顶点坐标。细分数越高返回的顶点数量越多,自然轮廓越接近于曲线形状。方法.getPoints()的返回值是一个由二维向量Vector2或三维向量Vector3构成的数组,Vector2表示位于同一平面内的点,Vector3表示三维空间中一点。

//getPoints是基类Curve的方法,平面曲线会返回一个vector2对象作为元素组成的数组
const pointsArr = arc.getPoints(50); //分段数50,返回51个顶点
console.log('曲线上获取坐标',pointsArr);

曲线Curve方法.getSpacedPoints()

.getSpacedPoints() 也是提取曲线的顶点数据,不同的是getSpacedPoints()方法是按照曲线长度等距来获取顶点数据,而getPoints()会考虑到斜率的变化,斜率变化快的位置顶点会更密集

3. 样条曲线

对于一些不规则的曲线,很难用圆弧去描述,可以使用threejs中的样条曲线和贝尔曲线来实现

三维样条曲线CatmullRomCurve3

在三维空间中随意设置几个顶点坐标,然后作为三维样条曲线CatmullRomCurve3的参数,你就可以生成一条穿过这几个点的光滑曲线。

// 三维向量Vector3创建一组顶点坐标
const arr = [
    new THREE.Vector3(-50, 20, 90),
    new THREE.Vector3(-10, 40, 40),
    new THREE.Vector3(0, 0, 0),
    new THREE.Vector3(60, -60, 0),
    new THREE.Vector3(70, 0, 80)
]
// 三维样条曲线
const curve = new THREE.CatmullRomCurve3(arr);

二维样条曲线SplineCurve 

CatmullRomCurve3是3D样条曲线API,曲线经过的点可以在3D空间中任何一个位置,二维样条曲线SplineCurve默认情况下就是在XOY平面生成一个平面的样条曲线。 SplineCurve的参数是二维向量对象Vector2构成的数组。

// 二维向量Vector2创建一组顶点坐标
const arr = [
    new THREE.Vector2(-100, 0),
    new THREE.Vector2(0, 30),
    new THREE.Vector2(100, 0),
];
// 二维样条曲线
const curve = new THREE.SplineCurve(arr);

将样条曲线通过线模型Line显示 

使用前面介绍的getPoints() 方法,获取曲线上任意数量的点的坐标,复制给BufferGeometry几何体,通过线模型Line可以将其曲线可视化出来

//曲线上获取点
const pointsArr = curve.getPoints(100); 
const geometry = new THREE.BufferGeometry();
//读取坐标数据赋值给几何体顶点
geometry.setFromPoints(pointsArr); 
// 线材质
const material = new THREE.LineBasicMaterial({
    color: 0x00fffff
});
// 线模型
const line = new THREE.Line(geometry, material);

 4. 贝塞尔曲线

二维二次贝塞尔曲线QuadraticBezierCurve

二维二次贝塞尔曲线,参数为三个二维向量对象

// p2为曲线的控制点
const p1 = new THREE.Vector2(-80, 0);
const p2 = new THREE.Vector2(20, 100);
const p3 = new THREE.Vector2(80, 0);
const curve = new THREE.QuadraticBezierCurve(p1, p2, p3);

三维二次贝赛尔曲线QuadraticBezierCurve3

三维二次贝赛尔曲线,参数为三个三维向量对象

// p2为曲线的控制点
const p1 = new THREE.Vector3(-80, 0, 0);
const p2 = new THREE.Vector3(20, 100, 0);
const p3 = new THREE.Vector3(80, 0, 100);
const curve = new THREE.QuadraticBezierCurve3(p1, p2, p3);

二维三次贝塞尔曲线CubicBezierCurve 

二维三次贝赛尔曲线,参数为四个二维向量对象

// p1、p4是曲线起始点,p2、p3是曲线的控制点
const p1 = new THREE.Vector2(-80, 0);
const p2 = new THREE.Vector2(-40, 50);
const p3 = new THREE.Vector2(50, 50);
const p4 = new THREE.Vector2(80, 0);
const curve = new THREE.CubicBezierCurve(p1, p2, p3, p4);

三维三次贝赛尔曲线CubicBezierCurve3 

三维三次贝赛尔曲线,参数为四个三维向量对象

// p1、p4是曲线起始点,p2、p3是曲线的控制点
const p1 = new THREE.Vector3(-80, 0, 0);
const p2 = new THREE.Vector3(-40, 50, 0);
const p3 = new THREE.Vector3(50, 50, 0);
const p4 = new THREE.Vector3(80, 0, 100);
const curve = new THREE.CubicBezierCurve3(p1, p2, p3, p4);

不同贝塞尔曲线的区别

控制点会着影响贝塞尔曲线的高度,参数点为二维向量的曲线只能在某平面展示,参数点为三味向量则可在空间中展示

  • 二维二次QuadraticBezierCurve :共有个参数点,中间的那个为控制点,参数点为二维向量Vectoer2
  • 三维二次QuadraticBezierCurve3 :共有个参数点,中间的那个为控制点,参数点为三维向量Vectoer3
  • 二维三次CubicBezierCurve :共有个参数点,中间的两个点为控制点,参数点为二维向量Vectoer2
  • 三维三次CubicBezierCurve3 :共有个参数点,中间的两个点为控制点,参数点为三维向量Vectoer3

5. 组合曲线CurvePath

通过CurvePath对象,你可以将直线、圆弧、贝塞尔曲线等线条连接成一条直线。

直线线段LineCurve3和LineCurve

// LineCurve3线段的参数为三维向量对象
new THREE.LineCurve3(new THREE.Vector3(), new THREE.Vector3());
// LineCurve3线段的参数为二维向量对象
new THREE.LineCurve(new THREE.Vector2(), new THREE.Vector2());

下面创建二条直线和一条圆弧并将其使用CurvePath对象连接起来

const R = 80;//圆弧半径
const H = 200;//直线部分高度
// 直线1
const line1 = new THREE.LineCurve(new THREE.Vector2(R, H), new THREE.Vector2(R, 0));
// 圆弧
const arc = new THREE.ArcCurve(0, 0, R, 0, Math.PI, true);
// 直线2
const line2 = new THREE.LineCurve(new THREE.Vector2(-R, 0), new THREE.Vector2(-R, H));

// CurvePath创建一个组合曲线对象
const CurvePath = new THREE.CurvePath();
//line1, arc, line2拼接出来一个U型轮廓曲线,注意顺序
CurvePath.curves.push(line1, arc, line2);

6. 管道几何体TubeGeometry

管道几何体就是基于一个3D的曲线,生成一个管道几何体

构造函数格式:TubeGeometry(path, tubularSegments, radius, radiusSegments, closed)

参数
path     扫描路径,路径要用三维曲线
tubularSegments     路径方向细分数,默认64
radius     管道半径,默认1
radiusSegments     管道圆弧细分数,默认8
closed     Boolean值,管道是否闭合
// 三维样条曲线
const path = new THREE.CatmullRomCurve3([
    new THREE.Vector3(-50, 20, 90),
    new THREE.Vector3(-10, 40, 40),
    new THREE.Vector3(0, 0, 0),
    new THREE.Vector3(60, -60, 0),
    new THREE.Vector3(70, 0, 80)
]);

// path:路径   40:沿着轨迹细分数  2:管道半径   25:管道截面圆细分数
const geometry = new THREE.TubeGeometry(path, 40, 2, 25);

7. 车削几何体LatheGeometry

车削几何体可以利用一个2D轮廓,将其旋转成一个3D的几何体曲面

格式:LatheGeometry(points, segments, phiStart, phiLength)
points    Vector2表示的坐标数据组成的数组
segments    圆周方向细分数,默认12
phiStart    开始角度,默认0
phiLength    旋转角度,默认2π

参数
points Vector2表示的坐标数据组成的数组
segments     圆周方向细分数,默认12
phiStart     开始角度,默认0
phiLength     旋转角度,默认2π
// Vector2表示的三个点坐标,三个点构成的轮廓相当于两端直线相连接
const pointsArr = [
    new THREE.Vector2(50, 60),
    new THREE.Vector2(25, 0),
    new THREE.Vector2(50, -60)
];
// LatheGeometry:pointsArr轮廓绕y轴旋转生成几何体曲面
// pointsArr:旋转几何体的旋转轮廓形状
const geometry = new THREE.LatheGeometry(pointsArr);

8. 轮廓几何体shapeGeometry

有些时候已知一个多边形的外轮廓坐标,想通过这些外轮廓坐标生成一个多边形几何体平面,这时候你可以借助threejs提供的轮廓填充shapeGeometry几何体实现。

// 一组二维向量表示一个多边形轮廓坐标
const pointsArr = [
    new THREE.Vector2(-50, -50),
    new THREE.Vector2(-60, 0),
    new THREE.Vector2(0, 50),
    new THREE.Vector2(60, 0),
    new THREE.Vector2(50, -50),
]
// Shape表示一个平面多边形轮廓,参数是二维向量构成的数组pointsArr
const shape = new THREE.Shape(pointsArr);

// 创建轮廓几何体
const geometry = new THREE.ShapeGeometry(shape);

9. 拉伸ExtrudeGeometry

拉伸ExtrudeGeometry像轮廓几何体一样,都是基于一个平面轮廓shape进行变化,生成一个几何体,轮廓几何体是将形状对象shape显现出来,拉伸几何体将形状对象shape进行向下拉伸后的形状显现出来

// Shape表示一个平面多边形轮廓
const shape = new THREE.Shape([
    // 按照特定顺序,依次书写多边形顶点坐标
    new THREE.Vector2(-50, -50), //多边形起点
    new THREE.Vector2(-50, 50),
    new THREE.Vector2(50, 50),
    new THREE.Vector2(50, -50),
]);

const geometry = new THREE.ExtrudeGeometry(
    // 平面轮廓
    shape, 
    {
        depth: 20,     // 拉伸长度
        bevelThickness: 5, //倒角尺寸:拉伸方向
        bevelSize: 5, //倒角尺寸:垂直拉伸方向
        bevelSegments: 20, //倒圆角:倒角细分精度,默认3
    }
);

10. 扫描ExtrudeGeometry

通过ExtrudeGeometry除了可以实现将形状Shape对象拉伸成型,还可以让一个形状Shape对象沿着一条曲线扫描成型。

// 扫描轮廓:Shape表示一个平面多边形轮廓
const shape = new THREE.Shape([
    // 按照特定顺序,依次书写多边形顶点坐标
    new THREE.Vector2(0,0), //多边形起点
    new THREE.Vector2(0,10),
    new THREE.Vector2(10,10),
    new THREE.Vector2(10,0),
]);

// 扫描轨迹:创建轮廓的扫描轨迹(3D样条曲线)
const curve = new THREE.CatmullRomCurve3([
    new THREE.Vector3( -10, -50, -50 ),
    new THREE.Vector3( 10, 0, 0 ),
    new THREE.Vector3( 8, 50, 50 ),
    new THREE.Vector3( -5, 0, 100)
]);

//扫描造型:扫描默认没有倒角
const geometry = new THREE.ExtrudeGeometry(
    shape, //扫描轮廓
    {
        extrudePath:curve,//扫描轨迹
        steps:100//沿着路径细分精度,越大越光滑
    }
);

11. 多边形轮廓shape

多边形轮廓shape,是直接通过一组二维向量Vector2表示的xy点坐标创建

shape的父类是path,有以下方法

  • .lineTo() 直线
  • .arc() 圆弧
  • .absarc() 绝对圆弧
  • .splineThru() 二维样条曲线
  • .bezierCurveTo() 二维三次贝塞尔曲线
  • .quadraticCurveTo() 二维二次贝塞尔曲线

// Shape表示一个平面多边形轮廓
const shape = new THREE.Shape([
    // 按照特定顺序,依次书写多边形顶点坐标
    new THREE.Vector2(-50, -50), //多边形起点
    new THREE.Vector2(-50, 50),
    new THREE.Vector2(50, 50),
    new THREE.Vector2(50, -50),
]);

.currentPoint属性

.currentPoint属性字面意思是当前点,默认值Vector2(0,0)。

// .currentPoint属性字面意思是当前点,默认值Vector2(0,0)。
const shape = new THREE.Shape();
console.log('currentPoint',shape.currentPoint)

.moveTo()方法

.moveTo()方法将改变.currentPoint属性

// .moveTo()方法可以改变当前currentPoint属性
const shape = new THREE.Shape();
shape.moveTo(10,0);

绘制直线.lineTo()

.lineTo()绘制直线线段,直线线段的起点是当前点属性.currentPoint表示的位置,结束点是.lineTo()的参数表示的坐标。 

// .lineTo()绘制直线线段,直线线段的起点是当前点属性.currentPoint表示的位置,结束点是.lineTo()的参数表示的坐标。
const shape = new THREE.Shape();
//.currentPoint变为(10,0)
shape.moveTo(10,0);
// 绘制直线线段,起点(10,0),结束点(100,0)
shape.lineTo(100,0);

12. 多边形Shape(内孔)

有些多边形是有内孔的,这时候需要借助shape的.holes()来实现

// 创建shape,绘制一个矩形轮廓
const shape = new THREE.Shape();
// .lineTo(100, 0)绘制直线线段,线段起点:.currentPoint,线段结束点:(100,0)
shape.lineTo(100, 0);
shape.lineTo(100, 100);
shape.lineTo(0, 100)

// 创建Shape内孔的轮廓
const path1 = new THREE.Path();// 圆孔1
path1.absarc(20, 20, 10);
const path2 = new THREE.Path();// 圆孔2
path2.absarc(80, 20, 10);
const path3 = new THREE.Path();// 方形孔
path3.moveTo(50, 50);
path3.lineTo(80, 50);
path3.lineTo(80, 80);
path3.lineTo(50, 80);

// 将内孔轮廓添加到shape中
shape.holes.push(path1, path2,path3);

// 使用ExtrudeGeometry拉伸成长方体,方便观看内孔效果
const geometry = new THREE.ExtrudeGeometry(shape, {
    depth:20,//拉伸长度
    bevelEnabled:false,//禁止倒角
    curveSegments:50,
});

13. 模型边界线EdgesGeometry

借助EdgesGeometry,可以展示出模型的边界线

const geometry = new THREE.BoxGeometry(50, 50, 50);
const material = new THREE.MeshLambertMaterial({
    color: 0x004444,
    transparent:true,
    opacity:0.5,
});
const mesh = new THREE.Mesh(geometry, material);

// 长方体geometry作为EdgesGeometry参数创建一个新的几何体
const edges = new THREE.EdgesGeometry(geometry);
const edgesMaterial = new THREE.LineBasicMaterial({
  color: 0x00ffff,
})
// 使用LineSegments将几何体边界线显示出来
const line = new THREE.LineSegments(edges, edgesMaterial);
mesh.add(line);

14. 曲线颜色渐变

通过几何体顶点颜色.attributes.color数据,可以实现曲线的渐变

//创建一个几何体对象
const geometry = new THREE.BufferGeometry(); 
// 三维样条曲线
const curve = new THREE.CatmullRomCurve3([
    new THREE.Vector3(-50, 20, 90),
    new THREE.Vector3(-10, 40, 40),
    new THREE.Vector3(0, 0, 0),
    new THREE.Vector3(60, -60, 0),
    new THREE.Vector3(70, 0, 80)
]);
const pointsArr = curve.getSpacedPoints(100); //曲线取点      
geometry.setFromPoints(pointsArr); //pointsArr赋值给顶点位置属性     

const pos = geometry.attributes.position;
const count = pos.count; //顶点数量
// 计算每个顶点的颜色值
const colorsArr = [];
for (let i = 0; i < count; i++) {
    const percent = i / count; //点索引值相对所有点数量的百分比
    //根据顶点位置顺序大小设置颜色渐变
    // 红色分量从0到1变化,蓝色分量从1到0变化
    colorsArr.push(percent, 0, 1 - percent); //蓝色到红色渐变色
}

//类型数组创建顶点颜色color数据
const colors = new Float32Array(colorsArr);
// 设置几何体attributes属性的颜色color属性
geometry.attributes.color = new THREE.BufferAttribute(colors, 3);

const material = new THREE.LineBasicMaterial({
    vertexColors: true, //使用顶点颜色渲染
});
const line = new THREE.Line(geometry, material);

15. Color颜色渐变插值

颜色渐变插值方法有.lerpColor()和.lerp(),他们功能是相同的,区别是使用的语法不一样

// lerpColors用法,percent是两颜色的混合百分比
.lerpColors(Color1,Color2, percent)

// lerp用法
const c1 = new THREE.Color(0xff0000); //红色
const c2 = new THREE.Color(0x0000ff); //蓝色
c1.lerp(c2, percent);
const geometry = new THREE.BufferGeometry(); //创建一个几何体对象
// 三维样条曲线
const curve = new THREE.CatmullRomCurve3([
    new THREE.Vector3(-50, 20, 90),
    new THREE.Vector3(-10, 40, 40),
    new THREE.Vector3(0, 0, 0),
    new THREE.Vector3(60, -60, 0),
    new THREE.Vector3(70, 0, 80)
]);
const pointsArr = curve.getSpacedPoints(100); //曲线取点      
geometry.setFromPoints(pointsArr); //pointsArr赋值给顶点位置属性     

const pos = geometry.attributes.position;
const count = pos.count; //顶点数量
// 计算每个顶点的颜色值
const colorsArr = [];
// 根据顶点距离起点远近进行颜色插值计算
const c1 = new THREE.Color(0x00ffff); //曲线起点颜色 青色
const c2 = new THREE.Color(0xffff00); //曲线结束点颜色 黄色
for (let i = 0; i < count; i++) {
    const percent = i / count; //点索引值相对所有点数量的百分比
    //根据顶点位置顺序大小设置颜色渐变
    const c = c1.clone().lerp(c2, percent);//颜色插值计算
    colorsArr.push(c.r, c.g, c.b); 
}

//类型数组创建顶点颜色color数据
const colors = new Float32Array(colorsArr);
// 设置几何体attributes属性的颜色color属性
geometry.attributes.color = new THREE.BufferAttribute(colors, 3);

const material = new THREE.LineBasicMaterial({
    vertexColors: true, //使用顶点颜色渲染
});
const line = new THREE.Line(geometry, material);

 文章中部分素材选取自Threejs中文网:Three.js中文网

猜你喜欢

转载自blog.csdn.net/weixin_60645637/article/details/131488679