之前的一篇文章实现的是完全基于四叉树的动态地形渲染,虽然感觉那种方案是最优美的方案,假设CPU和GPU速度上没有差别的话,那种方案应该是最佳的了。但是现实中CPU速度还是比GPU慢不少的,因此,参考了这篇文章:
http://nvidia.e-works.net.cn/document/200908/article8938_2.htm 并按其思路实现了分块的地形LOD算法,整体思路感觉比之前的完全动态地形渲染还要简单些。
1、文章中的裂缝消除部分提到了要把地形块分成5个部分,实际上只需要分成3个部分(中间独立部分、上或下,左或右)就可以了。
2、另外文章中提到的顶高度点渐变时的插值,好像需要实时频繁改变顶点数据,感觉对效率会影响很大,目前还不知道应该怎么处理好些,请教各位高手有没有具体实现思路。。。
3、还有文章提到的采用Triangle strip可以减少索引数目,也没有实现(偷懒),用四边形代替....
目前测试程序中该地形的块大小是33*33,总大小是1057*1057(即32*32个块),块距离lod比例是4,(即包围球半径 除以 中心到相机距离 再除以 4,如果值小于1就采用全分辨率,1--2是第2级分辨率.....直到一个块只用一个4边形表示的最低分辨率)
看起来效果好像还不如之前的完全动态LOD地形,可能还需要调整好每个块大小、距离比例等参数。

地形块之间的裂缝消除:

相关代码
1
#pragma once
2
3
#include "VertexBuffer.h"
4
#include "SceneObject.h"
5
#include <hash_map>
6
#include "Shader.h"
7
8
/**/////////////////////////////////////////////////////////////////////////// 9
#include "TGAFile.h"
10
/**/////////////////////////////////////////////////////////////////////////// 11
12
namespace C_Y
13

{
14
/**//*
15
每个地形块长度:2^n+1,每个地形块顶点数 (2^n+2)*(2^n+2)
16
17
地形块数量:2^m * 2^m
18
19
地形总顶点数满足:(2^n+1) * 2^m +1 的平方
20
*/
21
class CY_GeoMipMapTerrain
22
{
23
struct CY_LodBlock
24
{
25
CY_VertexBuffer m_VertexBuffer; //顶点buffer
26
27
CY_Vector3f m_CenterPos; //中心位置
28
float m_BoundingRadius; //包围球半径
29
};
30
struct CY_QuadTreeNode
31
{
32
CY_LodBlock *m_LeafBlock; //叶结点
33
CY_QuadTreeNode *m_Down; //相邻的下结点
34
CY_QuadTreeNode *m_Right; //相邻的右结点
35
36
CY_QuadTreeNode *m_UpLeft; //子结点
37
CY_QuadTreeNode *m_UpRight;
38
CY_QuadTreeNode *m_DownLeft;
39
CY_QuadTreeNode *m_DownRight;
40
41
CY_Vector3f m_CenterPos; //中心位置
42
float m_BoundingRadius; //包围球半径
43
44
int m_StartX; //索引所有顶点中,起始的顶点位置X
45
int m_EndX;
46
int m_StartY;
47
int m_EndY;
48
49
int m_SelfLevel; //lod级别,负数表示不渲染,level越低越精细
50
51
CY_QuadTreeNode():m_LeafBlock(0),m_Down(0),m_Right(0),m_UpLeft(0),m_UpRight(0),m_DownLeft(0),m_DownRight(0)
{}
52
~CY_QuadTreeNode()
53
{
54
if(m_LeafBlock)
55
delete m_LeafBlock;
56
if(m_UpLeft)
57
delete m_UpLeft;
58
if(m_UpRight)
59
delete m_UpRight;
60
if(m_DownRight)
61
delete m_DownRight;
62
if(m_DownLeft)
63
delete m_DownLeft;
64
}
65
void GenRender(CY_Camera*&cam,std::vector<CY_QuadTreeNode*>&renderlist,const int&maxlevel);
66
CY_Vector3f GetCenterPos(); //逐级获得中心点
67
float GetBoundingRadius(); //逐级获得包围球半径
68
};
69
//---------------------------------------------------------------------------------------------
70
71
int m_BlockSize; //每个块的边长是多少格,必须是 2^n+1
72
int m_BlockNum; //总的块数量的边长是多少块,宽和高一致,值必须是 2^m
73
74
int m_TotalSize; //总边长是多少个点(边上的顶点数),值必须是 m_BlockSize*m_BlockNum+1
75
76
CY_Vector3f m_UnitSize; //深、宽、高的比例
77
float m_DistanceRate; //Lod优化程度
78
79
CY_QuadTreeNode *m_Root; //根结点
80
CY_QuadTreeNode **m_AllLeaf; //所有叶节点,按照地形的排列进行排序
81
82
GLuint *m_LodBufferIndex; //所有lod下的顶点索引缓冲,
83
int *m_LodIndexCount; //缓冲的index数量
84
int m_LodBufferCount;
85
86
GLuint m_RightEdgeIndex; //右边缘的裂缝消除
87
unsigned *m_Right_1_Index;
88
unsigned *m_Right_Index;
89
90
GLuint m_DownEdgeIndex; //下边缘的裂缝消除
91
unsigned *m_Down_1_Index;
92
unsigned *m_Down_Index;
93
94
void InitIndexBuffer();
95
void InitNode(CY_QuadTreeNode *&currNode,int Blocklength,int startX,int startY,int endX,int endY,CTargaImage&image);//处理的node,node的大小,node的起始、结束索引的顶点
96
void InitLeaf(CY_LodBlock *&LeafBlock,int startX,int startY,int endX,int endY,CTargaImage&image);//处理叶子的block
97
void InitAdjLeaf();
98
public:
99
CY_GeoMipMapTerrain();
100
~CY_GeoMipMapTerrain();
101
102
void LoadTerrain(const std::wstring&);
103
void Render(const CY_EffectPassKind&pass);
104
};
105
}
1
#include "GeoMipMapTerrain.h"
2
#include "SceneManager.h"
3
/**/////////////////////////////////////////////////////////////////////////// 4
#include "TGAFile.h"
5
#include "MaterialSystem.h"
6
#include "LogManager.h"
7
/**/////////////////////////////////////////////////////////////////////////// 8
9
namespace C_Y
10

{
11
void CY_GeoMipMapTerrain::CY_QuadTreeNode::GenRender(CY_Camera*&cam,std::vector<CY_QuadTreeNode*>&renderlist,const int&maxlevel)
12
{
13
if(m_LeafBlock)
14
{
15
m_LeafBlock->m_VertexBuffer.PrepareThisGeometryChunk();
16
m_SelfLevel=(cam->GetWorldPos()-m_CenterPos).QuickLength()/(m_BoundingRadius*4);
17
if(m_SelfLevel>=maxlevel)
18
m_SelfLevel=maxlevel-1;
19
renderlist.push_back(this);
20
}
21
else
22
{
23
if(cam->GetFrustum()->SphereInFrustum(m_UpLeft->m_CenterPos,m_UpLeft->m_BoundingRadius))
24
m_UpLeft->GenRender(cam,renderlist,maxlevel);
25
if(cam->GetFrustum()->SphereInFrustum(m_UpRight->m_CenterPos,m_UpRight->m_BoundingRadius))
26
m_UpRight->GenRender(cam,renderlist,maxlevel);
27
if(cam->GetFrustum()->SphereInFrustum(m_DownLeft->m_CenterPos,m_DownLeft->m_BoundingRadius))
28
m_DownLeft->GenRender(cam,renderlist,maxlevel);
29
if(cam->GetFrustum()->SphereInFrustum(m_DownRight->m_CenterPos,m_DownRight->m_BoundingRadius))
30
m_DownRight->GenRender(cam,renderlist,maxlevel);
31
}
32
}
33
CY_Vector3f CY_GeoMipMapTerrain::CY_QuadTreeNode::GetCenterPos()
34
{
35
if(m_LeafBlock)
36
{
37
m_CenterPos=m_LeafBlock->m_CenterPos;
38
return m_CenterPos;
39
}
40
else
41
{
42
m_CenterPos=(m_UpLeft->GetCenterPos()+m_DownLeft->GetCenterPos()+m_UpRight->GetCenterPos()+m_DownRight->GetCenterPos())/4;
43
return m_CenterPos;
44
}
45
}
46
float CY_GeoMipMapTerrain::CY_QuadTreeNode::GetBoundingRadius()
47
{
48
if(m_LeafBlock)
49
{
50
m_BoundingRadius=m_LeafBlock->m_BoundingRadius;
51
return m_BoundingRadius;
52
}
53
else
54
{
55
m_BoundingRadius=0;
56
float currr=(m_CenterPos-m_UpLeft->m_CenterPos).Length()+m_UpLeft->GetBoundingRadius();
57
if(m_BoundingRadius<currr)
58
m_BoundingRadius=currr;
59
currr=(m_CenterPos-m_UpRight->m_CenterPos).Length()+m_UpRight->GetBoundingRadius();
60
if(m_BoundingRadius<currr)
61
m_BoundingRadius=currr;
62
currr=(m_CenterPos-m_DownLeft->m_CenterPos).Length()+m_DownLeft->GetBoundingRadius();
63
if(m_BoundingRadius<currr)
64
m_BoundingRadius=currr;
65
currr=(m_CenterPos-m_DownRight->m_CenterPos).Length()+m_DownRight->GetBoundingRadius();
66
if(m_BoundingRadius<currr)
67
m_BoundingRadius=currr;
68
return m_BoundingRadius;
69
}
70
}
71
//-----------------------------------------------------------------------------------------------------------------------
72
CY_GeoMipMapTerrain::CY_GeoMipMapTerrain()
73
{
74
m_Root=0;
75
m_AllLeaf=0;
76
m_LodBufferIndex=0;
77
m_LodIndexCount=0;
78
79
m_Right_1_Index=0;
80
m_Right_Index=0;
81
m_Down_1_Index=0;
82
m_Down_Index=0;
83
}
84
CY_GeoMipMapTerrain::~CY_GeoMipMapTerrain()
85
{
86
if(m_Root)
87
delete m_Root;
88
if(m_AllLeaf)
89
delete []m_AllLeaf;
90
if(m_LodBufferIndex)
91
{
92
glDeleteBuffers(m_LodBufferCount,m_LodBufferIndex);
93
delete []m_LodBufferIndex;
94
}
95
if(m_LodIndexCount)
96
delete []m_LodIndexCount;
97
if(m_Right_1_Index)
98
delete []m_Right_1_Index;
99
if(m_Right_Index)
100
delete []m_Right_Index;
101
if(m_Down_1_Index)
102
delete []m_Down_1_Index;
103
if(m_Down_Index)
104
delete []m_Down_Index;
105
}
106
107
void CY_GeoMipMapTerrain::InitIndexBuffer()
108
{
109
m_LodBufferCount=GetPow2Num(m_BlockSize-1)+1;
110
m_LodBufferIndex=new GLuint[m_LodBufferCount];
111
m_LodIndexCount=new int[m_LodBufferCount];
112
113
unsigned *AllIndex=new unsigned[(m_BlockSize-1)*(m_BlockSize-1)*4];
114
int step;
115
const int lineLength=m_BlockSize+1;
116
glGenBuffers(m_LodBufferCount,m_LodBufferIndex);
117
for(int i=0;i<m_LodBufferCount;++i) //计算索引值
118
{
119
step=1<<(m_LodBufferCount-i-1);
120
int n=0;
121
for(int y=0;y+step<m_BlockSize;y+=step)
122
{
123
for(int x=0;x+step<m_BlockSize;x+=step)
124
{
125
if((y+step)*lineLength+step>=(m_BlockSize+1)*(m_BlockSize+1))
126
{
127
bool success;
128
success=false;
129
}
130
AllIndex[n++]=y*lineLength+x+step;
131
AllIndex[n++]=y*lineLength+x;
132
133
AllIndex[n++]=(y+step)*lineLength+x;
134
AllIndex[n++]=(y+step)*lineLength+step+x;
135
136
}
137
}
138
if(n!=(m_BlockSize-1)*(m_BlockSize-1)*4)
139
{
140
bool success;
141
success=false;
142
}
143
m_LodIndexCount[m_LodBufferCount-1-i]=n;
144
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_LodBufferIndex[m_LodBufferCount-1-i]);//最高精度的地形从0起
145
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(unsigned)*n,AllIndex,GL_STATIC_DRAW);
146
}
147
delete []AllIndex;
148
}
149
void CY_GeoMipMapTerrain::InitNode(CY_QuadTreeNode *&currNode,int Blocklength,int startX,int startY,int endX,int endY,CTargaImage&image)
150
{
151
currNode=new CY_QuadTreeNode();
152
currNode->m_StartX=startX;
153
currNode->m_StartY=startY;
154
currNode->m_EndX=endX;
155
currNode->m_EndY=endY;
156
if(Blocklength>1)
157
{
158
InitNode(currNode->m_UpLeft,Blocklength/2,startX,startY,(startX+endX)/2,(startY+endY)/2,image);
159
InitNode(currNode->m_UpRight,Blocklength/2,(startX+endX)/2,startY,endX,(startY+endY)/2,image);
160
InitNode(currNode->m_DownLeft,Blocklength/2,startX,(startY+endY)/2,(startX+endX)/2,endY,image);
161
InitNode(currNode->m_DownRight,Blocklength/2,(startX+endX)/2,(startY+endY)/2,endX,endY,image);
162
}
163
else
164
{
165
InitLeaf(currNode->m_LeafBlock,startX,startY,endX,endY,image);
166
int index=startX/m_BlockSize+startY/m_BlockSize*m_BlockNum;
167
if(index>m_BlockNum*m_BlockNum)
168
bool success=false;
169
m_AllLeaf[index]=currNode;
170
}
171
}
172
173
void CY_GeoMipMapTerrain::InitLeaf(CY_LodBlock *&LeafBlock,int startX,int startY,int endX,int endY,CTargaImage&image)
174
{
175
bool success=(endX-startX)==m_BlockSize;
176
success=(endY-startY)==m_BlockSize;
177
178
LeafBlock=new CY_LodBlock();
179
180
LeafBlock->m_VertexBuffer.SetUsableVerAttr(CY_VER_ATT_POS);
181
LeafBlock->m_VertexBuffer.CreateBuffer((m_BlockSize+1)*(m_BlockSize+1));
182
183
int n=0,temp,tmpindex;
184
CY_Vector3f TotalPos(0,0,0);
185
CY_Vector3f tempPos;
186
for(int y=startY;y<=endY;++y)
187
{
188
for(int x=startX;x<=endX;++x)
189
{
190
tmpindex=x+y*m_TotalSize; //当前点在图中的索引
191
temp=image.GetImage()[tmpindex*4+3]; //点alpha
192
193
tempPos.Set(x*m_UnitSize.x,temp*m_UnitSize.z,y*m_UnitSize.y);
194
TotalPos+=tempPos;
195
LeafBlock->m_VertexBuffer.GetVertex(n)->m_Pos=tempPos;
196
++n;
197
}
198
}
199
success=n==LeafBlock->m_VertexBuffer.GetVertexCount();
200
LeafBlock->m_VertexBuffer.GenVertexBuffer();
201
202
LeafBlock->m_CenterPos=TotalPos/n; //得到这个地形块的中点
203
204
float r=0;
205
LeafBlock->m_BoundingRadius=0;
206
for(int i=0;i<n;++i) //得到这个地形块的包围球半径
207
{
208
r=(LeafBlock->m_VertexBuffer.GetVertex(i)->m_Pos - LeafBlock->m_CenterPos).Length();
209
if(r>LeafBlock->m_BoundingRadius)
210
LeafBlock->m_BoundingRadius=r;
211
}
212
}
213
void CY_GeoMipMapTerrain::InitAdjLeaf()
214
{
215
int n=m_BlockNum*m_BlockNum;
216
for(int i=0;i<n;++i)
217
{
218
if(i%m_BlockNum!=m_BlockNum-1)
219
m_AllLeaf[i]->m_Right=m_AllLeaf[i+1];
220
if(i/m_BlockNum<m_BlockNum-1)
221
m_AllLeaf[i]->m_Down=m_AllLeaf[i+m_BlockNum];
222
}
223
}
224
225
void CY_GeoMipMapTerrain::LoadTerrain(const std::wstring&file)
226
{
227
CTargaImage image;
228
image.Load(file);
229
//-----------------------------------设置参数
230
m_BlockSize=33;
231
m_UnitSize.Set(1.0f,1.0f,0.3f);
232
m_DistanceRate=3.0f;
233
234
m_BlockNum=(image.GetWidth()-1)/m_BlockSize;
235
m_AllLeaf=new CY_QuadTreeNode*[m_BlockNum*m_BlockNum];
236
237
m_TotalSize=image.GetWidth();
238
//------------------------------------产生tree结构和block
239
InitNode(m_Root,m_BlockNum,0,0,m_TotalSize-1,m_TotalSize-1,image);
240
//------------------------------------产生block的右、下近邻block
241
InitAdjLeaf();
242
//------------------------------------产生索引缓冲
243
InitIndexBuffer();
244
245
int i=0;
246
m_Right_1_Index=new unsigned[m_BlockSize];
247
for(;i<m_BlockSize;++i) //右内边缘的点
248
{
249
int temp=(m_BlockSize+1)*i+(m_BlockSize-1);
250
m_Right_1_Index[i]=temp;
251
}
252
253
m_Right_Index=new unsigned[m_BlockSize+1];
254
for(i=0;i<=m_BlockSize;++i) //右外边缘的点
255
{
256
int temp=(m_BlockSize+1)*(i+1)-1;
257
m_Right_Index[i]=temp;
258
}
259
260
m_Down_1_Index=new unsigned[m_BlockSize];
261
for(i=0;i<m_BlockSize;++i) //下内边缘的点
262
m_Down_1_Index[i]=(m_BlockSize+1)*(m_BlockSize-1)+i;
263
264
m_Down_Index=new unsigned[m_BlockSize+1];
265
for(i=0;i<=m_BlockSize;++i) //下外边缘的点
266
m_Down_Index[i]=m_BlockSize*(m_BlockSize+1)+i;
267
268
int edgesize=6*(m_BlockSize-1)+3;
269
unsigned *temp=new unsigned[edgesize];
270
for(i=0;i<edgesize;++i)
271
temp[i]=0;
272
273
temp[0]=m_BlockSize*m_BlockSize+m_BlockSize-1;
274
temp[1]=m_BlockSize*m_BlockSize+m_BlockSize-2;
275
temp[2]=(m_BlockSize+1)*(m_BlockSize+1)-1;
276
277
278
glGenBuffers(1,&m_RightEdgeIndex);
279
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_RightEdgeIndex);
280
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(unsigned)*edgesize,temp,GL_STREAM_DRAW);//设置了初始大小,最右下的三角形索引
281
282
283
temp[0]=m_BlockSize*m_BlockSize+m_BlockSize-2;
284
temp[1]=(m_BlockSize+1)*(m_BlockSize+1)-1;
285
temp[2]=(m_BlockSize+1)*(m_BlockSize+1)-2;
286
287
glGenBuffers(1,&m_DownEdgeIndex);
288
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_DownEdgeIndex);
289
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(unsigned)*edgesize,temp,GL_STREAM_DRAW);//设置了最右下的三角形索引
290
//------------------------------------产生包围球
291
m_Root->GetCenterPos();
292
m_Root->GetBoundingRadius();
293
}
294
void CY_GeoMipMapTerrain::Render(const CY_EffectPassKind&pass)
295
{
296
/**///////////////////////////////////////////////////////////////////////////
297
CY_EffectBase *e=CY_MaterialSystem::GetInstance()->GetEffectByName("terrainEff");
298
if(e)
299
e->PrepareEffectChunk(pass);
300
301
302
CY_Camera *camera=CY_SceneManager::GetInstance()->GetActiveCamera();
303
304
int i=0,temp;
305
for(;i<m_BlockNum*m_BlockNum;++i)
306
m_AllLeaf[i]->m_SelfLevel=-1;
307
308
std::vector<CY_QuadTreeNode*> AllRenderBlock;
309
m_Root->GenRender(camera,AllRenderBlock,m_LodBufferCount);
310
311
for(i=0;i<(int)AllRenderBlock.size();++i)
312
{
313
AllRenderBlock[i]->m_LeafBlock->m_VertexBuffer.PrepareThisGeometryChunk();
314
temp=AllRenderBlock[i]->m_SelfLevel;
315
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_LodBufferIndex[temp]);
316
glDrawElements(GL_QUADS,m_LodIndexCount[temp],GL_UNSIGNED_INT,0);
317
318
319
unsigned *tempIndex=new unsigned[6*(m_BlockSize-1)];
320
int r1step=(m_BlockSize-1)>>(m_LodBufferCount-1-AllRenderBlock[i]->m_SelfLevel);
321
//消除右裂缝
322
if(AllRenderBlock[i]->m_Right &&AllRenderBlock[i]->m_Right->m_SelfLevel>=0)
323
{
324
int n=0;
325
int rstep=(m_BlockSize-1)>>(m_LodBufferCount-1-AllRenderBlock[i]->m_Right->m_SelfLevel);
326
327
int currR1=0,currR=0;
328
while(currR<m_BlockSize-1 || currR1<m_BlockSize-1)
329
{
330
if(currR<currR1)
331
{
332
tempIndex[n++]=m_Right_Index[currR];
333
tempIndex[n++]=m_Right_1_Index[currR1];
334
currR+=rstep;
335
tempIndex[n++]=m_Right_Index[currR];
336
}
337
else
338
{
339
tempIndex[n++]=m_Right_Index[currR];
340
tempIndex[n++]=m_Right_1_Index[currR1];
341
currR1+=r1step;
342
tempIndex[n++]=m_Right_1_Index[currR1];
343
}
344
}
345
346
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_RightEdgeIndex);
347
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,sizeof(unsigned)*3,sizeof(unsigned)*n,tempIndex);
348
glDrawElements(GL_TRIANGLES,3+n,GL_UNSIGNED_INT,0);
349
}
350
//消除下裂缝
351
if(AllRenderBlock[i]->m_Down && AllRenderBlock[i]->m_Down->m_SelfLevel>=0)
352
{
353
int n=0;
354
int rstep=(m_BlockSize-1)>>(m_LodBufferCount-1-AllRenderBlock[i]->m_Down->m_SelfLevel);
355
356
int currR1=0,currR=0;
357
while(currR<m_BlockSize-1 || currR1<m_BlockSize-1)
358
{
359
if(currR<currR1)
360
{
361
tempIndex[n++]=m_Down_1_Index[currR1];
362
tempIndex[n++]=m_Down_Index[currR];
363
currR+=rstep;
364
tempIndex[n++]=m_Down_Index[currR];
365
}
366
else
367
{
368
tempIndex[n++]=m_Down_1_Index[currR1];
369
tempIndex[n++]=m_Down_Index[currR];
370
currR1+=r1step;
371
tempIndex[n++]=m_Down_1_Index[currR1];
372
}
373
}
374
375
376
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_DownEdgeIndex);
377
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,sizeof(unsigned)*3,sizeof(unsigned)*n,tempIndex);
378
glDrawElements(GL_TRIANGLES,3+n,GL_UNSIGNED_INT,0);
379
}
380
delete []tempIndex;
381
}
382
383
/**///////////////////////////////////////////////////////////////////////////
384
}
385
};
posted on 2010-02-09 19:24
陈昱(CY) 阅读(2006)
评论(0) 编辑 收藏 引用 所属分类:
C++ 、
游戏编程 、
图形学