手摸手,带你实现3D粒子特效

2023-10-27 21:50
文章标签 实现 特效 3d 粒子 摸手

本文主要是介绍手摸手,带你实现3D粒子特效,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章摘要:某天,产品小姐姐找到我,要在页面上放一个动态3D模型…不会webGL?没关系!今天就来聊一聊如何用从零实现3D粒子特效。

背景

近年来,随着互联网的迅速发展,用户对产品的视觉效果需求也更加强烈。生动逼真的 3D 动画效果可以让用户身临其境,叹为观止。

从上面的动图可以看到

  • 一开始在场景中是无数个乱序的点
  • 然后逐渐地汇集到一起,形成一个立体的 LOGO,
  • 最后 LOGO 中的粒子开始’呼吸‘起来。

下面我会介绍一下如何一步步实现这种粒子系统效果。

three

在 web 端实现 3D 效果时,第一个相到的当然都会是 webGL(web graphic language) ,即浏览器原生的一套图形API,但是使用 webGL 进行复杂 3D 效果的开发会大大增加工作量,比如坐标变换,法线贴图、透视模拟等等。所以 three 应运而生,官方对其的介绍是 A 3D javascript library ,早期是由计算机图形学天才Ricardo Cabello 在 2010年开源的框架,至今已有10年的历史。在 three 世界的三大概念分别是 camera(相机)scene(场景)renderer(渲染器) ,下图是三者的对应关系。

场景

场景我们可以理解为一个舞台,一个程序只能同时有一个场景。

创建一个场景:  ⬇️

相机

对应现实世界当中的照相机,我们在屏幕中所看到的所有图像都是由相机来捕捉到的。three 提供的相机有三种,分别是 PerspectiveCamera(透视相机)  、OrthographicCamera(正交相机)  以及 CubeCamera(立方体相机)。

  • 透视投影相机捕捉到的画面是类似人眼在真实世界中看到的有  “近大远小”  的效果(如下左图a);
  • 正交投影相机捕捉到的画面和他与相机的距离无关,即大小不会根据距离变大而收缩,对于在三维空间内平行的线,投影到二维空间中也一定是平行的(如下左图b);
  • 立方体相机则与前两个不同,他可以理解为在立方体的每一个面上都设有一个透视摄像机,用于模拟 3D 世界的反光效果(如下右图);

创建一个透视相机:  ⬇️

fov:  视场角,是显示边缘与摄像机连线的夹角,游戏中通常为40-60,这里取值50;

aspect:  渲染结果横向尺寸和纵向尺寸的比值,推荐默认值为窗口的长宽比;

near:  从距离摄像机多近的位置才开始渲染,推荐默认值0.1;

far:  从距离摄像机多近的位置才开始渲染,推荐默认值1000;

渲染器

决定使用什么方式来渲染到浏览器页面中,这里使用 webGL 渲染器:⬇️

除此之外我们还需要声明一个动画函数,在每一帧去调用这个函数,这个函数作为所有动画效果的入口: ⬇️

这样一个场景就搭建好了,我们先在场景中添加一个最简单的物体,点(point)

通常一个物体是由材质(material)  和 形状(geometry)  组成的,材质定义了物体的外观,形状则定义了物体的结构。在创建材质的时候可以选取一张 纹理贴图(texture)  去充当材质,这里加载一张的球形展开图。

一个点也可以理解为一个粒子,其中 vertices 是粒子的位置,它是一个只存储 XYZ 坐标的 32 位浮点类型数组,我们可以传入尽量多的粒子来充满屏幕。

粒子的位置信息是由他所在的坐标决定的。three 坐标系统遵从右手坐标系,是在平面直角坐标系的基础之上添加一个垂直于 X 轴,Y 轴的坐标轴:即 X 轴正方向向右,Y 轴正方向向上,Z 轴正方向向屏幕前。

利用随机数来创建10万个随机位置的粒子:  ⬇️

把创建好的粒子加入到场景中来:  ⬇️

然后将点添加到场景中,这样就在屏幕前渲染了一万个随机位置的粒子。  ✨

粒子系统原理

最开始看到的粒子 LOGO 的实现原理是将一个 3D 模型的顶点(vertices)一一对应到生成的粒子坐标中,可以理解为加载模型的目的是获取到粒子的坐标和数量。所以生成粒子的 LOGO 的步骤如下:

1.加载模型
2.模型的顶点信息提取
3.创建对应数量的粒子
4.将粒子渲染到屏幕上

加载模型

我们首先在场景中加载一个模型,并且将模型的正面朝向屏幕,这里使用 OBJLoader 加载obj格式的 3D 模型,然后先将模型添加到场景中:⬇️

模型的顶点提取

获取到解析出的对象中的顶点信息⬇️

根据顶点创建对应数量的粒子 & 将粒子渲染到屏幕上 ⬇️

最终实现了模型到粒子的效果 ⬇️

这样只需要提供一个 3D 模型就可以渲染出对应的粒子轮廓,下面我们让粒子动起来吧。

粒子过渡

我们获取到了模型中的所有顶点坐标,并且可以生成随机的点,如何将随机的点逐渐汇聚成一个模型呢,这里要应用到 Tween 动画的技术。

Tween 翻译成中文是补间动画,也就是说知道开始和结束的状态就可以计算出中间的过渡状态。我们只需要知道一个点位置的起始值和终止值,就可以知道他在当前进度的位置值。

我们将 currentTime/totalTime 提取出来 进行归一化为 progress 参数,  **(point(终)-point(始)) ** 提取出来作为计算差值 delta,则可以推导出当前位置的计算差值比例和时间的关系为线性关系

下图分别为线性 函数表达式式、函数、js代码

但是随着时间的线性运动略微显得生硬,在这里我们使用指数函数的形式对progress进行处理,使运动的速度 慢->快->慢.

(0 < x < 0.5)

(0.5 < x < 1)

下面是一些使用 Tween 动画技术处理后的效果

物体位置动画:  ⬇️

使用 Tween 动画将粒子从随机态过渡到模型态效果:  ⬇️

也可以将过渡动画用于一个模型到另一个模型的过渡:  ⬇️

到这里我们就完成了模型到粒子的所有工作,并且让粒子可以在模型之间互相切换,但是单纯从效果看来还是有一些生硬。就像没处理过的电影原片,在电影行业里拍摄完画面需要加上一些特效或者调色,称之为后期处理,下面我们来对粒子的效果做一些后期处理。

后期处理

辉光

辉光是一种现实世界中的光现象,通过它能够以较为适度的渲染性能成本极大地增加渲染图像的真实感。在现实世界中,辉光是由于光线在大气或我们眼睛中产生散射而造成的。我们用肉眼观察黑暗背景下非常明亮的物体时会看到辉光效果,比如夜晚的路灯,车灯和屋外的窗户等,它们提供了亮度和气氛的强烈视觉信息。然而通常我们的屏幕不支持 HDR(高动态范围)  ,无法渲染太亮的物体。于是我们模拟了当光线射到胶片或摄像机前时眼睛中出现的效果。辉光处理给屏幕上显示的 LDR(低动态范围)  图像添加真实感。

辉光参数配置,此处只给出核心配置代码⬇️

辉光作用前后对比

噪声

可以看到最终形成的模型的点位置还是有些太规整了,我们想让他呈现出一些不规则的毛边效果,但是整体上还是能保证轮廓的,我们先使用在每个点的位置加上一个随机数的offset来改变坐标,把它命名为白噪声

白噪声带来效果虽然每个点的位置的能够和原始位置保证差异,但是模型整体上会显得杂乱无章。

在1982年的《电子世界争霸战争》中,图形学专家_Ken Perlin_首次提出 柏林噪声(Perlin noise)  算法的概念,并应用到了电影中的地形处理,模拟出了高低起伏的地形。(并因此获得了奥斯卡最佳技术成就奖)

柏林噪声的实现有以下三个步骤:

1.定义一个晶格结构,每个晶格的顶点有一个  “伪随机”  的梯度向量。对于二维的柏林噪声来说,晶格结构就是一个平面网格,三维的就是一个立方体网格。

2.输入一个n维向量,我们找到和它相邻的 2ⁿ 个晶格顶点,计算该点到各个晶格顶点的距离向量,再分别与顶点上的梯度向量做点乘,得到 2ⁿ 个点乘结果。

3.使用缓和曲线来计算它们的权重和。在原始的柏林噪声实现中,缓和曲线是 s(t)=3t²−2t³,在2002年时Perlin本人将其改进为s(t)=6t⁵−15t⁴+10t³。如果直接使用的线性插值的话,它的一阶导在晶格顶点处(即t = 0或t = 1)不为0,会造成明显的不连续性。s(t)=3t²−2t³ 在一阶导满足连续性,s(t)=6t⁵−15t⁴+10t³ 在二阶导上仍然满足连续性。

一维晶格

使用噪声的算法对模型的顶点位置和颜色进行处理后

氛围&呼吸

我们在空白区域随机创建 1000 个粒子,然后让随机点绕 Y 坐标轴进行旋转:⬇️

运动可以赋予整个场景生命力,我们可以将粒子进行 沿 Z 轴的循环运动,让整个模型呼吸起来。这里只让随机20%的粒子进行运动,剩下的粒子保持静止。

呼吸代码省略;氛围和呼吸加上之后的最终效果如下:

展望

加上之后的最终效果如下:

展望

虚拟和现实的边界越来越模糊,计算机和移动设备的硬件算力的不断提高,可以预见在未来会有更多的仿真特效都是在现代客户端上完成的。而 WEB 作为跨端的低成本方案显得更加重要。相信 webAR,webVR 等技术将会在不久的将来大放异彩。

最后

整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

部分文档展示:



文章篇幅有限,后面的内容就不一一展示了

有需要的小伙伴,可以点下方卡片免费领取

这篇关于手摸手,带你实现3D粒子特效的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/288647

相关文章

使用Redis快速实现共享Session登录的详细步骤

《使用Redis快速实现共享Session登录的详细步骤》在Web开发中,Session通常用于存储用户的会话信息,允许用户在多个页面之间保持登录状态,Redis是一个开源的高性能键值数据库,广泛用于... 目录前言实现原理:步骤:使用Redis实现共享Session登录1. 引入Redis依赖2. 配置R

SpringBoot实现RSA+AES自动接口解密的实战指南

《SpringBoot实现RSA+AES自动接口解密的实战指南》在当今数据泄露频发的网络环境中,接口安全已成为开发者不可忽视的核心议题,RSA+AES混合加密方案因其安全性高、性能优越而被广泛采用,本... 目录一、项目依赖与环境准备1.1 Maven依赖配置1.2 密钥生成与配置二、加密工具类实现2.1

在Java中实现线程之间的数据共享的几种方式总结

《在Java中实现线程之间的数据共享的几种方式总结》在Java中实现线程间数据共享是并发编程的核心需求,但需要谨慎处理同步问题以避免竞态条件,本文通过代码示例给大家介绍了几种主要实现方式及其最佳实践,... 目录1. 共享变量与同步机制2. 轻量级通信机制3. 线程安全容器4. 线程局部变量(ThreadL

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

Redis客户端连接机制的实现方案

《Redis客户端连接机制的实现方案》本文主要介绍了Redis客户端连接机制的实现方案,包括事件驱动模型、非阻塞I/O处理、连接池应用及配置优化,具有一定的参考价值,感兴趣的可以了解一下... 目录1. Redis连接模型概述2. 连接建立过程详解2.1 连php接初始化流程2.2 关键配置参数3. 最大连

Python实现网格交易策略的过程

《Python实现网格交易策略的过程》本文讲解Python网格交易策略,利用ccxt获取加密货币数据及backtrader回测,通过设定网格节点,低买高卖获利,适合震荡行情,下面跟我一起看看我们的第一... 网格交易是一种经典的量化交易策略,其核心思想是在价格上下预设多个“网格”,当价格触发特定网格时执行买

python设置环境变量路径实现过程

《python设置环境变量路径实现过程》本文介绍设置Python路径的多种方法:临时设置(Windows用`set`,Linux/macOS用`export`)、永久设置(系统属性或shell配置文件... 目录设置python路径的方法临时设置环境变量(适用于当前会话)永久设置环境变量(Windows系统