Three.js——粒子效果、粒子水波、粒子组成立方体

news2024/10/6 1:44:48

个人简介

👀个人主页: 前端杂货铺
开源项目: rich-vue3 (基于 Vue3 + TS + Pinia + Element Plus + Spring全家桶 + MySQL)
🙋‍♂️学习方向: 主攻前端方向,正逐渐往全干发展
📃个人状态: 研发工程师,现效力于中国工业软件事业
🚀人生格言: 积跬步至千里,积小流成江海
🥇推荐学习:🍖开源 rich-vue3 🍍前端面试宝典 🍉Vue2 🍋Vue3 🍓Vue2/3项目实战 🥝Node.js实战 🍒Three.js

🌕个人推广:每篇文章最下方都有加入方式,旨在交流学习&资源分享,快加入进来吧

内容参考链接
WebGL专栏WebGL 入门
Three.js(一)创建场景、渲染三维对象、添加灯光、添加阴影、添加雾化
Three.js(二)scene场景、几何体位置旋转缩放、正射投影相机、透视投影相机
Three.js(三)聚光灯、环境光、点光源、平行光、半球光
Three.js(四)基础材质、深度材质、法向材质、面材质、朗伯材质、Phong材质、着色器材质、直线和虚线、联合材质
Three.js(五)Three.js——二维平面、二维圆、自定义二维图形、立方体、球体、圆柱体、圆环、扭结、多面体、文字
Three.js(六)Three.js——tween动画、光线投射拾取、加载.obj/.mtl外部文件、使用相机控制器
Three.js(七)Three.js——骨骼动画
Three.js(八)Three.js——基础纹理、凹凸纹理、法向贴图、环境贴图、canvas贴图

文章目录

    • 前言
    • 一、粒子效果
    • 二、粒子水波
    • 三、粒子组成立方体
    • 总结

前言

大家好,这里是前端杂货铺。

上篇文章我们学习了 基础纹理、凹凸纹理、法向贴图、环境贴图、canvas贴图。接下来,我们继续我们 three.js 的学习!

在学习的过程中,如若需要深入了解或扩展某些知识,可以自行查阅 => three.js官方文档。


一、粒子效果

Sprite 精灵,是一个总是面朝着摄像机的平面,通常含有使用一个半透明的纹理。

new THREE.Sprite( material : Material );
参数名称描述
material(可选值)是 SpriteMaterial 的一个实例。 默认值是一个白色的 SpriteMaterial

SpriteMaterial 点精灵材质,一种使用 Sprite 的材质。

new THREE.SpriteMaterial( parameters : Object )
参数名称描述
parameters(可选) 用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从 Material 继承的任何属性)。

接下来,我们创建一个 10 x 10 的粒子效果,通过精灵和点精灵材质构建,添加到场景中。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>*{ margin: 0; padding: 0;}</style>
    <script src="../lib/three/three.js"></script>
</head>

<body>
<script>
    const clock = new THREE.Clock();
    // 创建场景
    const scene = new THREE.Scene();
    // 创建相机 视野角度FOV、长宽比、近截面、远截面
    const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
    // 设置相机位置
    camera.position.set(0, 0, 200);
    camera.lookAt(new THREE.Vector3(0, 0, 0));

    // 创建渲染器
    const renderer = new THREE.WebGLRenderer();
    // 设置渲染器尺寸
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    renderer.setClearColor(0xffffff);

    // 添加灯光
    const spotLight = new THREE.SpotLight(0xffffff);
    scene.add(spotLight);

    createNormalSprite();

    // 基础粒子
    function createNormalSprite() {
        for (let i = -5; i < 5; i++) {
            for (let j = -5; j < 5; j++) {
                const material  = new THREE.SpriteMaterial({
                    color: Math.random() * 0xffff
                })
                const sprite = new THREE.Sprite(material);
                sprite.position.set(i * 10, j * 10, 0);
                sprite.scale.set(2, 2, 2);
                scene.add(sprite);
            }
        }
    }


    // createSystemSprite();
    // 粒子系统创建粒子
    function createSystemSprite() {
        const geometry = new THREE.Geometry();
        const material = new THREE.PointCloudMaterial({
            size: 4,
            vertexColors: true
        })
        for (let i = -5; i < 5; i++) {
            for (let j = -5; j < 5; j++) {
                // 坐标
                geometry.vertices.push(new THREE.Vector3(i * 10, j * 10, 0));
                // 颜色
                geometry.colors.push(new THREE.Color(Math.random() * 0xffffff));
            }
        }
        scene.add(new THREE.PointCloud(geometry, material));
    }

    const animation = () => {
        // 渲染
        renderer.render(scene, camera);
        requestAnimationFrame(animation);
    }

    animation();
</script>
</body>

</html>

在这里插入图片描述


二、粒子水波

接下来,我们基于上述的粒子效果和 canvas 纹理贴图,制作出水波的效果。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>*{ margin: 0; padding: 0;}</style>
    <script src="../lib/three/three.js"></script>
</head>

<body>
<script>
    const clock = new THREE.Clock();
    // 创建场景
    const scene = new THREE.Scene();
    // 创建相机 视野角度FOV、长宽比、近截面、远截面
    const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
    // 设置相机位置
    camera.position.set(0, 50, 200);
    camera.lookAt(new THREE.Vector3(0, 0, 0));

    // 创建渲染器
    const renderer = new THREE.WebGLRenderer();
    // 设置渲染器尺寸
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    // 添加灯光
    const spotLight = new THREE.SpotLight(0xffffff);
    scene.add(spotLight);

    // 使用canvas贴图实现圆形纹理
    function getSprite() {
        const canvas = document.createElement('canvas');
        const size = 8;
        canvas.width = size * 2;
        canvas.height = size * 2;

        const c = canvas.getContext('2d');
        c.fillStyle = '#00ff00';
        c.arc(size, size, size / 1.5, 0, Math.PI * 2);
        c.fill();

        const texture = new THREE.Texture(canvas);
        texture.needsUpdate = true;
        return texture;
    }

    // 存储粒子内容
    const spriteList = [];

    // 粒子数量
    const total = 20;

    createNormalSprite();

    // 基础粒子
    function createNormalSprite() {
        const material  = new THREE.SpriteMaterial({
            color: 0x008800,
            map: getSprite()
        })

        for (let i = -total; i < total; i++) {
            for (let j = -total; j < total; j++) {
                const sprite = new THREE.Sprite(material);
                sprite.position.set(i * 10, 0, j * 10);
                spriteList.push(sprite);
                scene.add(sprite);
            }
        }
    }

    // 变化的速度
    const speed = 0.1;
    // 波浪的高度
    const height = 5;
    // 波浪的幅度
    const step = 0.3;

    let status = 0;

    const animation = () => {
        // 渲染
        renderer.render(scene, camera);
        requestAnimationFrame(animation);

        let index = -1;

        // 通过 sin 曲线,设置点的位置
        for (let x = 0; x < total * 2; x++) {
            for (let y = 0; y < total * 2; y++) {
                index++;
                spriteList[index].position.y = ((Math.sin(x + status) * step) * height + (Math.sin(y + status) * step) * height);

                // 缩放系数
                const scaleValue = (Math.sin(x + status) * step) + 1;
                spriteList[index].scale.set(scaleValue, scaleValue, scaleValue);
            }
        }

        status += speed;
    }

    animation();
</script>
</body>

</html>

水波效果


三、粒子组成立方体

接下来,我们实现粒子组成立方体,组成法向材质的立方体。

这需要我们使用 canvas 贴图实现圆形纹理、使用法向材质创建几何体、随机设置点的位置创建点云、使用 TWEEN 实现动画效果等

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>*{ margin: 0; padding: 0;}</style>
  <script src="../lib/three/three.js"></script>
  <script src="../lib/three/tween.min.js"></script>
  <script src="../lib/three/dat.gui.js"></script>
</head>

<body>
<script>
  const clock = new THREE.Clock();
  // 创建场景
  const scene = new THREE.Scene();
  // 创建相机 视野角度FOV、长宽比、近截面、远截面
  const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
  // 设置相机位置
  camera.position.set(0, 30, 100);
  camera.lookAt(new THREE.Vector3(0, 0, 0));

  // 创建渲染器
  const renderer = new THREE.WebGLRenderer();
  // 设置渲染器尺寸
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  // 添加灯光
  const spotLight = new THREE.SpotLight(0xffffff);
  scene.add(spotLight);

  // 使用canvas贴图实现圆形纹理
  function getSprite() {
    const canvas = document.createElement('canvas');
    const size = 8;
    canvas.width = size * 2;
    canvas.height = size * 2;

    const c = canvas.getContext('2d');
    c.fillStyle = '#00ff00';
    c.arc(size, size, size / 1.5, 0, Math.PI * 2);
    c.fill();

    const texture = new THREE.Texture(canvas);
    texture.needsUpdate = true;
    return texture;
  }

  const geometry = new THREE.BoxGeometry(10, 10, 10, 10, 10, 10);

  // 存储原始坐标
  const indexList = [];

  // 设定当前随机的范围
  const range = 100;

  // gui 控制
  const controls = {
    polymeric: false, // 是否要组合成立方体
    completeMesh: false, // 组合之后是否要显示立方体
    showMesh: false // 是否要现在显示立方体
  }

  // 创建随机位置
  function createRandomPosition(i) {
    geometry.vertices[i].x = Math.random() * range - range / 2;
    geometry.vertices[i].y = Math.random() * range - range / 2;
    geometry.vertices[i].z = Math.random() * range - range / 2;
  }

  let cloud;

  // 创建法向材质的几何体
  function createMesh() {
    cloud = new THREE.Mesh(new THREE.BoxGeometry(10, 10, 10, 10, 10), new THREE.MeshNormalMaterial());
    scene.add(cloud);
  }

  function createPointCloud() {
    let listen = false;
    for (let i = 0; i < geometry.vertices.length; i++) {
      indexList.push({
        x: geometry.vertices[i].x,
        y: geometry.vertices[i].y,
        z: geometry.vertices[i].z,
      })
      // 随机坐标
      createRandomPosition(i);

      // 聚合点 => 体
      if (controls.polymeric) {
        // 聚合的动画为 2s
        const tween = new TWEEN.Tween(geometry.vertices[i]).to(indexList[i], 2000).start();
        if (!listen) {
          listen = true;

          // 动画完成时,创建法向材质的几何体
          if (controls.completeMesh) {
            tween.onComplete(() => {
              // 先移除点几何体
              scene.remove(cloud);
              createMesh();
            })
          }
        }
      }
    }

    // 点云材质
    const material = new THREE.PointCloudMaterial({
      size: 2,
      transparent: true,
      map: getSprite()
    });

    // 点云
    cloud = new THREE.PointCloud(geometry, material);
    cloud.sortParticles = true;
    scene.add(cloud);
  }

  createPointCloud();

  const gui = new dat.GUI();

  const onChange = () => {
    scene.remove(cloud);
    controls.showMesh ? createMesh() : createPointCloud();
  }

  // gui 控制
  for (const key in controls) {
    gui.add(controls, key).onChange(onChange);
  }

  const animation = () => {
    scene.rotation.y += 0.01;
    // 渲染
    renderer.render(scene, camera);
    TWEEN.update();
    requestAnimationFrame(animation);
  }

  animation();
</script>
</body>

</html>

粒子组成立方体


总结

本篇文章我们讲解了粒子的基本使用,包括 粒子效果、粒子水波、粒子组成立方体。

更多内容扩展请大家自行查阅 => three.js官方文档,真心推荐读一读!!

好啦,本篇文章到这里就要和大家说再见啦,祝你这篇文章阅读愉快,你下篇文章的阅读愉快留着我下篇文章再祝!


参考资料:

  1. Three.js 官方文档
  2. WebGL+Three.js 入门与实战【作者:慕课网_yancy】

在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1800957.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

blazehttp下载安装和自动化测试防护效果

blazehttp下载安装和自动化测试防护效果 说明测试环境的准备网站和waf配置blazehttp下载安装和测试测试效果waf安全日志查看 说明 需要docker环境和1panel面板 本测试使用blazehttp南墙waf进行测试&#xff0c;有兴趣的同学推荐使用雷池waf 测试环境的准备 使用1panel面板&am…

JavaSE--【类和对象】

本篇目标 1. 掌握类的定义方式以及对象的实例化 2. 掌握类中的成员变量和成员方法的使用 3. 掌握对象的整个初始化过程 一、面向对象的初步认知 1.1 面向对象的初步认知 Java是一门纯面向对象的语言(Object Oriented Program&#xff0c;简称OOP)&#xff0c;在面向对象的世界里…

【免费Web系列】大家好 ,今天是Web课程的第十七天点赞收藏关注,持续更新作品 !

这是Web第一天的课程大家可以传送过去学习 http://t.csdnimg.cn/K547r SpingBoot原理 在前面十多天的课程当中&#xff0c;我们学习的都是web开发的技术使用&#xff0c;都是面向应用层面的&#xff0c;我们学会了怎么样去用。而我们今天所要学习的是web后端开发的最后一个篇…

Fort Firewall防火墙工具v3.12.13

软件介绍 Fort Firewall是一款开源系统的免费防火墙&#xff0c;体积小巧、占用空间不大&#xff0c;可以为用户的电脑起到保护作用&#xff0c;该软件可以控制程序访问网络&#xff0c;控制用户的电脑网速&#xff0c;用户可以更轻松便捷的进行网络安全防护&#xff0c;保护系…

COM722-S浙大中控卡件

COM722-S浙大中控卡件。过程控制级 过程控制级功能 生产过程的数据采集、反馈控制、顺序控制、批量控制等。COM722-S浙大中控卡件。在其内部完成&#xff1a;A/D转换&#xff0c;各种控制算法的运算&#xff0c;对模拟量进行滤波及工程单位转换&#xff0c;COM722-S浙大中控卡件…

新手教程之使用LLaMa-Factory微调LLaMa3

文章目录 为什么要用LLaMa-Factory什么是LLaMa-FactoryLLaMa-Factory环境搭建微调LLaMA3参考博文 为什么要用LLaMa-Factory 如果你尝试过微调大模型&#xff0c;你就会知道&#xff0c;大模型的环境配置是非常繁琐的&#xff0c;需要安装大量的第三方库和依赖&#xff0c;甚至…

揭秘抖音矩阵号低成本高效运作批量账号的秘诀!

在当今互联网时代,抖音矩阵号搭建已经成为了许多企业和个人追求高效率媒介管理的重要方式,但是高效、低成本地运作这些账号却是一个相当具有挑战性的任务。 在这篇文章中,我将从抖音矩阵账号准备,如何低成本制作视频以及在进行内容制作时,如何高效运作批量账号等大家比较…

排查互联网敏感信息,对信息泄露说“不”

前言 01 近几年&#xff0c;随着我国对网络安全的重视&#xff0c;贴近实战的攻防演练活动越发丰富&#xff0c;各单位的网络安全建设也逐步从“事后补救”升级为“事前防控”。在演练中&#xff0c;进攻方会在指定时间内对防守方发动网络攻击&#xff0c;检测出防守方存在的…

Hadoop+Spark大数据技术 实验11 Spark 图

17周期末考试 重点从第五章 scala语言开始 比如&#xff1a;映射&#xff08;匿名函数&#xff09; 11.3.1创建属性图 import org.apache.spark.graphx._ import org.apache.spark.rdd.RDD //创建一个顶点集的RDD val users: RDD[(VertexId ,(String,String))] sc.paralle…

vue2组件封装实战系列之alert组件

组件之 GfAlert 消息组件一般用于提示用户&#xff0c;比如通知&#xff0c;警告等消息。 效果预览 属性 参数类型说明可选值默认值titleString显示的标题typeString类型effectString显示的标题descriptionString描述closeTextString显示的标题showIconBoolean显示左侧的图标c…

C++ | Leetcode C++题解之第137题只出现一次的数字II

题目&#xff1a; 题解&#xff1a; class Solution { public:int singleNumber(vector<int>& nums) {int a 0, b 0;for (int num: nums) {b ~a & (b ^ num);a ~b & (a ^ num);}return b;} };

“三夏”农忙:EasyCVR/EasyDSS无人机技术助推现代农业走向智能化

随着科技的飞速发展&#xff0c;无人机技术已经逐渐渗透到我们生活的方方面面。其中&#xff0c;无人机在农业领域的应用尤为引人注目。它们不仅提高了农业生产的效率&#xff0c;还为农民带来了更便捷、更智能的种植方式。 无人机在农业应用场景中&#xff0c;通过搭载各种设备…

Python魔法之旅-魔法方法(22)

目录 一、概述 1、定义 2、作用 二、应用场景 1、构造和析构 2、操作符重载 3、字符串和表示 4、容器管理 5、可调用对象 6、上下文管理 7、属性访问和描述符 8、迭代器和生成器 9、数值类型 10、复制和序列化 11、自定义元类行为 12、自定义类行为 13、类型检…

Python cProfile 输出解析及其解决方案

cProfile 是 Python 中用于性能分析的内置模块&#xff0c;它可以帮助你确定程序中哪些部分消耗了最多的时间。通常&#xff0c;使用 cProfile 会输出大量的数据&#xff0c;需要进行解析和分析。下面是关于 cProfile 输出解析及其解决方案的一些提示&#xff1a; 1、问题背景 …

读AI未来进行式笔记06自动驾驶技术

1. 跃层冲击 1.1. 每个社会其实都处于不同的楼层&#xff0c;往往处于更低楼层的社会&#xff0c;要承受来自更高楼层的社会发展带来的更大冲击 2. 驾驶 2.1. 开车时最关键的不是车&#xff0c;而是路 2.2. 人是比机器更脆弱的生命&am…

多线程leetcode编程题

synchronized 实现 class ReentrantTest {private int n;private volatile int flag 1;private Object lock new Object();public ReentrantTest(int n) {this.n n;}public void zero(IntConsumer printNumber) throws InterruptedException{for(int i1;i<n;){synchron…

.net core 使用js,.net core 使用javascript,在.net core项目中怎么使用javascript

.net core 使用js&#xff0c;.net core 使用javascript&#xff0c;在.net core项目中怎么使用javascript 我项目里需要用到“文字编码”&#xff0c;为了保证前端和后端的编码解码不处bug, 所以&#xff0c;我在项目中用了这个 下面推荐之前在.net F4.0时的方法 文章一&#…

08_旷视轻量化网络--ShuffleNet V1

1.1 简介 ShuffleNetV1是旷视科技&#xff08;Face&#xff09;在2017年提出的一种专为移动设备设计的高效卷积神经网络&#xff08;CNN&#xff09;架构。它的主要目标是在保证模型精度的同时&#xff0c;极大地降低计算成本&#xff0c;使其更适合资源受限的环境&#xff0c…

wx小程序自定义tabbar

1.在app.json文件中&#xff0c;添加自定义tabbar配置&#xff1a;"custom": true "tabBar": {"custom": true,"backgroundColor": "#fafafa","borderStyle": "white","selectedColor": &quo…

高精度加法的实现

这是C算法基础-基础算法专栏的第七篇文章&#xff0c;专栏详情请见此处。 引入 在C语言中&#xff0c;int的可存储数据范围是-2147483648~2147483647&#xff0c;long long的可存储数据范围是-9223372036854775808~9223372036854775807&#xff0c;但是如果一些数据比long long…