vue+three.js 五彩烟花效果封装+加载字体

嗨,我是小路。今天主要和大家分享的主题是"vue+three.js 五彩烟花效果封装+加载字体"。

在做烟花的基础的基础上,加上文字字体,这是很多背景版常用的基础极端。如节日庆典。今天主要是准备一个简单的端午节快乐的字体面板。

1.FontLoader、TextGeometry的加载

注意:在three.js中,在加载字体的时候,不能按照库包里面位置进行加载,需要加载成如下:

javascript 复制代码
import { FontLoader } from "three/addons/loaders/FontLoader.js";
import { TextGeometry } from "three/addons/geometries/TextGeometry.js";

2.字体json的加载

注意:在three.js中,在加载字体的时候,需要将字体转换成json格式;当然也可以用three.js提供的字体库;

3.烟花类的封装以及颜色的改变

注意:在进行方法封装时,可以将类通过export default进行封装,同时传入scene,这样保证整个屏幕在创建烟花之后,能在屏幕上加载出来;同时在材料中,进行颜色设置;去除顶点颜色配置,并设置默认的颜色;

二、实例代码

javascript 复制代码
<template>
  <div class="pageBox">
    <div class="leftBox" ref="leftRef"></div>
  </div>

</template>
<script setup>
import { onMounted, reactive, ref } from 'vue';
import * as THREE from 'three';
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { FontLoader } from "three/addons/loaders/FontLoader.js";
import { TextGeometry } from "three/addons/geometries/TextGeometry.js";
import Firework from "../utils/Firework"

const leftRef = ref();
// 定义相机输出画布的尺寸(单位:像素px)
let width = window.innerWidth; //宽度
let height = window.innerHeight; //高度
// 创建3D场景对象Scene
const scene = new THREE.Scene();
//设置背景色
scene.background = new THREE.Color(0x002244);

const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
camera.position.z = 5;

// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();

const createLight = () => {
  const pointLight = new THREE.PointLight(0xffffff, 0.8);
  pointLight.position.set(10, 10, 10);
  scene.add(pointLight);
  // 添加光源和背景等(可选)
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.8); // 环境光
  scene.add(ambientLight);
}
let currentText;//生成的字体模型

const createFont = (text = "端午节快乐",
  size = 1,
  height = 0.4,//字体的宽度
  bevel = false) => {
  if (currentText) {
    scene.remove(currentText);
  }

  const fontLoader = new FontLoader();
  fontLoader.load('./fonts/FangSong_Regular.json',function(font){
    const textGeometry = new TextGeometry(text,{
      font: font,
      size: size,
      height: height,
      curveSegments: 32,
      bevelEnabled: bevel,
      bevelThickness: 0.05,
      bevelSize: 0.02,
      bevelOffset: 0,
      bevelSegments: 8,
    });
    textGeometry.center();

    const material = new THREE.MeshStandardMaterial({
      color: 0xffaa00,//设置字体颜色
      metalness: 0.3,//金属性贴图
      roughness: 0.8,//粗糙程度
    });

    currentText = new THREE.Mesh(textGeometry, material);
    scene.add(currentText);

  })
}

const fireworks = [];
/**
 * 创建随机位置的烟花
 * 在场景的合理范围内随机选择位置
 */
const createRandomFirework = () => {
  const x = (Math.random() * 2 - 1) * 30; // x范围:-30到30
  const y = (Math.random() * 2 - 1) * 25; // y范围:-25到25
  const z = (Math.random() * 2 - 1) * 25; // y范围:-25到25
  fireworks.push(new Firework(x, y, z,scene));
}

const renderFirework = ()=>{
  // 有25%的概率生成新烟花
  if (Math.random() < 0.25) {
    createRandomFirework();
  }
  
  // 更新所有烟花,移除已经消失的烟花
  for (let i = fireworks.length - 1; i >= 0; i--) {
  
    const alive = fireworks[i].update(scene);
    if (!alive) {
      fireworks[i].dispose(scene);
      fireworks.splice(i, 1);
    }

  }
}

onMounted(() => {
  createLight();
  initData()

  //添加相机空间
  const controls = new OrbitControls(camera, renderer.domElement);
  // 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
  controls.addEventListener('change', function () {
    renderer.render(scene, camera); //执行渲染操作
  });//监听鼠标、键盘事件
  renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
  //将innerHTML置空,避免append重复添加渲染
  leftRef.value.innerHTML = ''
  leftRef.value.append(renderer.domElement);

})
const initData = () => {
  //创建字体
  createFont();
  render();
}
function render() {
  requestAnimationFrame(render);
  renderFirework();
  renderer.render(scene, camera);
}


</script>
<style scoped lang="less">
.pageBox {
  width: 100%;
  height: 100vh;
  padding: 0;
  margin: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;

  .rightBox {
    width: 100%;
    height: 100%;
  }
}
</style>
javascript 复制代码
/**
 * 烟花粒子类
 * 负责创建和管理单个烟花的所有粒子
 */
import * as THREE from 'three';
/**
 * 烟花粒子类
 * 负责创建和管理单个烟花的所有粒子
 */
export default class Firework {
  constructor(x, y, z,scene) {
    // 初始化属性
    this.particles = []; // 粒子数组
    this.geometry = new THREE.BufferGeometry(); // 粒子几何体
    this.count = 10000; // 粒子数量
    this.positions = new Float32Array(this.count * 3); // 粒子位置数组
    this.velocities = []; // 粒子速度数组
    this.colors = new Float32Array(this.count * 3); // 粒子颜色数组
    this.sizes = new Float32Array(this.count); // 粒子大小数组
    this.life = new Float32Array(this.count); // 粒子生命周期数组
    this.scene = scene;
    //定义可以渲染的颜色
    this.colorArr = [0xfff44ff,0xfff33ff,0xff00fff,0xff34fff,0xff45fff,0xfff33ff,0xfff22ff,0xfffff00,0xfffffff,0xfffff11]

    // 初始化每个粒子
    for (let i = 0; i < this.count; i++) {
      // 使用球面坐标系计算粒子初始方向
      const phi = Math.random() * Math.PI * 2; // 水平角度
      const theta = Math.random() * Math.PI; // 垂直角度
      const velocity = 2 + Math.random() * 2; // 随机速度

      // 计算粒子速度向量
      this.velocities.push(
        velocity * Math.sin(theta) * Math.cos(phi), // x方向速度
        velocity * Math.sin(theta) * Math.sin(phi), // y方向速度
        velocity * Math.cos(theta) // z方向速度
      );

      // 设置粒子初始位置
      this.positions[i * 3] = x; // x坐标
      this.positions[i * 3 + 1] = y; // y坐标
      this.positions[i * 3 + 2] = z; // z坐标

      // 设置粒子颜色(红色为主,带随机变化)
      this.colors[i * 3] = 1.0; // 红色通道
      this.colors[i * 3 + 1] = Math.random() * 0.2; // 绿色通道
      this.colors[i * 3 + 2] = Math.random() * 0.2; // 蓝色通道

      // 初始化粒子大小和生命值
      this.sizes[i] = 0.3; // 初始大小
      this.life[i] = 1.0; // 初始生命值
    }

    // 设置几何体属性
    this.geometry.setAttribute(
      "position",
      new THREE.BufferAttribute(this.positions, 3)
    );
    this.geometry.setAttribute(
      "color",
      new THREE.BufferAttribute(this.colors, 3)
    );
    this.geometry.setAttribute(
      "size",
      new THREE.BufferAttribute(this.sizes, 1)
    );


    // 创建粒子材质
    const material = new THREE.PointsMaterial({
      size: 0.3, // 粒子大小
      vertexColors: false, // 启用顶点颜色
      blending: THREE.AdditiveBlending, // 使用加法混合
      transparent: true, // 启用透明
      opacity: 0.8, // 设置透明度
      color:this.colorArr[Math.floor(Math.random()*10)]//生成随机颜色
    });

    // 创建粒子系统并添加到场景
    this.points = new THREE.Points(this.geometry, material);
    this.scene.add(this.points);
  }
  //生成随机颜色
  createColor(){
    let num = Math.floor(Math.random()*100)%16
    num.toString()
    let b = '0x'+(Math.floor(Math.random() * 0xFFFFFF).toString(16).padStart(6, '0')).toUpperCase();
    b = b.toUpperCase()
    console.log('color',b);
    return '0x'+b;
  }

  // 更新烟花状态
  update() {

    let alive = false;
    for (let i = 0; i < this.count; i++) {
      if (this.life[i] > 0) {
        alive = true;
        // 根据速度更新位置
        this.positions[i * 3] += this.velocities[i * 3] * 0.1;
        this.positions[i * 3 + 1] += this.velocities[i * 3 + 1] * 0.1;
        this.positions[i * 3 + 2] += this.velocities[i * 3 + 2] * 0.1;

        // 添加重力效果
        this.velocities[i * 3 + 1] -= 0.05;

        // 更新生命值和大小
        this.life[i] -= 0.015;
        this.sizes[i] = this.life[i] * 0.3;
      }
    }

    // 标记属性需要更新
    this.geometry.attributes.position.needsUpdate = true;
    this.geometry.attributes.size.needsUpdate = true;

    return alive; // 返回是否还有活着的粒子
  }

  // 清理烟花资源
  dispose() {
    this.scene.remove(this.points); // 从场景中移除
    this.geometry.dispose(); // 释放几何体
    this.points.material.dispose(); // 释放材质
  }
}

三、总结

宁可十年不将军,不可一日不拱卒。预祝大家端午节快乐!

都看到这里了,记得【点赞】+【关注】哟。

相关推荐
咖啡の猫1 小时前
JavaScript基础-作用域链
开发语言·javascript
2501_914286491 小时前
Web技术与Nginx网站环境部署
前端·nginx·php
啊啊啊~~1 小时前
css实现不确定内容的高度过渡
前端·javascript·css
tongjiwenzhang1 小时前
APPtrace 智能参数系统:重构 App 用户增长与运营逻辑
大数据·前端·重构
亲爱的马哥2 小时前
TDuckX 2.6 正式发布|API 能力开放,核心表单逻辑重构,多项实用功能上线。
java·服务器·前端
Raink老师2 小时前
制作大风车动画
前端·harmonyos·鸿蒙·案例实战
追求者20162 小时前
实现图片自动压缩算法,canvas压缩图片方法
前端·javascript·canvas
斯~内克3 小时前
深入解析前端 JSBridge:现代混合开发的通信基石与架构艺术
前端·架构
Jacky-0083 小时前
ajax post请求 解决自动再get请求一次
前端·javascript·ajax
不写八个3 小时前
Vue3.0教程005:watch监视ref定义的【基本类型】数据和【对象类型】数据
前端·javascript·vue.js