three.js如何实现3D动态文字效果

前言

大家好,这里是 CSS 魔法使——alphardex。

之前在逛国外网站的时候,发现有些网站的文字是刻在3D图形上的,并且能在图形上运动,视觉效果相当不错,于是笔者就也想用three.js来尝试复现出这种效果

上图只是所有效果的其中之一,接下来让我们一起开干吧~

准备工作

笔者自行封装的three.js模板:Three.js Starter

读者可以点击右下角fork一份后再开始本项目

本项目需要用到位图字体,可以直接复制demo的HTML里的font字体代码

一个注意点:three-bmfont-text这个库依赖全局的three.js,因此要在JS里额外引入一次three.js,如下图

实现思路

  1. 加载位图字体文件,将其转化为文字对象所需要的形状和材质
  2. 创建文字对象
  3. 创建渲染目标,可以理解为canvas中的canvas,因为接下来我们要将文字对象本身当做贴图
  4. 创建承载字体的容器,将文字对象作为贴图贴上去
  5. 动画

正片

搭好架子

<div class="relative w-screen h-screen">
 <div class="kinetic-text w-full h-full bg-blue-1"></div>
 <div class="font">
 <font>
  一坨从demo里CV而来的字体代码
 </font>
 </div>
</div>
:root {
 --blue-color-1: #2c3e50;
}

.bg-blue-1 {
 background: var(--blue-color-1);
}
import createGeometry from "https://cdn.skypack.dev/three-bmfont-text@3.0.1";
import MSDFShader from "https://cdn.skypack.dev/three-bmfont-text@3.0.1/shaders/msdf";
import parseBmfontXml from "https://cdn.skypack.dev/parse-bmfont-xml@1.1.4";

const font = parseBmfontXml(document.querySelector(".font").innerHTML);
const fontAtlas = "https://i.loli.net/2021/02/20/DcEhuYNjxCgeU42.png";

const kineticTextTorusKnotVertexShader = `(顶点着色器代码,先空着,具体见下文)`;

const kineticTextTorusKnotFragmentShader = `(片元着色器代码,先空着,具体见下文)`;

class KineticText extends Base {
 constructor(sel: string, debug: boolean) {
 super(sel, debug);
 this.cameraPosition = new THREE.Vector3(0, 0, 4);
 this.clock = new THREE.Clock();
 this.meshConfig = {
  torusKnot: {
  vertexShader: kineticTextTorusKnotVertexShader,
  fragmentShader: kineticTextTorusKnotFragmentShader,
  geometry: new THREE.TorusKnotGeometry(9, 3, 768, 3, 4, 3)
  }
 };
 this.meshNames = Object.keys(this.meshConfig);
 this.params = {
  meshName: "torusKnot",
  velocity: 0.5,
  shadow: 5,
  color: "#000000",
  frequency: 0.5,
  text: "ALPHARDEX",
  cameraZ: 2.5
 };
 }
 // 初始化
 async init() {
 this.createScene();
 this.createPerspectiveCamera();
 this.createRenderer(true);
 await this.createKineticText(this.params.text);
 this.createLight();
 this.createOrbitControls();
 this.addListeners();
 this.setLoop();
 }
 // 创建动态文字
 async createKineticText(text: string) {
 await this.createFontText(text);
 this.createRenderTarget();
 this.createTextContainer();
 }
}

加载和创建字体

首先加载字体文件,并创建出形状和材质,有了这两样就能创建出字体对象了

class KineticText extends Base {
 loadFontText(text: string): any {
 return new Promise((resolve) => {
  const fontGeo = createGeometry({
  font,
  text
  });
  const loader = new THREE.TextureLoader();
  loader.load(fontAtlas, (texture) => {
  const fontMat = new THREE.RawShaderMaterial(
   MSDFShader({
   map: texture,
   side: THREE.DoubleSide,
   transparent: true,
   negate: false,
   color: 0xffffff
   })
  );
  resolve({ fontGeo, fontMat });
  });
 });
 }
 async createFontText(text: string) {
 const { fontGeo, fontMat } = await this.loadFontText(text);
 const textMesh = this.createMesh({
  geometry: fontGeo,
  material: fontMat
 });
 textMesh.position.set(-0.965, -0.525, 0);
 textMesh.rotation.set(ky.deg2rad(180), 0, 0);
 textMesh.scale.set(0.008, 0.025, 1);
 this.textMesh = textMesh;
 }
}

着色器

顶点着色器

通用模板,直接CV即可

varying vec2 vUv;
varying vec3 vPosition;

void main(){
 vec4 modelPosition=modelMatrix*vec4(position,1.);
 vec4 viewPosition=viewMatrix*modelPosition;
 vec4 projectedPosition=projectionMatrix*viewPosition;
 gl_Position=projectedPosition;

 vUv=uv;
 vPosition=position;
}

片元着色器

利用fract函数创建重复的贴图,加上位移距离displacement使得贴图能随着时间的增加而动起来,再用clamp函数来根据z轴大小限定阴影的范围,意思是离画面越远则阴影越重,反之离画面越近则阴影越轻

uniform sampler2D uTexture;
uniform float uTime;
uniform float uVelocity;
uniform float uShadow;

varying vec2 vUv;
varying vec3 vPosition;

void main(){
 vec2 repeat=vec2(12.,3.);
 vec2 repeatedUv=vUv*repeat;
 vec2 displacement=vec2(uTime*uVelocity,0.);
 vec2 uv=fract(repeatedUv+displacement);
 vec3 texture=texture2D(uTexture,uv).rgb;
 // texture*=vec3(uv.x,uv.y,1.);
 float shadow=clamp(vPosition.z/uShadow,0.,1.);// farther darker (to 0).
 vec3 color=vec3(texture*shadow);
 gl_FragColor=vec4(color,1.);
}

此时文本显示到了屏幕上

创建渲染目标

为了将字体对象本身作为贴图,创建了一个渲染目标

class KineticText extends Base {
 createRenderTarget() {
 const rt = new THREE.WebGLRenderTarget(
  window.innerWidth,
  window.innerHeight
 );
 this.rt = rt;
 const rtCamera = new THREE.PerspectiveCamera(45, 1, 0.1, 1000);
 rtCamera.position.z = this.params.cameraZ;
 this.rtCamera = rtCamera;
 const rtScene = new THREE.Scene();
 rtScene.add(this.textMesh);
 this.rtScene = rtScene;
 }
}

创建字体容器

创建一个容器,并将字体对象本身作为贴图贴上去,再应用动画即可完成

class KineticText extends Base {
 createTextContainer() {
 if (this.mesh) {
  this.scene.remove(this.mesh);
  this.mesh = null;
  this.material!.dispose();
  this.material = null;
 }
 this.rtScene.background = new THREE.Color(this.params.color);
 const meshConfig = this.meshConfig[this.params.meshName];
 const geometry = meshConfig.geometry;
 const material = new THREE.ShaderMaterial({
  vertexShader: meshConfig.vertexShader,
  fragmentShader: meshConfig.fragmentShader,
  uniforms: {
  uTime: {
   value: 0
  },
  uVelocity: {
   value: this.params.velocity
  },
  uTexture: {
   value: this.rt.texture
  },
  uShadow: {
   value: this.params.shadow
  },
  uFrequency: {
   value: this.params.frequency
  }
  }
 });
 this.material = material;
 const mesh = this.createMesh({
  geometry,
  material
 });
 this.mesh = mesh;
 }
 update() {
 if (this.rtScene) {
  this.renderer.setRenderTarget(this.rt);
  this.renderer.render(this.rtScene, this.rtCamera);
  this.renderer.setRenderTarget(null);
 }
 const elapsedTime = this.clock.getElapsedTime();
 if (this.material) {
  this.material.uniforms.uTime.value = elapsedTime;
 }
 }
}

别忘了把相机调远一些

this.cameraPosition = new THREE.Vector3(0, 0, 40);

风骚的动态文字出现了:)

项目地址

Kinetic Text

demo里不止本文创建的这一种形状,大家可以随意把玩。

总结

到此这篇关于three.js如何实现3D动态文字效果的文章就介绍到这了,更多相关three.js 3D动态文字内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • vue页面引入three.js实现3d动画场景操作

    vue中安装Three.js 近来无聊顺便研究一些关于3D图形化库.three.js是JavaScript编写的WebGL第三方库.Three.js 是一款运行在浏览器中的 3D 引擎,你可以用它通过控制相机.视角.材质等相关属性来创造大量3D动画场景. 我们开始引入three.js相关插件. 1.首先利用淘宝镜像,操作命令为: cnpm install three 2.接下来利用npm安装轨道控件插件: 关注我的微信公众号[前端基础教程从0开始],加我微信,可以免费为您解答问题.回复"1&qu

  • Three.js实现3D机房效果

    3D机房系统是最近用户的需求,通过相关了解最后使用Three.js,也发现最近有东西可以写出来分享: webGL可以让我们在canvas上实现3D效果.而three.js是一款webGL框架,由于其易用性被广泛应用 Three.js是通过对WebGL接口的封装与简化而形成的一个易用的图形库 分步实现3D效果 初始化3D模型参数 开始搭建场景 初始化渲染器 初始化摄像机 创建场景 灯光布置 创建网格线 循环渲染界面 创建鼠标控制器 添加对象到场景中 一 . 初始化3D模型参数 //参数处理 thi

  • three.js实现3D视野缩放效果

    首先,不再废话了,什么是three.js,是干什么的,知道的就是知道,不知道的就百度吧. 小编为大家推荐一篇:Three.js快速入门教程 昨儿发现three.js中的3D视野的缩小和放大效果可以用照相机的远近焦来实现. 缩小后: 这里采用的是透视照相机: //照相机配置 var fov = 40;//拍摄距离 var near = 1;//最小范围 var far = 1000;//最大范围 var camera = new THREE.PerspectiveCamera(fov, windo

  • Three.js实现简单3D房间布局

    本文实例为大家分享了Three.js实现简单3D房间布局的具体代码,供大家参考,具体内容如下 废话不说了,直接上成果图. 代码如下 <!doctype html> <html lang="en"> <head> <title>房间布局</title> <meta charset="utf-8"> <meta name="viewport" content="w

  • three.js中3D视野的缩放实现代码

    通过Threejs基础学习--修改版知道创建一个相机的相关知识点 var camera = new THREE.PerspectiveCamera( fov, aspect , near,far ); 视野角:fov 这里视野角(有的地方叫拍摄距离)越大,场景中的物体越小,视野角越小,场景中的物体越大 纵横比:aspect   (3d物体的宽/高比例) 相机离视体积最近的距离:near 相机离视体积最远的距离:far 其中fov视野角(拍摄距离)越大,场景中的物体越小.fov视野角(拍摄距离)越

  • 利用three.js画一个3D立体的正方体示例代码

    简介 three.js 是一款WebGL框架,WebGL可以让我们在canvas上实现3D效果.实现3D效果在国内来说还算是比较新的东西,可供查阅的资料也不多.这篇文章仅是一个入门篇,介绍如何绘制一个3D正方体. Three.js中的基本概念 Three.js包含3个基本概念:场景(Scene).相机(Camera)和渲染器(Renderer). 场景就是需要绘制的对象,相机代表取景的视角,渲染器是绘制的载体(可以挂靠到浏览器的DOM元素中), 也就是我们通过相机拍摄场景然后绘制到目标介质中去.

  • three.js实现3D模型展示的示例代码

    由于项目需要展示3d模型,所以对three做了点研究,分享出来 希望能帮到大家 先看看效果: three.js整体来说 不是很难 只要你静下心来研究研究 很快就会上手的 首先我们在页面上需要创建一个能够放置3D模型的画布 也可以说是初始化 Three var WIDTH,HEIGHT; var renderer; function initThree() { WIDTH = document.documentElement.clientWidth/2; <!--{foreach from=$re

  • three.js实现炫酷的全景3D重力感应

    本文实例为大家分享了three.js 全景重力感应的具体代码,供大家参考,具体内容如下 实现three.js 全景图 demo 使用three.js 写了球体和圆柱体版本的3D重力感应全景图,支持手指触摸和陀螺仪感应,也支持PC端的鼠标.给大家介绍一下基于移动端H5球体的实现方法,圆柱体类似. 设置容器和展示的样式 设置容器的宽高为全屏展示,清除body的margin,引用three.min.js(3D渲染框架) 和orienter.js (陀螺仪经纬度计算) <div id="Canva

  • Three.js开发实现3D地图的实践过程总结

    前言 本文主要介绍Three.js的开发基础和基本原理,以及如何实现3D全景图.想在web端实现3D全景图的效果,除了全景图片.WebGL外,还需要处理很多细节.据我所知,目前国外3D全景图比较好的是KrPano,国内很多3D全景服务是在使用krpano的工具. 前段时间连续上了一个月班,加班加点完成了一个3D攻坚项目.也算是由传统web转型到webgl图形学开发中,坑不少,做了一下总结分享. Three.js 基于简化WebGL开发复杂度和降低入门难度的目的,mrdoob)在WebGL标准基础

  • Three.js的使用及绘制基础3D图形详解

    一. 前言 Three.js 是一款 webGL(3D绘图标准,在此不赘述)引擎,可以运行于所有支持 webGL 的浏览器.Three.js 封装了 webGL 底层的 API ,为我们提供了高级的开发接口,可以使用简单的代码去实现 3D 渲染.(官网:https://threejs.org/) 二. 为什么要选择Three.js? Three.js 作为原生 web3D 引擎,对插件式 web3D 引擎的优势不言而喻:不需要安装插件.在移动端支持好. Three.js 与其他原生 web3D

随机推荐