美文网首页
Three.js做一个粒子发射器

Three.js做一个粒子发射器

作者: 思我恋 | 来源:发表于2022-11-07 16:58 被阅读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);
      }
    }
    

    相关文章

      网友评论

          本文标题:Three.js做一个粒子发射器

          本文链接:https://www.haomeiwen.com/subject/iezbtdtx.html