生活随笔
收集整理的這篇文章主要介紹了
Metal之渲染绘制三角形
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
準備工作
- Metal渲染的構建流程, 請參考:Metal之簡單渲染動態切換屏幕顏色
- Metal三角形的渲染顯示與渲染構建流程大體一致, 本文主要介紹以下方面的修改和實現:
① metal渲染文件
② 創建C 與 OC 的橋接函數
③ initWithMetalKitView方法中需要加載metal文件
④ drawInMTKView方法中加載三角形數據 - Metal三角形的渲染顯示是基于世界坐標系下。
渲染流程
一、metal渲染文件
- command + N --> Metal File 創建metal著色器文件, 新建metal文件:YDWShaders.metal
- 定義頂點著色器輸入和片元著色器輸入,相當于OpenGL ES中的varying修飾的變量,即橋接變量;
typedef struct {float4 clipSpacePosition
[[position
]];float4 color
;} RasterizerData
;
- 定義頂點著色器函數和片元著色器函數:
① 處理頂點數據: 執行坐標系轉換,將生成的頂點剪輯空間寫入到返回值中; 將頂點顏色值傳遞給返回值;
② 初始化輸出剪輯空間位置: 索引到我們的數組位置以獲得當前頂點, 我們的位置是在像素維度中指定的, 每個頂點著色器的輸出位置在剪輯空間中(也稱為歸一化設備坐標空間,NDC),剪輯空間中的(-1,-1)表示視口的左下角,而(1,1)表示視口的右上角, 計算和寫入 XY值到我們的剪輯空間的位置.為了從像素空間中的位置轉換到剪輯空間的位置,我們將像素坐標除以視口的大小的一半;
③ 把輸入的顏色直接賦值給輸出顏色, 這個值將于構成三角形的頂點的其他顏色值插值, 從而為片段著色器中的每個片段生成顏色值;
vertex RasterizerData
vertexShader(uint vertexID
[[vertex_id
]],constant CJLVertex
*vertices
[[buffer(CJLVertexInputIndexVertices
)]],constant vector_uint2
*viewportSizePointer
[[buffer(CJLVertexInputIndexViewportSize
)]]) {RasterizerData out
; out
.clipSpacePosition
= vertices
[vertexID
].position
;out
.color
= vertices
[vertexID
].color
;return out
;
}
fragment float4
fragmentShader(RasterizerData
in [[stage_in
]]) {return in.color
;
}
二、創建C與OC的橋接文件
該頭文件的目的是為了c代碼與OC代碼可以共享與 shader 和 C 代碼 為了確保Metal Shader緩存區索引能夠匹配 Metal API Buffer 設置的集合調用
- 定義緩存區索引值,表示向metal著色器傳遞數據的入口枚舉值,相當于OpenGL ES中GLSL語言定義的頂點坐標入口position
typedef enum YDWVertexInputIndex
{YDWVertexInputIndexVertices
= 0,YDWVertexInputIndexViewportSize
= 1,
} YDWVertexInputIndex
;
- 定義圖形數據的結構體,包含頂點和顏色值,類似于OpenGL ES中的頂點數據的結構體
typedef struct {vector_float4 position
;vector_float4 color
;
} YDWVertex
;
三、initWithMetalKitView方法中需要加載metal文件
- 獲取GPU設備device
- 加載.metal著色器文件
- 配置用于創建管道狀態的管道描述符
- 同步創建并返回渲染管線狀態對象
- 創建命令隊列
- (nonnull instancetype
)initWithMetalKitView
:(nonnull MTKView
*)mtkView
{self = [super init
];if(self) {NSError
*error
= NULL;_device
= mtkView
.device
;id
<MTLLibrary
> defaultLibrary
= [_device newDefaultLibrary
];id
<MTLFunction
> vertexFunction
= [defaultLibrary newFunctionWithName
:@"vertexShader"];id
<MTLFunction
> fragmentFunction
= [defaultLibrary newFunctionWithName
:@"fragmentShader"];MTLRenderPipelineDescriptor
*pipelineStateDescriptor
= [[MTLRenderPipelineDescriptor alloc
] init
];pipelineStateDescriptor
.label
= @"Simple Pipeline";pipelineStateDescriptor
.vertexFunction
= vertexFunction
;pipelineStateDescriptor
.fragmentFunction
= fragmentFunction
;pipelineStateDescriptor
.colorAttachments
[0].pixelFormat
= mtkView
.colorPixelFormat
;_pipelineState
= [_device newRenderPipelineStateWithDescriptor
:pipelineStateDescriptor error
:&error
];if (!_pipelineState
) {NSLog(@"Failed to created pipeline state, error %@", error
);return nil
;}_commandQueue
= [_device newCommandQueue
];}return self;
}
四、drawInMTKView方法中加載三角形數據
static const YDWVertex triangleVertices
[] = {{ { 0.5, -0.25, 0.0, 1.0 }, { 1, 0, 0, 1 } },{ { -0.5, -0.25, 0.0, 1.0 }, { 0, 1, 0, 1 } },{ { -0.0f, 0.25, 0.0, 1.0 }, { 0, 0, 1, 1 } },};
id
<MTLCommandBuffer
> commandBuffer
= [_commandQueue commandBuffer
];commandBuffer
.label
= @"MyCommand";
MTLRenderPassDescriptor
*renderPassDescriptor
= view
.currentRenderPassDescriptor
;
id
<MTLRenderCommandEncoder
> renderEncoder
=[commandBuffer renderCommandEncoderWithDescriptor
:renderPassDescriptor
];renderEncoder
.label
= @"MyRenderEncoder";
- 設置我們繪制的可繪制區域:
視口指定Metal渲染內容的drawable區域。 視口是具有x和y偏移,寬度和高度以及近和遠平面的3D區域。
為管道分配自定義視口需要通過調用setViewport:方法將MTLViewport結構編碼為渲染命令編碼器。 如果未指定視口,Metal會設置一個默認視口,其大小與用于創建渲染命令編碼器的drawable相同。
MTLViewport viewPort
= {0.0,0.0,_viewportSize
.x
,_viewportSize
.y
,-1.0,1.0};[renderEncoder setViewport
:viewPort
];
[renderEncoder setRenderPipelineState
:_pipelineState
];
- 從應用程序OC代碼中發送數據給 Metal 頂點著色器函數
頂點數據+顏色數據: 指向要傳遞給著色器的內存的指針, 想要傳遞的數據的內存大小;
一個整數索引,它對應于我們的“vertexShader”函數中的緩沖區屬性限定符的索引。
[renderEncoder setVertexBytes
:triangleVerticeslength
:sizeof(triangleVertices
)atIndex
:YDWVertexInputIndexVertices
];
[renderEncoder setVertexBytes
:&_viewportSizelength
:sizeof(_viewportSize
)atIndex
:YDWVertexInputIndexViewportSize
];
[renderEncoder drawPrimitives
:MTLPrimitiveTypeTrianglevertexStart
:0vertexCount
:3];
- 結束編碼: 表示已該編碼器生成的命令都已完成, 且從NTLCommandBuffer中分離
[renderEncoder endEncoding
];
[commandBuffer presentDrawable
:view
.currentDrawable
];
[commandBuffer commit
];
效果展示
完整示例
Metal之基于世界坐標系下渲染繪制三角形
總結
以上是生活随笔為你收集整理的Metal之渲染绘制三角形的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。