Threejs 实现3D 地图(06)3d 地图飞线动画

3d 地图飞线

代码仓库:

King/threejs-3d-map

核心代码:


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"
  }
]

下一篇:

Threejs 实现3D 地图(07)3d 地图 完结-CSDN博客