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

news2024/11/15 21:03:50

文章摘要:某天,产品小姐姐找到我,要在页面上放一个动态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道面试题,并对每个问题作出了回答和解析。

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

部分文档展示:



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

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

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

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

相关文章

内网渗透(四十六)之横向移动篇-使用系统漏洞ms17010横向移动

系列文章第一章节之基础知识篇 内网渗透(一)之基础知识-内网渗透介绍和概述 内网渗透(二)之基础知识-工作组介绍 内网渗透(三)之基础知识-域环境的介绍和优点 内网渗透(四)之基础知识-搭建域环境 内网渗透(五)之基础知识-Active Directory活动目录介绍和使用 内网渗透(六)之基…

leaflet 加载geojson数据,随机显示不同颜色的circleMarker

第086个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet项目中加载geojson数据,随机显示不同颜色的circleMarker. 直接复制下面的 vue+leaflet源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源代码(共89行)相关API专栏目标示例效果 配置方式…

时间序列数据预测的类型

本文主要内容是使用LSTM网络进行不同类型的时间序列预测任务&#xff0c;不涉及代码&#xff0c;仅仅就不同类型的预测任务和数据划分进行说明。 参考文章&#xff1a;https://machinelearningmastery.com/how-to-develop-lstm-models-for-time-series-forecasting/ 注&#xf…

如何使用Hugo Academic Theme构建自己的github主页

前期条件 自己已经注册好GitHub 原文档&#xff1a;https://wowchemy.com/docs/getting-started/hugo-github-quickstart/ 搜索Hugo Academic Theme&#xff08;网址&#xff09; 进入后的网址为&#xff1a;https://academic-demo.netlify.app/ 点击Get Start 出现如下模板…

【观察】昇腾加速AI“走深向实”,打通落地“最后一公里”

毫无疑问&#xff0c;今天AI正与产业结合得越来越紧密&#xff0c;从智能制造&#xff0c;到智慧医疗&#xff0c;智慧金融、智慧城市等&#xff0c;AI已经开始渗透到我们生活的方方面面&#xff0c;即便是目前来自传统行业用户的AI转型需求尚未完全激活爆发&#xff0c;但仅仅…

利用组件注解符精简Spring配置文件

文章目录利用组件注解符精简Spring配置文件一、利用组件注解精简Spring配置文件1、创建新包2、将4个类给拷贝过去3、修改杀龙任务类4、修改救美任务类5、修改勇敢骑士类6、修改救美骑士类7、创建Spring配置文件利用组件注解符精简Spring配置文件 一、利用组件注解精简Spring配…

什么是生命周期?Activity生命周期的三种状态

什么是生命周期生命周期就是一个对象从创建到销毁的过程&#xff0c;每一个对象都有自己的生命周期。同样&#xff0c;Activity也具有相应的生命周期&#xff0c;Activity的生命周期中分为三种状态&#xff0c;分别是运行状态、暂停状态和停止状态。接下来将针对Activity生命周…

【自动化测试】自动化测试框架那些事儿

无论是在自动化测试实践&#xff0c;还是日常交流中&#xff0c;经常听到一个词&#xff1a;框架。在教学的过程中&#xff0c;同学们一直对“框架”这个词知其然不知其所以然。 最近看了很多自动化相关的资料&#xff0c;加上一些实践&#xff0c;算是对“框架”有了一些理解…

JVM13 类的生命周期

1. 概述 在 Java 中数据类型分为基本数据类型和引用数据类型。基本数据类型由虚拟机预先定义&#xff0c;引用数据类型则需要进行类的加载。 按照 Java 虚拟机规范&#xff0c;从 class 文件到加载到内存中的类&#xff0c;到类卸载出内存为止&#xff0c;它的整个生命周期包…

本地代码推送到Coding

话不多说&#xff0c;开门见山 一、coding准备 注册啊&#xff0c;建项目&#xff0c;这些就不用多说了。 1.创建一个代码仓库 填一下名称和描述就行&#xff0c;其他先不用填&#xff0c;然后点最下面完成创建就行。 2.保存代码仓库地址 二、本地代码仓库准备 已经是在…

Linux 忘记密码解决方法

很多朋友经常会忘记Linux系统的root密码&#xff0c;linux系统忘记root密码的情况该怎么办呢&#xff1f;重新安装系统吗&#xff1f;当然不用&#xff01;进入单用户模式更改一下root密码即可。 步骤如下&#xff1a; 重启linux系统 3 秒之内要按一下回车&#xff0c;出现如…

Web前端:什么是Vue Native 框架?有什么特点?

Vue Native是一个使用Vue.Js开发本地移动应用程序的框架。该框架将文档转换为React Native&#xff0c;进而为你提供适用于Android和iOS的本地应用程序。实际上&#xff0c;Vue Native应用程序据说是React API的包装。Vue将Vue.js和React结合在一起&#xff0c;让你的开发团队充…

【牛客刷题专栏】0x0C:JZ4 二维数组中的查找(C语言编程题)

前言 个人推荐在牛客网刷题(点击可以跳转)&#xff0c;它登陆后会保存刷题记录进度&#xff0c;重新登录时写过的题目代码不会丢失。个人刷题练习系列专栏&#xff1a;个人CSDN牛客刷题专栏。 题目来自&#xff1a;牛客/题库 / 在线编程 / 剑指offer&#xff1a; 目录前言问题…

Django框架之模板过滤器

过滤器 语法如下: 使用管道符号|来应用过滤器&#xff0c;用于进行计算、转换操作&#xff0c;可以使用在变量、标签中。如果过滤器需要参数&#xff0c;则使用冒号:传递参数。 变量|过滤器:参数列举几个如下&#xff1a; safe&#xff0c;禁用转义&#xff0c;告诉模板这个变…

大数据Hadoop教程-01大数据导论与Linux基础

目录 01、大数据导论 02、Linux操作系统概述 P007 P008 P009 P010 P011 P012 P013 P014 P015 P016 P017 01、大数据导论 企业数据分析方向 现状分析&#xff08;分析当下的数据&#xff09;&#xff1a;现阶段的整体情况&#xff0c;各个部分的构成占比、发展、变…

C++空指针和野指针

空指针&#xff1a;指针被赋值为空 例如&#xff1a; int* p nullptr;int* p NULL; 空指针指向的地址是00000000&#xff0c;但空指针不可以解引用 野指针&#xff1a;指针指向了不可控的位置 例如&#xff1a; 未初始化 int* p; //野指针 越界访问 int intArr[5]{0, 1, …

Echarts+大屏

先放上我做的大屏吧&#xff0c;做的不是很好看&#xff0c;希望大家能见谅。 一、实验目的 理解大数据可视化的原理和方法掌握ECharts可视化的原理、步骤和效果掌握使用D3读取数据的方法 二、实验任务与要求 通过网店运营的销售数据&#xff0c;分别从各月的销售情况、各产品…

【1】linux命令每日分享——mkdir创建目录

大家好&#xff0c;这里是sdust-vrlab&#xff0c;Linux是一种免费使用和自由传播的类UNIX操作系统&#xff0c;Linux的基本思想有两点&#xff1a;一切都是文件&#xff1b;每个文件都有确定的用途&#xff1b;linux涉及到IT行业的方方面面&#xff0c;在我们日常的学习中&…

剑指offer-消失的数字、数组中出现的次数

消失的数字 解法一&#xff1a;求和相减 假设nums为[0,1,2,4],消失的数字为3&#xff0c;完整的数组应该是[0,1,2,3,4]&#xff0c;则sum101247,sum20123410&#xff0c;我们很容易发现 sum2-sum1 01234 - 0124 3&#xff0c;即为消失的数字。因此&#xff0c;我们可以采用先…

国内有哪些值得一去的通信类博物馆?

众所周知&#xff0c;博物馆是收藏、展示和研究历史文物的地方。参观博物馆&#xff0c;既可以回顾历史往事&#xff0c;也可以学习知识。那么&#xff0c;作为通信人&#xff0c;你知道国内有哪些通信领域的博物馆吗&#xff1f;今天&#xff0c;就让小枣君给大家介绍介绍。█…