Laya 2.1.1.1 Unity模型导出后顶点处理小记
之前的一個項目,要做一個滑滑梯跑酷的效果且有物理表現(xiàn),綜合考量后決定就地取材使用laya自帶的物理系統(tǒng)(現(xiàn)在想想還是應(yīng)該用cannon庫的。。。laya自帶的物理系統(tǒng)問題忒多了。。。)。由此產(chǎn)生了一個問題,美術(shù)給過來的模型是各種整段整段的管道,如何在laya中生成擬合且高效的碰撞盒就成了首要問題。
半路出家的,,之前沒做過3D項目,若有術(shù)語描述不恰還煩請指出。。
先放下處理前后的圖:
處理前:
未做任何處理,將美術(shù)給到的資源直接放置入場景中(所有管道模型已經(jīng)約定截面為正八邊形
? ??
?處理中:
處理頂點:下圖中藍(lán)色和紅色均為讀取模型網(wǎng)格后繪制的頂點(紅色點下文詳述
黑色為模型位于場景中的坐標(biāo)點,對于模型也是其上頂點所在坐標(biāo)系的原點(黑色點繪制半徑較大是方便可視,因為有的模型其原點位于網(wǎng)格內(nèi),畫小了看不見
每一個黑點意味著一個單獨(dú)的模型
? ??
處理后:
根據(jù)處理后的頂點信息,以位于截面中線上的頂點(紅色點)倆倆一對,生成碰撞盒(關(guān)于這點后續(xù)會在另一篇小記中詳述),下圖中綠色部分即為可視化后的碰撞盒
? ??
正文:?
回到正文,前面說到項目需要生成擬合的碰撞盒,一開始想過使用Laya的Mesh碰撞盒,但查了一下貌似都說不太擬合且性能問題明顯,遂想到之前的項目用到的組合式碰撞盒,將多個碰撞盒組合后統(tǒng)一賦予一個剛體(而非多個碰撞盒多個剛體)以提高性能。此做法需要對一個單獨(dú)的網(wǎng)格模型,逐段生成擬合的碰撞盒。由于本項目中賽道只有高低起伏而不會轉(zhuǎn)彎,故可以在項目中鎖死Z軸,則每段可以用一矩形來擬合一小段圓柱。而在3D場景中生成一個矩形,此項目中至少需要倆個點的信息(矩形的“粗細(xì)”,即管道截面直徑,已知),這倆點信息則可以通過模型本身的頂點來獲得。實現(xiàn)這一點需要與美術(shù)溝通,以保證在模型的某至少一條中線處對于每一個截面均存在頂點。此處截面的稱呼可能表述不太詳盡,上文說到本項目中管道的模型其截面均為正八邊形,則每一段圓柱其首尾均是一八邊形環(huán),這個八邊形環(huán)即為一個截面。
這張網(wǎng)格線模型圖可以更加直觀的看到每段的結(jié)構(gòu)。
代碼上,Laya中的網(wǎng)格類型為Laya.Mesh(此文中Laya版本號均為2.1.1.1),在其字段中_vertexBuffers[0]["_buffer"]中存放該網(wǎng)格所有頂點的信息(過程就是試沒啥好說的。。):
export default class LayaMesh {private _mesh: Laya.Mesh;public get mesh(): Laya.Mesh { return this._mesh; }private _per: number; // 一個 vertext 對應(yīng) _vertexBuffer 中元素的個數(shù)public get roundCount(): number { return this._szVertexsFilteredByZ.length; } // 環(huán)數(shù)public get vertexCount(): number { return this._mesh && this._mesh.vertexCount || 0; }public get triangleCount(): number { return this._mesh && this._mesh._indexBuffer.indexCount / 3 || 0; }public get triangles(): Uint16Array { return this._mesh && this._mesh._indexBuffer["_buffer"] || null; }private _vertexBuffer: Float32Array;public get vertexBuffer(): Float32Array { return this._mesh && this._mesh._vertexBuffers[0]["_buffer"] || null; }private _szAllVertexs: Array<LayaVertex> = [];public get szAllVertexs(): Array<LayaVertex> { return this._szAllVertexs; }private _szVertexsFilteredByZ: Array<LayaVertex>; // 從所有剖面中取Z坐標(biāo)最小并以x降序(屏幕上從左到右)排序后的頂點public get szVertexsFilteredByZ(): Array<LayaVertex> { return this._szVertexsFilteredByZ; }constructor(mesh: Laya.Mesh) {this._mesh = mesh;this._per = this.vertexBuffer.length / this.vertexCount;this._vertexBuffer = this.vertexBuffer;this._calcSzVertex();}... }上述代碼中需要注意的是 _per 的值對于每個Mesh實例不確定,但是對于同一個Mesh實例是確定的(個人嘗試中遇到過一個頂點需要8個數(shù)組元素描述全部信息,也遇到過一個頂點需要12個數(shù)組元素描述全部信息,但前8位數(shù)據(jù)的意義是一樣的)。具體數(shù)據(jù)意義如下,此處只需前三位,xyz,也就是坐標(biāo)信息。
export default class LayaVertex {private _szBuffers: Array<number> = [];public get buffer(): Array<number> { return this._szBuffers; }public get x(): number { return this._szBuffers[0]; }public get y(): number { return this._szBuffers[1]; }public get z(): number { return this._szBuffers[2]; }public get normalX(): number { return this._szBuffers[3]; }public get normalY(): number { return this._szBuffers[4]; }public get normalZ(): number { return this._szBuffers[5]; }public get u(): number { return this._szBuffers[6]; }public get v(): number { return this._szBuffers[7]; }... }前面已經(jīng)明確過一點,每一段圓柱用一個矩形來進(jìn)行擬合,而一個矩形需要倆個點,此倆點正好是位于該段圓柱首尾八邊形環(huán)的截面上,那么問題就變成了,如何從環(huán)上篩選出這個點。
邏輯上每個環(huán)上有8個點,但實際操作中有個問題,所有的點共同存放于同一個數(shù)組中且排序?qū)嶋H上是雜亂無章的,無從獲知哪8個點屬于同一個環(huán)(規(guī)則模型還好說,但上圖中特意截取了幾個不對稱的模型),筆者一開始是想著先把點按環(huán)來進(jìn)行分類,后面發(fā)現(xiàn)如果是遇到凹環(huán)則完全不可行。此時需要另外一種思路。
嘗試中筆者發(fā)現(xiàn),以射入屏幕為Z軸正方向,則賽道模型垂直于Z軸時,每一個環(huán)上的8個點,在Z軸坐標(biāo)上有5個梯度? ??? ??
筆者選取Z軸最小值(即邏輯上最靠近屏幕)的點,即為上圖中的紅點。將所有紅點以X坐標(biāo)降序排序(Laya中從左到右),即可描摹出該管道模型的形狀,此時只需順序前后倆點確定一個矩形,即可擬合出管道的碰撞盒。而多個管道的連接,也可以使用紅點的世界坐標(biāo),計算得出模型坐標(biāo)的偏移量。依托于此,也無需手動擺放設(shè)計關(guān)卡。
結(jié)語:
第一次操作頂點,很多東西都是試出來的。。。應(yīng)該有更好的數(shù)學(xué)方法進(jìn)行操作。
總結(jié)
以上是生活随笔為你收集整理的Laya 2.1.1.1 Unity模型导出后顶点处理小记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: javax.net.ssl.SSLHan
- 下一篇: iAd可能比iPad更伟大?