最新-基于四叉樹的LOD地形設計
上次說過要在這里把最新的地形設計寫出來,不過一直沒時間寫,也想畫些UML圖,但沒工具畫,呵呵,只能通過手寫了。希望大家看得明白吧。基本設計思想:
主要有以下幾個類,
CTerrainBlock,地形一個block,每個對象擁有自己的頂點緩沖和相對應的LOD值。
HeightMap類,讀入高度圖,并根據策略創建一定數量的CTerrainBlock。例如1024x1024的地形,我把每個block大小設置為64x64,那么這個HeightMap有16 x 16個block。
CQuadTree類,四叉樹類,根據block的大小劃分四叉樹。
基本流程:當場景渲染時,在場景UpdateScene的時候,首先Update了Camera數據,然后從新計算Frustum,然后調用m_quadTree.GetRenderObject(list& renderList)函數,以遞歸形式把quadTree中的在可視區內的渲染對象加到渲染隊列,加入隊列前并計算出CTerrainBlock的LOD值。到渲染時,首先根據地形的LOD值與相鄰四個作判斷,然后修補裂縫,具體做法是動態改變IB的值,有些LOD算法是一開始就根據不同的LOD和四邊的情況生成N個公共的IB,到渲染時可根據當前情況選擇合適的IB以解決裂縫問題。這樣可省去計算IB的時間,不過IB的數量會增多,就是以內存換時間。我現在的做法是以時間換內存。
下面是UpdateScene的代碼:
void CTerrainSceneManager::UpdateScene()

{
//在這里應該把所有object更新一次,然后更新渲染隊列
CAMERAINST->Update();
FRUSTUM->CalculateFrustum();
m_listRender.clear();
m_quadTree.GetRenderableObject(m_listRender);
//下面的代碼也可以在每個Object的Render時調用Update,這里我還沒體會到底放在哪里好。當時考慮到shader的調用,所以放到Render里,把這里注釋了。
//for (list<CTerrainBlock*>::iterator it = m_listRender.begin(); it != m_listRender.end(); it++)
//{
// (*it)->Update();
//}
}下面是CTerrainBlock的部分代碼
void CTerrainBlock::Update()2


{3
4
FixCrack(TERRAINSCENE->GetTerrain()); //候補裂縫5
m_dwTotalIndex = ComputeIndics(); //計算索引并填充IB6
//UpdateShader();7
UpdateEffect(); //更新Shader8
}9

10
void CTerrainBlock::FixCrack(CHeightMap* pTerrain)11


{12
m_nLeftIndexCount = 0;13
m_nRightIndexCount = 0;14
m_nBottomIndexCount = 0;15
m_nTopIndexCount = 0;16

17
//上方18
CTerrainBlock* pBlock = pTerrain->GetBlock(m_nNeighbor[0]);19

20
if (pBlock)21

{22
FixCrackEdge(pBlock->GetLODLevel(), BLOCK_TOP);23
}24

25
//右方26
pBlock = pTerrain->GetBlock(m_nNeighbor[1]);27

28
if (pBlock)29

{30
FixCrackEdge(pBlock->GetLODLevel(), BLOCK_RIGHT);31
}32

33
//下方34
pBlock = pTerrain->GetBlock(m_nNeighbor[2]);35

36
if (pBlock)37

{38
FixCrackEdge(pBlock->GetLODLevel(), BLOCK_BOTTOM);39
}40

41
//左方42
pBlock = pTerrain->GetBlock(m_nNeighbor[3]);43

44
if (pBlock)45

{46
FixCrackEdge(pBlock->GetLODLevel(), BLOCK_LEFT);47
}48
}49

50
void CTerrainBlock::FixCrackEdge(int nNeighborLevel, BLOCKEDGE edge)51


{52
if (m_nLODLevel == 3 || nNeighborLevel == m_nLODLevel)53

{54
return;55
}56
if ((nNeighborLevel - m_nLODLevel) == 1)57

{58
switch(edge)59

{60
case BLOCK_TOP:61
//m_vtTopEdge.clear();62
m_nTopIndexCount = 1;63

64
break;65
case BLOCK_RIGHT:66
m_nRightIndexCount = 1;67

68
break;69
case BLOCK_BOTTOM:70
m_nBottomIndexCount = 1;71

72
break;73
case BLOCK_LEFT:74
m_nLeftIndexCount = 1;75

76
break;77
}78
}79
else if ((nNeighborLevel - m_nLODLevel) == 2)80

{81
switch(edge)82

{83
case BLOCK_TOP:84
m_nTopIndexCount = 3;85

86
break;87
case BLOCK_RIGHT:88
m_nRightIndexCount = 3;89

90
break;91
case BLOCK_BOTTOM:92
m_nBottomIndexCount = 3;93

94
break;95
case BLOCK_LEFT:96
m_nLeftIndexCount = 3;97

98
break;99
}100
}101
}102

103
void CTerrainBlock::ComputeNeighbor()104


{105
m_nNeighbor[0] = m_nTopLeftX + (m_nTopLeftY - m_wGridsPerRow) * m_dwTerrainSize; //上方106
m_nNeighbor[1] = m_nTopLeftX + m_wGridsPerRow + m_nTopLeftY * m_dwTerrainSize; //右方 //右方107
m_nNeighbor[2] = m_nTopLeftX + (m_nTopLeftY + m_wGridsPerRow) * m_dwTerrainSize; //下方 //下方108
m_nNeighbor[3] = m_nTopLeftX - m_wGridsPerRow + m_nTopLeftY * m_dwTerrainSize; //左方 //左方109
}110

111
DWORD CTerrainBlock::ComputeIndics()112


{113
WORD* pIndices = NULL;114

115
m_pIndexBuffer->Lock(0, 0, (void**)&pIndices, NULL);116

117
DWORD dwIndex = 0;118
119
DWORD dwTopLeft = 0;//m_data.dwTopLeft; //聲明,topleft是要在block里的topleft,而不是在整個地形的topleft120
DWORD dwTopRight = m_wBlockSize - 1;121
DWORD dwBottomRight = m_dwNumBlockVertices - 1;122
DWORD dwBottomLeft = dwBottomRight - (m_wBlockSize - 1);123
if (m_nLODLevel == 3) //最大層124

{125
for (DWORD nRow = 0; nRow < m_nRealCell; nRow++) //行126

{127
for (DWORD nCol = 0; nCol < m_nRealCell; nCol++) 128

{129
*(pIndices + dwIndex++) = dwTopLeft + nCol * m_wIndexStride + nRow * m_wIndexStride * m_wBlockSize;130
*(pIndices + dwIndex++) = dwTopLeft + (nCol + 1) * m_wIndexStride + nRow * m_wIndexStride * m_wBlockSize;131
*(pIndices + dwIndex++) = dwTopLeft + (nCol + 1) * m_wIndexStride + (nRow + 1) * m_wIndexStride * m_wBlockSize;132

133
*(pIndices + dwIndex++) = dwTopLeft + nCol * m_wIndexStride + nRow * m_wIndexStride * m_wBlockSize;134
*(pIndices + dwIndex++) = dwTopLeft + (nCol + 1) * m_wIndexStride + (nRow + 1) * m_wIndexStride * m_wBlockSize;135
*(pIndices + dwIndex++) = dwTopLeft + nCol * m_wIndexStride + (nRow + 1) * m_wIndexStride * m_wBlockSize;136
}137
}138

139
}140

141
if (m_nLODLevel <= 2) //第二、第三層142

{143
//處理上邊144
if (m_nTopIndexCount == 1)145

{146
for (DWORD nCol = 0; nCol < m_nRealCell; nCol += 2)147

{148
DWORD dwBottom = dwTopLeft + (nCol + 1) * m_wIndexStride + m_wIndexStride * m_wBlockSize;//m_wIndexStride + m_wIndexStride * m_wBlockSize + nCol * m_wIndexStride * 2;149

150
if (nCol == 0) //處理右邊的三角形151

{152

153
*(pIndices + dwIndex++) = dwBottom;154
*(pIndices + dwIndex++) = dwBottom + m_wIndexStride - m_wIndexStride * m_wBlockSize;155
*(pIndices + dwIndex++) = dwBottom + m_wIndexStride;156
}157
else if (nCol == m_nRealCell - 2)158

{159
//左下邊三角形160
*(pIndices + dwIndex++) = dwBottom; 161
*(pIndices + dwIndex++) = dwBottom - m_wIndexStride;162
*(pIndices + dwIndex++) = dwBottom - m_wIndexStride - m_wIndexStride * m_wBlockSize;163
}164
else165

{166
//左下邊三角形167
*(pIndices + dwIndex++) = dwBottom; 168
*(pIndices + dwIndex++) = dwBottom - m_wIndexStride;169
*(pIndices + dwIndex++) = dwBottom - m_wIndexStride - m_wIndexStride * m_wBlockSize;170

171
//右下邊三角形172
*(pIndices + dwIndex++) = dwBottom; 173
*(pIndices + dwIndex++) = dwBottom + m_wIndexStride - m_wIndexStride * m_wBlockSize;174
*(pIndices + dwIndex++) = dwBottom + m_wIndexStride;175
}176

177
//處理上邊的三角形178
*(pIndices + dwIndex++) = dwBottom; 179
*(pIndices + dwIndex++) = dwBottom - m_wIndexStride - m_wIndexStride * m_wBlockSize;180
*(pIndices + dwIndex++) = dwBottom + m_wIndexStride - m_wIndexStride * m_wBlockSize;181

182
}183
}184
else if (m_nTopIndexCount == 3)185

{186
for (DWORD nCol = 0; nCol < m_nRealCell; nCol += 4)187

{188
DWORD dwBottom = dwTopLeft + (nCol + 2) * m_wIndexStride + m_wIndexStride * m_wBlockSize;189

190
if (nCol == 0) //處理右邊的三角形191

{192
*(pIndices + dwIndex++) = dwBottom + m_wIndexStride;193
*(pIndices + dwIndex++) = dwBottom + m_wIndexStride * 2 - m_wIndexStride * m_wBlockSize;194
*(pIndices + dwIndex++) = dwBottom + m_wIndexStride * 2;195
}196
else if (nCol == m_nRealCell - 4)197

{198
//左下邊三角形199
*(pIndices + dwIndex++) = dwBottom - m_wIndexStride; 200
*(pIndices + dwIndex++) = dwBottom - 2 * m_wIndexStride;201
*(pIndices + dwIndex++) = dwBottom - 2 * m_wIndexStride - m_wIndexStride * m_wBlockSize;202
}203
else204

{205
//左下邊三角形206
*(pIndices + dwIndex++) = dwBottom - m_wIndexStride; 207
*(pIndices + dwIndex++) = dwBottom - 2 * m_wIndexStride;208
*(pIndices + dwIndex++) = dwBottom - 2 * m_wIndexStride - m_wIndexStride * m_wBlockSize;209

210
//右下邊三角形211
*(pIndices + dwIndex++) = dwBottom + m_wIndexStride; 212
*(pIndices + dwIndex++) = dwBottom + m_wIndexStride * 2 - m_wIndexStride * m_wBlockSize;213
*(pIndices + dwIndex++) = dwBottom + m_wIndexStride * 2;214
}215

216
//處理上邊的3個三角形217
*(pIndices + dwIndex++) = dwBottom; 218
*(pIndices + dwIndex++) = dwBottom - m_wIndexStride;219
*(pIndices + dwIndex++) = dwBottom - 2 * m_wIndexStride - m_wIndexStride * m_wBlockSize;220

221
*(pIndices + dwIndex++) = dwBottom; 222
*(pIndices + dwIndex++) = dwBottom - 2 * m_wIndexStride - m_wIndexStride * m_wBlockSize;223
*(pIndices + dwIndex++) = dwBottom + 2 * m_wIndexStride - m_wIndexStride * m_wBlockSize;224

225
*(pIndices + dwIndex++) = dwBottom; 226
*(pIndices + dwIndex++) = dwBottom + 2 * m_wIndexStride - m_wIndexStride * m_wBlockSize;227
*(pIndices + dwIndex++) = dwBottom + m_wIndexStride;228

229
}230
}231
else if (m_nTopIndexCount == 0) //不需要修補232

{233
for (DWORD i = 0; i < m_nRealCell; i++)234

{235
if (i == 0)236

{237
*(pIndices + dwIndex++) = dwTopLeft + m_wIndexStride + m_wIndexStride * m_wBlockSize;238
*(pIndices + dwIndex++) = dwTopLeft;239
*(pIndices + dwIndex++) = dwTopLeft + m_wIndexStride;240

241
}242
else if (i == m_nRealCell - 1)243

{244
*(pIndices + dwIndex++) = dwTopLeft + i * m_wIndexStride + m_wIndexStride * m_wBlockSize;245
*(pIndices + dwIndex++) = dwTopLeft + i * m_wIndexStride;246
*(pIndices + dwIndex++) = dwTopRight;247
}248
else249

{250
*(pIndices + dwIndex++) = dwTopLeft + (i + 1) * m_wIndexStride + m_wIndexStride * m_wBlockSize;251
*(pIndices + dwIndex++) = dwTopLeft + i * m_wIndexStride + m_wIndexStride * m_wBlockSize;252
*(pIndices + dwIndex++) = dwTopLeft + i * m_wIndexStride;253

254
*(pIndices + dwIndex++) = dwTopLeft + i * m_wIndexStride;255
*(pIndices + dwIndex++) = dwTopLeft + (i + 1) * m_wIndexStride;256
*(pIndices + dwIndex++) = dwTopLeft + (i + 1) * m_wIndexStride + m_wIndexStride * m_wBlockSize;257
}258
}259
}260


261


262
}這樣LOD的地形大概完成,下面是DEBUG版本貼圖:
1025 x1025 的地形:
WireFrame截圖:
129x129截圖:
因為129X129的頂點數較少,所以開了水面反射與折射幀數還是比較高。
posted on 2009-01-10 16:19 狂爛球 閱讀(7744) 評論(73) 編輯 收藏 引用 所屬分類: 圖形編程

