Shape 对象和轮廓填充 ShapeGeometry

优质
小牛编辑
130浏览
2023-12-01

填充顶点构成的轮廓

通过下面代码定义了6个顶点坐标,也可以说是5个,最后一个和第一个是重合的,构成一个五边形区域。然后使用这一组二维顶点坐标作为Shape的参数构成一个五边形轮廓。把五边形轮廓Shape作为ShapeGeometry的参数,可以根据轮廓坐标计算出一系列三角形面填充轮廓,形成一个平面几何体。

var points = [
  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),
  new THREE.Vector2(-50, -50),
]
// 通过顶点定义轮廓
var shape = new THREE.Shape(points);
// shape可以理解为一个需要填充轮廓
// 所谓填充:ShapeGeometry算法利用顶点计算出三角面face3数据填充轮廓
var geometry = new THREE.ShapeGeometry(shape, 25);

调用Shape圆弧方法.absarc()绘制一个圆形轮廓,然后通过ShapeGeometry可以把该圆形轮廓填充为一个圆形平面几何体。

你可以尝试更改ShapeGeometry的参数2,参数2表示细分数,然后网格材质设置为wireframe: true查看圆形区域填充三角形的数量变化。

// 通过shpae基类path的方法绘制轮廓(本质也是生成顶点)
var shape = new THREE.Shape();
shape.absarc(0,0,100,0,2*Math.PI);//圆弧轮廓
console.log(shape.getPoints(15));//查看shape顶点数据
var geometry = new THREE.ShapeGeometry(shape, 25);

下面代码是通过shpae绘制了一个矩形区域,更多相关的轮廓绘制方法可以查看Shape文档。

// 通过shpae基类path的方法绘制轮廓(本质也是生成顶点)
var shape = new THREE.Shape();
// 四条直线绘制一个矩形轮廓
shape.moveTo(0,0);//起点
shape.lineTo(0,100);//第2点
shape.lineTo(100,100);//第3点
shape.lineTo(100,0);//第4点
shape.lineTo(0,0);//第5点

shape外轮廓和内轮廓

shape可以用来绘制外轮廓,也可以用来绘制内轮廓,ShapeGeometry会使用三角形自动填充shape内轮廓和外轮廓中间的中部。

下面给出了几个通过shape绘制的轮廓图案。

1.jpg

// 圆弧与直线连接
var shape = new THREE.Shape(); //Shape对象
var R = 50;
// 绘制一个半径为R、圆心坐标(0, 0)的半圆弧
shape.absarc(0, 0, R, 0, Math.PI);
//从圆弧的一个端点(-R, 0)到(-R, -200)绘制一条直线
shape.lineTo(-R, -200);
// 绘制一个半径为R、圆心坐标(0, -200)的半圆弧
shape.absarc(0, -200, R, Math.PI, 2 * Math.PI);
//从圆弧的一个端点(R, -200)到(-R, -200)绘制一条直线
shape.lineTo(R, 0);
var geometry = new THREE.ShapeGeometry(shape, 30);

2

// 一个外轮廓圆弧嵌套三个内圆弧轮廓
var shape = new THREE.Shape(); //Shape对象
//外轮廓
shape.arc(0, 0, 100, 0, 2 * Math.PI);
// 内轮廓1
var path1 = new THREE.Path();
path1.arc(0, 0, 40, 0, 2 * Math.PI);
// 内轮廓2
var path2 = new THREE.Path();
path2.arc(80, 0, 10, 0, 2 * Math.PI);
// 内轮廓3
var path3 = new THREE.Path();
path3.arc(-80, 0, 10, 0, 2 * Math.PI);
//三个内轮廓分别插入到holes属性中
shape.holes.push(path1, path2, path3);

3.jpg

// 矩形嵌套矩形或圆弧
var shape=new THREE.Shape();//Shape对象
//外轮廓
shape.moveTo(0,0);//起点
shape.lineTo(0,100);//第2点
shape.lineTo(100,100);//第3点
shape.lineTo(100,0);//第4点
shape.lineTo(0,0);//第5点
//内轮廓
var path=new THREE.Path();//path对象
// path.arc(50,50,40,0,2*Math.PI);//圆弧
path.moveTo(20,20);//起点
path.lineTo(20,80);//第2点
path.lineTo(80,80);//第3点
path.lineTo(80,20);//第4点
path.lineTo(20,20);//第5点
shape.holes.push(path);//设置内轮廓

多个轮廓同时填充

// 轮廓对象1
 var shape=new THREE.Shape();
 shape.arc(-50,0,30,0,2*Math.PI);
 // 轮廓对象2
 var shape2=new THREE.Shape();
 shape2.arc(50,0,30,0,2*Math.PI);
 // 轮廓对象3
 var shape3=new THREE.Shape();
 shape3.arc(0,50,30,0,2*Math.PI);
// 多个shape作为元素组成数组,每一个shpae可以理解为一个要填充的轮廓
var geometry = new THREE.ShapeGeometry([shape,shape2,shape3], 30);

实例:根据河南边界坐标填充轮廓

// 河南边界轮廓坐标
let arr = [
  [110.3906, 34.585],
  [110.8301, 34.6289],
...
...
...
  [110.6543, 34.1455],
  [110.4785, 34.2334],
  [110.3906, 34.585]
]
var points = [];
// 转化为Vector2构成的顶点数组
arr.forEach(elem => {
  points.push(new THREE.Vector2(elem[0],elem[1]))
});
// 样条曲线生成更多的点
var SplineCurve = new THREE.SplineCurve(points)
var shape = new THREE.Shape(SplineCurve.getPoints(300));
// var shape = new THREE.Shape(points);
var geometry = new THREE.ShapeGeometry(shape);
geometry.center();//几何体居中
geometry.scale(30,30,30);//几何体缩放
var material = new THREE.MeshPhongMaterial({
  color: 0x0000ff,
  side: THREE.DoubleSide //两面可见
}); //材质对象
var mesh = new THREE.Mesh(geometry, material); //网格模型对象