版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2018.10.10 星期三 |
前言
很多做視頻和圖像的楣责,相信對這個框架都不是很陌生鹃栽,它渲染高級3D圖形穿扳,并使用GPU執(zhí)行數(shù)據(jù)并行計算。接下來的幾篇我們就詳細的解析這個框架借尿。感興趣的看下面幾篇文章刨晴。
1. Metal框架詳細解析(一)—— 基本概覽
2. Metal框架詳細解析(二) —— 器件和命令(一)
3. Metal框架詳細解析(三) —— 渲染簡單的2D三角形(一)
4. Metal框架詳細解析(四) —— 關(guān)于GPU Family 4(一)
5. Metal框架詳細解析(五) —— 關(guān)于GPU Family 4之關(guān)于Imageblocks(二)
6. Metal框架詳細解析(六) —— 關(guān)于GPU Family 4之關(guān)于Tile Shading(三)
7. Metal框架詳細解析(七) —— 關(guān)于GPU Family 4之關(guān)于光柵順序組(四)
8. Metal框架詳細解析(八) —— 關(guān)于GPU Family 4之關(guān)于增強的MSAA和Imageblock采樣覆蓋控制(五)
9. Metal框架詳細解析(九) —— 關(guān)于GPU Family 4之關(guān)于線程組共享(六)
10. Metal框架詳細解析(十) —— 基本組件(一)
11. Metal框架詳細解析(十一) —— 基本組件之器件選擇 - 圖形渲染的器件選擇(二)
12. Metal框架詳細解析(十二) —— 基本組件之器件選擇 - 計算處理的設(shè)備選擇(三)
13. Metal框架詳細解析(十三) —— 計算處理(一)
14. Metal框架詳細解析(十四) —— 計算處理之你好,計算(二)
15. Metal框架詳細解析(十五) —— 計算處理之關(guān)于線程和線程組(三)
16. Metal框架詳細解析(十六) —— 計算處理之計算線程組和網(wǎng)格大新贩(四)
17. Metal框架詳細解析(十七) —— 工具狈癞、分析和調(diào)試(一)
18. Metal框架詳細解析(十八) —— 工具、分析和調(diào)試之Metal GPU Capture(二)
19. Metal框架詳細解析(十九) —— 工具茂契、分析和調(diào)試之GPU活動監(jiān)視器(三)
20. Metal框架詳細解析(二十) —— 工具蝶桶、分析和調(diào)試之關(guān)于Metal著色語言文件名擴展名、使用Metal的命令行工具構(gòu)建庫和標記Metal對象和命令(四)
21. Metal框架詳細解析(二十一) —— 基本課程之基本緩沖區(qū)(一)
22. Metal框架詳細解析(二十二) —— 基本課程之基本紋理(二)
23. Metal框架詳細解析(二十三) —— 基本課程之CPU和GPU同步(三)
24. Metal框架詳細解析(二十四) —— 基本課程之參數(shù)緩沖 - 基本參數(shù)緩沖(四)
25. Metal框架詳細解析(二十五) —— 基本課程之參數(shù)緩沖 - 帶有數(shù)組和資源堆的參數(shù)緩沖區(qū)(五)
26. Metal框架詳細解析(二十六) —— 基本課程之參數(shù)緩沖 - 具有GPU編碼的參數(shù)緩沖區(qū)(六)
Advanced Techniques - 高級技術(shù)
通過有效使用Metal功能掉冶,了解如何實現(xiàn)高級技術(shù)真竖。
以下示例代碼項目演示了各種圖形和計算技術(shù),這些技術(shù)經(jīng)過專門優(yōu)化以利用Metal功能郭蕉。
-
Reflections with Layer Selection
- 演示如何使用圖層選擇來減少反射對象所需的渲染過程的數(shù)量疼邀。
-
LOD with Function Specialization
- 演示如何使用專用函數(shù)根據(jù)動態(tài)條件選擇細節(jié)級別喂江。
-
Dynamic Terrain with Argument Buffers
- 演示如何使用參數(shù)緩沖區(qū)通過GPU驅(qū)動的管道實時渲染動態(tài)地形召锈。
-
- 了解如何使用多個設(shè)備。
Reflections with Layer Selection - 圖層選擇的反射
演示如何使用圖層選擇來減少反射對象所需的渲染過程的數(shù)量获询。
此示例演示了鉻球上的動態(tài)反射涨岁,使用圖層選擇以兩次渲染幀。 第一遍將環(huán)境渲染到立方體貼圖上吉嚣。 第二遍將環(huán)境反射渲染到球體上梢薪;它渲染場景中的其他actors
;它呈現(xiàn)環(huán)境本身尝哆。
您可以通過從環(huán)境的立方體貼圖中對其反射進行采樣來實現(xiàn)反映其環(huán)境的對象秉撇。 立方體貼圖是由以立方體形狀排列的六個2D紋理層組成的單個紋理。 反射根據(jù)環(huán)境中其他對象的位置而變化秋泄,因此每個立方體貼圖的六個面必須在每個幀中動態(tài)渲染琐馆。 這通常需要六個單獨的渲染過程,每個面一個恒序,但Metal允許您在一次過程中渲染整個立方體貼圖瘦麸。
Separate the Scene - 分離場景
立方體貼圖表示為具有六個圖層的渲染目標數(shù)組,每個圖層對應(yīng)一個面歧胁。 為頂點函數(shù)返回值的結(jié)構(gòu)成員指定的[[render_target_array_index]]
屬性限定符分別標識每個數(shù)組層滋饲。 此圖層選擇功能允許樣本決定將環(huán)境的哪個部分渲染到哪個立方體貼圖面厉碟。
AAPLActorData
對象表示場景中的actor
。 在此示例中屠缭,每個actor都是具有相同網(wǎng)格數(shù)據(jù)但具有不同漫反射顏色的模型箍鼓。 這些actor坐在XZ平面上;它們總是相對于球體在X或Z方向上反射呵曹,并且可以渲染到立方體貼圖的任何+ X袄秩,-X,+ Z或-Z面逢并。
Perform Culling Tests for the Reflection Pass - 執(zhí)行反射通過的剔除測試
在渲染到立方體貼圖之前之剧,了解應(yīng)該渲染每個actor的面是很有用的。 確定此信息涉及稱為剔除測試的過程砍聊,并且針對每個立方體貼圖面對每個actor執(zhí)行該過程背稼。
在每個幀的開始處,對于每個立方體貼圖面玻蝌,計算視圖矩陣并且視圖的截錐體存儲在culler_probe
數(shù)組中蟹肘。
// 1) Get the view matrix for the face given the sphere's updated position
viewMatrix[i] = _cameraReflection.GetViewMatrixForFace_LH (i);
// 2) Calculate the planes bounding the frustum using the updated view matrix
// You use these planes later to test whether an actor's bounding sphere
// intersects with the frustum, and is therefore visible in this face's viewport
culler_probe[i].Reset_LH (viewMatrix [i], _cameraReflection);
這些culler probes
測試actor
和每個立方體貼圖面的視錐體之間的交叉點。 測試結(jié)果確定actor在反射過程中渲染到多少個面(instanceCount)
俯树,以及它渲染到哪個面(instanceParams)
帘腹。
if (_actorData[actorIdx].passFlags & EPassFlags::Reflection)
{
int instanceCount = 0;
for (int faceIdx = 0; faceIdx < 6; faceIdx++)
{
// Check if the actor is visible in the current probe face
if (culler_probe [faceIdx].Intersects (_actorData[actorIdx].modelPosition.xyz, _actorData[actorIdx].bSphere))
{
// Add this face index to the the list of faces for this actor
InstanceParams instanceParams = {(ushort)faceIdx};
instanceParams_reflection [MaxVisibleFaces * actorIdx + instanceCount].viewportIndex = instanceParams.viewportIndex;
instanceCount++;
}
}
_actorData[actorIdx].instanceCountInReflection = instanceCount;
}
下圖顯示了根據(jù)它們相對于反射球的位置對actors
進行的剔除測試的結(jié)果。 因為_actorData [0]
和actorData [1]
將兩個視錐體平分许饿,所以它們的instanceCount
屬性設(shè)置為2阳欲,并且它們的instanceParams
數(shù)組中有兩個元素。 (此數(shù)組包含actors
相交的視錐體的立方體貼圖面索引陋率。)
Configure Render Targets for the Reflection Pass - 配置Reflection Pass的渲染目標
反射過程的渲染目標是立方體貼圖球化。 該示例通過使用具有顏色渲染目標,深度渲染目標和六個圖層的MTLRenderPassDescriptor
對象來配置渲染目標瓦糟。 renderTargetArrayLength
屬性設(shè)置立方體貼圖面的數(shù)量筒愚,并允許渲染管道渲染到其中的任何一個或全部。
reflectionPassDesc.colorAttachments[0].texture = _reflectionCubeMap;
reflectionPassDesc.depthAttachment.texture = _reflectionCubeMapDepth;
reflectionPassDesc.renderTargetArrayLength = 6;
Issue Draw Calls for the Reflection Pass - 發(fā)出反射過程的繪制調(diào)用
drawActors:pass:
方法為每個actor
設(shè)置圖形渲染狀態(tài)菩浙。 只有在六個立方體貼圖面中的任何一個中可見時巢掺,才會繪制Actor,由visibleVpCount
值(通過instanceCountInReflection
屬性訪問)確定劲蜻。 visibleVpCount
的值確定實例化繪制調(diào)用的實例數(shù)陆淀。
[renderEncoder drawIndexedPrimitives: metalKitSubmesh.primitiveType
indexCount: metalKitSubmesh.indexCount
indexType: metalKitSubmesh.indexType
indexBuffer: metalKitSubmesh.indexBuffer.buffer
indexBufferOffset: metalKitSubmesh.indexBuffer.offset
instanceCount: visibleVpCount
baseVertex: 0
baseInstance: actorIdx * MaxVisibleFaces];
在此繪制調(diào)用中,示例將baseInstance
參數(shù)設(shè)置為actorIdx * 5
的值斋竞。此設(shè)置很重要倔约,因為它告訴頂點函數(shù)如何為每個實例選擇適當?shù)匿秩灸繕藞D層。
Render the Reflection Pass - 渲染反射Pass
在vertexTransform
頂點函數(shù)中坝初,instanceParams
參數(shù)指向包含每個actor應(yīng)渲染到的立方體貼圖面的緩沖區(qū)浸剩。 instanceId
值索引到instanceParams
數(shù)組中钾军。
vertex ColorInOut vertexTransform ( Vertex in [[ stage_in ]],
uint instanceId [[ instance_id ]],
device InstanceParams* instanceParams [[ buffer (BufferIndexInstanceParams) ]],
device ActorParams& actorParams [[ buffer (BufferIndexActorParams) ]],
constant ViewportParams* viewportParams [[ buffer (BufferIndexViewportParams) ]] )
頂點函數(shù)ColorInOut
的輸出結(jié)構(gòu)包含使用[[render_target_array_index]]
屬性限定符的face
成員。 face的返回值確定渲染管道應(yīng)渲染到的立方體貼圖面绢要。
typedef struct
{
float4 position [[position]];
float2 texCoord;
half3 worldPos;
half3 tangent;
half3 bitangent;
half3 normal;
uint face [[render_target_array_index]];
} ColorInOut;
因為draw
調(diào)用的baseInstance
參數(shù)的值設(shè)置為actorIdx * 5
吏恭,所以在draw調(diào)用中繪制的第一個實例的instanceId
值等于此值。 實例的每個后續(xù)呈現(xiàn)都將instanceId
值遞增1重罪。instanceParams
數(shù)組為每個actor提供五個槽樱哼,因為actor最多可以在五個立方體貼圖面中可見。 因此剿配,instanceParams [instanceId]
元素始終包含actor中可見的面部索引之一搅幅。 因此,該示例使用此值來選擇有效的渲染目標圖層呼胚。
out.face = instanceParams[instanceId].viewportIndex;
總之茄唐,為了將每個actor渲染到反射立方體貼圖,該示例為actor發(fā)出一個實例化繪制調(diào)用蝇更。 頂點函數(shù)使用內(nèi)置的instanceId
變量來索引instanceParams
數(shù)組沪编,該數(shù)組包含應(yīng)該渲染實例的立方體貼圖面的索引。 因此年扩,頂點函數(shù)在面返回值成員中設(shè)置此面的索引蚁廓,該成員使用[[render_target_array_index]]
屬性限定符。 這可確保每個actor都呈現(xiàn)給它應(yīng)該出現(xiàn)的每個立方體貼圖面厨幻。
Perform Culling Tests for the Final Pass - 執(zhí)行最終過程的剔除測試
該示例在最后過程中對主攝像機執(zhí)行類似的視圖更新相嵌。 在每個幀的開始處,計算視圖矩陣克胳,并且視圖的平截頭體存儲在culler_final
變量中平绩。
_cameraFinal.target = SceneCenter;
_cameraFinal.rotation = fmod ((_cameraFinal.rotation + CameraRotationSpeed), M_PI*2.f);
matrix_float3x3 rotationMatrix = matrix3x3_rotation (_cameraFinal.rotation, CameraRotationAxis);
_cameraFinal.position = SceneCenter;
_cameraFinal.position += matrix_multiply (rotationMatrix, CameraDistanceFromCenter);
const matrix_float4x4 viewMatrix = _cameraFinal.GetViewMatrix();
const matrix_float4x4 projectionMatrix = _cameraFinal.GetProjectionMatrix_LH();
culler_final.Reset_LH (viewMatrix, _cameraFinal);
ViewportParams *viewportBuffer = (ViewportParams *)_viewportsParamsBuffers_final[_uniformBufferIndex].contents;
viewportBuffer[0].cameraPos = _cameraFinal.position;
viewportBuffer[0].viewProjectionMatrix = matrix_multiply (projectionMatrix, viewMatrix);
這個最終的culler probe
用于測試actor和攝像機的視錐體之間的交叉點。 測試結(jié)果僅確定每個actor在最后一遍中是否可見漠另。
if (culler_final.Intersects (_actorData[actorIdx].modelPosition.xyz, _actorData[actorIdx].bSphere))
{
_actorData[actorIdx].visibleInFinal = YES;
}
else
{
_actorData[actorIdx].visibleInFinal = NO;
}
Configure Render Targets for the Final Pass - 配置最終過程的渲染目標
最終過程的渲染目標是視圖的drawable
,它是通過訪問視圖的currentRenderPassDescriptor
屬性獲得的可顯示資源跃赚。 但是笆搓,您不能過早訪問此屬性,因為它隱式檢索drawable
纬傲。Drawable
是由Core Animation
框架創(chuàng)建和維護的昂貴系統(tǒng)資源满败。 你應(yīng)該盡可能短暫地持有一個drawable
,以避免資源停滯叹括。 在此示例中算墨,在編碼最終渲染過程之前獲取drawable
沐旨。
MTLRenderPassDescriptor* finalPassDescriptor = view.currentRenderPassDescriptor;
finalPassDescriptor.renderTargetArrayLength = 1;
id<MTLRenderCommandEncoder> renderEncoder =
[commandBuffer renderCommandEncoderWithDescriptor:finalPassDescriptor];
renderEncoder.label = @"FinalPass";
[self drawActors: renderEncoder pass: EPassFlags::Final];
[renderEncoder endEncoding];
Issue Draw Calls for the Final Pass - 發(fā)出最終過程的繪制調(diào)用
drawActors:pass:
方法為每個actor
設(shè)置圖形渲染狀態(tài)车摄。 只有在主攝像機可見的情況下才會繪制Actor介时,由visibleVpCount
值(通過visibleInFinal
屬性訪問)確定椎咧。
因為每個actor
在最后一次傳遞中只繪制一次,所以instanceCount
參數(shù)始終設(shè)置為1挖藏,baseInstance
參數(shù)始終設(shè)置為0暑刃。
Render the Final Pass - 渲染最終過程
最后過程將最終幀直接渲染到視圖的drawable
,然后在屏幕上顯示膜眠。
[commandBuffer presentDrawable:view.currentDrawable];
后記
本篇主要講述了圖層選擇的反射岩臣,感興趣的給個贊或者關(guān)注~~~