最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

前言

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

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

上圖只是所有效果的其中之一,接下來讓我們一起開干吧~

準備工作

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

讀者可以點擊右下角fork一份后再開始本項目

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

一個注意點:three-bmfont-text這個庫依賴全局的three.js,因此要在JS里額外引入一次three.js,如下圖

實現(xiàn)思路

  1. 加載位圖字體文件,將其轉(zhuǎn)化為文字對象所需要的形狀和材質(zhì)
  2. 創(chuàng)建文字對象
  3. 創(chuàng)建渲染目標,可以理解為canvas中的canvas,因為接下來我們要將文字對象本身當做貼圖
  4. 創(chuàng)建承載字體的容器,將文字對象作為貼圖貼上去
  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();
 }
 // 創(chuàng)建動態(tài)文字
 async createKineticText(text: string) {
 await this.createFontText(text);
 this.createRenderTarget();
 this.createTextContainer();
 }
}

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

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

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函數(shù)創(chuàng)建重復(fù)的貼圖,加上位移距離displacement使得貼圖能隨著時間的增加而動起來,再用clamp函數(shù)來根據(jù)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.);
}

此時文本顯示到了屏幕上

創(chuàng)建渲染目標

為了將字體對象本身作為貼圖,創(chuàng)建了一個渲染目標

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)建一個容器,并將字體對象本身作為貼圖貼上去,再應(yīng)用動畫即可完成

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

別忘了把相機調(diào)遠一些

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

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

項目地址

Kinetic Text

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

總結(jié)

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

相關(guān)文章

  • 根據(jù)后端返回的json數(shù)據(jù)快速生成ts類型的實現(xiàn)代碼

    根據(jù)后端返回的json數(shù)據(jù)快速生成ts類型的實現(xiàn)代碼

    在前端開發(fā)中,我們通常需要處理來自后端或其他數(shù)據(jù)源的 JSON 數(shù)據(jù),這些數(shù)據(jù)可能非常復(fù)雜,包含不同類型的屬性,甚至嵌套對象和數(shù)組,為了更好地使用這些數(shù)據(jù),我們希望將其轉(zhuǎn)換為TypeScript類型定義,以獲得類型檢查和代碼智能提示的好處
    2023-10-10
  • JavaScript閉包原理與用法實例分析

    JavaScript閉包原理與用法實例分析

    這篇文章主要介紹了JavaScript閉包原理與用法,結(jié)合實例形式分析了javascript閉包的概念、功能、常見問題及相關(guān)操作技巧,需要的朋友可以參考下
    2018-08-08
  • JavaScript中的this使用詳解

    JavaScript中的this使用詳解

    this是javascript的一個關(guān)鍵字,隨著函數(shù)使用場合不同,this的值會發(fā)生變化。但是總有一個原則,那就是this指的是調(diào)用函數(shù)的那個對象。今天我們就來詳細探討下this的使用
    2016-07-07
  • javascript使用遞歸算法求兩個數(shù)字組合功能示例

    javascript使用遞歸算法求兩個數(shù)字組合功能示例

    這篇文章主要介紹了javascript使用遞歸算法求兩個數(shù)字組合功能,結(jié)合實例形式分析了JS基于遞歸算法的數(shù)組遍歷、判斷、轉(zhuǎn)換等相關(guān)操作技巧,需要的朋友可以參考下
    2017-01-01
  • 使用Ajax生成的Excel文件并下載的實例

    使用Ajax生成的Excel文件并下載的實例

    本篇文章主要介紹了使用Ajax生成的Excel文件并下載的實例,具有一定的參考價值,有需要的可以了解一下。
    2016-11-11
  • 網(wǎng)頁中的圖片查看器viewjs使用方法

    網(wǎng)頁中的圖片查看器viewjs使用方法

    下面小編就為大家?guī)硪黄W(wǎng)頁中的圖片查看器viewjs使用方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • JavaScript中eval函數(shù)的問題

    JavaScript中eval函數(shù)的問題

    這篇文章主要介紹了JavaScript中eval函數(shù)的問題,需要的朋友可以參考下
    2016-01-01
  • JavaScript中ES6字符串擴展方法

    JavaScript中ES6字符串擴展方法

    這篇文章主要介紹了JavaScript中ES6字符串擴展方法的相關(guān)資料,非常不錯,具有參考借鑒價值,感興趣的朋友一起學(xué)習(xí)吧
    2016-08-08
  • JavaScript實現(xiàn)瀑布流以及加載效果

    JavaScript實現(xiàn)瀑布流以及加載效果

    這篇文章主要為大家詳細介紹了JavaScript實現(xiàn)瀑布流以及加載效果的相關(guān)資料,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • JS實現(xiàn)網(wǎng)站吸頂條

    JS實現(xiàn)網(wǎng)站吸頂條

    這篇文章主要為大家詳細介紹了JS制作網(wǎng)站吸頂條,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-01-01

最新評論

嵊泗县| 响水县| 恩平市| 高要市| 牟定县| 建平县| 冷水江市| 阿合奇县| 双流县| 三江| 凯里市| 镇雄县| 南丰县| 鄂托克旗| 新和县| 安达市| 漾濞| 丰顺县| 滦平县| 安西县| 白玉县| 沈丘县| 年辖:市辖区| 丰都县| 武冈市| 霞浦县| 肇州县| 棋牌| 绍兴市| 安图县| 鹿邑县| 文登市| 华安县| 理塘县| 调兵山市| 分宜县| 明光市| 香港| 马鞍山市| 仁化县| 保德县|