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

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)文章

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

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

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

    JavaScript閉包原理與用法實(shí)例分析

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

    JavaScript中的this使用詳解

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

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

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

    使用Ajax生成的Excel文件并下載的實(shí)例

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

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

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

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

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

    JavaScript中ES6字符串?dāng)U展方法

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

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

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

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

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

最新評(píng)論

陆川县| 开江县| 鄂伦春自治旗| 永胜县| 若羌县| 佳木斯市| 玉环县| 张北县| 新巴尔虎左旗| 河津市| 荔浦县| 敦煌市| 微博| 齐齐哈尔市| 延庆县| 百色市| 景东| 铜梁县| 鲁甸县| 黔西县| 翼城县| 邛崃市| 体育| 丁青县| 含山县| 万山特区| 遂昌县| 温宿县| 修文县| 海伦市| 南开区| 桐柏县| 临漳县| 祁东县| 鞍山市| 长春市| 万载县| 沾益县| 巴林右旗| 竹北市| 凤城市|