3d 地图飞线
代码仓库:
核心代码:
import flyLine from "./constant/flyLine.json";
const initFlyLine = () => {
flyLine.forEach(item => {
const [from_x, from_y] = d3Function(item.from)
const [to_x, to_y] = d3Function(item.to)
const start = new THREE.Vector3(from_x, -from_y, 32); // 起点坐标
const v1Point = [item.from[0] + (item.to[0] - item.from[0]) / 4, item.from[1] + (item.to[1] - item.from[1]) / 4]
const [v1_x, v1_y] = d3Function(v1Point)
const v1 = new THREE.Vector3(v1_x, -v1_y, 100);
const v2Point = [item.from[0] + ((item.to[0] - item.from[0]) * 3) / 4, item.from[1] + ((item.to[1] - item.from[1]) * 3) / 4]
const [v2_x, v2_y] = d3Function(v2Point)
const v2 = new THREE.Vector3(v2_x, -v2_y, 100);
const end = new THREE.Vector3(to_x, -to_y, 32); // 终点坐标
// 创建三次贝塞尔曲线
const curve = new THREE.CubicBezierCurve3(start, v1, v2, end);
// 使用 TubeGeometry 根据贝塞尔曲线绘制管道
const tubeGeometry = new THREE.TubeGeometry(curve, 256, 2, 8, false); // 曲线256段, 半径2, 20个横截面
// 创建材质,颜色为白色
const material = new THREE.MeshBasicMaterial({color: item.color});
// 创建管道网格
const tubeMesh = new THREE.Mesh(tubeGeometry, material);
// 将管道添加到场景中
showScene.add(tubeMesh);
const points = curve.getPoints(1000)
const bufferGeometry = createBufferGeometry(points)
const shaderMaterial = createShaderMaterial()
const point = new THREE.Points(bufferGeometry, shaderMaterial)
showScene.add(point)
// 设置着色器的动画
gsap.fromTo(shaderMaterial.uniforms.uTime,
{ value: 0 },
{
// 实现飞线钻地效果需要让 动画节段数 = 飞线长度 + 飞线点数量
value: 80 + 1000,
duration: 3,
repeat: -1,
delay: 0,
ease: "none",
onUpdate: () => {},
}
);
})
}
// 创建着色器
function createShaderMaterial() {
// 起点颜色
let color1 = "#0c57e3";
return new THREE.ShaderMaterial({
depthTest: false,
uniforms: {
// 线条颜色
uColor: {
value: new THREE.Color(color1),
},
// 时间1-1000
uTime: {
value: 0,
},
// 水滴宽度
uWidth: {
value: 200,
},
// 水滴长度
uLength: {
value: 80,
},
vSize: {
value: 10.0
},
},
vertexShader: /*glsl*/ `
attribute float aIndex; // 内部属性 浮点 当前序号
uniform float uTime; // 全局变量 浮点 当前时间
uniform float uWidth; // 全局变量 浮点 线段宽度
uniform vec3 uColor; // 全局变量 颜色 设置的颜色
varying float vSize; // 片元变量(需要传递到片面着色器) 浮点 尺寸
uniform float uLength; // 全局变量 浮点 线段长度
void main(){
vec4 viewPosition = viewMatrix * modelMatrix * vec4(position,1);
gl_Position = projectionMatrix * viewPosition; // 顶点矩阵变换 设置各个点的位置
// 当前顶点的位置处于线段长度内 则设置水滴大小
if(aIndex >= uTime - uLength && aIndex < uTime){
// 水滴大小根据当前位置慢慢变小
// p1 uWidth越大水滴越粗
// vSize = uWidth * ((aIndex - uTime + uLength) / uLength);
// p2 uWidth越大水滴越细
vSize = (aIndex + uLength - uTime) / uWidth;
}
gl_PointSize = vSize;
}
`,
fragmentShader: /*glsl*/ `
varying float vSize;
uniform vec3 uColor;
void main(){
// 透明度根据当前大小确定是否展示
if(vSize<=0.0){
gl_FragColor = vec4(1,0,0,0);
}else{
gl_FragColor = vec4(uColor,1);
}
}
`,
transparent: true,
vertexColors: false,
});
}
// 创建bufferGeometry
function createBufferGeometry(points) {
const indexList = points.map((_, index) => index);
const bufferGeometry = new BufferGeometry().setFromPoints(points);
// 给几何体添加自定义的索引标识 用来后续根据索引设置点的透明度
bufferGeometry.setAttribute(
"aIndex",
new THREE.Float32BufferAttribute(indexList, 1)
);
return bufferGeometry;
}
[
{
"from": [
104.065735,
30.659462
],
"to": [
116.405285,
39.904989
],
"color": "#00fbff"
},
{
"from": [
104.065735,
30.659462
],
"to": [
121.472644,
31.231706
],
"color": "#ff0004"
},
{
"from": [
104.065735,
30.659462
],
"to": [
87.617733,
43.792818
],
"color": "#d8ff94"
},
{
"from": [
104.065735,
30.659462
],
"to": [
121.509062,
25.044332
],
"color": "#08c9ff"
},
{
"from": [
104.065735,
30.659462
],
"to": [
112.982279,
28.19409
],
"color": "#ff00ee"
}
]
下一篇: