Three.js做一个粒子发射器

2022-11-07  本文已影响0人  思我恋
import * as THREE from "three";
import TWEEN from "@tweenjs/tween.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import gltfUrl from "@/assets/models/11-5-1-processed.glb?url";
import pngUrl from "@/assets/textures/raindrop.png?url";

window.THREE = THREE;
export default function () {
  let camera: THREE.PerspectiveCamera,
    scene: THREE.Scene,
    renderer: THREE.WebGLRenderer,
    controls: OrbitControls;
  const textureLoader = new THREE.TextureLoader();
  const container = document.createElement("div");
  let clock = new THREE.Clock();
  let group: THREE.Group;
  let itemHeight: number;

  init();

  return container;

  function init() {
    createScene();
    createObj();
    createRenderer();
    createCamera();
    createControls();
    animate();
  }

  function createObj() {
    // 创建的单个粒子的尺寸为(radius * 2, height + radius * 2, radius * 2)
    const radius = 4;
    const height = 192;
    itemHeight = radius * 2 + height;
    // 存放样条曲线的点集
    const points = [];
    //上半部分四分之一圆弧
    for (let i = Math.PI / 2; i > 0; i -= 0.3) {
      points.push(
        new THREE.Vector2(
          Math.cos(i) * radius,
          Math.sin(i) * radius + height / 2
        )
      );
    }
    //中间直线
    for (let i = height / 2; i > -height / 2; i -= height) {
      points.push(new THREE.Vector2(radius, i));
    }
    //下半部分四分之一圆弧
    for (let i = 0; i <= Math.PI / 2; i += 0.3) {
      points.push(
        new THREE.Vector2(
          Math.cos(i) * radius,
          -Math.sin(i) * radius - height / 2
        )
      );
    }

    // 补充一个点,去掉底部的小洞
    points.push(new THREE.Vector2(0, -radius - height / 2));
    console.log(points);
    const geometry = new THREE.LatheGeometry(points);
    const pngec = textureLoader.load(pngUrl);
    // 围绕中心点旋转180度
    // pngec.center = new THREE.Vector2(0.5, 0.5);
    // pngec.rotation = Math.PI;
    // pngec.mapping = THREE.UVMapping;
    const material = new THREE.MeshBasicMaterial({
      transparent: true,
      opacity: 0.6,
      vertexColors: false,
      map: pngec,
      blending: THREE.AdditiveBlending,
      color: new THREE.Color(0xffffff),
    });
    const mesh = new THREE.Mesh(geometry, material);

    group = new THREE.Group();
    group.name = "粒子发射器";

    for (let i = 0; i < 10; i++) {
      const copy_mesh = mesh.clone();
      const position = new THREE.Vector3(
        THREE.MathUtils.randFloat(0, 1000),
        0,
        THREE.MathUtils.randFloat(0, 1000)
      );
      copy_mesh.position.set(position.x, position.y, position.z);
      copy_mesh.userData = {
        startTime: THREE.MathUtils.randFloat(0, 6),
        speed: THREE.MathUtils.randFloat(1, 10),
        // speed: 1,
      };
      copy_mesh.scale.set(1, 0, 1);
      group.add(copy_mesh);
    }
    scene.add(group);
  }

  function createCamera() {
    camera = new THREE.PerspectiveCamera(
      45,
      window.innerWidth / window.innerHeight,
      1,
      15000
    );
    camera.position.set(200, 500, 200);
  }

  function createScene() {
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0x333333);
    scene.add(new THREE.AxesHelper(1000));
  }

  function createControls() {
    controls = new OrbitControls(camera, renderer.domElement);
  }

  function createRenderer() {
    renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    container.appendChild(renderer.domElement);
  }

  //
  function animate() {
    requestAnimationFrame(animate);
    // 获取动画已经开始的时间
    const elapsedTime = clock.getElapsedTime();
    const topHeight = 1000;
    group.traverse((obj) => {
      // 粒子在y轴,由0到1000之间移动
      if (obj.type === "Mesh") {
        const startTime = obj.userData.startTime;
        const speed = obj.userData.speed;
        if (elapsedTime >= startTime || true) {
          const position_y = obj.position.y;
          // 用于获取物体的物理尺寸
          const sizeVect = new THREE.Vector3();
          const box = new THREE.Box3().setFromObject(obj);
          box.getSize(sizeVect);
          // 以下用于处理缩放
          let scaleY = obj.scale.y;
          if (position_y <= itemHeight / 2) {
            // 处于增长阶段
            scaleY = scaleY + speed / itemHeight;
          } else if (position_y >= topHeight - itemHeight / 2) {
            // 处于缩小阶段
            scaleY = scaleY - speed / itemHeight;
          }
          // 处理缩放的极限值
          if (scaleY >= 1) scaleY = 1;
          if (scaleY <= 0) scaleY = 0;

          obj.scale.setY(scaleY);
          // position记录的是中心点
          // 以下用于处理位移
          let add_posi_y = position_y + (scaleY === 1 ? speed : speed / 2);
          if (add_posi_y >= topHeight) add_posi_y = 0;
          obj.position.setY(add_posi_y);
          // console.log(box.max);
        }
      }
    });

    controls.update();
    renderer.render(scene, camera);
  }
}
上一篇下一篇

猜你喜欢

热点阅读