学习: Threejs (9)& Threejs (10)

Threejs (9)

一、生成圆弧顶点

model.js

生成圆弧顶点数据

首先定义

javascript 复制代码
const R = 100; //圆弧半径
const N = 50; //分段数量
const sp = 2 * Math.PI / N;//两个相邻点间隔弧度

循环

javascript 复制代码
for (let i = 0; i < N ; i++) {
    const angle =  sp * i;
    // 以坐标原点为中心,在XOY平面上生成圆弧上的顶点数据
    const x = R * Math.cos(angle);
    const y = R * Math.sin(angle);
  }

声明数组,存放圆弧上的顶点数据

javascript 复制代码
const R = 100; //圆弧半径
const N = 50; //分段数量
// 批量生成圆弧上的顶点数据
const arr = [];
const sp = 2 * Math.PI / N;//两个相邻点间隔弧度
// const sp = 1 * Math.PI / N;//半圆弧
for (let i = 0; i < N; i++) {
    const angle =  sp * i;
    // 以坐标原点为中心,在XOY平面上生成圆弧上的顶点数据
    const x = R * Math.cos(angle);
    const y = R * Math.sin(angle);
    arr.push(x, y, 0);
}

线模型渲染圆弧线

javascript 复制代码
//类型数组创建顶点数据
const vertices = new Float32Array(arr);
// 创建属性缓冲区对象
const attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组,表示一个顶点的xyz坐标
// 设置几何体attributes属性的位置属性
geometry.attributes.position = attribue;

// 线材质
const material = new THREE.LineBasicMaterial({
    color: 0xffffff //线条颜色
});
// 创建线模型对象   构造函数:Line、LineLoop、LineSegments

const line = new THREE.Line(geometry, material); 

或者将i<N改成 i<N+1

javascript 复制代码
for (let i = 0; i < N + 1; i++) {
    const angle =  sp * i;
    // 以坐标原点为中心,在XOY平面上生成圆弧上的顶点数据
    const x = R * Math.cos(angle);
    const y = R * Math.sin(angle);
    arr.push(x, y, 0);
}

绘制半圆弧

圆弧设置圆心坐标

javascript 复制代码
const R = 100; //圆弧半径
const N = 50; //分段数量
const sp = 2 * Math.PI / N;//两个相邻点间隔弧度
// 设置圆心坐标
const cx = 200;
const cy = 100;
for (let i = 0; i < N+1; i++) {
    const angle = sp * i;//当前点弧度
    const x = cx + R * Math.cos(angle);
    const y = cy + R * Math.sin(angle);
    arr.push(x, y, 0);
}

二、几何体方法.setFromPoints()

三维向量Vector3表示顶点坐标

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

javascript 复制代码
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()

javascript 复制代码
// 创建几何体对象
const geometry = new THREE.BufferGeometry();
// 把数组pointsArr里面的坐标数据提取出来,赋值给`geometry.attributes.position`属性
geometry.setFromPoints(pointsArr);
javascript 复制代码
console.log('几何体变化',geometry.attributes.position);

二维向量Vector2表示顶点坐标

javascript 复制代码
const pointsArr = [
    // 二维向量Vector2表示的坐标值
    new THREE.Vector2(0,0),
    new THREE.Vector2(100,0),
    new THREE.Vector2(100,100),
    new THREE.Vector2(0,100),
];

三、曲线Curve简介

曲线都有一个共同的父类Curve

椭圆EllipseCurve例子

javascript 复制代码
// 参数1和2表示椭圆中心坐标  参数3和4表示x和y方向半径
const arc = new THREE.EllipseCurve(0, 0, 120, 50);

曲线Curve方法.getPoints()

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

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

.setFromPoints()提取曲线坐标数据

javascript 复制代码
const geometry = new THREE.BufferGeometry();
geometry.setFromPoints(pointsArr);
console.log('geometry.attributes',geometry.attributes);
javascript 复制代码
// 点材质
const material = new THREE.PointsMaterial({
    color: 0xffff00,
    size: 10.0 //点对象像素尺寸
}); 
// 点模型
const points = new THREE.Points(geometry, material);

getPoints()

setFromPoints()

通过.getSpacedPoints().getPoints()一样也可以从曲线Curve上返回一系列曲线上的顶点坐标。

通过.getSpacedPoints()是按照曲线长度等间距返回顶点数据,.getPoints()获取点的方式并不是按照曲线等间距的方式,而是会考虑曲线斜率变化,斜率变化快的位置返回的顶点更密集。

四、椭圆、圆

椭圆弧线EllipseCurve

参数1和2表示椭圆中心坐标 参数3和4表示x和y方向半径

javascript 复制代码
const arc = new THREE.EllipseCurve(0, 0, 50, 50);//x和y方向半径相同就是圆形效果

圆弧线ArcCurve

javascript 复制代码
// 圆弧,参数3表示半径
const arc = new THREE.ArcCurve(0, 0, 60);

曲线精度

弧线起始角度

javascript 复制代码
// 完整圆弧
const arc = new THREE.ArcCurve(0, 0, 100, 0, 2 * Math.PI);
javascript 复制代码
// 半圆弧
const arc = new THREE.ArcCurve(0, 0, 100, 0, Math.PI);
javascript 复制代码
// 四分之一圆弧
const arc = new THREE.ArcCurve(0, 0, 100, 0, Math.PI/2);

顺逆时针

javascript 复制代码
// 逆时针绘制圆弧,参数5默认false,就是逆时针
const arc = new THREE.ArcCurve(0, 0, 100, 0, Math.PI/2,false);
javascript 复制代码
// 顺时针绘制圆弧
const arc = new THREE.ArcCurve(0, 0, 100, 0, Math.PI/2,true);

五、样条曲线

javascript 复制代码
// 三维向量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)
]

三维样条曲线CatmullRomCurve3

javascript 复制代码
// 三维样条曲线
const curve = new THREE.CatmullRomCurve3(arr);
javascript 复制代码
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);
javascript 复制代码
const group = new THREE.Group();
group.add(line);
export default group;

点模型可视化曲线经过的点

javascript 复制代码
// 用点模型可视化样条曲线经过的顶点位置;
const geometry2 = new THREE.BufferGeometry();
geometry2.setFromPoints(arr);
const material2 = new THREE.PointsMaterial({
  color: 0xff00ff,
  size: 10,
});
//点模型对象
const points = new THREE.Points(geometry2, material2);

const group = new THREE.Group();

group.add(line, points);

2D样条曲线

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

六、贝塞尔曲线

二维二次贝塞尔曲线QuadraticBezierCurve

javascript 复制代码
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);

线模型line渲染贝塞尔曲线

javascript 复制代码
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);

const group = new THREE.Group();
group.add(line);

观察贝塞尔曲线规则

javascript 复制代码
// 可视化p1、p2、p3三个点的位置,并用直线相连接,便于观察贝塞尔曲线的绘制规律
const geometry2 = new THREE.BufferGeometry();
geometry2.setFromPoints([p1,p2,p3]);
const material2 = new THREE.PointsMaterial({
    color: 0xff00ff,
    size: 10,
});
//点模型对象
const points = new THREE.Points(geometry2, material2);
// 三个点构成的线条
const line2 = new THREE.Line(geometry2, new THREE.LineBasicMaterial());


const group = new THREE.Group();

group.add(line, points, line2);

三维二次贝赛尔曲线QuadraticBezierCurve3

javascript 复制代码
// p1、p2、p3表示三个点坐标
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

二维三次贝塞尔曲线CubicBezierCurve与二维二次贝赛尔曲线QuadraticBezierCurve区别就是多了一个控制点。

javascript 复制代码
// p1、p2、p3、p4表示4个点坐标
// 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

三维三次贝赛尔曲线CubicBezierCurve3与二维三次贝塞尔曲线CubicBezierCurve区别就是多了一个维度,参数是三维向量对象Vector3。

七、样条、贝塞尔曲线应用

曲线的起始点设置在XOZ平面上,y方向为曲线高度方向。

三维样条曲线CatmullRomCurve3实现飞线轨迹

javascript 复制代码
// p1、p3轨迹线起始点坐标
const p1 = new THREE.Vector3(-100, 0, -100);
const p3 = new THREE.Vector3(100, 0, 100);
// 计算p1和p3的中点坐标
const x2 = (p1.x + p3.x)/2;
const z2 = (p1.z + p3.z)/2;
const h = 50;
const p2 = new THREE.Vector3(x2, h, z2);

const arr = [p1, p2, p3];
// 三维样条曲线
const curve = new THREE.CatmullRomCurve3(arr);

三维二次贝赛尔曲线QuadraticBezierCurve3实现飞线轨迹

javascript 复制代码
// p1、p3轨迹线起始点坐标
const p1 = new THREE.Vector3(-100, 0, -100);
const p3 = new THREE.Vector3(100, 0, 100);
// 计算p1和p3的中点坐标
const x2 = (p1.x + p3.x)/2;
const z2 = (p1.z + p3.z)/2;
const h = 100;
const p2 = new THREE.Vector3(x2, h, z2);
// 三维二次贝赛尔曲线
const curve = new THREE.QuadraticBezierCurve3(p1, p2, p3);

八、组合曲线CurvePath拼接不同曲线

直线线段

3D直线线段LineCurve3,参数是表示x、y、z坐标的三维向量Vector3对象。

javascript 复制代码
new THREE.LineCurve3(new THREE.Vector3(), new THREE.Vector3());

2D直线线段LineCurve,参数是表示x、y坐标的二维向量Vector2对象。

javascript 复制代码
new THREE.LineCurve(new THREE.Vector2(), new THREE.Vector2());

整体思路CurvePath.curves

javascript 复制代码
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);

组合曲线CurvePath取点

javascript 复制代码
//组合曲线上获取点
const pointsArr = CurvePath.getPoints(16); 
const geometry = new THREE.BufferGeometry();
geometry.setFromPoints(pointsArr); //读取坐标数据赋值给几何体顶点

点模型可视化组合曲线返回的顶点

javascript 复制代码
// 可视化curve.getPoints从曲线上获取的点坐标
const material2 = new THREE.PointsMaterial({
    color: 0xff00ff,
    size: 10,
});
//点模型对象
const points = new THREE.Points(geometry, material2);

// 可视化curve.getPoints从曲线上获取的点坐标
const material2 = new THREE.PointsMaterial({
    color: 0xff00ff,
    size: 10,
});
//点模型对象
const points = new THREE.Points(geometry, material2);

.getSpacedPoints()取点测试

直线部分会按照等间距方式返回顶点数据,需要把.getSpacedPoints()的精度参数提升,圆弧部分才会更加圆滑。

九、曲线路径管道TubeGeometry

样条曲线

javascript 复制代码
// 三维样条曲线
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)
]);

管道TubeGeometry

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

观察管道内壁

javascript 复制代码
const material = new THREE.MeshLambertMaterial({
    side:THREE.DoubleSide,//双面显示看到管道内壁
});

组合曲线CurvePath生成管道

javascript 复制代码
import * as THREE from 'three';


// 创建多段线条的顶点数据
const p1 = new THREE.Vector3(0, 0,100)
const p2 = new THREE.Vector3(0, 0,30);
const p3 = new THREE.Vector3(0, 0,0);
const p4 = new THREE.Vector3(30, 0, 0);
const p5 = new THREE.Vector3(100, 0, 0);
// 1. 3D直线线段
const line1 = new THREE.LineCurve3(p1, p2);
// 2. 三维二次贝塞尔曲线
const curve = new THREE.QuadraticBezierCurve3(p2, p3, p4);
// 3. 3D直线线段
const line2 = new THREE.LineCurve3(p4, p5);

const CurvePath = new THREE.CurvePath(); 
// 三条线拼接为一条曲线
CurvePath.curves.push(line1, curve, line2); 

// CurvePath:路径   40:沿着轨迹细分数  2:管道半径   25:管道截面圆细分数
const geometry = new THREE.TubeGeometry(CurvePath, 50, 2, 25);
const material = new THREE.MeshLambertMaterial({
    color: 0x00ffff,
    side: THREE.DoubleSide, //双面显示看到管道内壁
});
const mesh = new THREE.Mesh(geometry, material);


export default mesh;

十、旋转成型LatheGeometry

旋转LatheGeometry

javascript 复制代码
// 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);

旋转细分精度

javascript 复制代码
// 30:旋转圆周方向几何体细分精度
const geometry = new THREE.LatheGeometry(pointsArr, 30);

旋转角度

javascript 复制代码
// 0, Math.PI:旋转的开始角度和结束角度
const geometry = new THREE.LatheGeometry(pointsArr, 30,0, Math.PI);

曲线生成旋转轮廓

javascript 复制代码
// 通过三个点定义一个二维样条曲线
const curve = new THREE.SplineCurve([
    new THREE.Vector2(50, 60),
    new THREE.Vector2(25, 0),
    new THREE.Vector2(50, -60)
]);
javascript 复制代码
//曲线上获取点,作为旋转几何体的旋转轮廓
const pointsArr = curve.getPoints(50); 

十一、轮廓填充ShapeGeometry

javascript 复制代码
// 一组二维向量表示一个多边形轮廓坐标
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

javascript 复制代码
// Shape表示一个平面多边形轮廓,参数是二维向量构成的数组pointsArr
const shape = new THREE.Shape(pointsArr);

轮廓填充几何体ShapeGeometry

javascript 复制代码
// 多边形shape轮廓作为ShapeGeometry参数,生成一个多边形平面几何体
const geometry = new THREE.ShapeGeometry(shape);

查看ShapeGeometry生成的三角形

javascript 复制代码
  wireframe:true

十二、拉伸ExtrudeGeometry

拉伸几何体ExtrudeGeometry和上节课讲到的轮廓填充几何体ShapeGeometry一样,都是基于一个基础的平面轮廓Shape进行变换,生成一个几何体。

定义一个Shape轮廓

javascript 复制代码
// 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),
]);

拉伸成型

javascript 复制代码
//拉伸造型
const geometry = new THREE.ExtrudeGeometry(
    shape, //二维轮廓
    {
        depth: 20, //拉伸长度
    }
);

拉伸倒角

倒圆角

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

倒直角

javascript 复制代码
const geometry = new THREE.ExtrudeGeometry(
    shape,{
        bevelSegments: 1, //倒直角
    }
);

拉伸取消默认倒角

javascript 复制代码
//拉伸造型
const geometry = new THREE.ExtrudeGeometry(
    shape, //二维轮廓
    {
        depth: 20, //拉伸长度
        bevelEnabled: false, //禁止倒角,默认true
    }
);

十三、扫描ExtrudeGeometry

扫描轮廓

javascript 复制代码
// 扫描轮廓: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),
]);

扫描轨迹

javascript 复制代码
// 2.扫描轨迹:创建轮廓的扫描轨迹(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)
]);

扫描造型

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

十四、多边形轮廓Shape简介

多边形轮廓Shape的父类Path

Shape的父类是Path,Path提供了直线、圆弧、贝塞尔、样条等绘制方法

.currentPoint属性

默认值Vector2(0,0)

javascript 复制代码
const shape = new THREE.Shape();
console.log('currentPoint',shape.currentPoint);

.moveTo()方法

javascript 复制代码
shape.moveTo(10, 0); //.currentPoint变为(10,0)
console.log("currentPoint后", shape.currentPoint);

除了.moveTo()方法,Path其他的直线、圆弧等方法也可能会改变.currentPoint属性

绘制直线.lineTo()

.lineTo()方法和.moveTo()方法,一样会改变.currentPoint属性

创建好的多边形轮廓Shape作为几何体的参数

javascript 复制代码
// ShapeGeometry填充Shape获得一个平面几何体
const geometry = new THREE.ShapeGeometry(shape);
javascript 复制代码
// ExtrudeGeometry拉伸Shape获得一个长方体几何体
const geometry = new THREE.ExtrudeGeometry(shape, {
    depth:20,//拉伸长度
    bevelEnabled:false,//禁止倒角
});

十五、多边形轮廓Shape(圆弧)

圆弧方法.arc()

圆弧.arc()参数的圆心坐标是相对当前.currentPoint而言,而不是坐标原点。

javascript 复制代码
// 下面代码绘制了一个矩形+扇形的轮廓,圆心在(100, 0),半径50。
const shape = new THREE.Shape();
shape.lineTo(100+50, 0); //.currentPoint变为(100+50,0)
// 圆弧.arc参数的圆心0,0坐标是相对当前.currentPoint而言,而不是坐标原点
shape.arc(-50,0,50,0,Math.PI/2); //.currentPoint变为圆弧线结束点坐标
console.log('currentPoint',shape.currentPoint);
// 绘制直线,直线起点:圆弧绘制结束的点  直线结束点:(0, 0)
shape.lineTo(0, 50);

直线和圆弧起点之间的缺口threejs内部会自动补上

javascript 复制代码
// 下面代码绘制了一个矩形+扇形的轮廓,圆心在(100, 0),半径50。
const shape = new THREE.Shape();
shape.lineTo(100, 0); //.currentPoint变为(100,0)
// 圆弧.arc参数的圆心0,0坐标是相对当前.currentPoint而言,而不是坐标原点
shape.arc(0,0,50,0,Math.PI/2); //.currentPoint变为圆弧线结束点坐标
console.log('currentPoint',shape.currentPoint);
// 绘制直线,直线起点:圆弧绘制结束的点  直线结束点:(0, 0)
shape.lineTo(0, 50);

Shape作为几何体参数

javascript 复制代码
// shape:填充轮廓  
const geometry = new THREE.ShapeGeometry(shape, 20);
javascript 复制代码
const geometry = new THREE.ExtrudeGeometry(shape, {
    depth:20,//拉伸长度
    bevelEnabled:false,//禁止倒角
    curveSegments:20,//shape曲线对应曲线细分数
});

绝对圆弧方法.absarc()

javascript 复制代码
// 下面代码绘制了一个矩形+扇形的轮廓,圆心在(100, 0),半径50。
const shape = new THREE.Shape();
shape.lineTo(100, 0); //.currentPoint变为(100,0)
// absarc圆心坐标不受到.currentPoint影响,以坐标原点作为参考
shape.absarc(100,0,50,0,Math.PI/2); //.currentPoint变为圆弧线结束点坐标
console.log('currentPoint',shape.currentPoint);
shape.lineTo(0, 50);

十六、多边形Shape(内孔.holes)

外轮廓

javascript 复制代码
const shape = new THREE.Shape();
// .lineTo(100, 0)绘制直线线段,线段起点:.currentPoint,线段结束点:(100,0)
shape.lineTo(100, 0);
shape.lineTo(100, 100);
shape.lineTo(0, 100);

.holes设置内孔的轮廓

javascript 复制代码
//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);
//三个内孔轮廓分别插入到holes属性中
shape.holes.push(path1, path2,path3);
javascript 复制代码
const geometry = new THREE.ShapeGeometry(shape);
javascript 复制代码
const geometry = new THREE.ExtrudeGeometry(shape, {
    depth:20,//拉伸长度
    bevelEnabled:false,//禁止倒角
    curveSegments:50,
});

十七、模型边界线EdgesGeometry

长方体边线

model.js

javascript 复制代码
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);


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

圆柱边线

javascript 复制代码
const geometry = new THREE.CylinderGeometry(60, 60, 100, 30);
const edges = new THREE.EdgesGeometry(geometry);
javascript 复制代码
const edges = new THREE.EdgesGeometry(geometry,30);

外部gltf模型设置材质和边线

javascript 复制代码
loader.load("../建筑模型.gltf", function (gltf) {
    // 递归遍历设置每个模型的材质,同时设置每个模型的边线
    gltf.scene.traverse(function (obj) {
        if (obj.isMesh) {
            // 模型材质重新设置
            obj.material = new THREE.MeshLambertMaterial({
                color: 0x004444,
                transparent: true,
                opacity: 0.5,
            });
            // 模型边线设置
            const edges = new THREE.EdgesGeometry(obj.geometry);
            const edgesMaterial = new THREE.LineBasicMaterial({
                color: 0x00ffff,
            })
            const line = new THREE.LineSegments(edges, edgesMaterial);
            obj.add(line);
        }
    });
    model.add(gltf.scene);
})

十八、几何体顶点颜色数数据

几何体顶点颜色.attributes.color

javascript 复制代码
const geometry = new THREE.BufferGeometry(); //创建一个几何体对象
const vertices = new Float32Array([
    0, 0, 0, //顶点1坐标
    50, 0, 0, //顶点2坐标
    0, 25, 0, //顶点3坐标
]);
// 顶点位置
geometry.attributes.position = new THREE.BufferAttribute(vertices, 3);

与几何体BufferGeometry顶点位置数据.attributes.position一一对应的顶点颜色数据.attributes.color

javascript 复制代码
//类型数组创建顶点颜色color数据
const colors = new Float32Array([
    1, 0, 0, //顶点1颜色
    0, 0, 1, //顶点2颜色
    0, 1, 0, //顶点3颜色
]);
// 设置几何体attributes属性的颜色color属性
geometry.attributes.color = new THREE.BufferAttribute(colors, 3); //3个为一组,表示一个顶点的颜色数据RGB

需要设置材质属性vertexColors:true

javascript 复制代码
// 点渲染模式
const material = new THREE.PointsMaterial({
     vertexColors:true,//默认false,设置为true表示使用顶点颜色渲染
    size: 20.0, //点对象像素尺寸
});

颜色渐变(颜色插值)

自定几何体顶点颜色数据,然后用线模型Line渲染,可以看到直线的颜色是渐变的。

javascript 复制代码
// 线模型渲染几何体顶点颜色,可以看到直线颜色渐变效果
const material = new THREE.LineBasicMaterial({
    vertexColors:true,//默认false,设置为true表示使用顶点颜色渲染
});
const line = new THREE.Line(geometry, material);

网格模型颜色渐变

javascript 复制代码
// 定义好几何体顶点颜色,使用Mesh渲染,Mesh产生颜色渐变效果
const material = new THREE.MeshBasicMaterial({
    vertexColors:true,//默认false,设置为true表示使用顶点颜色渲染
    side: THREE.DoubleSide, //两面可见
});
const mesh = new THREE.Mesh(geometry, material); 

十九、一段曲线颜色渐变

样条曲线几何体

javascript 复制代码
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赋值给顶点位置属性 

设置几何体顶点颜色.attributes.color

javascript 复制代码
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);

线模型渲染渐变色曲线

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

二十、Color颜色渐变插值

javascript 复制代码
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赋值给顶点位置属性     

颜色对象Color颜色插值方法.lerpColors()

执行.lerpColors(Color1,Color2, percent)通过一个百分比参数percent,可以控制Color1和Color2两种颜色混合的百分比,Color1对应1-percent,Color2对应percent

javascript 复制代码
const c1 = new THREE.Color(0xff0000); //红色
const c2 = new THREE.Color(0x0000ff); //蓝色
const c = new THREE.Color();
javascript 复制代码
c.lerpColors(c1,c2, 0);
console.log('颜色插值结果',c);
javascript 复制代码
c.lerpColors(c1,c2, 0.5);
console.log('颜色插值结果',c);

颜色对象Color颜色插值方法.lerp()

javascript 复制代码
c1.lerp(c2, percent);

颜色克隆.clone()

javascript 复制代码
const c = c1.clone().lerp(c2, percent);//颜色插值计算

二十一、查看或设置gltf几何体顶点

获取gltf模型几何体顶点数据

javascript 复制代码
loader.load("../地形.glb", function (gltf) { //gltf加载成功后返回一个对象
    model.add(gltf.scene); //三维场景添加到model组对象中
    //mesh表示地形网格模型
    const mesh = gltf.scene.children[0];
    // 顶点数据
    const att = mesh.geometry.attributes;
    console.log('att', att);
    // 顶点位置数据
    const pos = mesh.geometry.attributes.position;
    console.log('pos', pos);
})

几何体顶点索引属性geometry.index

javascript 复制代码
console.log('index', mesh.geometry.index);

顶点数量BufferAttribute.count

javascript 复制代码
const count = pos.count; //几何体顶点数量
console.log('count', count);

.getX().getY().getZ()

javascript 复制代码
  // 获取几何体第一个顶点的x坐标
  const x = pos.getX(0);
  console.log("第一个顶点的x", x);

.setX().setY().setZ()

pos.setY(0,100)把索引为0,也就是第一个顶点的y坐标设置为100.

javascript 复制代码
pos.setX(0,100);

批量重置几何体顶点y坐标

重置前

javascript 复制代码
loader.load("../地形.glb", function (gltf) {
    model.add(gltf.scene);
    //mesh表示地形网格模型
    const mesh = gltf.scene.children[0];
    // 顶点位置数据
    const pos = mesh.geometry.attributes.position;
    const count = pos.count; //几何体顶点数量
    // 批量设置所有几何体顶点位置的y坐标
    for (let i = 0; i < count; i++) {
        const y = pos.getY(i);//获取第i+1个顶点y坐标
        pos.setY(i,y*2)//设置第i+1个顶点y坐标为自身2倍
    }
})

重置后

二十二、山脉地形高度可视化

山脉几何体y坐标范围

javascript 复制代码
// 1. 计算模型y坐标高度差
    const yArr = [];//顶点所有y坐标,也就是地形高度
    for (let i = 0; i < count; i++) {
        yArr.push(pos.getY(i));//获取顶点y坐标,也就是地形高度
    }
    yArr.sort();//数组元素排序,从小到大
    const miny = yArr[0];//y最小值
    const maxy = yArr[yArr.length - 1];//y最大值
    const height = maxy - miny; //山脉整体高度 

根据山脉顶点高度设置渐变颜色

javascript 复制代码
// 2. 计算每个顶点的颜色值
const colorsArr = [];
const c1 = new THREE.Color(0x0000ff);//山谷颜色
const c2 = new THREE.Color(0xff0000);//山顶颜色
for (let i = 0; i < count; i++) {
    //当前高度和整体高度比值
    const percent = (pos.getY(i) - miny) / height;
    const c = c1.clone().lerp(c2, percent);//颜色插值计算
    colorsArr.push(c.r, c.g, c.b); 
}
const colors = new Float32Array(colorsArr);
// 设置几何体attributes属性的颜色color属性
mesh.geometry.attributes.color = new THREE.BufferAttribute(colors, 3);

Mesh渲染山脉顶点颜色

javascript 复制代码
// 3. 设置材质,使用顶点颜色渲染
mesh.material = new THREE.MeshLambertMaterial({
    vertexColors:true,
});

三种颜色渐变

model.js

javascript 复制代码
// 引入Three.js
import * as THREE from 'three';
// 引入gltf模型加载库GLTFLoader.js
import {
    GLTFLoader
} from 'three/addons/loaders/GLTFLoader.js';


const loader = new GLTFLoader(); //创建一个GLTF加载器

const model = new THREE.Group(); //声明一个组对象,用来添加加载成功的三维场景

loader.load("../地形.glb", function (gltf) { //gltf加载成功后返回一个对象

    model.add(gltf.scene); //三维场景添加到model组对象中
    //mesh表示地形网格模型
    const mesh = gltf.scene.children[0];
    const pos = mesh.geometry.attributes.position;
    const count = pos.count; //几何体顶点数量

    // 1. 计算模型y坐标高度差
    const yArr = []; //顶点所有y坐标,也就是地形高度
    for (let i = 0; i < count; i++) {
        yArr.push(pos.getY(i)); //获取顶点y坐标,也就是地形高度
    }
    yArr.sort();//数组元素排序,从小到大
    const miny = yArr[0];//y最小值
    const maxy = yArr[yArr.length - 1];//y最大值
    
    const height = maxy - miny; //山脉整体高度  

    // 2. 计算每个顶点的颜色值
    const colorsArr = [];
    const color1 = new THREE.Color(0x0000ff); //山谷颜色
    const color2 = new THREE.Color(0x00ff00); //山腰颜色
    const color3 = new THREE.Color(0xff0000); //山顶颜色
    for (let i = 0; i < count; i++) {
        //当前高度和整体高度比值
        const percent = (pos.getY(i) - miny) / height;
        // 颜色插值计算
        let c;
        if (percent <= 0.5) { //0.5作为颜色插值分界点
            // color1到color2之间插值
            c = color1.clone().lerp(color2, percent * 2)
        } else {
            // color2到color3之间插值
            c = color2.clone().lerp(color3, (percent - 0.5) * 2)
        }
        colorsArr.push(c.r, c.g, c.b);
    }
    const colors = new Float32Array(colorsArr);
    // 设置几何体attributes属性的颜色color属性
    mesh.geometry.attributes.color = new THREE.BufferAttribute(colors, 3);
    // 3. 设置材质,使用顶点颜色渲染
    mesh.material = new THREE.MeshLambertMaterial({
        vertexColors: true,
    });
})


export default model;

Threejs (10)

一、正投影相机

渲染范围设置

javascript 复制代码
// 正投影相机
const width = window.innerWidth; //canvas画布宽度
const height = window.innerHeight; //canvas画布高度
const k = width / height; //canvas画布宽高比
const s = 600;//控制left, right, top, bottom范围大小
const camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 8000);

相机位置和观察目标设置

javascript 复制代码
camera.position.set(1000, 2000, 1000);// 设置相机的 x、y、z 坐标值
camera.lookAt(0, 0, 0);//指向坐标原点

改变观察目标

正投影相机和透视投影相机区别

透视投影 相机模拟人在空中俯视地面的效果,如果使用正投影相机渲染效果就不太自然

透视投影

正投影

二、正投影相机-Canvas尺寸变化

WebGL渲染器更新Canvas画布尺寸

javascript 复制代码
// 画布跟随窗口变化
window.onresize = function () {
    renderer.setSize(window.innerWidth, window.innerHeight);

};

相机参数更新

当canvas画布尺寸发生变化的时候,需要更新透视投影相机PerspectiveCamera.aspect属性。

javascript 复制代码
// 画布跟随窗口变化
window.onresize = function () {
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
};

正投影相机OrthographicCameraleftright属性受到canvas画布宽高比影响,所以需要随着canvas画布更新。

javascript 复制代码
// Canvas画布跟随窗口变化
window.onresize = function () {
    const width = window.innerWidth; //canvas画布宽度
    const height = window.innerHeight; //canvas画布高度
    // 1. WebGL渲染器渲染的Cnavas画布尺寸更新
    renderer.setSize(width, height);
    // 2.1.更新相机参数
    const k = width / height; //canvas画布宽高比
    camera.left = -s*k;
    camera.right = s*k;
    // 2.2.相机的left, right, top, bottom属性变化了,通知threejs系统
    camera.updateProjectionMatrix();
};

三、包围盒Box3

包围盒Box3

javascript 复制代码
const box3 = new THREE.Box3()
console.log('box3',box3);
box3.min = new THREE.Vector3(-10, -10,0);
box3.max = new THREE.Vector3(100, 20,50);

计算模型最小包围盒.expandByObject()

javascript 复制代码
const box3 = new THREE.Box3();
box3.expandByObject(mesh); // 计算模型包围盒
console.log("查看包围盒", box3);

包围盒尺寸.getSize()

javascript 复制代码
const scale = new THREE.Vector3();
// getSize()计算包围盒尺寸
// 获得包围盒长宽高尺寸,结果保存在参数三维向量对象scale中
box3.getSize(scale);
console.log("模型包围盒尺寸", scale);

包围盒几何中心.getCenter()

javascript 复制代码
// 计算包围盒中心坐标
const center = new THREE.Vector3()
box3.getCenter(center)
console.log('模型中心坐标', center);

四、地图案例(包围盒、正投影)

data.js

javascript 复制代码
export default [
  // 河南边界轮廓边界经纬度坐标
  [110.3906, 34.585],
  [110.8301, 34.6289],
  [111.1816, 34.8047],
  [111.5332, 34.8486],
  [111.7969, 35.0684],
  [112.0605, 35.0684],
  [112.0605, 35.2881],
  [112.7637, 35.2002],
  [113.1152, 35.332],
  [113.6426, 35.6836],
  [113.7305, 36.3428],
  [114.873, 36.123],
  [114.9609, 36.0791],
  [115.1367, 36.2109],
  [115.3125, 36.0791],
  [115.4883, 36.167],
  [115.3125, 35.8154],
  [116.1035, 36.0791],
  [115.4883, 35.7275],
  [115.2246, 35.4199],
  [115.0488, 35.376],
  [114.7852, 35.0684],
  [115.4004, 34.8486],
  [115.5762, 34.585],
  [116.1914, 34.585],
  [116.1914, 34.4092],
  [116.543, 34.2773],
  [116.6309, 33.9258],
  [116.1914, 33.7061],
  [116.0156, 33.9697],
  [115.6641, 34.0576],
  [115.5762, 33.9258],
  [115.5762, 33.6621],
  [115.4004, 33.5303],
  [115.3125, 33.1787],
  [114.873, 33.1348],
  [114.873, 33.0029],
  [115.1367, 32.8711],
  [115.2246, 32.6074],
  [115.5762, 32.4316],
  [115.8398, 32.5195],
  [115.9277, 31.7725],
  [115.4883, 31.6846],
  [115.4004, 31.4209],
  [115.2246, 31.4209],
  [115.1367, 31.5967],
  [114.7852, 31.4648],
  [114.6094, 31.5527],
  [114.5215, 31.7725],
  [114.1699, 31.8604],
  [113.9941, 31.7725],
  [113.8184, 31.8604],
  [113.7305, 32.4316],
  [113.4668, 32.2998],
  [113.2031, 32.4316],
  [112.3242, 32.3438],
  [111.5332, 32.6074],
  [111.0059, 33.2666],
  [111.0059, 33.5303],
  [110.6543, 33.8379],
  [110.6543, 34.1455],
  [110.4785, 34.2334],
  [110.3906, 34.585],
];

model.js

javascript 复制代码
const pointsArr = []; // 一组二维向量表示一个多边形轮廓坐标
data.forEach(function (e) {
  // data坐标数据转化为Vector2构成的顶点数组
  const v2 = new THREE.Vector2(e[0], e[1]);
  pointsArr.push(v2);
});
// Shape表示一个平面多边形轮廓,参数是二维向量构成的数组pointsArr
const shape = new THREE.Shape(pointsArr);
// 多边形shape轮廓作为ShapeGeometry参数,生成一个多边形平面几何体
const geometry = new THREE.ShapeGeometry(shape);

const material = new THREE.MeshLambertMaterial({
  color: 0xffffff,
  side: THREE.DoubleSide,
});
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh


export default mesh;

选择相机

javascript 复制代码
// 正投影相机
const width = window.innerWidth; //canvas画布宽度
const height = window.innerHeight; //canvas画布高度
const k = width / height; //canvas画布宽高比
const s = 50; //控制left, right, top, bottom范围大小
const camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 8000);
camera.position.set(300, 300, 300); 
camera.lookAt(0, 0, 0); //指向坐标原点

河南地图并没有居中显示,在canvas画布上显示的效果也比较小。

包围盒Box3计算模型的中心位置和尺寸

javascript 复制代码
// 包围盒计算模型对象的大小和位置
const box3 = new THREE.Box3();
box3.expandByObject(mesh); // 计算模型包围盒
const size = new THREE.Vector3();
box3.getSize(size); // 计算包围盒尺寸
// console.log('模型包围盒尺寸',size);
const center = new THREE.Vector3();
box3.getCenter(center); // 计算包围盒中心坐标
// console.log('模型中心坐标',center);

地图居中显示

设置相机.lookAt()参数指向包围盒几何中心即可。

javascript 复制代码
const x = 113.51,y = 33.88;
camera.lookAt(x, y, 0);

注意如果使用了OrbitControls,需要设置.target.lookAt()参数是相同坐标。

javascript 复制代码
const controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(x, y, 0); //与lookAt参数保持一致
controls.update();//update()函数内会执行camera.lookAt(controls.target)

地图基本填充cnavas画布

把正投影相机控制上下左右的变量s,设置为地图模型整体尺寸的一半左右即可。

javascript 复制代码
// const s = 50; //控制left, right, top, bottom范围大小
const s = 2.5;//根据包围盒大小调整s,包围盒y方向尺寸的一半左右
const camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 8000);

地图平行于canvas画布

javascript 复制代码
camera.position.set(x, y, 300);

五、相机动画(.position和.lookAt())

相机运动动画

javascript 复制代码
// 渲染循环
function render() {
    camera.position.z -= 0.3;//相机直线运动动画
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}
render();

相机圆周运动

javascript 复制代码
// 渲染循环
let angle = 0; //用于圆周运动计算的角度值
const R = 100; //相机圆周运动的半径
function render() {
    angle += 0.01;
    // 相机y坐标不变,在XOZ平面上做圆周运动
    camera.position.x = R * Math.cos(angle);
    camera.position.z = R * Math.sin(angle);
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}
render();

执行lookAt()计算相机视线方向

改变.position属性后,如果不执行.lookAt()方法,相机的观察方向默认不变。

javascript 复制代码
// .position改变,重新执行lookAt(0,0,0)计算相机视线方向
    camera.lookAt(0,0,0);

六、不同方向的投影视图

javascript 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Three.js中文网:www.webgl3d.cn</title>
    <style>
        body {
            overflow: hidden;
            margin: 0px;
        }

        .bu {
            background: #393535;
            width: 60px;
            height: 60px;
            text-align: center;
            color: #ffffff;
            display: inline-block;
            background-color: rgb(100, 91, 91);
            border-radius: 30px;
        }

        .bu:hover {
            background-color: rgb(150, 141, 141);
        }

        .pos {
            position: absolute;
            left: 50%;
            margin-left: -65px;
            bottom: 100px;
        }
    </style>
</head>

<body>
    <div class="pos">
        <div id="x"
            class="bu">x</div>
        <div id="y"
            class="bu"
            style="margin-left: 10px;">y</div>
        <div id="z"
            class="bu"
            style="margin-left: 10px;">z</div>
    </div>
    <!-- type="importmap"功能:.html文件中也能和nodejs开发环境中一样方式,引入npm安装的js库 -->
    <script type="importmap">
        {
			"imports": {
				"three": "../../../three.js/build/three.module.js",
                "three/addons/": "../../../three.js/examples/jsm/"
			}
		}
	</script>
    <script src="./index.js"
        type="module">
        </script>
</body>

</html>

x轴方向观察

javascript 复制代码
document.getElementById("x").addEventListener("click", function () {
  camera.position.set(500, 0, 0); //x轴方向观察
  camera.lookAt(0, 0, 0); //重新计算相机视线方向
});

y轴方向观察

javascript 复制代码
// 通过UI按钮改变相机观察角度
document.getElementById("y").addEventListener("click", function () {
  camera.position.set(0, 500, 0); //y轴方向观察
  camera.lookAt(0, 0, 0); //重新计算相机视线方向
});

z轴方向观察

javascript 复制代码
// 通过UI按钮改变相机观察角度
document.getElementById('z').addEventListener('click', function () {
    camera.position.set(0, 0, 500); //z轴方向观察
    camera.lookAt(0, 0, 0); //重新计算相机视线方向
})

七、旋转渲染结果(.up相机上方向)

测试改变上方向.up

注意执行顺序问题

注意.up属性和.position属性一样,如果在.lookAt()执行之后改变,需要重新执行.lookAt()

八、管道漫游案例

管道模型

javascript 复制代码
// 三维样条曲线
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(90, -40, 60),
    new THREE.Vector3(120, 30, 30),
]);
// 样条曲线path作为TubeGeometry参数生成管道
const geometry = new THREE.TubeGeometry(path, 200, 5, 30);
const texLoader = new THREE.TextureLoader(); 
//纹理贴图
const texture = texLoader.load('./diffuse.jpg');
//UV坐标U方向阵列模式
texture.wrapS = THREE.RepeatWrapping;
//纹理沿着管道方向阵列(UV坐标U方向)
texture.repeat.x = 10;
const material = new THREE.MeshLambertMaterial({
    map:texture,
    side: THREE.DoubleSide, //双面显示看到管道内壁
});
const mesh = new THREE.Mesh(geometry, material);

相机选择透视投影相机

获得运动轨迹上的顶点

model.js

javascript 复制代码
// 从曲线上等间距获取一定数量点坐标
const pointsArr = path.getSpacedPoints(500);
console.log("pointsArr:", pointsArr);
javascript 复制代码
export {mesh,pointsArr};

相机放在管道内轨迹线上

index.js

javascript 复制代码
import {mesh,pointsArr} from './model.js'; //模型对象
// 从曲线上等间距获取一定数量点坐标
const pointsArr = path.getSpacedPoints(500);
const i = 100;
// 相机位置:曲线上当前点pointsArr[i]
camera.position.copy(pointsArr[i]);
// 相机观察目标:当前点的下一个点pointsArr[i + 1]
camera.lookAt(pointsArr[i + 1]);

改变视场角度fov调节渲染效果

javascript 复制代码
const camera = new THREE.PerspectiveCamera(90, width / height, 1, 3000);

相机控件.target.lookAt()参数一致

javascript 复制代码
const controls = new OrbitControls(camera, renderer.domElement);
controls.target.copy(pointsArr[i+1]);
controls.update();
javascript 复制代码
// 从曲线上等间距获取一定数量点坐标
const pointsArr = path.getSpacedPoints(500);
// 渲染循环
let i = 0; //在渲染循环中累加变化
function render() {
    if (i < pointsArr.length - 1) {
        // 相机位置设置在当前点位置
        camera.position.copy(pointsArr[i]);
        // 曲线上当前点pointsArr[i]和下一个点pointsArr[i+1]近似模拟当前点曲线切线
        // 设置相机观察点为当前点的下一个点,相机视线和当前点曲线切线重合
        camera.lookAt(pointsArr[i + 1]);
        i += 1; //调节速度
    } else {
        i = 0
    }
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}
render();

九、9.OrbitControls旋转缩放限制

禁止右键平移.enablePan属性

index.js

javascript 复制代码
controls.enablePan = false; //禁止右键拖拽

禁止缩放或旋转

javascript 复制代码
controls.enableZoom = false;//禁止缩放
javascript 复制代码
controls.enableRotate = false; //禁止旋转

OrbitControls.target属性

相机控件OrbitControls.target属性对应的就是相机的.lookAt()观察目标。

执行controls.update();,相机控件内部会执行camera.lookAt(controls.target)

javascript 复制代码
// controls.target默认值是坐标原点
controls.target.set(x, y, z);
//update()函数内会执行camera.lookAt(x, y, z)
controls.update(); 

透视投影相机缩放范围

.minDistance表示相机位置.position和相机目标观察点controls.target的最小距离。

javascript 复制代码
//相机位置与观察目标点最小值
controls.minDistance = 200;

.maxDistance表示相机位置.position和相机目标观察点controls.target的最大距离。

javascript 复制代码
//相机位置与观察目标点最大值
controls.maxDistance = 500;

正投影缩放范围

javascript 复制代码
// 缩放范围
controls.minZoom = 0.5;
controls.maxZoom = 2;

相机位置与目标观察点距离.getDistance()

javascript 复制代码
//相机位置与目标观察点距离
const dis = controls.getDistance();
console.log('dis',dis);

可视化设置相机缩放范围

javascript 复制代码
controls.addEventListener('change',function(){
    //相机位置与目标观察点距离
    const dis = controls.getDistance();
    console.log('dis',dis);
})

设置旋转范围

javascript 复制代码
// 上下旋转范围
controls.minPolarAngle = 0;//默认值0
controls.maxPolarAngle = Math.PI;//默认值Math.PI

.maxPolarAngle属性设置为90度,这样不能看到工厂模型底部

javascript 复制代码
controls.maxPolarAngle = Math.PI/2;

通过.minAzimuthAngle.maxAzimuthAngle属性控制左右的旋转范围。

javascript 复制代码
// 左右旋转范围
controls.minAzimuthAngle = -Math.PI/2;
controls.maxAzimuthAngle = Math.PI/2;

十、相机控件MapControls

引入相机控件MapControls

javascript 复制代码
// 引入相机控件`MapControls`
import { MapControls } from 'three/addons/controls/MapControls.js';

使用MapControls

javascript 复制代码
const controls = new MapControls(camera, renderer.domElement);

MapControls本质

javascript 复制代码
controls.addEventListener('change', function () {
    // 鼠标右键旋转时候,查看.position变化
    // 鼠标左键拖动的时候,查看.position、.target的位置会变化
    console.log('camera.position',camera.position);
    console.log('controls.target',controls.target);
});

缩放、旋转或平移禁止

整体思路是一样的,只是鼠标操作有差异。

javascript 复制代码
controls.enablePan = false; //禁止平移
javascript 复制代码
controls.enableZoom = false;//禁止缩放
javascript 复制代码
controls.enableRotate = false; //禁止旋转

透视投影相机缩放范围

javascript 复制代码
//相机位置与观察目标点最小值
controls.minDistance = 200;
//相机位置与观察目标点最大值
controls.maxDistance = 500;

设置旋转范围

javascript 复制代码
// 上下旋转范围
controls.minPolarAngle = 0;
controls.maxPolarAngle = Math.PI/2;
javascript 复制代码
// 左右旋转范围
controls.minAzimuthAngle = -Math.PI/2;
controls.maxAzimuthAngle = Math.PI/2;
相关推荐
只想要搞钱2 小时前
python 学习记录--1(开发工具,链接数据库mysql)
python·学习
kitsch0x972 小时前
论文学习_Binary-level Directed Fuzzing for Use-After-Free Vulnerabilities
学习
丝斯20112 小时前
AI学习笔记整理(43)——NLP之大规模预训练模型BERT
人工智能·学习·自然语言处理
saoys3 小时前
Opencv 学习笔记:形态学开 / 闭运算(解决噪点与孔洞问题)
笔记·opencv·学习
小猪佩奇TONY3 小时前
Linux 内核学习(16) --- linux x86-64 虚拟地址空间和区域
linux·运维·学习
深蓝海拓3 小时前
PySide6,QEventLoop.exec()的使用
笔记·python·qt·学习·pyqt
开开心心_Every3 小时前
离线黑白照片上色工具:操作简单效果逼真
java·服务器·前端·学习·edge·c#·powerpoint
爱喝水的鱼丶3 小时前
SAP-ABAP:SAP性能侦探:STAD事务码的深度解析与应用实战
开发语言·数据库·学习·sap·abap
专注于大数据技术栈3 小时前
java学习--Collection
java·开发语言·学习