three.js 如何更新場(chǎng)景

2023-02-16 17:23 更新

默認(rèn)情況下,所有對(duì)象都會(huì)自動(dòng)更新它們的矩陣(如果它們已添加到場(chǎng)景中)

const object = new THREE.Object3D();
scene.add( object );

或者它們是已添加到場(chǎng)景中的另一個(gè)對(duì)象的子節(jié)點(diǎn):

const object1 = new THREE.Object3D();
const object2 = new THREE.Object3D();

object1.add( object2 );
scene.add( object1 ); //object1 和 object2 會(huì)自動(dòng)更新它們的矩陣

但是,如果你知道對(duì)象將是靜態(tài)的,則可以禁用此選項(xiàng)并在需要時(shí)手動(dòng)更新轉(zhuǎn)換矩陣。

object.matrixAutoUpdate = false;
object.updateMatrix();

BufferGeometry

BufferGeometries 將信息(例如頂點(diǎn)位置,面索引,法線,顏色,uv和任何自定義屬性)存儲(chǔ)在buffers —— 也就是, typed arrays. 這使得它們通常比標(biāo)準(zhǔn)Geometries更快,缺點(diǎn)是更難用。

關(guān)于更新BufferGeometries,最重要的是理解你不能調(diào)整 buffers 大?。ㄟ@種操作開(kāi)銷很大,相當(dāng)于創(chuàng)建了個(gè)新的geometry)。 但你可以更新 buffers的內(nèi)容。

這意味著如果你知道BufferGeometry的一個(gè)屬性會(huì)增長(zhǎng),比如頂點(diǎn)的數(shù)量, 你必須預(yù)先分配足夠大的buffer來(lái)容納可能創(chuàng)建的任何新頂點(diǎn)。 當(dāng)然,這也意味著B(niǎo)ufferGeometry將有一個(gè)最大大小 —— 無(wú)法創(chuàng)建一個(gè)可以高效地?zé)o限擴(kuò)展的BufferGeometry。

我們以在渲染時(shí)擴(kuò)展的line來(lái)示例。我們將分配可容納500個(gè)頂點(diǎn)的空間但起初僅繪制2個(gè),使用 在500個(gè)頂點(diǎn)的緩沖區(qū)中,但首先只使用 BufferGeometry.drawRange。

const MAX_POINTS = 500;

// geometry
const geometry = new THREE.BufferGeometry();

// attributes
const positions = new Float32Array( MAX_POINTS * 3 ); // 3 vertices per point
geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );

// draw range
const drawCount = 2; // draw the first 2 points, only
geometry.setDrawRange( 0, drawCount );

// material
const material = new THREE.LineBasicMaterial( { color: 0xff0000 } );

// line
const line = new THREE.Line( geometry, material );
scene.add( line );

然后我們隨機(jī)增加頂點(diǎn)到line中,以這樣的一種方式:

const positions = line.geometry.attributes.position.array;

let x, y, z, index;
x = y = z = index = 0;

for ( let i = 0, l = MAX_POINTS; i < l; i ++ ) {

    positions[ index ++ ] = x;
    positions[ index ++ ] = y;
    positions[ index ++ ] = z;

    x += ( Math.random() - 0.5 ) * 30;
    y += ( Math.random() - 0.5 ) * 30;
    z += ( Math.random() - 0.5 ) * 30;

}

如果要更改第一次渲染后渲染的點(diǎn)數(shù),執(zhí)行以下操作:

line.geometry.setDrawRange( 0, newValue );

如果要在第一次渲染后更改position數(shù)值,則需要像這樣設(shè)置needsUpdate標(biāo)志:

line.geometry.attributes.position.needsUpdate = true; // 需要加在第一次渲染之后

這個(gè)fiddle展示了一個(gè)你可以參考的運(yùn)動(dòng)的line。

例子

WebGL / custom / attributes

WebGL / buffergeometry / custom / attributes / particles

材質(zhì)(Materials)

所有uniforms值都可以自由改變(比如 colors, textures, opacity 等等),這些數(shù)值在每幀都發(fā)給shader。

GL狀態(tài)相關(guān)參數(shù)也可以隨時(shí)改變(depthTest, blending, polygonOffset 等)。

在運(yùn)行時(shí)無(wú)法輕松更改以下屬性(一旦material被渲染了一次):

  • uniforms的數(shù)量和類型
  • 是否存在
    • texture
    • fog
    • vertex colors
    • morphing
    • shadow map
    • alpha test
    • transparent

這些變化需要建立新的shader程序。你需要設(shè)置

material.needsUpdate = true

請(qǐng)記住,這可能會(huì)非常緩慢并導(dǎo)致幀率的波動(dòng)。(特別是在Windows上,因?yàn)閟hader編譯在directx中比opengl慢)。

為了獲得更流暢的體驗(yàn),您可以通過(guò)“虛擬”值(如零強(qiáng)度光,白色紋理或零密度霧)在一定程度上模擬這些功能的變化。

您可以自由更改用于幾何塊的材質(zhì),但是無(wú)法更改對(duì)象如何劃分為塊(根據(jù)面材料)。

如果你需要在運(yùn)行時(shí)使用不同的材料配置:

如果材料/塊的數(shù)量很少,您可以事先預(yù)先劃分物體(例如,人的頭發(fā)/臉部/身體/上衣/褲子,汽車的前部/側(cè)面/頂部/玻璃/輪胎/內(nèi)部)。

如果數(shù)量很大(例如,每個(gè)面可能有所不同),請(qǐng)考慮不同的解決方案,例如使用屬性/紋理來(lái)驅(qū)動(dòng)不同的每個(gè)面部外觀。

例子

WebGL / materials / car

WebGL / webgl_postprocessing / dof

紋理(Textures)

如果更改了圖像,畫(huà)布,視頻和數(shù)據(jù)紋理,則需要設(shè)置以下標(biāo)志:

texture.needsUpdate = true;

渲染對(duì)象就會(huì)自動(dòng)更新。

例子

WebGL / materials / video

WebGL / rtt

相機(jī)(Cameras)

相機(jī)的位置和目標(biāo)會(huì)自動(dòng)更新。 如果你需要改變

  • fov
  • aspect
  • near
  • far

那么你需要重新計(jì)算投影矩陣:

camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)