青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

的筆記

隨時(shí)隨地編輯

Ogre TerrainGroup地形賞析

Ogre TerrainGroup地形賞析

1.1  參考

http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Ogre+Terrain+System

http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Ogre+Terrain+Component+FAQ

 

New Terrain Early Shots

http://www.ogre3d.org/forums/viewtopic.php?f=11&t=50674

 

http://tulrich.com/geekstuff/sig-notes.pdf

 

ogre_src_v1-8-1\Components\Terrain

├─include

      OgreTerrain.h

      OgreTerrainGroup.h

      OgreTerrainLayerBlendMap.h

      OgreTerrainMaterialGenerator.h

      OgreTerrainMaterialGeneratorA.h

      OgreTerrainPagedWorldSection.h

      OgreTerrainPaging.h

      OgreTerrainPrerequisites.h

      OgreTerrainQuadTreeNode.h

     

└─src

        OgreTerrain.cpp

        OgreTerrainGroup.cpp

        OgreTerrainLayerBlendMap.cpp

        OgreTerrainMaterialGenerator.cpp

        OgreTerrainMaterialGeneratorA.cpp

        OgreTerrainPagedWorldSection.cpp

        OgreTerrainPaging.cpp

        OgreTerrainQuadTreeNode.cpp

 

Sample

ogre_src_v1-8-1\Samples\Terrain

1.2  類圖

<帖不了圖圖> 


1.3  使用流程

1、首先需要?jiǎng)?chuàng)建terrain options

TerrainGlobalOptions* mTerrainGlobals;
TerrainGroup* mTerrainGroup;
mTerrainGlobals = OGRE_NEW TerrainGlobalOptions();
mTerrainGlobals->setMaxPixelError(8);
mTerrainGlobals->setCompositeMapDistance(3000);
 
mTerrainGlobals->setLightMapDirection(l->getDerivedDirection());
mTerrainGlobals->setCompositeMapAmbient(mSceneMgr->getAmbientLight());
mTerrainGlobals->setCompositeMapDiffuse(l->getDiffuseColour());

 

2、其次要?jiǎng)?chuàng)建TerrainGroup對象

mTerrainGroup = OGRE_NEW Ogre::TerrainGroup(mSceneMgr, Ogre::Terrain::ALIGN_X_Z, 513, 12000.0f);
mTerrainGroup->setFilenameConvention(Ogre::String("BasicTutorial3Terrain"), Ogre::String("dat"));
mTerrainGroup->setOrigin(Ogre::Vector3::ZERO);

 

3、然后設(shè)置Terrain Group

// Configure default import settings for if we use imported image
Terrain::ImportData& defaultimp = mTerrainGroup->getDefaultImportSettings();
defaultimp.terrainSize = TERRAIN_SIZE;
defaultimp.worldSize = TERRAIN_WORLD_SIZE;
defaultimp.inputScale = 600;
defaultimp.minBatchSize = 33;
defaultimp.maxBatchSize = 65;
// textures
defaultimp.layerList.resize(3);
defaultimp.layerList[0].worldSize = 100;
defaultimp.layerList[0].textureNames.push_back("dirt_grayrocky_diffusespecular.dds");
defaultimp.layerList[0].textureNames.push_back("dirt_grayrocky_normalheight.dds");
defaultimp.layerList[1].worldSize = 30;
defaultimp.layerList[1].textureNames.push_back("grass_green-01_diffusespecular.dds");
defaultimp.layerList[1].textureNames.push_back("grass_green-01_normalheight.dds");
defaultimp.layerList[2].worldSize = 200;
defaultimp.layerList[2].textureNames.push_back("growth_weirdfungus-03_diffusespecular.dds");
defaultimp.layerList[2].textureNames.push_back("growth_weirdfungus-03_normalheight.dds");


     4、最后執(zhí)行加載

mTerrainGroup->loadAllTerrains(true)
后續(xù)需要計(jì)算blendmaps 

6、清理Terrain Group

mTerrainGroup->freeTemporaryResources();

Terrain GroupTerrain的集合,如此可以取到集合里的terrain

TerrainGroup::TerrainIterator ti = mTerrainGroup->getTerrainIterator();

while(ti.hasMoreElements())

{

       Terrain* t = ti.getNext()->instance;

} 

  

至此完成了ogre最新的TerrainGroup的生命周期。

 

1.4  地形文件

 1.4.1  Terrain文件格式 

TerrainData (Identifier 'TERR')
[Version 1]

Name

Type

Description

Terrain orientation

uint8

The orientation of the terrain; XZ = 0, XY = 1, YZ = 2

Terrain size

uint16

The number of vertices along one side of the terrain

Terrain world size

Real

The world size of one side of the terrain

Max batch size

uint16

The maximum batch size in vertices along one side

Min batch size

uint16

The minimum batch size in vertices along one side

Position

Vector3

The location of the centre of the terrain

Height data

float[size*size]

List of floating point heights

LayerDeclaration

LayerDeclaration*

The layer declaration for this terrain (see below)

Layer count

uint8

The number of layers in this terrain

LayerInstance list

LayerInstance*

A number of LayerInstance definitions based on layer count (see below)

Layer blend map size

uint16

The size of the layer blend maps as stored in this file

Packed blend texture data

uint8*

layerCount-1 sets of blend texture data interleaved as either RGB or RGBA depending on layer count

Optional derived map data

TerrainDerivedMap list

0 or more sets of map data derived from the original terrain

Delta data

float[size*size]

At each vertex, delta information for the LOD at which this vertex disappears

Quadtree delta data

float[quadtrees*lods]

At each quadtree node, for each lod a record of the max delta value in the region

 

TerrainLayerDeclaration (Identifier 'TDCL')
[Version 1]

Name

Type

Description

TerrainLayerSampler Count

uint8

Number of samplers in this declaration

TerrainLayerSampler List

TerrainLayerSampler*

List of TerrainLayerSampler structures

Sampler Element Count

uint8

Number of sampler elements in this declaration

TerrainLayerSamplerElement List

TerrainLayerSamplerElement*

List of TerrainLayerSamplerElement structures

TerrainLayerSampler (Identifier 'TSAM')
[Version 1]

Name

Type

Description

Alias

String

Alias name of this sampler

Format

uint8

Desired pixel format

 

TerrainLayerSamplerElement (Identifier 'TSEL')
[Version 1]

Name

Type

Description

Source

uint8

Sampler source index

Semantic

uint8

Semantic interpretation of this element

Element start

uint8

Start of this element in the sampler

Element count

uint8

Number of elements in the sampler used by this entry

 

LayerInstance (Identifier 'TLIN')
[Version 1]

Name

Type

Description

World size

Real

The world size of this layer (determines UV scaling)

Texture list

String*

List of texture names corresponding to the number of samplers in the layer declaration

 

TerrainDerivedData (Identifier 'TDDA')
[Version 1]

Name

Type

Description

Derived data type name

String

Name of the derived data type ('normalmap', 'lightmap', 'colourmap', 'compositemap')

Size

uint16

Size of the data along one edge

Data

varies based on type

The data  

1.4.2  加載地形文件

 OgreTerrain_d.dll!Ogre::Terrain::determineLodLevels
OgreTerrain_d.dll!Ogre::Terrain::prepare
OgreTerrain_d.dll!Ogre::Terrain::prepare
OgreTerrain_d.dll!Ogre::TerrainGroup::handleRequest
OgreMain_d.dll!Ogre::DefaultWorkQueueBase::RequestHandlerHolder::handleRequest
OgreMain_d.dll!Ogre::DefaultWorkQueueBase::processRequest
OgreMain_d.dll!Ogre::DefaultWorkQueueBase::processRequestResponse
OgreMain_d.dll!Ogre::DefaultWorkQueueBase::addRequest
OgreTerrain_d.dll!Ogre::TerrainGroup::loadTerrainImpl
OgreTerrain_d.dll!Ogre::TerrainGroup::loadAllTerrains
Sample_Terrain_d.dll!Sample_Terrain::setupContent

 

首先加載全局選項(xiàng)TerrainGlobalOptions

然后從本地terrain文件中讀取(@Terrain::prepare)
  

18:12:36: DefaultWorkQueueBase('Root') - QUEUED(thread:main): ID=1 channel=1 requestType=1

18:12:36: DefaultWorkQueueBase('Root') - PROCESS_REQUEST_START(main): ID=1 channel=1 requestType=1

18:12:36: Terrain created; size=513 minBatch=33 maxBatch=65 treeDepth=4 lodLevels=5 leafLods=2

18:12:36: Terrain::distributeVertexData processing source terrain size of 513

18:12:36:   Assigning vertex data, resolution=513 startDepth=2 endDepth=4 splits=4

18:12:36:   Assigning vertex data, resolution=129 startDepth=0 endDepth=2 splits=1

18:12:36: Terrain::distributeVertexData finished

18:12:36: DefaultWorkQueueBase('Root') - PROCESS_REQUEST_END(main): ID=1 channel=1 requestType=1 processed=1

18:12:36: DefaultWorkQueueBase('Root') - PROCESS_RESPONSE_START(thread:main): ID=1 success=1 messages=[] channel=1 requestType=1

18:12:36: Font Default/Vera using texture size 512x256

18:12:36: Info: Freetype returned null for character 160 in font Default/Vera

18:12:36: Texture: Default/VeraTexture: Loading 1 faces(PF_BYTE_LA,512x256x1) with 0 generated mipmaps from Image. Internal format is PF_BYTE_LA,512x256x1.

18:12:36: Mesh: Loading axes.mesh.

18:12:36: WARNING: axes.mesh is an older format ([MeshSerializer_v1.30]); you should upgrade it as soon as possible using the OgreMeshUpgrade tool.

18:12:36: Texture: axes.png: Loading 1 faces(PF_R8G8B8,256x256x1) Internal format is PF_X8R8G8B8,256x256x1.

18:12:36: DefaultWorkQueueBase('Root') - PROCESS_RESPONSE_END(thread:main): ID=1 success=1 messages=[] channel=1 requestType=1 

1.4.3  地形表面網(wǎng)格

 已經(jīng)不存在一個(gè)具體的地形表面網(wǎng)格的概念了,地形是“分層分批處理”的東西,地形對象不再擁有一個(gè)具體的地形頂點(diǎn)數(shù)據(jù),這些數(shù)據(jù)是在LODs中的。

 

http://www.ogre3d.org/forums/viewtopic.php?f=11&t=50674&start=275#p365005

Actually, the Terrain object doesn't hold this information. The terrain is what I call "hierarchically batched" which means there is no set of vertex data at the highest LOD which covers the entire terrain - instead there are a series of hierarchical nodes which each store a specific range of LODs, each of which has a different coverage of the terrain. The only batch which has the whole terrain stored in one are the lowest LOD levels - used when the terrain is very far away. This allows us to efficiently render the entire terrain in one batch when far away, but closer up smaller (physically) batches are used for higher LODs but overall the vertex data for each batch is of the same size (or within a small range). This also allows us to deal with terrains that would be impossible to address with 16-bit indexes - any patch with more than 256 vertices on each side is actually impossible to address as one batch anyway without 32-bit indexes, which I avoid for compatibility. My hierarchical batch system allows very large terrain patches while still respecting 16-bit indexes and generally giving better performance. Unfortunately, it can never be as simple as a single top-level set of vertex data.

 

So, if I gave you access to what we use internally, I think you'd just be very confused  You really do just need to extract the raw heights or just walk across the terrain using getPoint() if you want something 'raw'. I suppose I could provide an API which dumps unindexed full-LOD triangles into a buffer (or maybe with 32-bit indexing), but this will be really inefficient if you then have to re-process the buffer yourself anyway. It's much better just to hook out the points and plug those into your system directly.

  

1.5  四叉樹結(jié)構(gòu)

       每個(gè)葉子節(jié)點(diǎn)的size都是允許劃分的批次最大size,也即65。它有2個(gè)LodLevel,其size33,這個(gè)LodLevel已經(jīng)是不可劃分的批次最小size了。而非葉子節(jié)點(diǎn)的size都比允許的批次最大size大,并且它只有一個(gè)LodLevel,其size也是批次最大size

       由此可見,允許的批次最大和最小size是劃分樹節(jié)點(diǎn)和LodLevel的直接依據(jù),它們約束了節(jié)點(diǎn)和Lod劃分的頂點(diǎn)尺寸。對于樹節(jié)點(diǎn),簡單來說劃分的方法是將其平均分割成4塊,如果每塊比允許的批次最大size還要大,則用同樣的方式對它再次遞歸分割。對于Lod來說,如果其所有者樹節(jié)點(diǎn)不是葉子,那這個(gè)Lod就讓其大小設(shè)為批次的最大size,否則,就對其進(jìn)行Lod細(xì)分,讓每個(gè)Lod盡量的小,但是不能小于批次允許的最小值。

       批次最大最小size約束存在的意義是,一方面讓每個(gè)lod的頂點(diǎn)盡可能的少,這樣在渲染的時(shí)候可以更準(zhǔn)確的找出最少的空間分割塊,以便選擇盡可能少的頂點(diǎn);另一方面每個(gè)Lod的頂點(diǎn)又不能太少,否則會增加顯卡的渲染批次。

 

 +[0]New Node,size:513,lod:4,depth:0,quadrant:0,batch range[33,65]
   +[1]New Node,size:257,lod:3,depth:1,quadrant:0,batch range[33,65]
            +[2]New Node,size:129,lod:2,depth:2,quadrant:0,batch range[33,65]
                  +[ 3]New Node,size: 65,lod:1,depth:3,quadrant:0,batch range[33,65]
                  +[ 4]New Node,size: 65,lod:1,depth:3,quadrant:1,batch range[33,65]
                  +[ 5]New Node,size: 65,lod:1,depth:3,quadrant:2,batch range[33,65]
                  +[ 6]New Node,size: 65,lod:1,depth:3,quadrant:3,batch range[33,65]
            +[7]New Node,size:129,lod:2,depth:2,quadrant:1,batch range[33,65]
                  +[ 8]New Node,size: 65,lod:1,depth:3,quadrant:0,batch range[33,65]
                  +[ 9]New Node,size: 65,lod:1,depth:3,quadrant:1,batch range[33,65]
                  +[10]New Node,size: 65,lod:1,depth:3,quadrant:2,batch range[33,65]
                  +[11]New Node,size: 65,lod:1,depth:3,quadrant:3,batch range[33,65]
            +[12]New Node,size:129,lod:2,depth:2,quadrant:2,batch range[33,65]
                  +[13]New Node,size: 65,lod:1,depth:3,quadrant:0,batch range[33,65]
                  +[14]New Node,size: 65,lod:1,depth:3,quadrant:1,batch range[33,65]
                  +[15]New Node,size: 65,lod:1,depth:3,quadrant:2,batch range[33,65]
                  +[16]New Node,size: 65,lod:1,depth:3,quadrant:3,batch range[33,65]
            +[17]New Node,size:129,lod:2,depth:2,quadrant:3,batch range[33,65]
                  +[18]New Node,size: 65,lod:1,depth:3,quadrant:0,batch range[33,65]
                  +[19]New Node,size: 65,lod:1,depth:3,quadrant:1,batch range[33,65]
                  +[20]New Node,size: 65,lod:1,depth:3,quadrant:2,batch range[33,65]
                  +[21]New Node,size: 65,lod:1,depth:3,quadrant:3,batch range[33,65]
       +[22]New Node,size:257,lod:3,depth:1,quadrant:1,batch range[33,65]
            +[23]New Node,size:129,lod:2,depth:2,quadrant:0,batch range[33,65]
                  +[24]New Node,size: 65,lod:1,depth:3,quadrant:0,batch range[33,65]
                  +[25]New Node,size: 65,lod:1,depth:3,quadrant:1,batch range[33,65]
                  +[26]New Node,size: 65,lod:1,depth:3,quadrant:2,batch range[33,65]
                  +[27]New Node,size: 65,lod:1,depth:3,quadrant:3,batch range[33,65]
            +[28]New Node,size:129,lod:2,depth:2,quadrant:1,batch range[33,65]
                  +[29]New Node,size: 65,lod:1,depth:3,quadrant:0,batch range[33,65]
                  +[30]New Node,size: 65,lod:1,depth:3,quadrant:1,batch range[33,65]
                  +[31]New Node,size: 65,lod:1,depth:3,quadrant:2,batch range[33,65]
                  +[32]New Node,size: 65,lod:1,depth:3,quadrant:3,batch range[33,65]
            +[33]New Node,size:129,lod:2,depth:2,quadrant:2,batch range[33,65]
                  +[34]New Node,size: 65,lod:1,depth:3,quadrant:0,batch range[33,65]
                  +[35]New Node,size: 65,lod:1,depth:3,quadrant:1,batch range[33,65]
                  +[36]New Node,size: 65,lod:1,depth:3,quadrant:2,batch range[33,65]
                  +[37]New Node,size: 65,lod:1,depth:3,quadrant:3,batch range[33,65]
            +[38]New Node,size:129,lod:2,depth:2,quadrant:3,batch range[33,65]
                  +[39]New Node,size: 65,lod:1,depth:3,quadrant:0,batch range[33,65]
                  +[40]New Node,size: 65,lod:1,depth:3,quadrant:1,batch range[33,65]
                  +[41]New Node,size: 65,lod:1,depth:3,quadrant:2,batch range[33,65]
                  +[42]New Node,size: 65,lod:1,depth:3,quadrant:3,batch range[33,65]
       +[43]New Node,size:257,lod:3,depth:1,quadrant:2,batch range[33,65]
            +[44]New Node,size:129,lod:2,depth:2,quadrant:0,batch range[33,65]
                  +[45]New Node,size: 65,lod:1,depth:3,quadrant:0,batch range[33,65]
                  +[46]New Node,size: 65,lod:1,depth:3,quadrant:1,batch range[33,65]
                  +[47]New Node,size: 65,lod:1,depth:3,quadrant:2,batch range[33,65]
                  +[48]New Node,size: 65,lod:1,depth:3,quadrant:3,batch range[33,65]
            +[49]New Node,size:129,lod:2,depth:2,quadrant:1,batch range[33,65]
                  +[50]New Node,size: 65,lod:1,depth:3,quadrant:0,batch range[33,65]
                  +[51]New Node,size: 65,lod:1,depth:3,quadrant:1,batch range[33,65]
                  +[52]New Node,size: 65,lod:1,depth:3,quadrant:2,batch range[33,65]
                  +[53]New Node,size: 65,lod:1,depth:3,quadrant:3,batch range[33,65]
            +[54]New Node,size:129,lod:2,depth:2,quadrant:2,batch range[33,65]
                  +[55]New Node,size: 65,lod:1,depth:3,quadrant:0,batch range[33,65]
                  +[56]New Node,size: 65,lod:1,depth:3,quadrant:1,batch range[33,65]
                  +[57]New Node,size: 65,lod:1,depth:3,quadrant:2,batch range[33,65]
                  +[58]New Node,size: 65,lod:1,depth:3,quadrant:3,batch range[33,65]
            +[59]New Node,size:129,lod:2,depth:2,quadrant:3,batch range[33,65]
                  +[60]New Node,size: 65,lod:1,depth:3,quadrant:0,batch range[33,65]
                  +[61]New Node,size: 65,lod:1,depth:3,quadrant:1,batch range[33,65]
                  +[62]New Node,size: 65,lod:1,depth:3,quadrant:2,batch range[33,65]
                  +[63]New Node,size: 65,lod:1,depth:3,quadrant:3,batch range[33,65]
       +[64]New Node,size:257,lod:3,depth:1,quadrant:3,batch range[33,65]
            +[65]New Node,size:129,lod:2,depth:2,quadrant:0,batch range[33,65]
                  +[66]New Node,size: 65,lod:1,depth:3,quadrant:0,batch range[33,65]
                  +[67]New Node,size: 65,lod:1,depth:3,quadrant:1,batch range[33,65]
                  +[68]New Node,size: 65,lod:1,depth:3,quadrant:2,batch range[33,65]
                  +[69]New Node,size: 65,lod:1,depth:3,quadrant:3,batch range[33,65]
            +[70]New Node,size:129,lod:2,depth:2,quadrant:1,batch range[33,65]
                  +[71]New Node,size: 65,lod:1,depth:3,quadrant:0,batch range[33,65]
                  +[72]New Node,size: 65,lod:1,depth:3,quadrant:1,batch range[33,65]
                  +[73]New Node,size: 65,lod:1,depth:3,quadrant:2,batch range[33,65]
                  +[74]New Node,size: 65,lod:1,depth:3,quadrant:3,batch range[33,65]
            +[75]New Node,size:129,lod:2,depth:2,quadrant:2,batch range[33,65]
                  +[76]New Node,size: 65,lod:1,depth:3,quadrant:0,batch range[33,65]
                  +[77]New Node,size: 65,lod:1,depth:3,quadrant:1,batch range[33,65]
                  +[78]New Node,size: 65,lod:1,depth:3,quadrant:2,batch range[33,65]
                  +[79]New Node,size: 65,lod:1,depth:3,quadrant:3,batch range[33,65]
            +[80]New Node,size:129,lod:2,depth:2,quadrant:3,batch range[33,65]
                  +[81]New Node,size: 65,lod:1,depth:3,quadrant:0,batch range[33,65]
                  +[82]New Node,size: 65,lod:1,depth:3,quadrant:1,batch range[33,65]
                  +[83]New Node,size: 65,lod:1,depth:3,quadrant:2,batch range[33,65]
                  +[84]New Node,size: 65,lod:1,depth:3,quadrant:3,batch range[33,65]
 


Depth

Size

LOD

節(jié)點(diǎn)數(shù)

0

513

4

1

1

257

3

4

2

129

2

16

3

65

1

64

 

1.5.1  葉子節(jié)點(diǎn)

葉子節(jié)點(diǎn)的順序如下

1

2

 

 

 

 

 

 

3

4

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

每個(gè)節(jié)點(diǎn)記錄了一個(gè)當(dāng)前節(jié)點(diǎn)的偏移值,這個(gè)偏移值是相對于父節(jié)點(diǎn)的繼承偏移方式計(jì)算出的數(shù)值,有點(diǎn)類似場景管理器中的Node._getDerivedPosition,也即是相對于當(dāng)前地形的偏移值,準(zhǔn)確來說是相對于當(dāng)前地形左上角的偏移,而不是相對其父節(jié)點(diǎn)。這個(gè)偏移值需要注意2點(diǎn):

偏移用+x向下,+y向左的二維坐標(biāo)系計(jì)算

偏移值與頂點(diǎn)數(shù)有-1差,也即最小的格子(LOD=1)的寬度的整數(shù)倍,當(dāng)前是64

  

1.6  預(yù)計(jì)算基礎(chǔ)數(shù)據(jù)

首先,預(yù)先計(jì)算好一些全局基礎(chǔ)數(shù)據(jù),例如樹深度,最大Lod,葉子節(jié)點(diǎn)的Lod。見Terrain::determineLodLevels。例如,計(jì)算結(jié)果如下:

 

18:12:36: DefaultWorkQueueBase('Root') - QUEUED(thread:main): ID=1 channel=1 requestType=1

18:12:36: DefaultWorkQueueBase('Root') - PROCESS_REQUEST_START(main): ID=1 channel=1 requestType=1

18:12:36: Terrain created; size=513 minBatch=33 maxBatch=65 treeDepth=4 lodLevels=5 leafLods=2

18:12:36: Terrain::distributeVertexData processing source terrain size of 513

18:12:36:   Assigning vertex data, resolution=513 startDepth=2 endDepth=4 splits=4

18:12:36:   Assigning vertex data, resolution=129 startDepth=0 endDepth=2 splits=1

18:12:36: Terrain::distributeVertexData finished

18:12:36: DefaultWorkQueueBase('Root') - PROCESS_RESPONSE_END(thread:main): ID=1 success=1 messages=[] channel=1 requestType=1

 

由于我們預(yù)先定義好了批次中最大最小頂點(diǎn)數(shù)、地形的頂點(diǎn)尺寸(分別是6533513),通過這個(gè)預(yù)先定義好的值,可以生成一個(gè)基于四叉樹的LOD關(guān)系數(shù)據(jù)結(jié)構(gòu)。這個(gè)數(shù)據(jù)結(jié)構(gòu)可以映射到任意面積尺寸的地形中,例如一個(gè)單邊為12000的正方形的地形。

  

1.7  分配地形頂點(diǎn)

地形定義都取到后,就開始分配地形頂點(diǎn)數(shù)據(jù)了。

OgreTerrain_d.dll!Ogre::Terrain::distributeVertexData
OgreTerrain_d.dll!Ogre::Terrain::prepare
OgreTerrain_d.dll!Ogre::Terrain::prepare
OgreTerrain_d.dll!Ogre::TerrainGroup::handleRequest
OgreMain_d.dll!Ogre::DefaultWorkQueueBase::RequestHandlerHolder::handleRequest
OgreMain_d.dll!Ogre::DefaultWorkQueueBase::processRequest
OgreMain_d.dll!Ogre::DefaultWorkQueueBase::processRequestResponse
OgreMain_d.dll!Ogre::DefaultWorkQueueBase::addRequest
OgreTerrain_d.dll!Ogre::TerrainGroup::loadTerrainImpl
OgreTerrain_d.dll!Ogre::TerrainGroup::loadAllTerrains
Sample_Terrain_d.d 


(分配頂點(diǎn)的流程圖...只能看pdf了)
 

 

1.7.1  算法思想 

現(xiàn)在需要找出如何分配頂點(diǎn)數(shù)據(jù)。我們要兼容16位的索引,這意味著我們最多可以拼湊129x129個(gè)地形,即使是松散的拼湊低細(xì)節(jié)的LODs也如此,因?yàn)橄乱粋€(gè)可拼湊數(shù)是257x257,這個(gè)數(shù)字太大了,所以不用它。

 

因此,我們需要將頂點(diǎn)數(shù)據(jù)分割成129塊。主要地磚上創(chuàng)建的的數(shù)目也即表明了它上面的點(diǎn),如果不使用其他的頂點(diǎn)數(shù)據(jù)我們在樹節(jié)點(diǎn)中就不能在更低的LODs中合并地磚了。例如,使用如上所述的257x257的輸入,頂點(diǎn)數(shù)據(jù)為了適合129x129的范圍將不得不被分為2個(gè)(在每個(gè)維度上)。這些數(shù)據(jù)可以被樹深度從1開始的所有的樹共享,不過Lods 3-1將會從129x129的稀疏數(shù)據(jù)中采樣,而LOD0將會從所有頂點(diǎn)數(shù)據(jù)中采樣。

 

然而,最低的LOD4將不能使用同樣的頂點(diǎn)數(shù)據(jù)進(jìn)行處理,因?yàn)樗枰采w整個(gè)地形。這里有2個(gè)選擇:在17x17上創(chuàng)建另一組僅用于LOD4的頂點(diǎn)數(shù)據(jù)的,或者在出現(xiàn)樹深度為1的時(shí)候用LOD4(例如仍舊分拆),并且沿著每一邊像2x9一樣渲染。

 

由于渲染非常小的批次不理想,以及頂點(diǎn)總數(shù)本質(zhì)上不會很大,所以創(chuàng)建一個(gè)單獨(dú)的頂點(diǎn)集還是有可行性。在出現(xiàn)遙遠(yuǎn)的地形時(shí)也將會讓頂點(diǎn)緩存機(jī)制更高效。

 

我們可能需要一個(gè)更大尺寸的例子,因?yàn)樵谶@種情況下只有層級1LOD0)需要使用這種單獨(dú)的頂點(diǎn)數(shù)據(jù)。較高細(xì)節(jié)的地形將會需要多種層次,這里有一個(gè)65/33批次設(shè)置的2049x2049的例子:

 

LODlevels = log2(2049 - 1) - log2(33 - 1) + 1 = 11 - 5 + 1 = 7

TreeDepth = log2((2049 - 1) / (65 - 1)) + 1 = 6

 

在最多細(xì)節(jié)層次上拆分的頂點(diǎn)數(shù)

 

(size - 1) / (TERRAIN_MAX_BATCH_SIZE - 1) = 2048 / 128 = 16

 

 

 

 

 

 

 

 

 

 

 

LOD

0:

2049

vertices

32 x 65

vertex

tiles

(tree depth 5)

vdata

0-15

[129x16]

LOD

1:

1025

vertices

32 x 33

vertex

tiles

(tree depth 5)

vdata

0-15

[129x16]

LOD

2:

513

vertices

16 x 33

vertex

tiles

(tree depth 4)

vdata

0-15

[129x16]

LOD

3:

257

vertices

8 x 33

vertex

tiles

(tree depth 3)

vdata

16-17

[129x2]

LOD

4:

129

vertices

4 x 33

vertex

tiles

(tree depth 2)

vdata

16-17

[129x2]

LOD

5:

65

vertices

2 x 33

vertex

tiles

(tree depth 1)

vdata

16-17

[129x2]

LOD

6:

33

vertices

1 x 33

vertex

tiles

(tree depth 0)

vdata

18

[33]

 

所有的頂點(diǎn)總數(shù)都是一個(gè)平方數(shù),它們正好是沿著一條邊的情形。所以,你可以看到我們需要有3個(gè)級別的頂點(diǎn)數(shù)據(jù)來滿足(誠然,相當(dāng)極端)這個(gè)情況,并且一共有19個(gè)頂點(diǎn)數(shù)據(jù)集。完整的細(xì)節(jié)幾何,12916個(gè)子集(X16)這樣的有完全細(xì)節(jié)的幾何體被用作LODs0-2 LOD3不能使用這個(gè)子集,因?yàn)樗枰ㄟ^這些子集進(jìn)行組合,而且它只有8塊地磚,所以我們需要在每一個(gè)頂點(diǎn)數(shù)據(jù)段最大是129個(gè)頂點(diǎn)的時(shí)候構(gòu)造出另外一個(gè)集合來滿足這個(gè)情況。因?yàn)樵谶@種情況下LOD3需要整個(gè)257X257)個(gè)的頂點(diǎn),所以我們?nèi)匀粚?/span>129分割成2X2)個(gè)集合。雖然這一套集合是好用了,也包括了LOD5,但LOD6需要一個(gè)單一且連續(xù)的頂點(diǎn)集,所以我們?yōu)樗鼧?gòu)造了一個(gè)33x33的頂點(diǎn)集。

 

在頂點(diǎn)的數(shù)據(jù)存儲方面,這意味著當(dāng)我們的主要數(shù)據(jù)是:

2049^ 2 =4198401個(gè)頂點(diǎn)

最終我們存儲的頂點(diǎn)數(shù)據(jù)是

16 *129^ 2+2* 129^ 2+ 33^ 2 =4327749個(gè)頂點(diǎn)

 

這相當(dāng)于有3%的頂點(diǎn)冗余,但是為了從分組中減少批次它既必要又值得。此外,在LODs36(或樹深度為30)中將有機(jī)會釋放被更多細(xì)節(jié)LODs使用的數(shù)據(jù),這在有巨大的地形的時(shí)候很重要。例如,如果我們在中等距離時(shí)為LOD0-2釋放(GPU)頂點(diǎn)數(shù)據(jù),就會為地形節(jié)省平均有98%的內(nèi)存開銷。

 

1.7.2  頂點(diǎn)數(shù)據(jù)

LODs在當(dāng)前4叉樹節(jié)點(diǎn)構(gòu)造時(shí)候被創(chuàng)建,其中有個(gè)字段指向頂點(diǎn)數(shù)據(jù),這個(gè)頂點(diǎn)數(shù)據(jù)在讀取地形文件時(shí)被創(chuàng)建。

 

創(chuàng)建頂點(diǎn)數(shù)據(jù)

   //---------------------------------------------------------------------
   void TerrainQuadTreeNode::createGpuIndexData()
   {
      for (size_t lod = 0; lod < mLodLevels.size(); ++lod)
      {
        LodLevel* ll = mLodLevels[lod];
 
        if (!ll->gpuIndexData)
        {
           // clone, using default buffer manager ie hardware
           ll->gpuIndexData = OGRE_NEW IndexData();
           populateIndexData(ll->batchSize, ll->gpuIndexData);
        }
 
      }
   }

 

取回頂點(diǎn)數(shù)據(jù)

   //---------------------------------------------------------------------
   
//渲染數(shù)據(jù)
   void TerrainQuadTreeNode::getRenderOperation(RenderOperation& op)
   {
      mNodeWithVertexData->updateGpuVertexData();
 
      op.indexData = mLodLevels[mCurrentLod]->gpuIndexData;
      op.operationType = RenderOperation::OT_TRIANGLE_STRIP;
      op.useIndexes = true;
      op.vertexData = getVertexDataRecord()->gpuVertexData;
   }
 
 

 

1.7.3  同步-異步機(jī)制

異步加載機(jī)制是Steven Streeting離開前奉獻(xiàn)的一個(gè)重量級模塊Paging的核心功能,Paging的異步加載實(shí)現(xiàn)了一個(gè)通用的分頁機(jī)制,目前只知道在地形中有應(yīng)用。但是這個(gè)優(yōu)秀的分頁機(jī)制可以在所有時(shí)間、幀率、消息、事件、渲染命令出現(xiàn)瓶頸的時(shí)候使用其擴(kuò)展的各種靈活策略進(jìn)行異步和有區(qū)分度的分解處理從而降低單幀負(fù)載。其算法思想Steven StreetingOgre官網(wǎng)有詳細(xì)闡述,見章節(jié)“Page系統(tǒng)設(shè)計(jì)思想

       為了區(qū)別異步加載給地形帶來的復(fù)雜度,關(guān)閉了異步線程和地形Paging

 #define OGRE_THREAD_SUPPORT 0

 
//#define PAGING
 

        Root維護(hù)一個(gè)默認(rèn)的工作隊(duì)列DefaultWorkQueue,執(zhí)行類似壓入執(zhí)行命令的邏輯用這個(gè)工作隊(duì)列完成。由于關(guān)閉了異步,壓入請求后會立即執(zhí)行響應(yīng)請求的子程序。

Class DefaultWorkQueue : public DefaultWorkQueueBase
OgreTerrain_d.dll!Ogre::TerrainQuadTreeNode::load
OgreTerrain_d.dll!Ogre::Terrain::load
OgreTerrain_d.dll!Ogre::TerrainGroup::handleResponse
OgreMain_d.dll!Ogre::DefaultWorkQueueBase::processResponse
OgreMain_d.dll!Ogre::DefaultWorkQueueBase::processRequestResponse
OgreMain_d.dll!Ogre::DefaultWorkQueueBase::addRequest
OgreTerrain_d.dll!Ogre::TerrainGroup::loadTerrainImpl
OgreTerrain_d.dll!Ogre::TerrainGroup::loadAllTerrains
Sample_Terrain_d.dll!Sample_Terrain::setupContent
Sample_Terrain_d.dll!OgreBites::SdkSample::_setup
 

 

1.8  動態(tài)LOD計(jì)算

動態(tài)LOD計(jì)算主要目的是通過相機(jī)與四叉樹節(jié)點(diǎn)的相對關(guān)系計(jì)算出幾個(gè)關(guān)鍵指標(biāo):

當(dāng)前Lod,標(biāo)記當(dāng)前節(jié)點(diǎn)LodLevel中第N個(gè)被使用的Lod

當(dāng)前節(jié)點(diǎn)是否渲染,標(biāo)記當(dāng)前節(jié)點(diǎn)帶領(lǐng)的子樹是否有節(jié)點(diǎn)需要被渲染

 

LodLevel定義

      Struct LodLevel{
        /// Number of vertices rendered down one side (not including skirts)
        uint16 batchSize;
        /// Index data on the gpu
        IndexData* gpuIndexData;
        /// Maximum delta height between this and the next lower lod
        Real maxHeightDelta;
        /// Temp calc area for max height delta
        Real calcMaxHeightDelta;
        /// The most recently calculated transition distance
        Real lastTransitionDist;
        /// The cFactor value used to calculate transitionDist
        Real lastCFactor;
 
        LodLevel() : gpuIndexData(0), maxHeightDelta(0), calcMaxHeightDelta(0),
           lastTransitionDist(0), lastCFactor(0) {}
      };

 

1.8.1  LodLevel數(shù)據(jù)細(xì)節(jié)

一個(gè)節(jié)點(diǎn)聚合了4個(gè)LOD相關(guān)屬性

 

 

基礎(chǔ)Lod(Base Lod)

預(yù)先計(jì)算好,最深的葉子節(jié)點(diǎn)是0,然后由內(nèi)向外遞增,且兄弟節(jié)點(diǎn)一樣

當(dāng)前Lod(Current Lod)

動態(tài)計(jì)算,@TerrainQuadTreeNode::calculateCurrentLod

Lod層級(Lod Level)

保存Lod對應(yīng)的具體頂點(diǎn)信息,每個(gè)節(jié)點(diǎn)“掛”一個(gè)或多個(gè)LodLevel

Lod層級列表(Lod Level List)

 

 

所有節(jié)點(diǎn)的Lod相關(guān)屬性大部分都是初始化時(shí)就計(jì)算好,只有當(dāng)前LOD是動態(tài)計(jì)算的。非葉子節(jié)點(diǎn)只有一個(gè)LodLevel,其頂點(diǎn)數(shù)量(LodLevel.batchSize)是當(dāng)前terrain的批次頂點(diǎn)最小值;非葉子節(jié)點(diǎn)的基礎(chǔ)Lod是父節(jié)點(diǎn)的基礎(chǔ)Lod-1。葉子節(jié)點(diǎn)有多個(gè)LodLevel,其數(shù)量是由當(dāng)前terrain預(yù)先計(jì)算好(NumLodLevelsPerLeaf),每個(gè)LodLevel中的頂點(diǎn)數(shù)量(LodLevel.batchSize)是當(dāng)前terrain的批次頂點(diǎn)最大值(MaxBatchSize)------與非葉子節(jié)點(diǎn)的情況正好相反;葉子節(jié)點(diǎn)的基礎(chǔ)LOD總是0

可以看到,節(jié)點(diǎn)的Lod值由內(nèi)從0開始向外逐漸遞增,且同一深度(depth)的節(jié)點(diǎn)Lod也一樣。而每個(gè)節(jié)點(diǎn)都會“掛”上一個(gè)或多個(gè)LodLevel,非葉子節(jié)點(diǎn)只“掛”一個(gè),葉子節(jié)點(diǎn)“掛”多個(gè),這個(gè)數(shù)量是有terrain根據(jù)世界尺寸、最大、最小單批次頂點(diǎn)數(shù)等值預(yù)先計(jì)算好的。

非葉子節(jié)點(diǎn)“掛LodLevel所包含的頂點(diǎn)數(shù)是terrain的允許的單個(gè)批次頂點(diǎn)最小數(shù)量。葉子節(jié)點(diǎn)的情況則不同,“掛”的第一個(gè)LodLevel所包含的頂點(diǎn)數(shù)是單個(gè)批次頂點(diǎn)的最大數(shù),然后第二個(gè)減少一半---實(shí)際情況稍微復(fù)雜,數(shù)量由公式(((sz - 1) * 0.5) + 1)給出,也即幾何學(xué)上的四邊形頂點(diǎn)減半。有點(diǎn)類似D3DX中的層級紋理。

       一切都很天衣無縫,只等當(dāng)前Lod動態(tài)計(jì)算時(shí),按照特定的規(guī)則決定哪些頂點(diǎn)需要被渲染,也即哪些LodLevel參與渲染。


1.8.2  動態(tài)計(jì)算Lod

一般的,Lod表示的值從0開始,依次遞增,越到后面對象的細(xì)節(jié)越少。典型的如層級紋理。在地形中也如此。首先,在整個(gè)四叉樹節(jié)點(diǎn)中,每個(gè)節(jié)點(diǎn)有自己的Lod,或者叫基礎(chǔ)Lod,這個(gè)值是固定的:葉子節(jié)點(diǎn)的Lod占用0~M;兄弟關(guān)系的Lod一樣;非葉子節(jié)點(diǎn)占用1個(gè)Lod,從M+1開始,越往樹根走Lod越大。這樣Lod最大的節(jié)點(diǎn)就是樹根了。

       動態(tài)計(jì)算Lod的關(guān)鍵因素是相機(jī)到節(jié)點(diǎn)中心的距離與節(jié)點(diǎn)中LodLevel的過渡距離,后者好比是一把尺子,用于判斷這個(gè)Lod是否可以被相機(jī)可見。計(jì)算方法見TerrainQuadTreeNode::calculateCurrentLod

 

 

每幀地形的Lod計(jì)算過程是對四叉樹遞歸遍歷的過程。首先遍歷所有子樹,然后在進(jìn)行自身的計(jì)算。將計(jì)算過錯(cuò)分解為第一類計(jì)算過程和第二類計(jì)算過程:

bool TerrainQuadTreeNode::calculateCurrentLod(const Camera* cam, Real cFactor)
{
  mSelfOrChildRendered = false;
  ///------------------------------------------------------------------------
  //深度優(yōu)先的遍歷,首先檢查第一個(gè)葉子節(jié)點(diǎn),考察其可見性,然后是兄弟節(jié)點(diǎn),軟后是父節(jié)點(diǎn)
  int childRenderedCount = 0;
  if (!isLeaf())
  {
    for (int i = 0; i < 4; ++i)
    {
       if (mChildren[i]->calculateCurrentLod(cam, cFactor))
          ++childRenderedCount;
    }

  }
 

  //需要渲染的子節(jié)點(diǎn)數(shù)是0,或者是葉子節(jié)點(diǎn),或者是所有子節(jié)點(diǎn)都不參與渲染的子樹
  
//所有葉子節(jié)點(diǎn)都不需要渲染,那就只有考察節(jié)點(diǎn)自身是否需要渲染了
  if (childRenderedCount == 0)
  {

    ///  第一類計(jì)算過程  ///

  }
  //當(dāng)前節(jié)點(diǎn)有子節(jié)點(diǎn)參與渲染,那自身就不需要參與渲染了,
  
//如果需要渲染的子節(jié)點(diǎn)數(shù)量大于或等于4,只需做個(gè)標(biāo)記,不用再計(jì)算當(dāng)前節(jié)點(diǎn)了
  else
  {
    ///  第二類計(jì)算過程  ///

    //跳過自身的渲染
    mCurrentLod = -1;
    //當(dāng)前子樹需要被渲染
    mSelfOrChildRendered = true;
    //只考慮需要渲染的子節(jié)點(diǎn)小于4的情形
    if (childRenderedCount < 4)
    {
       // only *some* children decided to render on their own, but either
       
// none or all need to render, so set the others manually to their lowest
       for (int i = 0; i < 4; ++i)
       {
          TerrainQuadTreeNode* child = mChildren[i];
          if (!child->isSelfOrChildRenderedAtCurrentLod())
          {
             child->setCurrentLod(child->getLodCount()-1);
             child->setLodTransition(1.0);
          }
       }
    } // (childRenderedCount < 4)
  } // (childRenderedCount == 0)
}

 

1.8.3  LOD第一類計(jì)算過程

 // no children were within their LOD ranges, so we should consider our own
Vector3 localPos = cam->getDerivedPosition() - mLocalCentre - mTerrain->getPosition();
       
//相機(jī)到當(dāng)前節(jié)點(diǎn)中心的絕對距離
Real dist = localPos.length();
dist -= (mBoundingRadius * 0.5f);
 
// For each LOD, the distance at which the LOD will transition *downwards*
// is given by
// distTransition = maxDelta * cFactor;
 
uint lodLvl = 0;
mCurrentLod = -1;
for (LodLevelList::iterator i = mLodLevels.begin(); i != mLodLevels.end(); ++i, ++lodLvl)
{
   // If we have no parent, and this is the lowest LOD, we always render
   
// this is the 'last resort' so to speak, we always enoucnter this last
   if (lodLvl+1 == mLodLevels.size() && !mParent)
   {
      mCurrentLod = lodLvl;
      mSelfOrChildRendered = true;
      mLodTransition = 0;
   }
   else
   {
      // check the distance
 
      ///------------------------------------------------------------------------
      //計(jì)算過渡距離distTransition
      
// Calculate or reuse transition distance
      Real distTransition;
      LodLevel* ll = *i;
      if (Math::RealEqual(cFactor, ll->lastCFactor))
        distTransition = ll->lastTransitionDist;
      else
      {
        distTransition = ll->maxHeightDelta * cFactor;
        ll->lastCFactor = cFactor;
        ll->lastTransitionDist = distTransition;
      }
 
      ///------------------------------------------------------------------------
      //相機(jī)是否離Lod足夠近
      
//相機(jī)到節(jié)點(diǎn)中心的距離小于過渡距離,則讓其顯示
      
//對于葉子節(jié)點(diǎn),Lod0的過渡距離小于Lod1
      if (dist < distTransition)
      {
        // we're within range of this LOD
        mCurrentLod = lodLvl;
        mSelfOrChildRendered = true;
 
        // Lod在節(jié)點(diǎn)中的存儲順序是用最高細(xì)節(jié)Lod到最低細(xì)節(jié)Lod的順序
        
// 碰到第一個(gè)Lod就結(jié)束了,因?yàn)檫@個(gè)Lod細(xì)節(jié)已經(jīng)是最高了
        
// 一般是葉子的第一個(gè)Lod,也即Lod0
        break;
      }//~相機(jī)足夠近
 
   }
}//~foreach LodLevelList  

1.8.4  LOD第二類計(jì)算過程

//跳過自身的渲染;we should not render ourself
mCurrentLod = -1;
//當(dāng)前子樹需要被渲染
mSelfOrChildRendered = true;
//只考慮需要渲染的子節(jié)點(diǎn)小于4的情形
if (childRenderedCount < 4)
{
   // only *some* children decided to render on their own, but either
   
// none or all need to render, so set the others manually to their lowest
   for (int i = 0; i < 4; ++i)
   {
      TerrainQuadTreeNode* child = mChildren[i];
      if (!child->isSelfOrChildRenderedAtCurrentLod())
      {
        child->setCurrentLod(child->getLodCount()-1);
        child->setLodTransition(1.0);
      }
   }
// (childRenderedCount < 4)
 

第二類計(jì)算步驟比較簡單,當(dāng)前節(jié)點(diǎn)有子節(jié)點(diǎn)參與渲染,那自身就不需要參與渲染了。首先標(biāo)記下這個(gè)子樹需要被渲染,然后考察其遞歸子節(jié)點(diǎn)需要被渲染的數(shù)量,如果數(shù)量在[1,3]這個(gè)區(qū)間,則需要處理這個(gè)節(jié)點(diǎn)的4個(gè)直接子節(jié)點(diǎn)。

需要處理當(dāng)前節(jié)點(diǎn)的4個(gè)直接子節(jié)點(diǎn)的了,如果這個(gè)子節(jié)點(diǎn)包含自身的樹都不需要渲染,則將這個(gè)節(jié)點(diǎn)的Lod數(shù)量-1。之前在預(yù)計(jì)算全局基礎(chǔ)數(shù)據(jù)時(shí)已經(jīng)知道,就當(dāng)前這個(gè)實(shí)例而言,葉子節(jié)點(diǎn)的Lod數(shù)量是2,非葉子節(jié)點(diǎn)的Lod數(shù)量是0。這樣,對于當(dāng)前節(jié)點(diǎn)的4個(gè)子樹,如果這個(gè)子樹不參與渲染,則其當(dāng)前Lod=0

  

1.9  渲染

地形四叉樹的渲染使用了2個(gè)小技巧。一是每個(gè)樹節(jié)點(diǎn)Hook了一個(gè)內(nèi)嵌類TerrainQuadTreeNode.RendMovable參與到場景的管理,而它們并不是一個(gè)真實(shí)的場景對象和渲染對象,可以將它們理解為很多人喜歡使用的虛擬對象,在真正需要渲染的時(shí)候,將邏輯還是傳遞給TerrainQuadTreeNode。二是地形監(jiān)聽了場景管理器預(yù)渲染方法,這個(gè)方法正好在場景管理器八叉樹遍歷場景對象前執(zhí)行。好處顯而易見:讓復(fù)雜的程序結(jié)構(gòu)清晰易讀。

首先,地形四叉樹只應(yīng)用于到地形,而不干涉場景。地形在渲染方面主要做了三件事,一是構(gòu)建了一個(gè)四叉樹和對應(yīng)的Lod;二是構(gòu)建了與每個(gè)Lod關(guān)聯(lián)的頂點(diǎn)數(shù)據(jù);三是每個(gè)四叉樹節(jié)點(diǎn)都構(gòu)造一個(gè)影子render對象和movable對象。

影子moveable對象在地形初次load的時(shí)候構(gòu)建完成,每個(gè)四叉樹節(jié)點(diǎn)都會新建一個(gè)場景節(jié)點(diǎn),并關(guān)節(jié)上這個(gè)引子movable對象,這樣讓每個(gè)地形四叉樹節(jié)點(diǎn)參與到場景八叉樹節(jié)點(diǎn)的可見性計(jì)算中(當(dāng)前考慮的場景管理器是默認(rèn)的八叉樹場景管理器)

 

而在最開始,地形對象監(jiān)聽了場景管理器的SceneManager.firePreFindVisibleObjects方法,而這個(gè)方法正好僅僅在計(jì)算場景可見渲染對象的前一步:

 Class Terrain : public SceneManager::Listener

 
void SceneManager::_renderScene(Camera* camera, Viewport* vp, bool includeOverlays)
{
   
   firePreFindVisibleObjects(vp);
 
   findVisibleObjects(camera);
   firePostFindVisibleObjects(vp);
   
 
    // Begin the frame
    mDestRenderSystem->_beginFrame();
 
    // Set rasterisation mode
    mDestRenderSystem->_setPolygonMode(camera->getPolygonMode());
 
   // Set initial camera state
   mDestRenderSystem->_setProjectionMatrix(mCameraInProgress->getProjectionMatrixRS());
  
  
    // Render scene content
   renderVisibleObjects();
  
    // End frame
mDestRenderSystem->_endFrame();
 
 ......

 

于是在渲染場景的時(shí)候,每個(gè)地形的四叉樹節(jié)點(diǎn)由2個(gè)緊鄰的分計(jì)算完成。首先預(yù)計(jì)算地形Lod,然后的計(jì)算其實(shí)是一個(gè)通用的場景管理器計(jì)算過程,地形并未與場景中其他節(jié)點(diǎn)有所不同。

OgreTerrain_d.dll!Ogre::TerrainQuadTreeNode::calculateCurrentLod
OgreTerrain_d.dll!Ogre::Terrain::calculateCurrentLod
OgreTerrain_d.dll!Ogre::Terrain::preFindVisibleObjects
OgreMain_d.dll!Ogre::SceneManager::firePreFindVisibleObjects
OgreMain_d.dll!Ogre::SceneManager::_renderScene
OgreMain_d.dll!Ogre::Camera::_renderScene
OgreMain_d.dll!Ogre::Viewport::update
OgreMain_d.dll!Ogre::RenderTarget::_updateViewport
RenderSystem_Direct3D9_d.dll!Ogre::D3D9RenderWindow::_updateViewport
OgreMain_d.dll!Ogre::RenderTarget::_updateAutoUpdatedViewports
OgreMain_d.dll!Ogre::RenderTarget::updateImpl
OgreMain_d.dll!Ogre::RenderTarget::update
OgreMain_d.dll!Ogre::RenderSystem::_updateAllRenderTargets
OgreMain_d.dll!Ogre::Root::_updateAllRenderTargets
OgreMain_d.dll!Ogre::Root::renderOneFrame

(地形預(yù)計(jì)算Lod )

OgreMain_d.dll!Ogre::RenderQueue::addRenderable
OgreTerrain_d.dll!Ogre::TerrainQuadTreeNode::updateRenderQueue
OgreTerrain_d.dll!Ogre::TerrainQuadTreeNode::Movable::_updateRenderQueue
OgreMain_d.dll!Ogre::RenderQueue::processVisibleObject
Plugin_OctreeSceneManager_d.dll!Ogre::OctreeNode::_addToRenderQueue
Plugin_OctreeSceneManager_d.dll!Ogre::OctreeSceneManager::walkOctree
Plugin_OctreeSceneManager_d.dll!Ogre::OctreeSceneManager::walkOctree
Plugin_OctreeSceneManager_d.dll!Ogre::OctreeSceneManager::walkOctree
Plugin_OctreeSceneManager_d.dll!Ogre::OctreeSceneManager::walkOctree
Plugin_OctreeSceneManager_d.dll!Ogre::OctreeSceneManager::_findVisibleObjects
OgreMain_d.dll!Ogre::SceneManager::_renderScene
OgreMain_d.dll!Ogre::Camera::_renderScene
OgreMain_d.dll!Ogre::Viewport::update
OgreMain_d.dll!Ogre::RenderTarget::_updateViewport
RenderSystem_Direct3D9_d.dll!Ogre::D3D9RenderWindow::_updateViewport
OgreMain_d.dll!Ogre::RenderTarget::_updateAutoUpdatedViewports
OgreMain_d.dll!Ogre::RenderTarget::updateImpl
OgreMain_d.dll!Ogre::RenderTarget::update
OgreMain_d.dll!Ogre::RenderSystem::_updateAllRenderTargets
OgreMain_d.dll!Ogre::Root::_updateAllRenderTargets
OgreMain_d.dll!Ogre::Root::renderOneFrame

 

(場景管理器通用渲染過程)

       實(shí)際計(jì)算場景中的可見對象時(shí),如果當(dāng)前地形四叉樹的影子Movable對象在相機(jī)中可見,那么只要這個(gè)四叉樹節(jié)點(diǎn)中的當(dāng)前Lod不是-1,就將其加入到渲染隊(duì)列。還記得當(dāng)前Lod表示的時(shí)候這個(gè)四叉樹節(jié)點(diǎn)LodLevel層級中需要被渲染的那個(gè)Lod,這樣在這里,這個(gè)渲染對象還是間接的渲染的一個(gè)LodLevel,這個(gè)真實(shí)的渲染對象在于場景管理器打交道的時(shí)候,表現(xiàn)為它的影子渲染對象TerrainQuadTreeNode.Rend

 

       如此這般,場景中需要渲染的對象都組裝好了,好好的躺在渲染隊(duì)列中。萬事俱備只欠東風(fēng),是時(shí)候渲染了,這個(gè)渲染方法SceneManager.renderVisibleObjects在場景對象的預(yù)計(jì)算、實(shí)際計(jì)算兩個(gè)步驟之后。

OgreTerrain_d.dll!Ogre::TerrainQuadTreeNode::getRenderOperation
OgreTerrain_d.dll!Ogre::TerrainQuadTreeNode::Rend::getRenderOperation
OgreMain_d.dll!Ogre::SceneManager::renderSingleObject
OgreMain_d.dll!Ogre::SceneManager::SceneMgrQueuedRenderableVisitor::visit
OgreMain_d.dll!Ogre::QueuedRenderableCollection::acceptVisitorGrouped
OgreMain_d.dll!Ogre::QueuedRenderableCollection::acceptVisitor
OgreMain_d.dll!Ogre::SceneManager::renderObjects
OgreMain_d.dll!Ogre::SceneManager::renderBasicQueueGroupObjects
OgreMain_d.dll!Ogre::SceneManager::_renderQueueGroupObjects
OgreMain_d.dll!Ogre::SceneManager::renderVisibleObjectsDefaultSequence
OgreMain_d.dll!Ogre::SceneManager::_renderVisibleObjects
OgreMain_d.dll!Ogre::SceneManager::_renderScene
OgreMain_d.dll!Ogre::Camera::_renderScene
OgreMain_d.dll!Ogre::Viewport::update
OgreMain_d.dll!Ogre::RenderTarget::_updateViewport
RenderSystem_Direct3D9_d.dll!Ogre::D3D9RenderWindow::_updateViewport
OgreMain_d.dll!Ogre::RenderTarget::_updateAutoUpdatedViewports
OgreMain_d.dll!Ogre::RenderTarget::updateImpl
OgreMain_d.dll!Ogre::RenderTarget::update
OgreMain_d.dll!Ogre::RenderSystem::_updateAllRenderTargets
OgreMain_d.dll!Ogre::Root::_updateAllRenderTargets
OgreMain_d.dll!Ogre::Root::renderOneFrame

 

//渲染數(shù)據(jù)
void TerrainQuadTreeNode::getRenderOperation(RenderOperation& op)
{
   mNodeWithVertexData->updateGpuVertexData();
 
   op.indexData = mLodLevels[mCurrentLod]->gpuIndexData;
   op.operationType = RenderOperation::OT_TRIANGLE_STRIP;
   op.useIndexes = true;
   op.vertexData = getVertexDataRecord()->gpuVertexData;
}

 


       之前說過,加入到渲染隊(duì)列的是影子渲染對象,真實(shí)渲染對象是一個(gè)LodLevel,這是一個(gè)很好的橋接模式,避免了地形四叉樹場景八叉樹之間的耦合。其實(shí)實(shí)現(xiàn)原理也非常簡單,不能直接交互的2個(gè)對象之間需要交互,就讓可以變通的對象投其所好,構(gòu)建一個(gè)讓另外那個(gè)對象熟悉的影子對象給它使用,只是在這個(gè)引子對象被訪問的時(shí)候,將訪問權(quán)限還是還給它的“真身”。

       這樣在渲染具體的LodLevel的時(shí)候,立即通過當(dāng)前Lod標(biāo)記找到這個(gè)具體的LodLevel,裝配好需要的數(shù)據(jù)交給GPU完成圖形設(shè)備的渲染流程。


posted on 2013-05-07 23:32 的筆記 閱讀(5524) 評論(3)  編輯 收藏 引用

評論

# re: Ogre TerrainGroup地形賞析 2013-05-09 22:53 eryar

使用LiveWriter可以貼圖……  回復(fù)  更多評論   

# re: Ogre TerrainGroup地形賞析 2013-05-10 21:32 夸父的筆記

多謝@eryar
  回復(fù)  更多評論   

# re: Ogre TerrainGroup地形賞析 2013-05-22 01:49 Render Donkey

樓主很認(rèn)真啊。 我反正是寫不出這么細(xì)致的BLOG。  回復(fù)  更多評論   


只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产精品久久二区二区| 亚洲影院色在线观看免费| 亚洲综合国产| 亚洲日本视频| 久久久青草婷婷精品综合日韩 | 欧美中文在线免费| 亚洲免费小视频| 一区二区成人精品| 亚洲欧美另类久久久精品2019| 亚洲国产精选| 亚洲精品人人| 在线亚洲国产精品网站| 一区二区三区四区国产| 亚洲一区二区在线看| 亚洲综合国产激情另类一区| 在线亚洲欧美| 久久精品国产v日韩v亚洲| 欧美在线日韩| 欧美精品www| 国产精品美女一区二区| 今天的高清视频免费播放成人| 在线欧美日韩国产| 日韩亚洲一区二区| 欧美一区二区三区免费视| 久久精品1区| 亚洲国语精品自产拍在线观看| 日韩天堂在线视频| 亚洲欧美国产精品va在线观看| 久久久久久久波多野高潮日日| 欧美大尺度在线| 国产亚洲欧美一区二区| 一区二区三区精品视频在线观看| 久久九九国产精品| 亚洲视频在线一区观看| 欧美~级网站不卡| 国产色产综合产在线视频| 一区二区欧美日韩视频| 欧美成人精品一区二区| 欧美一区二区成人6969| 欧美日韩一区免费| 亚洲美女在线观看| 永久免费精品影视网站| 亚洲在线视频免费观看| 日韩视频免费在线观看| 欧美日韩八区| 亚洲小说区图片区| 宅男噜噜噜66一区二区| 欧美日韩国产系列| 亚洲无线视频| 亚洲视频福利| 国产美女高潮久久白浆| 久久精品国产一区二区三区免费看 | 毛片av中文字幕一区二区| 国产精品国产三级国产专区53| 亚洲三级色网| 日韩视频精品| 国产亚洲精品福利| 欧美大色视频| 国产精品高潮呻吟视频| 午夜一区二区三区在线观看 | 亚洲毛片av在线| 亚洲午夜一级| 亚洲日本在线观看| 亚洲欧美视频一区| 亚洲精品在线一区二区| 午夜精品久久久久久久久久久久久 | 99在线热播精品免费99热| 在线亚洲高清视频| 亚洲精品1234| 欧美在线二区| 久久夜色精品国产亚洲aⅴ | 国产精品久久久久久妇女6080| 欧美亚洲一区三区| 欧美日韩一区在线观看视频| 久久综合狠狠| 国产偷久久久精品专区| 亚洲免费不卡| 亚洲一区二区三区在线播放| 久久在线免费视频| 久久久久久久综合日本| 国产精品视频网址| 亚洲欧美在线看| 欧美夜福利tv在线| 国产日产精品一区二区三区四区的观看方式 | 国产精品一二三四区| 一区二区免费在线观看| 国产精品99久久不卡二区| 欧美日本一道本| 亚洲一本视频| 久久久久久久97| 在线观看中文字幕不卡| 欧美成人午夜激情| 一级成人国产| 久久伊伊香蕉| 日韩一级成人av| 国产亚洲成年网址在线观看| 久久精品五月婷婷| 亚洲区一区二| 国产综合精品一区| 久久av二区| 日韩视频一区二区在线观看 | 久久一二三四| 亚洲午夜免费福利视频| 国产欧美日韩免费| 欧美fxxxxxx另类| 欧美有码在线观看视频| 亚洲青色在线| 欧美国产日韩一区二区三区| 在线亚洲欧美专区二区| 欧美在线免费一级片| 日韩视频中午一区| 亚洲日产国产精品| 亚洲国产清纯| 欧美电影在线观看完整版| 久久精品国产成人| 欧美一区二区成人| 亚洲欧洲99久久| 香蕉久久a毛片| 亚洲欧美制服另类日韩| 亚洲一区在线免费| 欧美一区二区三区在| 亚洲欧美另类中文字幕| 亚洲午夜三级在线| 亚洲欧美日本在线| 久久精品一二三区| 久久久久久久999| 久久综合99re88久久爱| 欧美激情视频在线免费观看 欧美视频免费一 | 亚洲人成网站影音先锋播放| 亚洲电影在线| av成人福利| 午夜精品一区二区三区在线| 欧美一区二区视频在线观看| 欧美在线一二三区| 欧美精品国产精品| 国产欧美另类| 99国产成+人+综合+亚洲欧美| 一本在线高清不卡dvd| 久久精品国产欧美激情| 亚洲韩国青草视频| 另类亚洲自拍| 美女主播精品视频一二三四| 蜜臀av国产精品久久久久| 夜夜精品视频一区二区| 久久在线免费| 国产原创一区二区| 亚洲自拍啪啪| 亚洲精品国产精品国自产观看浪潮| 亚洲午夜激情| 欧美性大战久久久久久久| 在线欧美日韩国产| 免费看亚洲片| 久久精品在线免费观看| 国产欧美日韩在线播放| 午夜精品短视频| 亚洲天堂av综合网| 欧美日韩999| 亚洲深爱激情| 亚洲天堂av在线免费| 欧美午夜大胆人体| 一区二区三区波多野结衣在线观看| 免费观看欧美在线视频的网站| 亚洲午夜精品久久久久久浪潮| 欧美午夜视频在线观看| 亚洲女人小视频在线观看| 99精品视频免费观看| 欧美日韩中文字幕| 欧美一区二区三区在线观看| 午夜视频一区二区| 在线观看精品一区| 91久久久在线| 欧美网站在线观看| 久久综合九色综合久99| 蜜桃av一区| 亚洲免费在线视频| 久久精品国产精品亚洲精品| 在线欧美福利| 性做久久久久久久久| 亚洲国产精品久久久久婷婷老年 | 国产精品亚洲综合天堂夜夜| 亚洲欧美影院| 欧美精品七区| 欧美成人三级在线| 国产麻豆午夜三级精品| 99精品福利视频| 91久久精品美女| 久久精品国产一区二区三区| 一区二区三区免费在线观看| 久久精品夜色噜噜亚洲aⅴ| 亚洲在线一区二区| 欧美天堂亚洲电影院在线观看| 久久综合九色综合欧美狠狠| 国产精品久久久久久户外露出 | 夜夜狂射影院欧美极品| 欧美一区二区日韩一区二区| 亚洲午夜电影网| 欧美性猛交99久久久久99按摩 | 免费成人黄色片| 国外精品视频| 久久婷婷麻豆|