Thirty Days of Metal — Day 4: MTKView
This series of posts is my attempt to present the Metal graphics programming framework in small, bite-sized chunks for Swift app developers…
medium.com
요약: iOS, 맥용 응용 프로그램에서 Metal을 사용하게 도와주는 MTKView
MTKView와 MetalKit 대한 소개
MetalKit은 Metal을 고차원 레벨에서 쉽게 사용하도록 도와주는 프레임워크이다.
MTKView는 UIKit에 있는 기본 View 클래스의 하위 클래스이다. 맥 OS의 경우는 NSView를 상속받고 iOS를 UIView를 상속 받는다.
추가적으로, SwiftUI는 Metal View를 직접적으로 지원하지 않아서 UIViewRepresentable을 사용해야한다.
MTKView의 특징
- MTKView는 다른 뷰 타입과 같이 스토리보드에서 지원해 추가할 수 있다.
- MTKView는 메탈을 이용해 GPU로 뷰를 그릴 수 있다.
- 사실 MTKView가 일반적인 뷰와 달라지는 근본적인 이유는 CALayer에 하위타입 CAMetalLayer를 갖기 때문에 발생한 것이다.
MTKView에 필요한 요소
- MTKView와 device
- MTKView에서 GPU로 그리기 위해서는 이 뷰에 device를 할당해 줘야한다.
import MetalKit
class ViewController: UIViewController, MTKViewDelegate {
@IBOutlet weak var metalView: MTKView!
var device: MTLDevice!
override func viewDidLoad() {
super.viewDidLoad()
device = MTLCreateSystemDefaultDevice()
metalView.device = device
}
}
- MTKView와 MTKViewDelegate 프로토콜
- MTKView delegate 프로토콜을 지키는 객체를 이어줘야한다.
...metalView.delegate = self ...
MTKView 프로토콜이 구현해야하는 필드는 다음과 같다.
func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {}
func draw(in view: MTKView) {}
- func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {}
- ⇒ 뷰의 사이즈가 바뀔 때 불러지는 함수다.
ex) 핸드폰 가로모드, 세로 모드, 아이패드 듀얼 모드… - func draw(in view: MTKView) {} ⇒ 매 프레임마다 호출되는 함수다.
주로 커맨드 버퍼를 생성해서 다음 프레임에 작업할 내용을 적고 커맨드 큐에 넣는 코드를 여기에 작성한다.
캔버스 Clearing과 RenderPassDescriptor
MetaKit을 통해 GPU에게 배경을 그리는 것만 실행해보자
커맨드 버퍼에 명령어를 설정은 렌더링 인코딩 객체를 통해 진행한다.
인코딩 객체는 다양한 명령어 정보를 담을 수 있는데 이를 생성하기 위해선 MTKView로 그려지는 영역(배경)의 텍스쳐에 대한 정보를 담는 파라미터가 필요한 생성자를 사용한다.
이 MTKView로 그려지는 영역(배경)의 텍스쳐에 대한 정보를 담는 객체를 RenderPassDescriptor라고 한다.
MTKView는 현재 renderPassDescriptor가 무엇인지 알고 있어서 이 값을 통해 렌더링 인코딩 객체를 만든다.
/// commandBuffer를 매 프레임마다 넣어야 하기 때문에 draw 메서드 내부에 구현한다.
let commandBuffer = commandQueue.makeCommandBuffer()!
guard let renderPassDescriptor = mtkView.currentRenderPassDescriptor else {
print("MTKView에서 렌더링 패스 설명자를 얻지 못함; 프레임 삭제...")
)
renderPassEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor)!
이제 이런 설정값을 GPU에 전달해보자
...
renderPassEncoder.endEncoding()
commandBuffer.present(mtkView.currentDrawable!)
commandBuffer.commit()
- 인코딩이 끝난다.
- 명령어 버퍼가 mtkView가 그림을 그릴 수 있을 때 그린다.
- 명령어 버퍼를 명령어 큐에 넣는다.
하지만 이렇게만 실행 하면 오류가 발생한다…!
⇒ 우리는 초기에 MTKView로 그려지는 영역의 텍스쳐가 무엇인지 설정하지 않았기 때문이다. 이를 위해 처음 mtkView를 구성하는 영역에서 MTLClearColor 객체를 사용해 mtkView의 초기 배경을 설정한다.
mtkView.clearColor = MTLClearColor(red: Float,
blue:Float,
green:Float,
alpha:Float)
'Metal > Thirty Days of Metal (Warren Moore)' 카테고리의 다른 글
Day6. Pipelines + CommandEncoder (0) | 2023.07.21 |
---|---|
Day5. Shaders (0) | 2022.12.04 |
Day1. Devices (0) | 2022.11.17 |
Day2. Buffers (0) | 2022.11.17 |
Day3. Commands (0) | 2022.11.17 |
댓글