日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Laya 2.1.1.1 Unity模型导出后顶点处理小记

發布時間:2024/1/18 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Laya 2.1.1.1 Unity模型导出后顶点处理小记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

之前的一個項目,要做一個滑滑梯跑酷的效果且有物理表現,綜合考量后決定就地取材使用laya自帶的物理系統(現在想想還是應該用cannon庫的。。。laya自帶的物理系統問題忒多了。。。)。由此產生了一個問題,美術給過來的模型是各種整段整段的管道,如何在laya中生成擬合且高效的碰撞盒就成了首要問題。

半路出家的,,之前沒做過3D項目,若有術語描述不恰還煩請指出。。

先放下處理前后的圖:

處理前:

未做任何處理,將美術給到的資源直接放置入場景中(所有管道模型已經約定截面為正八邊形

? ??

?處理中:

處理頂點:下圖中藍色和紅色均為讀取模型網格后繪制的頂點(紅色點下文詳述

黑色為模型位于場景中的坐標點,對于模型也是其上頂點所在坐標系的原點(黑色點繪制半徑較大是方便可視,因為有的模型其原點位于網格內,畫小了看不見

每一個黑點意味著一個單獨的模型

? ??

處理后:

根據處理后的頂點信息,以位于截面中線上的頂點(紅色點)倆倆一對,生成碰撞盒(關于這點后續會在另一篇小記中詳述),下圖中綠色部分即為可視化后的碰撞盒

? ??

正文:?

回到正文,前面說到項目需要生成擬合的碰撞盒,一開始想過使用Laya的Mesh碰撞盒,但查了一下貌似都說不太擬合且性能問題明顯,遂想到之前的項目用到的組合式碰撞盒,將多個碰撞盒組合后統一賦予一個剛體(而非多個碰撞盒多個剛體)以提高性能。此做法需要對一個單獨的網格模型,逐段生成擬合的碰撞盒。由于本項目中賽道只有高低起伏而不會轉彎,故可以在項目中鎖死Z軸,則每段可以用一矩形來擬合一小段圓柱。而在3D場景中生成一個矩形,此項目中至少需要倆個點的信息(矩形的“粗細”,即管道截面直徑,已知),這倆點信息則可以通過模型本身的頂點來獲得。實現這一點需要與美術溝通,以保證在模型的某至少一條中線處對于每一個截面均存在頂點。此處截面的稱呼可能表述不太詳盡,上文說到本項目中管道的模型其截面均為正八邊形,則每一段圓柱其首尾均是一八邊形環,這個八邊形環即為一個截面。

這張網格線模型圖可以更加直觀的看到每段的結構。

代碼上,Laya中的網格類型為Laya.Mesh(此文中Laya版本號均為2.1.1.1),在其字段中_vertexBuffers[0]["_buffer"]中存放該網格所有頂點的信息(過程就是試沒啥好說的。。):

export default class LayaMesh {private _mesh: Laya.Mesh;public get mesh(): Laya.Mesh { return this._mesh; }private _per: number; // 一個 vertext 對應 _vertexBuffer 中元素的個數public get roundCount(): number { return this._szVertexsFilteredByZ.length; } // 環數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坐標最小并以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個數組元素描述全部信息,也遇到過一個頂點需要12個數組元素描述全部信息,但前8位數據的意義是一樣的)。具體數據意義如下,此處只需前三位,xyz,也就是坐標信息。

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]; }... }

前面已經明確過一點,每一段圓柱用一個矩形來進行擬合,而一個矩形需要倆個點,此倆點正好是位于該段圓柱首尾八邊形環的截面上,那么問題就變成了,如何從環上篩選出這個點。

邏輯上每個環上有8個點,但實際操作中有個問題,所有的點共同存放于同一個數組中且排序實際上是雜亂無章的,無從獲知哪8個點屬于同一個環(規則模型還好說,但上圖中特意截取了幾個不對稱的模型),筆者一開始是想著先把點按環來進行分類,后面發現如果是遇到凹環則完全不可行。此時需要另外一種思路。

嘗試中筆者發現,以射入屏幕為Z軸正方向,則賽道模型垂直于Z軸時,每一個環上的8個點,在Z軸坐標上有5個梯度? ??? ??

筆者選取Z軸最小值(即邏輯上最靠近屏幕)的點,即為上圖中的紅點。將所有紅點以X坐標降序排序(Laya中從左到右),即可描摹出該管道模型的形狀,此時只需順序前后倆點確定一個矩形,即可擬合出管道的碰撞盒。而多個管道的連接,也可以使用紅點的世界坐標,計算得出模型坐標的偏移量。依托于此,也無需手動擺放設計關卡。

結語:

第一次操作頂點,很多東西都是試出來的。。。應該有更好的數學方法進行操作。

總結

以上是生活随笔為你收集整理的Laya 2.1.1.1 Unity模型导出后顶点处理小记的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。