ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Hello Again, Metal
    OpenGL/iOS_Metal 2019. 7. 1. 21:48

    안녕하세요 dely입니다:)

    iOS Metal을 사용하여 하나씩 이해해나가며 그래픽스 실습을 해보려합니다.

    일단 가볍게 화면 background에 노란색 칠하기를 해보겠습니다.

     

    먼저 프로젝트를 하나 만들고, ViewController에 MetalKit을 import합니다.

    import MetalKit

     

    MetalKit 안에는 렌더링 후 출력에 필요한 View를 구성하는 역할을 가진 MTKView가 있습니다.

    storyboard에서 MTKView를 배치하고 ViewController와 연결해줍니다.

    @IBOutlet weak var metalView: MTKView!

     

    Metal에서 Metal App과 GPU의 관계는 클라이언트-서버 패턴의 관계입니다.

     

    Metal 클라이언트-서버 패턴

     

    클라이언트인 Metal App에서 어떤 그림을 그려줘~ 라고 명령어를 전달하면

    서버인 GPU에서 뚝딱뚝딱 명령어를 처리하고 알림을 주는 패턴을 가지고 있습니다.

     

    Metal APP에서 서버에 명령어를 요청할 때는 command queue에 명령 buffer를 추가하고

    명령 buffer를 commit하는 방법으로 합니다.

     

    다음 코드와 같이 makeCommandQueue() 메소드가 있는 MTLDevice를 선언 및 초기화해주고,

    MTLCommandQueue 객체에 넣어줍니다.

    private var device: MTLDevice!
    private var commandQueue: MTLCommandQueue!
    device = MTLCreateSystemDefaultDevice() 
    commandQueue = device.makeCommandQueue()  

    뷰 컨트롤러를 뷰의 위임자로 설정하여 그리기 및 크기 조정시 콜백을 수신합니다.

    metalView.device = device 
    metalView.delegate = self

     

    이제 MTKViewDelegate 프로토콜 을 구현해야 합니다.

    (MTKViewDelegate 에서 상속받은 객체는 MTKView 에 드로잉 메서드를 제공하고,

    MTKView 를 서브 클래싱하지 않고 렌더링 이벤트에 응답 할 수 있습니다.)

     

    즉, 이 부분에서는 '그려줘~'라는 역할의 위임을 받고 Renderer 역할을 하게 됩니다.

    extension ViewController: MTKViewDelegate {
      func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
      
      }
      
      func draw(in view: MTKView) { 
      
      }
    }
    

     

    각 메소드들은 다음과 같은 기능을 합니다.

    • mtkView() : 화면이 회전하는 경우와 같이 드로어 블 크기가 변경 될 때 호출됩니다.
    • draw() : 실제 그리기를 수행하기 위해 호출됩니다.

    여기서 draw() 메소드를 사용하여 노란색을 칠해보겠습니다.

    이후의 코드들은 모두 draw() 메소드 안에 들어갑니다.

     

    guard let drawable = view.currentDrawable else {
      return
    }

    위의 코드와 같이 draw() 메소드의 매개변수로 받은 view(MTKView type)의 currentDrawable을 사용하여

    현재 프레임에 사용할 유효한 drawable이 있는지 확인하는 작업을 합니다.

     

    let renderPassDescriptor = MTLRenderPassDescriptor()

    그리고 MTLRenderPassDescriptor() 클래스 객체를 하나 만들어줍니다.

    렌더링 패스는 하나의 scene을 만들어내기 위해 파이프라인을 쭉 통과하여거치는 것을 말하는데요

    여기서 각 파이프라인 요소들이 색상, 깊이, 스텐실과 같은 렌더링 관련 상태정보들을

    세팅해주기 위함입니다.

     

    renderPassDescriptor.colorAttachments[0].texture = drawable.texture
    renderPassDescriptor.colorAttachments[0].loadAction = .clear
    renderPassDescriptor.colorAttachments[0]
      .clearColor = MTLClearColor(red: 0.5, green: 0.5, blue: 0.0, alpha: 1.0)

    View texture를 그리기 대상으로 설정

    (시뮬레이터가 아닌 device로 설정해야 drawable.texture 코드 작성 가능ㅠㅠ

    cf, https://stackoverflow.com/questions/41916306/metal-texture-not-found),

    렌더링을 시작할 때 clear 설정,

    렌더링 색상은 노랑으로 설정을 합니다.

     

    guard let commandBuffer = commandQueue.makeCommandBuffer() else {
      return
    }

    위에서 생성한 commandQueue를 통해 새로운 명령 버퍼를 생성합니다.

     

    guard let renderEncoder = commandBuffer
      .makeRenderCommandEncoder(descriptor: renderPassDescriptor) else {
        return
    }

    이 명령 버퍼를 GPU에 전달하기 위해서는 인코딩을 해서 보내줍니다.

    인코더 개체를 사용하여 해당 호출을 명령 버퍼에 캡슐화하는 명령을 삽입합니다.

     

    renderEncoder.endEncoding()

    이제 모든 명령이 완료되었다고 선언을 하고,

     

    commandBuffer.present(drawable)
    commandBuffer.commit()

    커맨드 버퍼가 실행되도록 drawable을 추가합니다.

    마지막으로 커맨드 버퍼를 커밋합니다.

    Metal은 그것을 GPU로 보내고 활성 파이프라인 객체를 사용하여 명령을 처리합니다.

     

    자, device에서 실행을 시켜보면

    아름다운 노랑이 나오게 됩니다!

     

     

    출처

    https://www.raywenderlich.com/9211-moving-from-opengl-to-metal#toc-anchor-009

    반응형

    'OpenGL > iOS_Metal' 카테고리의 다른 글

    Drawing Primitives  (0) 2019.07.03
    Add red triangle  (0) 2018.10.13
    Refactoring Fill the Yellow texture  (0) 2018.10.12
    Fill the Yellow texture  (0) 2018.10.07
    Hello Metal  (0) 2018.10.06

    댓글

Designed by Tistory.