gpu合成方案 Unity網格動態合併方案

2021-10-11 08:52:30 字數 4350 閱讀 5748

什麼是網格合併:網格合併是指將零散的幾個模型的網格合併成乙個新的整體網格模型。

為什麼要進行網格合併:在3d遊戲開發中,網格合併是乙個繞不過的技術問題。

從優化的角度考慮,網格需要進行合併,其目的是為了減少drawcall;

從換裝的角度,如果我們的換裝不是掛點型的換裝,而是需要換形狀、換組成部件,這也需要網格合併跟材質合併。如果是人物換裝,那麼需要合併skinnedmeshrender,並重刷對應的骨骼列表。

unity 網格合併 - wuzhang - ​www.cnblogs.com

如果場景中的模型使用相同的材質,unity自身會進行批處理合併。若使用不同的材質,也可以通過動態網格合併來解決。下面先介紹一種常見的方案:

private void combinemesh()

// 合併 mesh

// 後去自身和子物體中所有 msehfilter 元件

meshfilter meshfilters = getcomponentsinchildren();

combineinstance combines = new combineinstance[meshrenderers.length];

for (int i = 0; i < meshfilters.length; i++)

//重新生成mesh

meshfilter meshfilter = transform.getcomponent();

if (meshfilter == null)

// 給 meshfilter 元件的 mesh 賦值

meshfilter.mesh = new mesh();

//合併mesh, 第二個引數 false,表示並不合併為乙個網格,而是乙個自網格列表

transform.getcomponent().mesh.combinemeshes(combines, false);

transform.gameobject.setactive(true);

//為合併後的新mesh 指定材質

= materials;

meshrenderer meshrender = transform.getcomponent();

if (meshrender == null)

meshrender.sharedmaterials = materials;

}

網格合併的目的之一是為了降低gpu的渲染負擔,但是經過測試,雖然網格合併了由於子物體網格的材質還是不同的並沒有降低drawcall。

圖一是沒有合併前的結果,圖二是合併後的結果,根據statistics面板顯示,batches都是11,並沒有減少。

方案2

針對方案1使用不同材質的網格合併沒有降低drawcall的問題,乙個解決方案是對材質球進行合併,不過這個方案只對使用相同shader的材質球有效。基本思路是這樣,首先需要建立乙個新的材質球,然後把原來子網格使用的同名貼圖合併成一張大的貼圖並賦給新建立的材質球,並計算合併後的網格的座標。

下面一步步來講解怎麼實現:

建立乙個字串陣列,用來儲存需要合併的貼圖名稱。

//要合併的材質貼圖

string combinetexturenamelist = new string[1] ;

2.建立乙個紋理陣列,用來儲存合併後的貼圖。

//合併後的貼圖陣列

rendertexture combinetextures;

3.將所有子網格材質球的同名貼圖合併,這裡設定的貼圖大小為combinetexturewidth =1024,combinetextureheight=1024。

//合成建立新貼圖

private void generatetextures(ref material combinematerial,material combinemateriallist)

}

4.貼圖合併的原理其實是將多張貼圖合併到一張貼圖上,然後每張貼圖佔據乙個固定的區域,這裡我採用的方案是等分法,等級合併貼圖的數量,將合併後的貼圖進行1等分(就是不等分),2等分或4等分。這樣,我們的大貼圖分別可以合併1張貼圖,4張貼圖,跟16張貼圖。這裡通過引數scale來控制。

scale = meshrenderers.length == 1 ? 1 : meshrenderers.length > 4 ? 4 : 2;
然後我們修改一下generatetextures函式,分別計算每個貼圖在大貼圖中的座標位置。

//合成建立新貼圖

private void generatetextures(ref material combinematerial,material combinemateriallist)

if (!hasprocesstextureuv)

combinematerial.settexture(combinetexturenamelist[i], rt);

setuvs(ref combinemesh);}}

5. 生成合併貼圖的工作,我們實際交給了gpupacktexturetile函式來出來,它首先是將每個子網格的材質屬性渲染到一張臨時貼圖目標上,然後我們再將這個貼圖放到大貼圖對應的位置上。

//建立級聯貼圖

void gpupacktexturetile(ref rendertexture dsttex,material combinematerial,int srcidx)

//將結果渲染到紋理

static void blitex(ref rendertexture dst, material mat, rect rect)

這裡我們用到了乙個packmaterial材質,它的工作就是負責合併子網格材質球的屬性,使用的shader原始碼如下:

guipack.shader

shader "util/gpupack"

}}

guipackdetails.hlsl

#ifndef gpupack_details_included

#define gpupack_details_included

#include "packages/com.unity.render-pipelines.universal/shaderlibrary/core.hlsl"

;struct v2f

;texture2d(_basemap); sampler(sampler_basemap);

cbuffer_start(unitypermaterial)

float4 _basemap_st;

half4 _basecolor;

cbuffer_end

half4 frag(v2f in) : sv_target

#endif

6. 最後一步是uv座標的計算和賦值。

//給合併網格賦值新的uv座標

public void setuvs(ref mesh combinedmesh)

}//計算uv座標

void processtextureuv()

for (int i = 0; i < uvlengtharray[rectindex]; i++)}}

//對映合併後的uv座標

private float uvlerp(float newuvmin, float newuvmax, float olduv)

float ret = mathf.lerp(newuvmin, newuvmax, olduv);

return ret;

}

最後,我們看一下採用第二種方案後的測試結果。

很明顯,現在的batches是7,比原來的11小了。

作為一名程式設計師,必不可少的滑鼠墊。

推送系統整合方案

一套完整的推送流程應該包含 1 客戶端上傳使用者標識 token uid等 到前置機 2 前置機獲取使用者標識通過日誌分析程式 我的另一篇關於日誌同步分發框架的文章會提到 入庫儲存 3 各種提送訊息源傳送訊息給推送服務程式 4 推送程式接收各種需要推送的內容,廣播或者個性化推送給客戶端。當然,在推送...

struts與spring整合方案

和struts 的依賴包配置 struts 拷貝struts 和jstl 的依賴包 在 web.xml 檔案中配置 actionservlet 提供 struts config.xml 檔案 提供國際化支援,提供預設的國際化資源檔案 spring 拷貝spring 相關依賴包 提供 spring 的...

表示式組成方案

題目描述 對於乙個只由0 假 1 真 邏輯與 邏輯或 和 異或 五種字元組成的邏輯表示式,再給定乙個結果值。現在可以對這個沒有括號的表示式任意加合法的括號,返回得到能有多少種加括號的方式,可以達到這個結果。給定乙個字串表示式exp及它的長度len,同時給定結果值ret,請返回方案數。保證表示式長度小...