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

前端杂货铺 2024-06-11 09:35:03 阅读 52

个人简介

👀个人主页: 前端杂货铺

开源项目: 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官方文档,真心推荐读一读!!

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


参考资料:

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


在这里插入图片描述




声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。