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();
};
正投影相机OrthographicCamera的left、 right属性受到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;