个人简介
👀个人主页: 前端杂货铺
⚡开源项目: 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】