Three.js中實現(xiàn)一個OBBHelper實例詳解
本文參考Box3Helper源碼,并寫出一個OBBHelper
1. 引言
Three.js中,Box3對象指的是AABB式的包圍盒,這種包圍盒會隨物體的旋轉(zhuǎn)而變換大小,精度較差
Three.js中還有OBB對象,這是一種能表現(xiàn)物體主要特征的、不隨物體的旋轉(zhuǎn)而變換大小的包圍盒
兩者如下圖所示:
Three.js中雖然有OBB,卻沒有OBB Helper,即OBB包圍盒線框?qū)ο?/p>
本文參考Box3Helper源碼,并寫出一個OBBHelper
2. Box3Helper
以下是Three.js源碼中的Box3Helper:
import { LineSegments } from '../objects/LineSegments.js'; import { LineBasicMaterial } from '../materials/LineBasicMaterial.js'; import { BufferAttribute, Float32BufferAttribute } from '../core/BufferAttribute.js'; import { BufferGeometry } from '../core/BufferGeometry.js'; class Box3Helper extends LineSegments { constructor( box, color = 0xffff00 ) { const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ]; const geometry = new BufferGeometry(); geometry.setIndex( new BufferAttribute( indices, 1 ) ); geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); this.box = box; this.type = 'Box3Helper'; this.geometry.computeBoundingSphere(); } updateMatrixWorld( force ) { const box = this.box; if ( box.isEmpty() ) return; box.getCenter( this.position ); box.getSize( this.scale ); this.scale.multiplyScalar( 0.5 ); super.updateMatrixWorld( force ); } dispose() { this.geometry.dispose(); this.material.dispose(); } } export { Box3Helper };
這段代碼是一個名為 Box3Helper
的類的定義,它繼承自 LineSegments
類。 Box3Helper
類用于創(chuàng)建一個輔助框,用來可視化 Box3
對象的邊界框。
代碼中首先導入了一些依賴的模塊,包括 LineSegments
、 LineBasicMaterial
、 BufferAttribute
、 Float32BufferAttribute
和 BufferGeometry
。
在 Box3Helper
類的構(gòu)造函數(shù)中,首先創(chuàng)建了一個表示邊界框的索引數(shù)組 indices
,然后創(chuàng)建了一個表示邊界框的頂點坐標數(shù)組 positions
。
接下來,創(chuàng)建了一個 BufferGeometry
對象,并使用 indices
數(shù)組創(chuàng)建了一個 BufferAttribute
對象來表示索引,使用 positions
數(shù)組創(chuàng)建了一個 Float32BufferAttribute
對象來表示頂點坐標。然后將這兩個屬性設置到 geometry
對象中。
然后調(diào)用父類 LineSegments
的構(gòu)造函數(shù),傳入 geometry
和一個 LineBasicMaterial
對象作為參數(shù),來創(chuàng)建一個可視化邊界框的線段對象。
接著,將傳入構(gòu)造函數(shù)的 box
參數(shù)賦值給 this.box
屬性。
然后設置 this.type
屬性為 'Box3Helper'
。
最后調(diào)用 geometry
對象的 computeBoundingSphere
方法來計算邊界球。
Box3Helper
類還定義了一個 updateMatrixWorld
方法,用于更新輔助框的世界矩陣。在該方法中,首先獲取 this.box
的中心點和尺寸,然后根據(jù)尺寸縮放輔助框的比例,并調(diào)用父類的 updateMatrixWorld
方法來更新世界矩陣。
最后,定義了一個 dispose
方法,用于釋放資源,包括釋放 geometry
和 material
對象。
最后通過 export
語句將 Box3Helper
類導出,以便在其他地方使用。
3. OBBHelper
參考上面的代碼。給出OBBHelper的代碼如下:
import { Vector3, LineSegments, LineBasicMaterial, BufferAttribute, Float32BufferAttribute, BufferGeometry } from 'three'; class OBBHelper extends LineSegments { constructor(obb, object, color = 0xffff00) { const indices = new Uint16Array([0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7, 0, 2, 1, 3, 4, 6, 5, 7]); const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ]; const geometry = new BufferGeometry(); geometry.setIndex(new BufferAttribute(indices, 1)); geometry.setAttribute('position', new Float32BufferAttribute(positions, 3)); super(geometry, new LineBasicMaterial({ color: color, toneMapped: false })); this.obb = obb; this.object = object; this.type = 'OBBHelper'; this.lastMatrix4 = object.matrixWorld.clone(); } updateMatrixWorld(force) { this.obb.applyMatrix4(this.lastMatrix4.invert()) this.obb.applyMatrix4(this.object.matrixWorld); this.lastMatrix4 = this.object.matrixWorld.clone(); const positions = this.geometry.attributes.position.array; const halfSize = this.obb.halfSize; const center = this.obb.center; const rotation = this.obb.rotation; const corners = []; for (let i = 0; i < 8; i++) { const corner = new Vector3(); corner.x = (i & 1) ? center.x + halfSize.x : center.x - halfSize.x; corner.y = (i & 2) ? center.y + halfSize.y : center.y - halfSize.y; corner.z = (i & 4) ? center.z + halfSize.z : center.z - halfSize.z; corner.applyMatrix3(rotation); corners.push(corner); } for (let i = 0; i < corners.length; i++) { const corner = corners[i]; positions[i * 3] = corner.x; positions[i * 3 + 1] = corner.y; positions[i * 3 + 2] = corner.z; } this.geometry.attributes.position.needsUpdate = true; super.updateMatrixWorld(force); } dispose() { this.geometry.dispose(); this.material.dispose(); } } export { OBBHelper };
這段代碼是一個自定義的 OBBHelper
類,用于創(chuàng)建一個輔助對象來顯示一個方向包圍盒(OBB)的邊界框。以下是代碼的解釋:
導入了所需的 Three.js 模塊和類。這些模塊和類包括 Vector3
、 LineSegments
、 LineBasicMaterial
、 BufferAttribute
、 Float32BufferAttribute
和 BufferGeometry
。
OBBHelper
類繼承自 LineSegments
類,因此它是一個線段對象。
OBBHelper
構(gòu)造函數(shù)接收三個參數(shù): obb
、 object
和 color
。 obb
是一個方向包圍盒對象, object
是一個 Three.js 對象, color
是邊界框的顏色,默認為黃色(0xffff00)。
- 創(chuàng)建一個
indices
數(shù)組,其中包含了邊界框的頂點索引。這些索引指定了邊界框的邊的連接關系。 - 創(chuàng)建一個
positions
數(shù)組,其中包含了邊界框的頂點位置。這些位置定義了邊界框的形狀。 - 創(chuàng)建一個
BufferGeometry
對象,用于存儲幾何數(shù)據(jù)。 - 使用
geometry.setIndex
方法將索引數(shù)據(jù)分配給幾何體的索引屬性。 - 使用
geometry.setAttribute
方法將頂點位置數(shù)據(jù)分配給幾何體的位置屬性。 - 調(diào)用父類
LineSegments
的構(gòu)造函數(shù),傳遞幾何體和材質(zhì)作為參數(shù),創(chuàng)建一個線段對象。 - 設置
OBBHelper
對象的屬性,包括obb
、object
和type
。 - 在
updateMatrixWorld
方法中,更新輔助對象的世界矩陣。首先,將上一次的世界矩陣的逆矩陣應用于obb
對象,然后將當前的世界矩陣應用于obb
對象。接著,根據(jù)obb
對象的屬性計算出邊界框的頂點位置,并更新幾何體的位置屬性。 - 最后,調(diào)用父類的
updateMatrixWorld
方法,更新輔助對象的世界矩陣。 dispose
方法用于釋放幾何體和材質(zhì)的內(nèi)存。- 導出
OBBHelper
類供其他模塊使用。
通過使用這個 OBBHelper
類,可以創(chuàng)建一個輔助對象來顯示一個方向包圍盒的邊界框,并將其添加到場景中以進行渲染和顯示。
實現(xiàn)的效果如下(黃色為Box3Helper,紅色為OBBHelper):
4. 參考資料
[1] OBB – three.js docs (three3d.cn)
[2] three.js/src/helpers/Box3Helper.js at master · mrdoob/three.js (github.com)
[3] three.js examples (three3d.cn)
[4] three.js/examples/jsm/math/OBB.js at master · mrdoob/three.js (github.com)
[5] BufferGeometry.boundingBox的應用:BoxHelper的實現(xiàn)
[6] 113 Three.js的obb (OrientedboundingBox)方向包圍盒的使用
到此這篇關于Three.js中實現(xiàn)一個OBBHelper的文章就介紹到這了,更多相關Three.js實現(xiàn)OBBHelper內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!