MINRYUL
류링류링
MINRYUL
전체 방문자
오늘
어제
  • 분류 전체보기
    • Swift
      • 학습
    • iOS
      • Toy-Project
      • 학습
      • Metal
    • CS
    • TIL

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • ViewStore
  • tuist
  • RxCocoa
  • TableView Cell
  • AttributeText
  • CollectionView Cell
  • RxSwift
  • Existential any
  • urlsession
  • RxNimble
  • TDD
  • Any
  • Custom Calendar
  • ios
  • METAL
  • WWDC 2024
  • Clean Architecture
  • opaque type
  • Protocol
  • demangle
  • static framework
  • dynamic frameworkm
  • collectionView
  • configuration_bulid_dir
  • Existential type
  • some
  • RxTest
  • Swift
  • WWDC
  • BDD

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
MINRYUL

류링류링

iOS/Metal

Metal Rendering

2024. 2. 5. 22:49

Rendering the Triangle

랜더링은 다섯 단계로 수행된다.

  1. Display Link 생성
  2. Render Pass Descriptor 생성
  3. Command Buffer 생성
  4. Render Command Encoder 생성
  5. Command Buffer를 커밋

Note: 이론적으로 이 앱은 실제로 프레임 마다 랜더링할 필요가 없다. 왜냐하면 삼각형이 그려진 후에는 움직이지 않기 때문이다. 그러나 대부분의 앱은 움직이는 부분이 있기 때문에 이 방식을 배우면, 미래의 튜토리얼에 좋은 시작점을 제공할 수 있을 것이다.

 

1. Creating a Display Link

화면이 갱신될 때마다 화면을 다시 그릴 수 있는 방법이 필요할 것이다.

CADisplayLink는 디스플레이의 새로 고침 속도에 동기화된 타이머다.

새로운 프로퍼티를 추가하자

var timer: CADisplayLink!

viewDidLoad()에서 초기화하자

timer = CADisplayLink(target: self, selector: #selector(gameloop))
timer.add(to: RunLoop.main, forMode: .default)

해당 코드를 작성하면 화면이 새로 고침될 때마다 gameloop() 함수를 호출하도록 설정된다.

클래스에 다음 stub 함수를 추가하자

func render() {
  // TODO
}

@objc func gameloop() {
  autoreleasepool {
    self.render()
  }
}

여기서 gameloop()는 각 프레임마다 render()를 호출하며, 현재는 빈 코드만 있다. 구체화 해보자.

 

2. Creating a Render Pass Descriptor

다음 단계로 MTLRenderPassDescriptor를 생성하자. 이는 어떤 텍스쳐가 렌더링 되는지, clear color가 무엇인지 및 기타 몇몇개의 구성을 설정하는 객체이다. 즉 renderPassDescriptor는 어떤 텍스처에 렌더링 할 것인지(동시에 여러 개의 텍스처에도 렌더링 가능), 배경에 어떤 색상이 있어야 하는지 등을 설명하는 객체이다.

render() 함수 코드를 추가하자

guard let drawable = metalLayer?.nextDrawable() else { return }
let renderPassDescriptor = MTLRenderPassDescriptor()
renderPassDescriptor.colorAttachments[0].texture = drawable.texture
renderPassDescriptor.colorAttachments[0].loadAction = .clear
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(
  red: 0.0, 
  green: 104.0/255.0, 
  blue: 55.0/255.0, 
  alpha: 1.0
)

먼저, 이전에 생성한 Metal 레이어에서 nextDrawable()을 호출한다. 이는 화면에 무엇인가 나타날때 그릴 텍스쳐를 반환한다.

다음으로, renderPassDescriptor를 해당 텍스처로 사용하도록 구성한다. loadAction을 Clear로 설정해서 “어떤 그림을 그리기 전에 텍스쳐를 clear 색으로 설정하라”고 지정한 뒤, clear 색을 녹색으로 설정한다.

colorAttachments 필드는 배열이며, 이는 한번에 여러 개를 가질 수 있다. texture와 attachment가 혼용되어 사용되는 것에는 이유가 있다. texture는 메모리에 저장된 일종의 “Image”이며, attachment는 이 texture에 대한 렌더링 방식을 설명하는 객체이기 때문이다. clearColor는 MTLClearColor를 생성하는데, red, green, blue, alpha 구성 요소를 갖는다. 이 값들은 0.0에서 1.0 사이의 범위에 있으며, 이를 정규화(normalized)라고도 한다.

 

3. Creating a Command Buffer

다음 단계는 Command buffer를 생성하는 것이다. 이것은 현재 프레임에 실행하려는 render commands 목록으로 생각할 수 있다. 이 것이 좋은 것은 command buffer를 커밋할 때까지 실제로 아무 일도 일어나지 않는 것이다. 이렇게 함으로써 언제 랜더링에 일어나길 원하는지 세세한 제어를 제공할 수 있다.

Command buffer를 생성하는 것은 간단하다. render() 함수 끝에 다음 프로퍼티를 추가하자.

let commandBuffer = commandQueue.makeCommandBuffer()!

Command buffer는 하나 이상의 render command를 포함한다. 이제 이 중에 하나를 생성할 것이다.

 

4. Creating a Render Command Encoder

대부분의 Commands는 직접적으로 Command Buffer에 기록될 수 없으며, 인코딩되어야 한다. 이를 위해서는 Command Encoder가 필요한데, 이것을 위해서 Render Command Encoder를 사용할 것이다. 우리가 하고 싶은 것은 Rendering Command를 기록하는 것이기 때문.

Render Command를 생성하려면 Render command encoder라는 핼퍼 객체를 사용한다. 이를 해보려면 render() 끝에 다음 코드를 추가하자.

let renderEncoder = commandBuffer
  .makeRenderCommandEncoder(descriptor: renderPassDescriptor)!
renderEncoder.setRenderPipelineState(pipelineState)
renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
renderEncoder
  .drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: 3, instanceCount: 1)
renderEncoder.endEncoding()

여기서는 command encoder를 생성하고 이전에 만든 pipeline과 vertex buffer를 지정한다.

모든 Command는 makeRenderCommandEncoder 와 endEncoding 함수 사이에 위치하게 된다.

가장 중요한 부분은 drawPrimitives(type:vertexStart:vertexCount:instanceCount:) 함수를 호출하는 부분이다. 여기서 GPU에게 vertex buffer를 기반으로 a set of triangles를 그리라고 알려준다. 여기서는 하나의 삼각형만 그릴 것이다. 함수의 매개변수는 각각의 삼각형이 vertex buffer 내에서 index 0에서 시작해서 세 개의 정점으로 이루어져 있으며 전체적으로 하나의 삼각형이라고 Metal에 알려주는 것이다.

작업이 끝났으면 endEncoding()을 호출하자

 

5. Committing Tour Command Buffer

마지막 단계는 Command buffer를 Commit하는 것이다. render() 함수의 끝에 다음 코드를 추가하자

commandBuffer.present(drawable)
commandBuffer.commit()

present는 그림 그리기가 완료되면 GPU가 새로운 텍스처를 표시하도록 하는 데 필요하다. 그런 다음 transaction을 commit해서 task를 GPU로 보낸다.

 

 

Metal Tutorial: Getting Started

 

Metal Tutorial: Getting Started

In this Metal tutorial, you will learn how to get started with Apple’s 3D graphics API by rendering a simple triangle to the screen.

www.kodeco.com

'iOS > Metal' 카테고리의 다른 글

Metal Start  (0) 2024.02.05
    'iOS/Metal' 카테고리의 다른 글
    • Metal Start
    MINRYUL
    MINRYUL
    열심히 살자

    티스토리툴바