Metal框架詳細(xì)解析(二十九) —— 高級(jí)技術(shù)之具有參數(shù)緩沖區(qū)的動(dòng)態(tài)地形(一)

版本記錄

版本號(hào) 時(shí)間
V1.0 2018.10.10 星期三

前言

很多做視頻和圖像的,相信對(duì)這個(gè)框架都不是很陌生,它渲染高級(jí)3D圖形,并使用GPU執(zhí)行數(shù)據(jù)并行計(jì)算。接下來(lái)的幾篇我們就詳細(xì)的解析這個(gè)框架。感興趣的看下面幾篇文章。
1. Metal框架詳細(xì)解析(一)—— 基本概覽
2. Metal框架詳細(xì)解析(二) —— 器件和命令(一)
3. Metal框架詳細(xì)解析(三) —— 渲染簡(jiǎn)單的2D三角形(一)
4. Metal框架詳細(xì)解析(四) —— 關(guān)于GPU Family 4(一)
5. Metal框架詳細(xì)解析(五) —— 關(guān)于GPU Family 4之關(guān)于Imageblocks(二)
6. Metal框架詳細(xì)解析(六) —— 關(guān)于GPU Family 4之關(guān)于Tile Shading(三)
7. Metal框架詳細(xì)解析(七) —— 關(guān)于GPU Family 4之關(guān)于光柵順序組(四)
8. Metal框架詳細(xì)解析(八) —— 關(guān)于GPU Family 4之關(guān)于增強(qiáng)的MSAA和Imageblock采樣覆蓋控制(五)
9. Metal框架詳細(xì)解析(九) —— 關(guān)于GPU Family 4之關(guān)于線程組共享(六)
10. Metal框架詳細(xì)解析(十) —— 基本組件(一)
11. Metal框架詳細(xì)解析(十一) —— 基本組件之器件選擇 - 圖形渲染的器件選擇(二)
12. Metal框架詳細(xì)解析(十二) —— 基本組件之器件選擇 - 計(jì)算處理的設(shè)備選擇(三)
13. Metal框架詳細(xì)解析(十三) —— 計(jì)算處理(一)
14. Metal框架詳細(xì)解析(十四) —— 計(jì)算處理之你好,計(jì)算(二)
15. Metal框架詳細(xì)解析(十五) —— 計(jì)算處理之關(guān)于線程和線程組(三)
16. Metal框架詳細(xì)解析(十六) —— 計(jì)算處理之計(jì)算線程組和網(wǎng)格大小(四)
17. Metal框架詳細(xì)解析(十七) —— 工具、分析和調(diào)試(一)
18. Metal框架詳細(xì)解析(十八) —— 工具、分析和調(diào)試之Metal GPU Capture(二)
19. Metal框架詳細(xì)解析(十九) —— 工具、分析和調(diào)試之GPU活動(dòng)監(jiān)視器(三)
20. Metal框架詳細(xì)解析(二十) —— 工具、分析和調(diào)試之關(guān)于Metal著色語(yǔ)言文件名擴(kuò)展名、使用Metal的命令行工具構(gòu)建庫(kù)和標(biāo)記Metal對(duì)象和命令(四)
21. Metal框架詳細(xì)解析(二十一) —— 基本課程之基本緩沖區(qū)(一)
22. Metal框架詳細(xì)解析(二十二) —— 基本課程之基本紋理(二)
23. Metal框架詳細(xì)解析(二十三) —— 基本課程之CPU和GPU同步(三)
24. Metal框架詳細(xì)解析(二十四) —— 基本課程之參數(shù)緩沖 - 基本參數(shù)緩沖(四)
25. Metal框架詳細(xì)解析(二十五) —— 基本課程之參數(shù)緩沖 - 帶有數(shù)組和資源堆的參數(shù)緩沖區(qū)(五)
26. Metal框架詳細(xì)解析(二十六) —— 基本課程之參數(shù)緩沖 - 具有GPU編碼的參數(shù)緩沖區(qū)(六)
27. Metal框架詳細(xì)解析(二十七) —— 高級(jí)技術(shù)之圖層選擇的反射(一)
28. Metal框架詳細(xì)解析(二十八) —— 高級(jí)技術(shù)之使用專(zhuān)用函數(shù)的LOD(一)

Dynamic Terrain with Argument Buffers - 具有參數(shù)緩沖區(qū)的動(dòng)態(tài)地形

演示如何使用參數(shù)緩沖區(qū)通過(guò)GPU驅(qū)動(dòng)的管道實(shí)時(shí)渲染動(dòng)態(tài)地形。

此示例演示了室外景觀的動(dòng)態(tài)地形生成,使用參數(shù)緩沖區(qū)在GPU驅(qū)動(dòng)的管道中選擇地形材質(zhì),植被幾何體和粒子效果。 該示例創(chuàng)建了一個(gè)具有視覺(jué)上不同區(qū)域的景觀,稱(chēng)為棲息地,根據(jù)土地的高度而不同。 這些是示例中的棲息地,從最高海拔到最低海拔排序:

注意:此示例使用參數(shù)緩沖區(qū)來(lái)避免需要在CPU上單獨(dú)編碼和發(fā)出命令的等效功能的CPU開(kāi)銷(xiāo)。 有關(guān)參數(shù)緩沖區(qū)的介紹,請(qǐng)參閱Argument Buffers中列出的示例。


Respond to Landscape Alterations - 回應(yīng)景觀變更

景觀的初始拓?fù)溆伸o態(tài)高度圖Terrain HeightMap.png確定。

_targetHeightmap = CreateTextureWithDevice (device, @"Textures/TerrainHeightMap.png", false, false);

在運(yùn)行時(shí),當(dāng)您使用提供的控件更改格局時(shí),樣本會(huì)評(píng)估最新的拓?fù)洌源_定是否應(yīng)將新的棲息地應(yīng)用于新的陸地高程。 如果是這樣,樣本將更新對(duì)應(yīng)于土地的參數(shù)緩沖區(qū),其中包含新棲息地的正確材料和植被幾何形狀。 該示例通過(guò)將陸地高程值傳遞給EvaluateTerrainAtLocation函數(shù)來(lái)渲染此新棲息地。

static void EvaluateTerrainAtLocation(float2 uv,
                                      float3 worldPosition,
                                      texture2d<float> heightMap,
                                      texture2d<float> normalMap,
                                      texture2d<float> propertiesMap,
                                      constant const TerrainParams& terrainParams,
                                      thread float outHabitat[TerrainHabitatTypeCOUNT],
                                      thread float3 &outNormal)

Define an Argument Buffer for Terrain Habitats - 為地形棲息地定義參數(shù)緩沖區(qū)

該示例定義了一個(gè)自定義參數(shù)緩沖區(qū)結(jié)構(gòu)TerrainHabitat,它定義了地形棲息地的元素。

struct TerrainHabitat
{
#ifndef METAL
    // This struct should not be instantiated in C++ because it contains textures that aren't visible on the CPU
private:
    TerrainHabitat ();
public:
#endif

    float slopeStrength      IAB_INDEX(TerrainHabitat_MemberIds::slopeStrength);
    float slopeThreshold     IAB_INDEX(TerrainHabitat_MemberIds::slopeThreshold);
    float elevationStrength  IAB_INDEX(TerrainHabitat_MemberIds::elevationStrength);
    float elevationThreshold IAB_INDEX(TerrainHabitat_MemberIds::elevationThreshold);
    float specularPower      IAB_INDEX(TerrainHabitat_MemberIds::specularPower);
    float textureScale       IAB_INDEX(TerrainHabitat_MemberIds::textureScale);
    bool  flipNormal         IAB_INDEX(TerrainHabitat_MemberIds::flipNormal);
    
    struct ParticleProperties
    {
        // The fields of this struct must be reflected in TerrainHabitat_MemberIds
        simd::float4    keyTimePoints;
        simd::float4    scaleFactors;
        simd::float4    alphaFactors;
        simd::float4    gravity;
        simd::float4    lightingCoefficients;
        int             doesCollide;
        int             doesRotate;
        int             castShadows;
        int             distanceDependent;
    } particleProperties;
    
#ifdef METAL
    texture2d_array <float,access::sample> diffSpecTextureArray IAB_INDEX(TerrainHabitat_MemberIds::diffSpecTextureArray);
    texture2d_array <float,access::sample> normalTextureArray   IAB_INDEX(TerrainHabitat_MemberIds::normalTextureArray);
#endif
};

在這些元素中,elevationStrengthelevationThreshold確定棲息地活躍的高程范圍。 此外,diffSpecTextureArraynormalTextureArray確定用于渲染棲息地的紋理。

TerrainHabitat嵌套在另一個(gè)參數(shù)緩沖區(qū)TerrainParams中,它提供了許多輕微的視覺(jué)變化以增加真實(shí)感。

struct TerrainParams
{
    TerrainHabitat habitats [TerrainHabitatTypeCOUNT];
    float ambientOcclusionScale    IAB_INDEX(TerrainParams_MemberIds::ambientOcclusionScale);
    float ambientOcclusionContrast IAB_INDEX(TerrainParams_MemberIds::ambientOcclusionContrast);
    float ambientLightScale        IAB_INDEX(TerrainParams_MemberIds::ambientLightScale);
    float atmosphereScale          IAB_INDEX(TerrainParams_MemberIds::atmosphereScale);
};

TerrainHabitat是地形棲息地的特定參數(shù)緩沖區(qū)定義。 但是,由于此定義嵌套在TerrainParams中,因此TerrainParams對(duì)象是沿GPU管道傳遞的對(duì)象。


Render Terrain - 渲染地形

該示例為GPU提供了與各種棲息地相對(duì)應(yīng)的紋理。 首先,該示例調(diào)用useResource:usage:方法來(lái)指示GPU使用哪些紋理。

for (int i = 0; i < _terrainTextures.size(); i++)
{
    [renderEncoder useResource: _terrainTextures[i].diffSpecTextureArray
                         usage: MTLResourceUsageSample | MTLResourceUsageRead];
    [renderEncoder useResource: _terrainTextures[i].normalTextureArray
                         usage: MTLResourceUsageSample | MTLResourceUsageRead];
}

然后,該示例調(diào)用setFragmentBuffer:offset:atIndex:方法來(lái)設(shè)置包含這些紋理terrainParamsBuffer的參數(shù)緩沖區(qū)。

[renderEncoder setFragmentBuffer:_terrainParamsBuffer offset:0 atIndex:_iabBufferIndex_PplTerrainMainView];

該示例訪問(wèn)片段函數(shù)terrain_fragment中的參數(shù)緩沖區(qū),以輸出地形的正確材質(zhì)。 首先,樣本將mat參數(shù)傳遞給片段函數(shù)。

fragment GBufferFragOut terrain_fragment (
                                          const TerrainVertexOut in [[stage_in]],
                                          constant TerrainParams & mat [[buffer(1)]],
                                          constant AAPLUniforms& globalUniforms [[buffer(2)]],
                                          texture2d<float> heightMap [[texture(0)]],
                                          texture2d<float> normalMap [[texture(1)]],
                                          texture2d<float> propertiesMap [[texture(2)]]
                                          )

然后,樣本將當(dāng)前平臺(tái)高程傳遞到EvaluateTerrainAtLocation函數(shù),其中片段對(duì)與該高程對(duì)應(yīng)的紋理進(jìn)行采樣。

BrdfProperties curSubLayerBrdf = sample_brdf (
                                              mat.habitats [curLayerIdx].diffSpecTextureArray,
                                              mat.habitats [curLayerIdx].normalTextureArray,
                                              curSubLayerIdx,
                                              mat.habitats [curLayerIdx].textureScale,
                                              mat.habitats [curLayerIdx].specularPower,
                                              mat.habitats [curLayerIdx].flipNormal,
                                              in.worldPosition,
                                              normal,
                                              tangent,
                                              bitangent );

Render Vegetation - 渲染植被

該示例通過(guò)AAPLTerrainRenderer實(shí)例將terrainParamsBuffer參數(shù)緩沖區(qū)傳遞給植被渲染過(guò)程。 此數(shù)據(jù)確定在給定位置呈現(xiàn)的植被類(lèi)型。 首先,該示例調(diào)用setBuffer:offset:atIndex:方法為植被渲染過(guò)程設(shè)置參數(shù)緩沖區(qū)。

[computeEncoder setBuffer:terrain.terrainParamsBuffer offset:0 atIndex:3];

然后,示例將參數(shù)緩沖區(qū)傳遞給EvaluateTerrainAtLocation函數(shù),該函數(shù)輸出habitatPercentages值:

EvaluateTerrainAtLocation(uv_pos, world_pos, heightMap,
                          normalMap, propertiesMap, terrainParams,
                          habitatPercentages,
                          worldNormal);

處理?xiàng)⒌匕俜直纫赃x擇植被幾何中的特定索引,由pop_idx的值確定:

pop_idx = rules[rule_index].populationStartIndex + uint((s / rules[rule_index].densityInHabitat * float(rules[rule_index].populationIndexCount)));

最后,該示例使用此population索引在景觀上渲染特定植被幾何的實(shí)例:

vegetationSpawnInstance(pop_idx, world_matrix, float4(world_pos, radius), globalUniforms, instances, indirect);

Render Particles - 渲染粒子

該示例通過(guò)AAPLTerrainRenderer實(shí)例將terrainParamsBuffer參數(shù)緩沖區(qū)傳遞給粒子渲染過(guò)程。 此數(shù)據(jù)確定在給定位置呈現(xiàn)的粒子類(lèi)型。 首先,該示例調(diào)用setBuffer:offset:atIndex:方法為粒子渲染過(guò)程設(shè)置參數(shù)緩沖區(qū)。

[enc setBuffer:[terrain terrainParamsBuffer] offset:0 atIndex:14];

然后,樣本使用EvaluateTerrainAtLocation函數(shù)檢查改變的景觀中棲息地覆蓋的相對(duì)百分比,其中示例傳遞粒子的3D位置。

EvaluateTerrainAtLocation (mouseUvPos, mouseWorldPos, heightMap,
                           normalMap, propsMap, terrainParams,
                           habitatPercentages,
                           worldNormal);

示例通過(guò)選擇棲息地覆蓋率最高的地形來(lái)選擇適當(dāng)?shù)臈⒌亍?/p>

float highestLevel = 0.f;
for (uint i = 0; i < TerrainHabitatTypeCOUNT; i++)
{
    if (habitatPercentages [i] > highestLevel)
    {
        highestLevel = habitatPercentages [i];
        habitatIndex = i;
    }
}

最后,從參數(shù)緩沖區(qū)中檢索粒子的相應(yīng)棲息地材料并將其設(shè)置到新粒子上。

ParticleData data;
data.habitatIndex = habitatIndex;
data.texture = terrainParams.habitats [habitatIndex].diffSpecTextureArray;

后記

本篇主要講述了具有參數(shù)緩沖區(qū)的動(dòng)態(tài)地形,感興趣的給個(gè)贊或者關(guān)注~~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容