前言
模型較大的時候,出現卡頓,那麼使用LOD(細節層次)進行層次細節調整,可以讓原本卡頓的模型變得不卡頓。
本就是LOD介紹。
LOD也稱為層次細節模型,是一種實時三維計算機圖形技術,旨在透過根據物體在場景中的位置和重要性動態調整其渲染的詳細程度,從而提高渲染效率和效能。
視點離物體近時,能觀察到的模型細節豐富;視點遠離模型時,觀察到的細節逐漸模糊。系統繪圖程式根據一定的判斷條件,選擇相應的細節進行顯示,從而避免了因繪製那些意義相對不大的細節而造成的時間浪費,同時有效地協調了畫面連續性與模型解析度的關係。
在OSG中,LOD技術透過osg::LOD節點來實現。osg::LOD節點是一個特殊的場景節點,它可以包含多個子節點,每個子節點代表一個不同詳細程度的模型。根據視點與物體的距離或螢幕上的畫素大小,osg::LOD節點會選擇相應的子節點進行渲染。
透過addChild方法,可以將不同詳細程度的模型作為子節點新增到osg::LOD節點中。每個子節點都需要指定一個距離範圍(或畫素大小範圍),在這個範圍內,該子節點會被渲染。
osg::LOD節點支援兩種切換模式距離模式和畫素大小模式。
- 距離模式:根據視點到物體包圍盒中心的距離來選擇子節點;
- 畫素大小模式:根據物體在螢幕上的畫素大小來選擇子節點。
對於距離模式,osg::LOD節點還支援兩種中心模式:包圍盒中心模式和自定義中心模式。包圍盒中心模式使用物體的包圍盒中心作為計算距離的點;自定義中心模式則允許使用者指定一個自定義的中心點。
LOD技術的優點和應用
- 提高渲染效率:透過動態調整模型的詳細程度,LOD技術可以顯著減少需要渲染的多邊形數量,從而提高渲染速度。
- 最佳化記憶體使用:雖然OSG中的osg::LOD節點會一次性載入所有模型進入記憶體,但它只是有選擇地進行繪製,這仍然有助於最佳化記憶體使用,因為不需要為每個模型都分配獨立的記憶體空間。此外,OSG還提供了osg::PagedLOD節點,它支援動態分頁載入,可以根據需要來載入模型檔案,進一步最佳化記憶體使用。
- 提升視覺效果:LOD技術可以在保證視覺效果的前提下,透過簡化模型來減少渲染負擔,從而允許開發者在場景中放置更多的物體或實現更復雜的視覺效果。
- 廣泛的應用場景:LOD技術適用於各種需要高效渲染的三維場景,如城市規劃、地形渲染、遊戲開發等。在這些場景中,物體的數量和詳細程度往往非常高,使用LOD技術可以顯著提高渲染效能和使用者體驗。
儘管LOD技術具有諸多優點,但它也存在一些侷限性。例如,在切換不同詳細程度的模型時,可能會出現視覺上的跳躍現象,特別是當兩個模型之間的詳細程度差異較大時。此外,設計和管理不同詳細程度的模型也需要一定的時間和資源投入。
OSG中的LOD技術是一種高效且靈活的三維渲染技術,它透過動態調整模型的詳細程度來最佳化渲染效能和記憶體使用。在開發大規模三維場景時,LOD技術是一個不可或缺的工具。
模型就不多說了,關鍵就是osg::Lod結點,如何新增的問題:
// 新增模式,0~100範圍內使用線模型
pLod->addChild(pGeode, 0, 100);
// 新增模型,非設定的範圍內的都是這個
// pLod->addChild(pGeode); // 不能使用,預想中是沒設定的都使用這個,實際上這個函式實際無用,反正都不顯示
pLod->addChild(pGeode, 100, 1000);
// 繪圖
{
#if 1
// 第一個模型
for(int partIndex = 0; partIndex < kMode.listPart.size(); partIndex++)
{
// 建立一個使用者儲存幾何資訊的物件
osg::ref_ptr<osg::Geometry> pGeometry = new osg::Geometry;
// 建立四個頂點的陣列
osg::ref_ptr<osg::Vec3Array> pVec3Array = new osg::Vec3Array;
// 新增四個頂點
pGeometry->setVertexArray(pVec3Array.get());
// 建立四種顏色的資料
osg::ref_ptr<osg::Vec4Array> pVec4Array = new osg::Vec4Array;
// 新增四種顏色
pGeometry->setColorArray(pVec4Array.get());
// 繫結顏色
pGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
double r, g, b;
r = 1.0f;
g = 1.0f;
b = 0.0f;
for(int elementShellIndex = 0; elementShellIndex < kMode.listPart.at(partIndex).listElementShell.size(); elementShellIndex++)
{
// x y z
pVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n1).x,
kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n1).y,
kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n1).z));
pVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n2).x,
kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n2).y,
kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n2).z));
pVec3Array->push_back(osg::Vec3(kMode.hashNid2Node