国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

如何用Three.js + Blender打造一個web 3D展覽館

這篇具有很好參考價值的文章主要介紹了如何用Three.js + Blender打造一個web 3D展覽館。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

作者:vivo 互聯(lián)網(wǎng)前端團(tuán)隊(duì)- Wei Xing?

運(yùn)營活動新玩法層出不窮,web 3D炙手可熱,本文將一步步帶大家了解如何利用Three.js和Blender來打造一個沉浸式web 3D展覽館。

一、前言

3D展覽館是什么,先來預(yù)覽下效果:

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

看起來像個3D冒險類手游,用戶可以操縱屏幕中央的虛擬搖桿,以第一人稱視角在房間內(nèi)自由移動、看展覽。

1.1 為什么做3D展覽館

首先介紹一個背景,我們的工作內(nèi)容是做游戲中心的用戶運(yùn)營活動,會做些好玩的活動讓用戶參與,并get一些福利。

當(dāng)時的活動背景是我司一年一度的vivo游戲節(jié),并且元宇宙是大熱詞。所以做它的原因有幾個:

  • vivo游戲節(jié)主題

  • 契合元宇宙熱點(diǎn)

  • 新玩法、新體驗(yàn)

1.2?技術(shù)選型

用到的組合方案:Three.js + Blender。

  • why Three.js

開源的3D框架有很多,但最常用的有兩種:Three.js、Babylon.js,我們只需要從中二選一。分析后發(fā)現(xiàn)兩者各有優(yōu)勢:

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

考慮到3D展覽館的幾個基本特性:

  1. 簡單的小型3D場景,沒有復(fù)雜的交互(對鏡頭的要求不高)

  2. 投放在移動設(shè)備,需要盡可能小的包體,以提升性能

  3. 工期短,需要快速上手及更多的案例參考

Three.js包體更小、有更多參考案例、上手更快,所以雖然Babylon.js有它的優(yōu)勢,但Three.js更適合這個項(xiàng)目。

  • why Blender

Blender是一款輕量的開源3D建模軟件,有很多好用的免費(fèi)插件,而且Blender能導(dǎo)出GLTF / GLB模型(后面會對GLTF / GLB模型做簡介),匹配Three.js的使用方式,整體更簡單好用一些。

所以,就是它了。

二、實(shí)踐部分

2.1 了解GLTF / GLB模型

在進(jìn)入開發(fā)之前,先簡單了解Blender和GLTF / GLB模型。

  • 簡單了解 Blender

首先,Blender大概長這樣,圖中是設(shè)計師交付的3D展覽館稿子。簡單理解為,左側(cè)是模型的層次結(jié)構(gòu),中間是模型的預(yù)覽效果,右側(cè)是模型的屬性面板。

一般來說,作為開發(fā)者我們不需要掌握太多Blender相關(guān)知識,只需知道如何看懂模型結(jié)構(gòu)、導(dǎo)出GLTF / GLB模型以及烘焙的基本原理即可。

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

  • GLTF / GLB模型

GLTF(Graphics Language Transmission Format)是一種標(biāo)準(zhǔn)的3D模型文件格式,它以JSON的形式存儲3D模型信息,例如模型的層次結(jié)構(gòu)、材質(zhì)、動畫、紋理等。

模型中依賴的靜態(tài)資源,比如圖片,可以通過外部URI的方式來引入,也可以轉(zhuǎn)成base64直接插入在GLTF文件中。

它包含兩種形式的后綴,分別是.gltf(JSON/ASCII).glb(Binary)。.gltf是以JSON的形式存儲信息。.glb則是.gltf的擴(kuò)展格式,它以二進(jìn)制的形式存儲信息,因此導(dǎo)出的模型體積也更小一些。如果我們不需要通過JSON對.gltf模型進(jìn)行直接修改,建議使用.glb模型,它更小、加載更快。

  • Blender導(dǎo)出GLTF / GLB模型

在blender中,可以直接將模型導(dǎo)出為GLTF / GLB格式,三種選項(xiàng)的差別不再贅述,我們先簡單選擇最高效的.glb格式。

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

有了模型之后,我們可以開始通過Three.js創(chuàng)建場景,并導(dǎo)入這個模型了。

2.2 Three.js 加載模型

為了防止篇幅過長,這里假設(shè)大家已經(jīng)掌握了Three.js的一些基本語法。文章重點(diǎn)放在如何加載模型,并一步步進(jìn)行調(diào)優(yōu)和實(shí)現(xiàn)最終的3D展覽館效果。

怎么加載一個模型?

(1)創(chuàng)建一個空場景

首先創(chuàng)建一個空場景scene,后續(xù)所有的模型或材質(zhì)都會被添加到這個場景中。

import * as THREE from 'three'

// 1. 創(chuàng)建場景
const scene = new THREE.Scene(); 


// 2. 創(chuàng)建鏡頭
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
// 3. 創(chuàng)建Renderer
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

(2)導(dǎo)入GLTF / GLB模型

通過GLTFLoader導(dǎo)入.glb模型,并添加到場景中。

import GLTFLoader from 'GLTFLoader'
const loader = new GLTFLoader()
loader.load('path/to/gallery.glb',
  gltf => {
    scene.add(gltf.scene) // 添加到場景中
  } 
}

(3)開始渲染

通過requestAnimationFrame來調(diào)用renderer.render方法,開始實(shí)時渲染場景。

function animate() {
      requestAnimationFrame( animate );
      renderer.render( scene, camera );
}
animate();

ok,這樣我們就完成了3D模型的導(dǎo)入,但是發(fā)現(xiàn)整個場景一片漆黑。

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

試試加個環(huán)境光。

const ambientLight = new THREE.AmbientLight(0xffffff, 1)

scene.add(ambientLight)

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

ok,亮起來了,但是效果依然很差,很劣質(zhì)。

原因是模型中的材質(zhì)效果、光源、陰影、環(huán)境紋理,這些全都丟失了,所以當(dāng)我們導(dǎo)入模型時,看到的就是一堆簡陋的純色形狀。

所以我們要一步步將這些丟失東西找回,還原設(shè)計稿。

2.3 還原設(shè)計稿

接下來一步步還原設(shè)計稿。

(1)加上光源

查看Blender模型,看到設(shè)計稿中添加了一堆點(diǎn)光源、平行光源。

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

點(diǎn)光源可以理解為房間中的燈泡,光線強(qiáng)弱隨著距離衰減;

平行光源可以理解為太陽的直射光,它和點(diǎn)光源不同,光線強(qiáng)弱不隨著距離衰減。

于是我們也增加一些光源:

// 一些燈光選項(xiàng)
// 如果是平行光則沒有distance、decay選項(xiàng)
const lightOptions = [

  {
    type: 'point', // 燈光類型:1. point點(diǎn)光源、2. directional平行光源
    color: 0xfff0bf, // 燈光顏色
    intensity: 0.4, // 燈光強(qiáng)度
    distance: 30,    // 光照距離
    decay: 2,    // 衰減速度
    position: { // 光源位置
      x: 2,
      y: 6,
      z: 0
    }
  },
  ...

]

function createLights() {
  pointLightOptions.forEach(option => {
    const light = option.type === 'point' ?
        new THREE.PointLight(option.color, option.intensity, option.distance, option.decay) :
        new THREE.DirectionalLight(option.color, option.intensity)
    const position = option.position
    light.position.set(position.x, position.y, position.z)
    scene.add(light)
  })
}

createLights()

可以看到場景比之前好了一些,有了光源后,模型變得立體和真實(shí)了,多了一些反色的光澤。

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

但是我們注意到,畫面中的logo、長椅的兩側(cè)都是黑色的,并且旁邊的球體、椅子等都顯得不夠真實(shí)。

所以,我們需要進(jìn)行下一步調(diào)整:調(diào)整模型材質(zhì)、增加環(huán)境紋理。

(2)調(diào)整模型材質(zhì),增加環(huán)境紋理

先簡單了解一下材質(zhì)和環(huán)境紋理。

  • 材質(zhì)(material)

材質(zhì)就像物體的皮膚,我們可以調(diào)整皮膚的光澤、金屬度、粗糙度、透明與否等屬性,讓物體有不同的視覺效果。

一般從blender導(dǎo)出的模型中,已經(jīng)包含了一些材質(zhì)屬性,但是Three.js中的材質(zhì)屬性和Blender中的屬性并非完全的映射關(guān)系,模型在導(dǎo)入到Three.js后,效果和設(shè)計稿會有差異。這時候我們需要手動調(diào)整材質(zhì)的屬性,來達(dá)到和設(shè)計稿近似的效果。

  • 環(huán)境紋理(environment map)

環(huán)境紋理就是讓模型映射周圍的環(huán)境,讓場景或物體更真實(shí)。例如我們要渲染一個立方體,把立方體放進(jìn)一個屋子里,這個屋子的環(huán)境就會影響立方體的渲染效果。

比如鏡面的物體被貼上環(huán)境紋理后,就可以實(shí)時反射周圍的環(huán)境鏡像,看起來很real。

設(shè)計稿中也是將一個大廳作為了環(huán)境紋理,讓場景更真實(shí)。

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

環(huán)境紋理分為:球形紋理和立方體形紋理。兩者都可以,這里我們采用一張大廳的球形紋理作為環(huán)境貼圖。

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

以畫面中的vivo游戲節(jié)logo為例,我們通過調(diào)整它的材質(zhì)和環(huán)境紋理,讓它變得更真實(shí)。

  1. 根據(jù)在blender中的命名,找到logo模型

  2. 調(diào)整logo的表面粗糙度和金屬度

  3. 加載并設(shè)置環(huán)境紋理貼圖

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

const loader = new GLTFLoader()
loader.load('path/to/gallery.glb',
  gltf => {
      // 1. 根據(jù)Blender中物體的名字,找到logo模型
      gltf.scene.traverse(child => {
        if (isLogo(child)) {
       initLogo(child)   // 2. 調(diào)整材質(zhì)
       setEnvMap(child)  // 3. 設(shè)置環(huán)境紋理
      }
      })
    scene.add(gltf.scene)
  } 
}


// 判斷是否為Logo
const isLogo = object.name === 'logo'

function initLogo(object) {
  object.material.roughness = 0   // 調(diào)整表面粗糙度
  object.material.metalness = 1   // 調(diào)整金屬度
}
// 加載環(huán)境紋理

let envMap
const envmaploader = new THREE.PMREMGenerator(renderer)

const setEnvMap = (object) => {
      if(envMap) {
        object.material.envMap = envMap.texture
      } else {
        textureLoader.load('path/to/envMap.jpg',
             texture => {
             texture.encoding = THREE.sRGBEncoding
             envMap = envmaploader.fromCubemap(texture)
                 object.material.envMap = envMap.texture
             })
      }
}

經(jīng)過上面的處理后,可以看到原先黑色的logo有了金屬光澤,并且會反射周圍的環(huán)境紋理。

其它物體經(jīng)過類似的處理后,也變得更真實(shí)一些。

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

現(xiàn)在整個場景更接近了設(shè)計稿一些,但場景中少了陰影,顯得很干癟。

加上陰影。

(3)增加陰影

增加陰影分四步:

  1. 對renderer開啟陰影支持:renderer.shadowMap.enabled = true

  2. 對光源設(shè)置:castShadow = true

  3. 對需要投影的物體設(shè)置:castShadow = true

  4. 對需要被投影的平面或物體(比如地板)設(shè)置:receiveShadow = true

// 1. renderer
const renderer = new THREE.WebGLRenderer()
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;

// 2. light
const light = new THREE.DirectionalLight()
light.castShadow = true;

// 3. object
gltf.scene.traverse(function (child) {
   if (child.isMesh) {
     child.castShadow = true;
   }
});
// 4. floor
floor.receiveShadow = true

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

添加陰影后,有質(zhì)的提升,發(fā)現(xiàn)整個場景立體了很多,此時還原度已經(jīng)很高。

如果不考慮性能損耗,這個場景的樣式已經(jīng)可以投入使用了。(后續(xù)會提到性能優(yōu)化)

小結(jié)一下,剛剛做的幾件事:

  1. 添加光源

  2. 調(diào)整模型材質(zhì)、增加環(huán)境紋理

  3. 增加陰影

現(xiàn)在3D展覽館場景已經(jīng)還原的差不多了,接下來要構(gòu)造一個虛擬移動搖桿,控制第一人稱鏡頭的移動和轉(zhuǎn)向,實(shí)現(xiàn)沉浸式逛展的效果。

2.4 虛擬移動搖桿

要實(shí)現(xiàn)通過虛擬移動搖桿控制鏡頭的移動和轉(zhuǎn)向,我們需要三個東西:

  • 一個移動搖桿(handler)

  • 一個長方體(player):用于承載第一人稱視角

  • 一個鏡頭(camera):之前已經(jīng)創(chuàng)建過了

有人會問為什么需要一個player,通過搖桿直接控制鏡頭不就行了嗎?其實(shí)player的作用是用于做碰撞檢測,當(dāng)player遇到凳子、墻壁等障礙物時,需要停止鏡頭移動。直接控制鏡頭,是無法做碰撞檢測的。

所以,實(shí)際上鏡頭移動的邏輯是:

用戶操縱搖桿 → 更新player位置和朝向 →從而同步更新camera位置和朝向

(1)創(chuàng)建移動搖桿

移動搖桿的實(shí)現(xiàn)原理很簡單,這里僅做簡述。

核心在于創(chuàng)建一個圓盤,監(jiān)聽觸摸手勢,并根據(jù)手勢的方向來實(shí)時更新move參數(shù),控制鏡頭的移動和轉(zhuǎn)向。

const speed = 8 // 移動速度
const turnSpeed = 3  // 轉(zhuǎn)向速度
// move option,用于調(diào)整第一人稱鏡頭的移動和轉(zhuǎn)向
const move = {
      turn: 0,  // 旋轉(zhuǎn)角度
      forward: 0     // 前進(jìn)距離
}

// 創(chuàng)建一個handler,并監(jiān)聽手勢,調(diào)整move option
const handler = new Handler()
handler.onTouchMove = () => { // update move option }

(2)創(chuàng)建player

首先創(chuàng)建一個player對象,它是一個1.2 * 2 * 1的透明長方體。

function createPlayer() {
  const box = new THREE.BoxGeometry(1.2, 2, 1)
  const mat = new THREE.MeshBasicMaterial({
    color: 0x000000,
    wireframe: true
  })

  const mesh = new THREE.Mesh(box, mat)
  box.translate(0, 1, 0)
  return mesh
}

const player = createPlayer() // 創(chuàng)建player
player.position.set(4.5, 2, 12)     // 設(shè)置player的初始位置

(3)updatePlayer & updateCamera

每次渲染(render)時,更新player的位置和朝向,并同步更新鏡頭的位置和朝向。

const clock = THREE.clock()

function render() {
  const dt = clock.delta()   // 獲取每幀之間的時間間隔,根據(jù)時間間隔長短來更新player和camera的移動距離和轉(zhuǎn)向的多少
  updatePlayer(dt)
  updateCamera(dt)
  renderer.render(scene, camera)
  window.requestAnimationFrame(render)
}

// 更新player的位置和朝向

function updatePlayer(dt) {
  const pos = player.position.clone()
  pos.y -= 1.5 // 降低高度,后續(xù)用于計算碰撞檢測
  const dir = new THREE.Vector3()
  player.getWorldDirection(dir)
  dir.negate()
  if (move.forward < 0) dir.negate()
  // 調(diào)整鏡頭前進(jìn) or 后退

  if (move.forward !== 0) {
    player.translateZ(move.forward > 0 ? -dt * speed : dt * speed * 0.5)
  }
  // 調(diào)整鏡頭朝向

  if (move.turn !== 0) {
    player.rotateY(move.turn * 1.2 * dt)
  }
}

// 根據(jù)player的位置和朝向,同步更新camera的位置和朝向

function updateCamera(dt) {
  camera.position.lerp(activeCamera.getWorldPosition(new THREE.Vector3()), 0.08)
  const pos = player.position.clone()
  pos.y += 2.5
  camera.lookAt(pos)
}

注意:render方法中使用clock.delta()來計算每次渲染之間的時間間隔,并使用這個時間間隔來更新player和camera。因?yàn)樵诶硐氲?0幀率情況下,兩幀時間間隔為16.67ms,但實(shí)際上該數(shù)值會有波動,因此我們要根據(jù)實(shí)際的渲染時間間隔來更新player和camera,讓鏡頭的移動和轉(zhuǎn)向幅度更自然一些。

完成上述步驟后,我們就可以通過控制虛擬移動搖桿,來讓鏡頭移動和轉(zhuǎn)向了。

接下來加入碰撞檢測,對鏡頭移動加點(diǎn)限制。

2.5?碰撞檢測

碰撞檢測的步驟也很簡單:

  • 收集障礙物(colliders)

  • 檢測碰撞(基于THREE.Raycaster)

(1)收集障礙物

模型加載完成后,遍歷所有的child,如果child是一個物體(mesh),則把它加入到障礙物隊(duì)列(colliders)中。

const colliders = []

loader.load('path/to/gallery.glb',
  gltf => {
    gltf.scene.traverse(child => {
        // 收集障礙物
        if(isMesh(child)) {
          colliders.push(child) 
        }
    })
  } 
})

(2)檢測碰撞

調(diào)整剛剛的updatePlayer方法,在其中插入檢測碰撞的邏輯。

碰撞檢測邏輯基于THREE.Raycaster來實(shí)現(xiàn),racaster可以理解為一個射線,當(dāng)射線穿過了某個物體,我們就認(rèn)為射線和物體相交了。

我們讓射線的方向和player的朝向保持一致,并且在移動過程中不斷判斷射線前方/后面是否有相交的物體,如果有相交的物體,且和射線頂點(diǎn)距離distance < 2.5則認(rèn)為遇到了障礙物,不能再繼續(xù)前進(jìn)。

function updatePlayer(dt) {
  const pos = player.position.clone()
  pos.y -= 1.5 // 降低高度,用于計算collision
  const dir = new THREE.Vector3()

  // 獲取當(dāng)前player的朝向
  player.getWorldDirection(dir)
  dir.negate()
  // 如果是向后退,需要對朝向取反
  if (move.forward < 0) dir.negate()

  // 利用Raycaster判斷player是否和colliders有碰撞行為
  const raycaster = new THREE.Raycaster(pos, dir)
  let blocked = false

  if (colliders.length > 0) {
    const intersect = raycaster.intersectObjects(colliders)
    if (intersect.length > 0) {
      // 如果相交距離<2.5,表示前方或后面有障礙物
      if (intersect[0].distance < 2.5) {
        blocked = true
      }
    }
  }
  // 如果遇到障礙物,則停滯移動

  if (!blocked) {
    // 調(diào)整鏡頭前進(jìn) or 后退
    if (move.forward !== 0) {
      player.translateZ(move.forward > 0 ? -dt * speed : dt * speed * 0.5)
    }
  }

  // 調(diào)整鏡頭朝向
  if (move.turn !== 0) {
    player.rotateY(move.turn * 1.2 * dt)
  }
}

這樣鏡頭的移動和碰撞檢測就完成了。

當(dāng)我們移動到椅子、墻壁等障礙物附近時,鏡頭會停止移動。鏡頭的移動范圍也被我們限制在房間里,不會穿到房間外部。

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

三、性能調(diào)優(yōu)

3.1 紋理烘培

3D展覽館的基本功能已經(jīng)完成了,但還沒有做任何的性能調(diào)優(yōu)。當(dāng)我們把項(xiàng)目運(yùn)行在手機(jī)上,會發(fā)現(xiàn)設(shè)備發(fā)熱發(fā)燙,幀率很低,低端機(jī)型甚至無法運(yùn)行。

經(jīng)過分析,實(shí)時的光影渲染是罪魁禍?zhǔn)住?/p>

頁面中有10+個光源,每個光源都在實(shí)時投射陰影(尤其是點(diǎn)光源十分消耗資源,引起卡頓)。但實(shí)際,場景中的光源和物體位置都沒有發(fā)生改變,這意味著我們不需要計算實(shí)時陰影,只需要固定的陰影。

這點(diǎn)可以通過紋理烘焙來實(shí)現(xiàn)。并且在移動端,經(jīng)過紋理烘焙的光影效果實(shí)際上要優(yōu)于設(shè)備計算的實(shí)時光影效果。

  • 紋理烘焙(Texture Baking)

紋理烘焙,是指通過將場景效果預(yù)渲染到指定紋理上,生成一個模型貼圖。在Blender中,我們可以選中任意對象進(jìn)行烘焙。

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

以3D展覽館的地板為例,我們可以通過紋理烘焙,將光影效果直接渲染到貼圖上。

左圖是原本的棋盤格紋理,右圖是結(jié)合了光影效果的烘焙貼圖。烘焙完成后,地板上的光影效果就被固定下來了,我們也不需要再做實(shí)時的光影渲染。

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

用同樣的方式,將地板、墻壁、天花板等物體,一一進(jìn)行烘焙處理,導(dǎo)出一個新的模型。由于光影效果已經(jīng)被渲染到貼圖上,我們可以將大部分光源去掉,只保留2-3個必要的點(diǎn)、平行光源和全局光。再次運(yùn)行后,發(fā)現(xiàn)卡頓、發(fā)燙的問題已經(jīng)不再明顯。并且效果其實(shí)比實(shí)時渲染更精細(xì)一些。

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

這里沒有對烘焙做過多介紹,要生成精致的烘焙結(jié)果還需要依賴對UV Map、烘焙參數(shù)的了解,雖然這些偏向于設(shè)計同學(xué)的工作,一般由他們來輸出烘焙紋理。但是作為開發(fā)者,了解了這些后才能和UI更好地溝通和配合。

3.2 優(yōu)化模型大小

模型大小約為23M,首次加載模型需要9s左右。(尤其是在做完紋理烘焙后,由于貼圖變得復(fù)雜,模型更大了)

以下是幾個優(yōu)化模型大小的建議:

  1. 優(yōu)先使用.glb而非.gltf格式。.glb是二進(jìn)制格式,它比.gltf的JSON格式小25% - 30%左右。

  2. 將紋理(Texture)和模型分離,并行加載。23M的模型中,其實(shí)只有2.3M為模型大小,其余都為紋理貼圖。將模型和紋理分開后,可以極大減少模型的加載速度。

  3. 使用Draco、gltfpack等工具或一些online compressor來壓縮模型(Blender在導(dǎo)出gltf模型時,就帶有基于Draco的壓縮選項(xiàng))。本項(xiàng)目通過該步驟壓縮了50%的模型大?。?M → 1.2M。

  4. 壓縮紋理(Texture)。本項(xiàng)目用到了5張的Texture,壓縮后:18M→ 2M。

經(jīng)過優(yōu)化,初始模型大小由23M縮小為1.2M,首次加載時間由9s縮短到3s以內(nèi)。

(左圖為優(yōu)化前,右圖為優(yōu)化后)

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

如何用Three.js + Blender打造一個web 3D展覽館,前端,blender,Three.js,3D展覽館,javascript

四、總結(jié)

現(xiàn)在,我們基本完成了整個3D展覽館的開發(fā)。雖然有一些細(xì)節(jié)沒有在文中涉及到,但開發(fā)過程大致如此。

(1)了解Blender、GLTF / GLB模型

(2)js導(dǎo)入GLTF / GLB模型

(3)還原設(shè)計稿

  • 添加光源

  • 調(diào)整模型材質(zhì)、增加環(huán)境紋理

  • 增加陰影

(4)實(shí)現(xiàn)虛擬移動搖桿,控制鏡頭移動

(5)增加碰撞檢測

(6)性能調(diào)優(yōu):

  • 紋理烘培:通過紋理烘焙降低實(shí)時光影的性能損耗。

  • 優(yōu)化包體大?。?/p>

- 優(yōu)先使用.glb而非.gltf格式

- 紋理和模型分離

- 壓縮模型

- 壓縮紋理

五、其他

一些建議:

  • 設(shè)計師在Blender中命名物體、材質(zhì)時要規(guī)范化,避免出現(xiàn)奇怪或沒有標(biāo)識意義的命名,因?yàn)樵陂_發(fā)過程中會使用到,容易混淆。

  • 設(shè)計師在在Blender中復(fù)用材質(zhì)要謹(jǐn)慎,避免開發(fā)在調(diào)整某個材質(zhì)時,影響到其它使用到相同材質(zhì)的物體(潛在bug)。

  • 模型加載緩慢時,可以增加loading進(jìn)度條,緩解等待焦慮。Three.js loader支持加載進(jìn)度查詢。

  • Three.js在不同版本之間,接口頻繁變更,在使用時注意版本差異,google問題時也要注意接口兼容性。

  • Three.js實(shí)現(xiàn)物體發(fā)光效果較繁瑣,且消耗性能,設(shè)計時可盡量避免使用。

  • Three.js的鏡頭移動不夠絲滑,注重鏡頭切換流暢性的項(xiàng)目,可以嘗試用Babylon.js。

  • 部分瀏覽器不支持videoTexture(在模型中播放視頻),謹(jǐn)慎設(shè)計該類型功能,或做好兼容處理。

參考:

  • Threejs+Blender打造3D全景VR畫展「1」 – 碼語派教室

  • three js blender animation - Google Search

  • Loading Animated Characters in React Three Fiber

  • 淺談three.js中的needsUpdate - pissang - 博客園

  • Directional Light Shadow - Three.js Tutorials

  • Shadows not working

  • 自適應(yīng)Shadow Bias算法

  • GLB Modify Material and add emission

  • How can I improve the performance of a three.js script?

  • HTML5 Audio events not triggering on Chrome

  • http://jeromeetienne.github.io/threex.videotexture/examples/videotexture.html

  • 部分代碼參考自:GitHub - mayupi/3dvr-gallery: 3dvr gallery with threejs and blender文章來源地址http://www.zghlxwxcb.cn/news/detail-572860.html

到了這里,關(guān)于如何用Three.js + Blender打造一個web 3D展覽館的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Blender Three.js 智慧3D機(jī)房開發(fā) 模型創(chuàng)建與導(dǎo)入中的常見問題與解決方案

    Blender Three.js 智慧3D機(jī)房開發(fā) 模型創(chuàng)建與導(dǎo)入中的常見問題與解決方案

    目錄 機(jī)房效果展示 可能出現(xiàn)的問題及解決方法 Three. js服務(wù)器運(yùn)行環(huán)境搭建及文件配置 使用Node.js搭建本地服務(wù)器 文件配置? Blender材質(zhì)處理 Blender導(dǎo)出GLTF模型出現(xiàn)材質(zhì)丟失 Three.js玻璃材質(zhì)制作 ?Blender導(dǎo)出glTF格式模型 Three. js模型顯示場景的設(shè)置 總結(jié) ? 機(jī)房正面圖: 機(jī)房背面

    2024年02月05日
    瀏覽(169)
  • 用Three.js打造酷炫3D個人網(wǎng)站(含源碼)

    個人網(wǎng)站是程序員的第二張簡歷。如果你有酷炫的個人網(wǎng)頁,面試官對你的好感度會蹭蹭蹭往上漲。 在疫情隔離期間,我用 Three.js 和 Ammo.js 制作了一個可交互的3D個人網(wǎng)頁。 在線預(yù)覽地址: www.ryan-floyd.com/ 當(dāng)我在Google Experiments閑逛時,我發(fā)現(xiàn)非常多的作品都是用 three.js 寫的

    2023年04月19日
    瀏覽(51)
  • 【中秋快樂】如何用three.js實(shí)現(xiàn)我的太空遐想3D網(wǎng)頁

    【中秋快樂】如何用three.js實(shí)現(xiàn)我的太空遐想3D網(wǎng)頁

    ? 目錄 創(chuàng)作背景 功能分解 創(chuàng)建3d地球 創(chuàng)建3d月球 ?創(chuàng)建3d小火箭

    2024年02月21日
    瀏覽(26)
  • three.js(一):認(rèn)識three.js并創(chuàng)建第一個3D應(yīng)用

    three.js(一):認(rèn)識three.js并創(chuàng)建第一個3D應(yīng)用

    1-three.js 是什么? three.js是用JavaScript編寫的WebGL第三方庫; three.js 提供了非常多的3D顯示和編輯功能; 具體而言,three.js 是一款運(yùn)行在瀏覽器中的 3D 引擎,可以用three.js 創(chuàng)建各種三維場景,并對其進(jìn)行編輯; 在three.js 的官網(wǎng)上看到許多精彩的演示和文檔 three.js 官網(wǎng):https://thre

    2024年02月11日
    瀏覽(310)
  • WEB 3D技術(shù) three.js 點(diǎn)光源

    WEB 3D技術(shù) three.js 點(diǎn)光源

    本文的話 我們來設(shè)置一下點(diǎn)光源 點(diǎn)光源其實(shí)最直觀的就是可以做螢火蟲 也可以做星光 點(diǎn)點(diǎn)的效果 我們可以直接在官網(wǎng)中搜索 Pointlight 大家可以在官網(wǎng)這里看一下 其實(shí) SpotLight 聚關(guān)燈中的屬性 Pointlight 點(diǎn)光源也有的 我們先編寫代碼如下 PointLight 創(chuàng)建一個點(diǎn)光源 這里我們給了

    2024年01月19日
    瀏覽(92)
  • WEB 3D技術(shù) three.js 陰影屬性

    WEB 3D技術(shù) three.js 陰影屬性

    上文 WEB 3D技術(shù) three.js 光照與陰影 我們說了陰影 那么 我們繼續(xù)將陰影的屬性 目前 我們的代碼 目前陰影效果是這樣的 我們可以設(shè)置它的一個模糊度 我們官網(wǎng)搜索 LightShadow 下面找到 radius 模糊度的一個屬性 這里 我們可以 設(shè)置 20 的一個模糊度 運(yùn)行代碼 然后看我們的模糊度

    2024年01月22日
    瀏覽(85)
  • Three.js教程:第一個3D場景

    Three.js教程:第一個3D場景

    推薦:將 NSDT場景編輯器加入你3D工具鏈 其他工具系列: NSDT簡石數(shù)字孿生 下面的代碼完整展示了通過three.js引擎創(chuàng)建的一個三維場景,在場景中繪制并渲染了一個立方體的效果,為了大家更好的宏觀了解three.js引擎, 盡量使用了一段短小但完整的代碼實(shí)現(xiàn)一個實(shí)際的三維效果

    2023年04月12日
    瀏覽(164)
  • WEB 3D技術(shù) three.js 聚光燈

    WEB 3D技術(shù) three.js 聚光燈

    本文 我們來說說 點(diǎn)光源和聚光燈 點(diǎn)光源 就像一個電燈泡一樣 想四周發(fā)散光 而聚光燈就像手電筒一樣 像一個方向射過去 距離越遠(yuǎn)范圍越大 光越弱 我們先來看一個聚光燈的效果 我們可以編寫代碼如下 SpotLight 聚光燈 然后通過 position 設(shè)置一下光的位置 運(yùn)行代碼如下 目前看

    2024年01月21日
    瀏覽(96)
  • WEB 3D技術(shù) three.js 3D賀卡(1) 搭建基本項(xiàng)目環(huán)境

    WEB 3D技術(shù) three.js 3D賀卡(1) 搭建基本項(xiàng)目環(huán)境

    好 今天 我也是在網(wǎng)上學(xué)的 帶著大家一起來做個3D賀卡 首先 我們要創(chuàng)建一個vue3的項(xiàng)目、 先創(chuàng)建一個文件夾 裝我們的項(xiàng)目 終端執(zhí)行 vue create 項(xiàng)目名稱 例如 我的名字想叫 greetingCards 就是 因?yàn)檫@個名錄 里面是全部都小寫的 然后 下面選擇 vue3 然后按下回車 等待項(xiàng)目創(chuàng)建完成

    2024年01月19日
    瀏覽(94)
  • WEB 3D技術(shù) three.js 3D賀卡(3) 點(diǎn)光源燈光動畫效果

    WEB 3D技術(shù) three.js 3D賀卡(3) 點(diǎn)光源燈光動畫效果

    經(jīng)過 上文 WEB 3D技術(shù) three.js 3D賀卡(2) 加入天空與水面效果 我們將水面 和 天空的效果搭建了一下 那么 我們將四周 點(diǎn)光源的效果做一下 首先 我們將 renderer.toneMappingExposure 的值 改為 0.1 讓效果看著明顯一點(diǎn) 這樣 整個界面就會暗下來 然后 我們在任意位置 加入代碼 創(chuàng)建一個點(diǎn)

    2024年01月19日
    瀏覽(105)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包