欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

three.js如何實(shí)現(xiàn)3D動(dòng)態(tài)文字效果

 更新時(shí)間:2021年03月03日 14:31:14   作者:alphardex  
這篇文章主要給大家介紹了關(guān)于three.js如何實(shí)現(xiàn)3D動(dòng)態(tài)文字效果的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

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

之前在逛國(guó)外網(wǎng)站的時(shí)候,發(fā)現(xiàn)有些網(wǎng)站的文字是刻在3D圖形上的,并且能在圖形上運(yùn)動(dòng),視覺(jué)效果相當(dāng)不錯(cuò),于是筆者就也想用three.js來(lái)嘗試復(fù)現(xiàn)出這種效果

上圖只是所有效果的其中之一,接下來(lái)讓我們一起開(kāi)干吧~

準(zhǔn)備工作

筆者自行封裝的three.js模板:Three.js Starter

讀者可以點(diǎn)擊右下角fork一份后再開(kāi)始本項(xiàng)目

本項(xiàng)目需要用到位圖字體,可以直接復(fù)制demo的HTML里的font字體代碼

一個(gè)注意點(diǎn):three-bmfont-text這個(gè)庫(kù)依賴全局的three.js,因此要在JS里額外引入一次three.js,如下圖

實(shí)現(xiàn)思路

  1. 加載位圖字體文件,將其轉(zhuǎn)化為文字對(duì)象所需要的形狀和材質(zhì)
  2. 創(chuàng)建文字對(duì)象
  3. 創(chuàng)建渲染目標(biāo),可以理解為canvas中的canvas,因?yàn)榻酉聛?lái)我們要將文字對(duì)象本身當(dāng)做貼圖
  4. 創(chuàng)建承載字體的容器,將文字對(duì)象作為貼圖貼上去
  5. 動(dòng)畫(huà)

正片

搭好架子

<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而來(lái)的字體代碼
 </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 = `(頂點(diǎn)著色器代碼,先空著,具體見(jiàn)下文)`;

const kineticTextTorusKnotFragmentShader = `(片元著色器代碼,先空著,具體見(jiàn)下文)`;

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();
 }
 // 創(chuàng)建動(dòng)態(tài)文字
 async createKineticText(text: string) {
 await this.createFontText(text);
 this.createRenderTarget();
 this.createTextContainer();
 }
}

加載和創(chuàng)建字體

首先加載字體文件,并創(chuàng)建出形狀和材質(zhì),有了這兩樣就能創(chuàng)建出字體對(duì)象了

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;
 }
}

著色器

頂點(diǎn)著色器

通用模板,直接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函數(shù)創(chuàng)建重復(fù)的貼圖,加上位移距離displacement使得貼圖能隨著時(shí)間的增加而動(dòng)起來(lái),再用clamp函數(shù)來(lái)根據(jù)z軸大小限定陰影的范圍,意思是離畫(huà)面越遠(yuǎn)則陰影越重,反之離畫(huà)面越近則陰影越輕

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.);
}

此時(shí)文本顯示到了屏幕上

創(chuàng)建渲染目標(biāo)

為了將字體對(duì)象本身作為貼圖,創(chuàng)建了一個(gè)渲染目標(biāo)

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;
 }
}

創(chuàng)建字體容器

創(chuàng)建一個(gè)容器,并將字體對(duì)象本身作為貼圖貼上去,再應(yīng)用動(dòng)畫(huà)即可完成

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;
 }
 }
}

別忘了把相機(jī)調(diào)遠(yuǎn)一些

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

風(fēng)騷的動(dòng)態(tài)文字出現(xiàn)了:)

項(xiàng)目地址

Kinetic Text

demo里不止本文創(chuàng)建的這一種形狀,大家可以隨意把玩。

總結(jié)

到此這篇關(guān)于three.js如何實(shí)現(xiàn)3D動(dòng)態(tài)文字效果的文章就介紹到這了,更多相關(guān)three.js 3D動(dòng)態(tài)文字內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JS事件處理機(jī)制及事件代理(事件委托)實(shí)例詳解

    JS事件處理機(jī)制及事件代理(事件委托)實(shí)例詳解

    這篇文章主要介紹了JS事件處理機(jī)制及事件代理,結(jié)合實(shí)例形式詳細(xì)分析了JS時(shí)間處理機(jī)制與事件代理功能、用法及相關(guān)使用技巧,需要的朋友可以參考下
    2023-06-06
  • JS操作字符串轉(zhuǎn)換為數(shù)值并取整的代碼

    JS操作字符串轉(zhuǎn)換為數(shù)值并取整的代碼

    這篇文章主要介紹了JS操作字符串轉(zhuǎn)換為數(shù)值并取整的代碼,代碼比較短,需要的朋友可以參考下
    2014-01-01
  • js+html5實(shí)現(xiàn)canvas繪制圓形圖案的方法

    js+html5實(shí)現(xiàn)canvas繪制圓形圖案的方法

    這篇文章主要介紹了js+html5實(shí)現(xiàn)canvas繪制圓形圖案的方法,涉及html5圖形繪制的基礎(chǔ)技巧,需要的朋友可以參考下
    2015-06-06
  • 詳解TypeScript中type與interface的區(qū)別

    詳解TypeScript中type與interface的區(qū)別

    在寫(xiě) ts 相關(guān)代碼的過(guò)程中,總能看到 interface 和 type 的身影。它們的作用好像都一樣的,相同的功能用哪一個(gè)都可以實(shí)現(xiàn),也都很好用,所以也很少去真正的理解它們之間到底有啥區(qū)別,因此本文將詳細(xì)講解二者的區(qū)別,需要的可以參考一下
    2022-04-04
  • Javascript注入技巧

    Javascript注入技巧

    Javascript注入技巧...
    2007-06-06
  • javascript獲取URL參數(shù)與參數(shù)值的示例代碼

    javascript獲取URL參數(shù)與參數(shù)值的示例代碼

    本篇文章主要是對(duì)javascript獲取URL參數(shù)與參數(shù)值的示例代碼進(jìn)行了介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助
    2013-12-12
  • 標(biāo)題過(guò)長(zhǎng)使用javascript按字節(jié)截取字符串

    標(biāo)題過(guò)長(zhǎng)使用javascript按字節(jié)截取字符串

    在網(wǎng)頁(yè)展示中經(jīng)常會(huì)碰到,標(biāo)題過(guò)長(zhǎng),需要截取字符串,用CSS的實(shí)現(xiàn)的話各種兼容問(wèn)題,下面為大家介紹下javascript如何按字節(jié)截取字符串
    2014-04-04
  • JavaScript封裝單向鏈表的示例代碼

    JavaScript封裝單向鏈表的示例代碼

    這篇文章主要介紹了JavaScript如何封裝單向鏈表,幫助大家更好的理解和使用JavaScript,感興趣的朋友可以了解下
    2020-09-09
  • 與iframe進(jìn)行跨域交互的解決方案(推薦)

    與iframe進(jìn)行跨域交互的解決方案(推薦)

    這篇文章主要介紹了與iframe進(jìn)行跨域交互的解決方案,本文通過(guò)實(shí)例代碼給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • JavaScript深入介紹WebAPI的用法

    JavaScript深入介紹WebAPI的用法

    JS分成三個(gè)大的部分:ECMAScript、DOM API、BOM API,其中:ECMAScript是讓前端開(kāi)發(fā)建立基本的編程思維。但是要想真正來(lái)寫(xiě)一個(gè)更加復(fù)雜的有交互式的頁(yè)面,還需要WebAPI的支持,相當(dāng)于把后端編程實(shí)現(xiàn)成前端交互。DOM+BOM就組成了WebAPI
    2022-06-06

最新評(píng)論