首頁 > 軟體

threejs太陽光與陰影效果範例程式碼

2022-04-05 10:00:02

前言

這篇文章實現智慧城市中模擬太陽光隨時間變化產生對應場景效果。為了場景能夠更逼真,我們一般會通過對接天氣以及陽光等各種環境因素同步到場景中,使得場景能夠更貼近現實。比如一些常見的天氣系統,下雨、下雪、陰天、霧霾等,我之後會獨立一篇文章中提現。這邊文章主要介紹一系列燈光,主要是平行光對於太陽的模仿,以及一些材質的問題~

燈光與材質基礎篇

常見的燈光:

       - 點光源 (點光源可以理解為一個同時向四面八方散發光線,我們通常用來模擬燈泡,可以產生陰影)

       - 平行光 (平行光可以想象成一個從無限遠照射來的光束,通常用來模擬太陽光,可以產生陰影)

       - 聚光燈 (聚光燈字面意思就是類似舞臺燈光一樣,照射突出特定圓弧形範圍,可以產生陰影)

       - 環境光 (一般用於改變整體場景的亮度,也是最常用的光源之一)

這裡提一嘴材質:(僅僅列舉常用的)

       - 網格基礎材質(MeshBasicMaterial,不支援陰影)

       - FBR材質

           - 物理標準材質(MeshStandardMaterial)

           - MeshPhysicalMaterial

           - 以上兩者FBR材質相對於高光網格材質效果更好

       - MeshPhongMaterial(高光網格材質,高亮表面、鏡面反射)

       - MeshLambertMaterial(網格Lambert材質,暗淡,漫反射)

這裡簡單做一下介紹,不懂的同學可以具體去了解某個材質

太陽光

新增平行光-----從東至西調整位置-----調整亮度以及顏色-----新增過渡模擬太陽光

接下來介紹本文的重點,如何模擬太陽光照的變化。其實原理非常簡單,就是新增平行光,調整場景模型的陰影關係,根據時間實時變化平行光的位置以及光照強度以及顏色即可模擬~

整體呼叫程式碼

由於是一個demo,所以注重效果,一切從簡實現功能

sun() { //兩秒變化一次平行光
  let i=0
  setInterval(()=>{
    this.initSun(i)
    i++
  },2000)
}

簡單實現通過定時器以及提前寫好對應位置光照的資訊。主要是思想,酌情根據自己的需求可以改變~

這裡這麼寫主要是實現效果,真實的應該根據系統時間將太陽光做出調整,包括根據天氣原因,換湯不換藥,主要還是

手動調整並儲存為json通過傳入時間以及天氣去做出轉化~ 

Viewer.prototype.initSun = function (type) {
  let position = {}
  let color = '#ffffff'
  let intensity = 1
  switch (type) {
    case 0:
      position = {
        x: 270,
        y: 150,
        z: 0
      }
      intensity = 5
      break
    case 1:
      position = {
        x: 258,
        y: 170,
        z: 0
      }
      intensity = 7
      color = '#fcffc9'
      break
    case 2:
      position = {
        x: 245,
        y: 180,
        z: 0
      }
      intensity = 10
      color = '#ffe69f'
      break
    case 3:
      position = {
        x: 0,
        y: 100,
        z: 0
      }
      intensity = 15
      color = '#ffe69f'
      break
    case 4:
      position = {
        x: -245,
        y: 180,
        z: 0
      }
      intensity = 10
      color = '#e3894d'
      break
    case 5:
      position = {
        x: -258,
        y: 160,
        z: 0
      }
      intensity = 10
      color = '#ff8400'
      break
    default :
      position = {
        x: -270,
        y: 150,
        z: 0
      }
      intensity = 8
      color = '#ff8400'
      break
  }
  if (this.directionalLight) {
    this.directionalLight.setSun(position,color,intensity)
  } else {
    this.directionalLight = new zhdSun()
    this.directionalLight.renderFn(this.renderFunction)
    this.directionalLight.init({
      position,
      color,
      intensity,
      scene: this.scene,
      currentlayers: this.currentlayers
    })
  }
}

太陽光類

這裡主要對太陽光類的拆解與分析,封裝的比較粗糙,酌情個人可以優化

import TWEEN from '@tweenjs/tween.js'
import {zhdObject} from './zhdObject'
export class zhdSun extends zhdObject {
  constructor() {
    super()
    this.light = null
  }
}
//由於新增了TWEEN動畫庫,記得在animate中實時更新TWEEN
TWEEN.update()

初始化

這裡做的是向場景中新增平行光,設定其陰影的範圍以及距離等屬性,因為我這邊涉及層級,所以設定了平行光的層級

平行光可謂是所有燈光中陰影調整最麻煩的,想要平行光能夠產生對的陰影效果,模型的產生陰影以及接收陰影要調整好,並且平行光的照射範圍也要調整好。我效果圖中不知大家有沒有發現,在正午時刻的時候太陽光照射地面產生了一個長方形的範圍陰影,這裡是特地錄製一個相對不那麼完美的版本。

產生原因:平行光範圍太小,但是一旦你調整平行光範圍過大,由於地面是通過多個瓦片載入的,就會出現條紋狀的陰影

如下圖

解決方法:調整平行光陰影的bias屬性,有助於減少陰影中的偽影

init({position, color, intensity , currentlayers, scene}) {
  const directionalLight = new THREE.DirectionalLight(color, intensity) // 新建一個平行光源,顏色未白色,強度為1
  this.light = directionalLight
  directionalLight.position.set(position.x, position.y, position.z) // 將此平行光源調整到一個合適的位置
  directionalLight.castShadow = true // 將此平行光源產生陰影的屬性開啟
  // 設定平行光的的陰影屬性,即一個長方體的長寬高,在設定值的範圍內的物體才會產生陰影
  const d =100 //陰影範圍
  directionalLight.shadow.camera.left = -d
  directionalLight.shadow.camera.right = d
  directionalLight.shadow.camera.top = d
  directionalLight.shadow.camera.bottom = -d
  directionalLight.shadow.camera.near = 20
  directionalLight.shadow.camera.far = 8000
  directionalLight.shadow.mapSize.x = 2048 // 定義陰影貼圖的寬度和高度,必須為2的整數此冪
  directionalLight.shadow.mapSize.y = 2048 // 較高的值會以計算時間為代價提供更好的陰影質量
  directionalLight.shadow.bias = -0.0005 //解決條紋陰影的出現
  this.setlayers(directionalLight, currentlayers)
  scene.add(directionalLight) // 將此平行光源加入場景中,我們才可以看到這個光源
  return directionalLight
}

設定平行光資訊

設定平行光的資訊:包括位置、顏色、強度

setSun(position, color, intensity) {
  this.setTweens(this.light.position, position, 2000)
  this.light.color = new THREE.Color( color )
  this.light.intensity = intensity
}

Tween

這裡簡單介紹TWEEN不懂的可以去看我之前的文章,主要是一個動畫庫,這裡做簡單的封裝

setTweens(obj, newObj, duration = 1500) {
  var ro = new TWEEN.Tween(obj)
  ro.to(newObj, duration) // 變化後的位置以及動畫時間
  ro.easing(TWEEN.Easing.Sinusoidal.InOut)
  ro.onUpdate(function () {
  })
  ro.start()
}

總結

到此這篇關於threejs太陽光與陰影效果的文章就介紹到這了,更多相關threejs太陽光與陰影內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com