three.js如何实现3D动态文字效果
网络编程 2021-07-04 14:07www.168986.cn编程入门
这篇文章主要给大家介绍了关于three.js如何实现3D动态文字效果的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们狼蚁网站SEO优化随着长沙网络推广来一起学习学习吧
前言
大家好,这里是 CSS 魔法使——alphardex。
之前在逛国外网站的时候,发现有些网站的文字是刻在3D图形上的,并且能在图形上运动,视觉效果相当不错,于是笔者就也想用three.js来尝试复现出这种效果
上图只是所有效果的其中之一,接下来让我们一起开干吧~
准备工作
笔者自行封装的three.js模板
读者可以点击右下角fork一份后再开始本项目
本项目需要用到位图字体,可以直接复制的HTML里的font字体代码
一个注意点three-bmfont-text这个库依赖全局的three.js,要在JS里额外引入一次three.js,如下图
实现思路
- 加载位图字体文件,将其转化为文字对象所需要的形状和材质
- 创建文字对象
- 创建渲染目标,可以理解为canvas中的canvas,因为接下来我们要将文字对象本身当做贴图
- 创建承载字体的容器,将文字对象作为贴图贴上去
- 动画
正片
搭好架子
<div class="relative w-screen h-screen"> <div class="kiic-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./2021/02/20/DcEhuYNjxCgeU42.png"; const kiicTextTorusKnotVertexShader = `(顶点着色器代码,先空着,具体见下文)`; const kiicTextTorusKnotFragmentShader = `(片元着色器代码,先空着,具体见下文)`; class KiicText 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: kiicTextTorusKnotVertexShader, fragmentShader: kiicTextTorusKnotFragmentShader, 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.createKiicText(this.params.text); this.createLight(); this.createOrbitControls(); this.addListeners(); this.setLoop(); } // 创建动态文字 async createKiicText(text: string) { await this.createFontText(text); this.createRenderTarget(); this.createTextContainer(); } }
加载和创建字体
加载字体文件,并创建出形状和材质,有了这两样就能创建出字体对象了
class KiicText 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=modelMatrixvec4(position,1.); vec4 viewPosition=viewMatrixmodelPosition; vec4 projectedPosition=projectionMatrixviewPosition; 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=vUvrepeat; vec2 displacement=vec2(uTimeuVelocity,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(textureshadow); gl_FragColor=vec4(color,1.); }
此时文本显示到了屏幕上
创建渲染目标
为了将字体对象本身作为贴图,创建了一个渲染目标
class KiicText 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 KiicText 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);
风骚的动态文字出现了:)
项目地址
demo里不止本文创建的这一种形状,大家可以随意把玩。
到此这篇关于three.js如何实现3D动态文字效果的文章就介绍到这了,更多相关three.js 3D动态文字内容请搜索狼蚁SEO以前的文章或继续浏览狼蚁网站SEO优化的相关文章希望大家以后多多支持狼蚁SEO!
编程语言
- 如何快速学会编程 如何快速学会ug编程
- 免费学编程的app 推荐12个免费学编程的好网站
- 电脑怎么编程:电脑怎么编程网咯游戏菜单图标
- 如何写代码新手教学 如何写代码新手教学手机
- 基础编程入门教程视频 基础编程入门教程视频华
- 编程演示:编程演示浦丰投针过程
- 乐高编程加盟 乐高积木编程加盟
- 跟我学plc编程 plc编程自学入门视频教程
- ug编程成航林总 ug编程实战视频
- 孩子学编程的好处和坏处
- 初学者学编程该从哪里开始 新手学编程从哪里入
- 慢走丝编程 慢走丝编程难学吗
- 国内十强少儿编程机构 中国少儿编程机构十强有
- 成人计算机速成培训班 成人计算机速成培训班办
- 孩子学编程网上课程哪家好 儿童学编程比较好的
- 代码编程教学入门软件 代码编程教程