关于前端:1000粉使用Threejs实现一个创意纪念页面-🏆

申明:本文波及图文和模型素材仅用于集体学习、钻研和观赏,请勿二次批改、非法流传、转载、出版、商用、及进行其余获利行为。

背景

人不知;鬼不觉,掘金关注者人数曾经超过 1000 人,因而顺便做了这个页面留念一下,感激大家关注 🙇‍,心愿思否的粉丝也涨涨。后续也将持续致力,继续输入一些有价值的文章。本文内容波及的技术栈为 React + Three.js + Stulus,本文中次要蕴含的知识点包含:圆锥几何体 ConeGeometry、圆柱几何体 CylinderGeometry、材质捕获纹理材质 MeshMatcapMaterial、文字创立和润饰的 FontLoaderTextGeometry、应用 Gsap 和它的插件 Physics2DPlugin 创立一些动画、rotateOnAxis 办法实现绕轴自转等。

对了,后续我专门新建了一个专门针对 Three.js 系列的专栏【Three.js 奥德赛进阶之旅】,是掘金签约的专栏 📚。从根底入门开始,全方位理解 Three.js 的各种个性,并联合和利用对应个性,实现令人眼前一亮的 Web 创意页面,进而逐渐开掘 Three.jsWebGL 深层次的常识。在这里推广一下,大家感兴趣的话能够关注一波 😘

成果

页面 📃 主体内容次要由四局部组成,别离是:文字 1000!、文字 THANK YOU、掘金三维 Logo、以及 纸片礼花 🎉。其中文字各自具备翻转动画,掘金 Logo 有自转动画成果,当用 🖱 鼠标点击屏幕时,会呈现 *★,°*:.☆( ̄▽ ̄)/$:*.°★* 。 撒花成果。

关上以下链接中的任意一个能够在线预览成果。本页面适配PC端挪动端,大屏拜访成果更佳。

  • 👁‍🗨 在线预览地址1:https://3d-eosin.vercel.app/#/fans
  • 👁‍🗨 在线预览地址2:https://dragonir.github.io/3d/#/fans

实现

📦 资源引入

首先在顶部引入开发必备的资源,除了根底的 React 和样式表之外,THREEThree.js 库;OrbitControls 用于镜头轨道控制,能够应用鼠标挪动或旋转模型;Text 是用于创立文字模型的一个类;Confetti 是一个用于创立礼花成果的类,在前面内容中会做具体介绍。

import './index.styl';
import React from 'react';
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import Text from '@/assets/utils/Text';
import Confetti from '@/assets/utils/Confetti';

📃 页面构造

页面次要构造非常简单,其中 .webgl 用于渲染 3D 元素;.logo 是页面上的一些图标装璜,.github 是寄存本我的项目的 Github 链接地址。

<div className='fans_page'>
  <canvas className='webgl'></canvas>
  <i className='logo'></i>
  <i className='logo click'></i>
  <a className='github' href='https://github.com/dragonir/3d' target='_blank'></a>
</div>

创立 Logo

创立 Logo 时,先创立一个 Group,而后将 Logo 的各个局部增加到 Group 中,这样有利于对 Logo 整体调整地位和增加动画,也有利于页面加载性能。接着,通过以下步骤创立 Logo 模型的三局部:

  • 创立通用的材质 MeshMatcapMaterialLogo 模型的所有组成网格都将应用这种材质;
  • 应用 ConeGeometry 创立顶部的 四棱锥,并利用材质;
  • 应用 CylinderGeometry 创立两头的 四棱台,并利用材质;
  • 应用 CylinderGeometry 创立底部的 四棱台,并利用材质;
  • 将上述网格模型增加到 Group 中,并调整整体的地位、大小,并设置歪斜角度以便取得更好的页面视觉效果。

📌 在理论开发中,利用了 ConeBufferGeometryCylinderBufferGeometry 代替 ConeGeometryCylinderGeometry,以便取得更好的性能。

本示例中模型的计算参数如上图所示,顶部四棱柱的四个面都是边长为 4等边三角形,其余两个棱台的侧边长也是 4,其余边的长度参数都能够通过勾股定理以及三角函数计算得出,本文中不做具体计算。(PS:模型示意图是用 Windows 画图工具画的,有点丑 🤣

const logo = new THREE.Group();
// 材质捕获纹理材质
const logoMaterial = new THREE.MeshMatcapMaterial({
  matcap: this.matcaps.logoMatcap,
  side: THREE.DoubleSide,
});
// 顶部四棱锥
const cone = new THREE.Mesh(new THREE.ConeGeometry(4, 4, 4), logoMaterial);
logo.add(cone);
// 两头四棱台
const cylinder = new THREE.Mesh(new THREE.CylinderGeometry(6, 10, 4, 4, 1), logoMaterial);
cylinder.position.y = -6
logo.add(cylinder);
// 底部四棱台
const cylinder2 = new THREE.Mesh(new THREE.CylinderGeometry(12, 16, 4, 4, 1), logoMaterial);
cylinder2.position.y = -12
logo.add(cylinder2);
logo.position.set(0, 0, 0);
logo.scale.set(11, 11, 11);
// 设置歪斜角度
logo.rotateY(Math.PI * 0.2);
logo.rotateZ(Math.PI * 0.1);
scene.add(logo);

💡 知识点 圆锥几何体ConeGeometry

圆锥几何体 ConeGeometry,是一个用于生成圆锥几何体的类,侧面分段数越多则越圆,本例中分段数为 4,所以看起来是个四棱锥。

构造函数

ConeGeometry(radius: Float, height: Float, radialSegments: Integer, heightSegments: Integer, openEnded: Boolean, thetaStart: Float, thetaLength: Float);

参数阐明

  • radius:圆锥底部的半径,默认值为 1
  • height:圆锥的高度,默认值为 1
  • radialSegments:圆锥侧面四周的分段数,默认为 8
  • heightSegments:圆锥侧面沿着其高度的分段数,默认值为 1
  • openEnded:一个 Boolean 值,指明该圆锥的底面是凋谢的还是封顶的。默认值为 false,即其底面默认是封顶的。
  • thetaStart:第一个分段的起始角度,默认为 0
  • thetaLength:圆锥底面圆扇区的中心角,通常被称为 θ。默认值是 2*PI,这使其成为一个残缺的圆锥。

💡 知识点 圆柱几何体CylinderGeometry

圆柱几何体 CylinderGeometry,是一个用于生成圆柱几何体的类。本文中 Logo 的两头和底部就由此类生成。

构造函数

CylinderGeometry(radiusTop: Float, radiusBottom: Float, height: Float, radialSegments: Integer, heightSegments: Integer, openEnded : Boolean, thetaStart: Float, thetaLength: Float)

参数阐明

  • radiusTop:圆柱的顶部半径,默认值是 1
  • radiusBottom:圆柱的底部半径,默认值是 1
  • height:圆柱的高度,默认值是 1
  • radialSegments:圆柱侧面四周的分段数,默认为 8
  • heightSegments:圆柱侧面沿着其高度的分段数,默认值为 1
  • openEnded:一个 Boolean值,指明该圆锥的底面是凋谢的还是封顶的。默认值为 false,即其底面默认是封顶的。
  • thetaStart:第一个分段的起始角度,默认为 0
  • thetaLength:圆柱底面圆扇区的中心角,通常被称为 θ。默认值是 2*PI,这使其成为一个残缺的圆柱。

💡 知识点 材质捕获纹理材质MeshMatcapMaterial

MeshMatcapMaterial 由一个材质捕获 MatCap或光照球 纹理所定义,其编码了材质的色彩与明暗。因为 mapcap 图像文件编码了烘焙过的光照,因而MeshMatcapMaterial不对灯光作出反应。它能够投射暗影到一个承受暗影的物体上,但不会产生本身暗影或是接管暗影。

构造函数

MeshMatcapMaterial(parameters: Object)

parameters:可选,用于定义材质外观的对象,具备一个或多个属性,材质的任何属性都能够从此处传入,包含从 Material 继承的任何属性。

  • .color[Color]:材质的色彩,默认值为红色 0xffffff
  • .matcap[Texture]matcap 贴图,默认为 null
  • 其余Material基类的共有属性等。

MeshMatcapMaterial 是一种十分好用的材质,简略应用这种材质就能实现简单的纹理成果,如本文中 Logo 的光泽成果,以及后续文字的金属成果以及通明玻璃成果,抉择适合的材质,能够实现各种各样的神奇成果。上面这张图就是本文中所有元素的材质贴图,能够看出它们是一个个光照球体款式。

除了在 BlenderPhotoshop等设计软件中生成 MeshMatcapMaterial 之外,上面几个网站能够收费下载各种难看的材质,并且具备在线实时预览性能,大家能够依据页面元素内容和本身需要找到适合的材质图片,感兴趣的话能够亲手试试看 😉

🔗 https://observablehq.com/@makio135/matcaps?ui=classic 🔗 https://github.com/nidorx/matcaps

🔗 [http://jeanmoreno.com/unity/m…]()http://jeanmoreno.com/unity/m…

创立文字 1000!

接着,来创立文字,此时须要引入 FontLoader,用于加载字体文件,它返回一个字体实例,而后应用 TextGeometry 创立文字网格,将它增加到场景中就能够了。

import { FontLoader } from 'three/examples/jsm/loaders/FontLoader';
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry';

fontLoader.load('fontface.json', font => {
  textMesh.geometry = new TextGeometry('1000!', {
    font: font,
    size: 100,
    height: 40
  });
  scene.add(textMesh);
});

看起来十分一般对不对,此时能够对 TextGeometry 进行对字符的厚度、斜角大小等参数的调整,咱们能够按相似上面这种略微优化一下,直至调整到本人称心的后果为止。

textMesh.geometry = new TextGeometry('1000!', {
  font: font,
  size: 100,
  height: 40,
  curveSegments: 100,
  bevelEnabled: true,
  bevelThickness: 10,
  bevelSize: 10,
  bevelOffset: 2,
  bevelSegments: 10
});

看看优化后的成果,霎时高大上了有木有

创立文字 THANK YOU

应用同样的办法增加 THANK YOU 文字网格到场景中,并为它设置半透明玻璃成果的 MeshMatcapMaterial 和文字厚度斜角款式。

📌 对于文字网格的具体利用能够看看我的这篇文章 《应用Three.js实现神奇的3D文字悬浮成果》,本文中不再赘述了。

创立文字动画

文字创立实现后,能够给它们增加一些文字翻转动画成果。动画成果是通过 Gsap 实现的,本文中给1000! 文字增加了一个缩放并翻转的动画成果,给 THANK YOU 增加了一个高低翻转的动画成果,能够参考如下办法来实现。

import gsap from 'gsap';
// 高低翻转动画
zoomAndFlip() {
  gsap.timeline({
    repeat: -1,
    defaults: {
      duration: 2,
      ease: 'elastic.out(1.2, 1)',
      stagger: 0.1,
    },
  })
  .to(this.meshesPosition, { z: this.meshesPosition[0].z + 100 }, 'start')
  .to(this.meshesRotation, { duration: 2, y: Math.PI * 2 }, 'start')
  .to(this.meshesRotation, { duration: 2, y: Math.PI * 4 }, 'end')
  .to(this.meshesPosition, { z: this.meshesPosition[0].z }, 'end');
}

创立礼花 🎉

页面每次关上以及点击屏幕时,能够产生礼花成果。其中礼花中的每个小碎片应用了面根底缓冲模型 PlaneBufferGeometry 以及 MeshBasicMaterial 根底材质形成,在场景中创立三束礼花,每束礼花内的碎片地位和大小随机,并在一段时间后主动隐没。同样,礼花的动画成果也是应用了 Gsap,并且应用了它的插件 Physics2DPlugin 来实现,Physics2DPlugin 插件能够模仿物理动画成果包含重力、速度、加速度、摩擦力动画等,有了它就能更好地实现礼花爆炸和散落成果。能够像本文中这样应用它们:

import gsap from 'gsap';
const physics2D = require('./physics2D');
gsap.registerPlugin(physics2D.Physics2DPlugin);
// 对每一片礼花利用动画成果
gsap.to(this.confettiSprites[id], DECAY, {
  physics2D: {
    velocity,
    angle,
    gravity,
    friction,
  },
  ease: 'power4.easeIn',
  onComplete: () => {
    _.pull(this.confettiSpriteIds, id);
    this.parent.remove(this.meshes[id]);
    this.meshes[id].material.dispose();
    delete this.confettiSprites[id];
  },
});

💡 知识点 Physics2DPlugin

Physics2DPlugin 设置二维物理动画抛物线成果可选参数:

  • velocity:初始速度
  • angle:角度
  • gravity:重力
  • acceleration:加速度
  • accelerationAngle:加速度角度
  • friction:摩擦力

点击页面时触发动画

window.addEventListener('pointerdown', e => {
  e.preventDefault();
  this.confetti && this.confetti.pop();
});

📌 文字和礼花成果在理论中实现,其实是别离封装了两个类,不便从内部调用,具体实现具体代码能够拜访文末提供的源码链接。

缩放监听及重绘动画

增加页面缩放适配和重绘动画来更新相机和轨道控制器等。在重绘动画中,给 Logo 增加了一个绕本身 Y轴 旋转的成果,能够通过 rotateOnAxis 实现。

window.addEventListener('resize', () => {
  this.width = window.innerWidth;
  this.height = window.innerHeight;
  this.camera.aspect = this.width / this.height;
  this.camera.updateProjectionMatrix();
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
  this.renderer.setSize(this.width, this.height);
}, {
  passive: true
});

const animate = () => {
  requestAnimationFrame(animate);
  controls && controls.update();
  // 旋转动画
  logo && logo.rotateOnAxis(axis, Math.PI / 400);
  renderer.render(scene, camera);
}

大家能够亲自动手试试 rotateOnAxisrotateY 实现的旋转成果有何不同来辨别两者。

💡 知识点 rotateOnAxis

.rotateOnAxisThree.js 中三维物体基类 Object3D 的一个办法,它能够在部分空间中绕着该物体的轴来旋转一个物体,假如这个轴已被标准化,它的应用办法如下所示。

.rotateOnAxis(axis: Vector3, angle: Float)
  • axis:一个在部分空间中的标准化向量。
  • angle:角度,以弧度来示意。

款式细节优化

到这一步,页面的性能曾经全副实现了 🍾,最初能够装璜一下页面,如将 renderer 设置为通明,而后在 CSS 中应用一张难看的科技感图片作为页面背景,最初加上几个角落里的图片装饰物和 Github 图标链接,加一点点 CSS 动画,页面整体视觉效果就失去了不错的晋升 😉。最初再次感激大家关注!🙇‍ 谢谢、栓Q、阿里嘎多

🔗 源码地址:https://github.com/dragonir/3d/tree/master/src/containers/Fans

总结

本文蕴含的知识点次要包含:

  • 圆锥几何体 ConeGeometry
  • 圆柱几何体 CylinderGeometry
  • 材质捕获纹理材质 MeshMatcapMaterial
  • 文字创立和润饰的 FontLoaderTextGeometry
  • 应用 Gsap 和它的插件 Physics2DPlugin 创立一些动画
  • rotateOnAxis 办法实现绕轴自转

想理解其余前端常识或其余未在本文中详细描述的 Web 3D 开发技术相干常识,可浏览我往期的文章。转载请注明原文地址和作者。如果感觉文章对你有帮忙,不要忘了一键三连哦 👍

附录

  • 新建【Three.js 进阶之旅】Three.js 系列专栏 👈
  • [1]. 🌴 Three.js 打造缤纷夏日3D梦中情岛
  • [2]. 🔥 Three.js 实现炫酷的赛博朋克格调3D数字地球大屏
  • [3]. 🐼 Three.js 实现2022冬奥主题3D趣味页面,含冰墩墩
  • 更多往期【3D】专栏拜访 👈
  • ...
  • [1]. 📷 前端实现很哇塞的浏览器端扫码性能
  • [2]. 🌏 前端瓦片地图加载之塞尔达传说旷野之息
  • [3]. 🌊 应用前端技术实现动态图片部分流动成果
  • 更多往期【前端】专栏拜访 👈
  • ...

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理