OpenGL/iOS_Metal

Add red triangle

dely 2018. 10. 13. 11:48

안녕하세요 dely입니다:)

 

저번 글에서 Metal로 노란색으로 배경 채우기에 이어 빨간색 삼각형을 추가해보겠습니다.

 

(참고영상: Working with Triangles in Metal)

 

오늘의 목표!!

 

 

이번에는 빨간색 삼각형을 추가로 그려주기 위해 vertex개념과 shader를 이용해보려 합니다.

 

1. 삼각형 vertex 추가 및 pipelineState와 vertexBuffer 프로퍼티 선언

 

그려줄 삼각형 위치를 vertices 배열로 지정해줍니다.

 

화면의 중점이 (0, 0)이고, 좌측하단이 (-1, -1), 우측상단이 (1, 1)입니다.

 

여기서 눈에 보이는 것은 2d지만 사실상 3d 형태이기 때문에 x, y, z 축을 입력합니다.

 

var vertices: [Float] = [

        0, 1, 0,

        -1, -1, 0,

        1, -1, 0

]

 

파이프라인과 vertex를 담을 프로퍼티를 선언합니다.

 

var pipelineState: MTLRenderPipelineState?

var vertexBuffer: MTLBuffer?

 

 

2. buildBuffer

 

Renderer.swift에 buildModel() method를 만듭니다.

 

여기서 vertices 배열을 담을 버퍼를 만들게 됩니다.

 

bytes에 vertex 배열을, length에 배열 x Float크기를 지정하여 만들게 됩니다.

 

private func buildModel() {

        vertexBuffer = device.makeBuffer(bytes: vertices, length: vertices.count * MemoryLayout<Float>.size, options: [])

}

 

 

3. Shader.metal

 

Shader를 이용하여 색깔을 칠할 위치(vertex_shader)와 어떤 색을 칠할지(fragment_shader)를 정하게 됩니다.

 

vertex float4 vertex_shader(const device packed_float3 *vertices [[buffer(0)]],

                            uint vertexId [[vertex_id]]) {

    return float4(vertices[vertixId], 1);

}

 

fragment half4 fragment_shader(){

    return half4(1, 0, 0, 1);

}

 

 

4. pipeline

 

Renderer.swift에서 buildPipelineState() method를 만듭니다.

 

여기서는 Shader.metal에서 만들어준 vertex_shader과 fragment_shader를 연결해줍니다.

 

    private func buildPipelineState(){

        let library = device.makeDefaultLibrary()

        let vertexFunction = library?.makeFunction(name: "vertex_shader")

        let fragmentFunction = library?.makeFunction(name: "fragment_shader")

        

        let pipelineDesciptor = MTLRenderPipelineDescriptor()

        pipelineDesciptor.vertexFunction = vertexFunction

        pipelineDesciptor.fragmentFunction = fragmentFunction

        pipelineDesciptor.colorAttachments[0].pixelFormat = .bgra8Unorm

        

        do {

            pipelineState = try device.makeRenderPipelineState(descriptor: pipelineDesciptor)

        } catch let error as NSError {

            print("error: \(error.localizedDescription)")

        }

    }

 

5. draw()

 

이제 위에서 만든 pipelineState를 가져와서 draw() method에서 인코딩합니다.

 

(굵은 글씨로 지정한 코드 추가)

 

func draw(in view: MTKView) {

guard let drawable = view.currentDrawable,

 

let pipelineState = pipelineState,

 

let descriptor = view.currentRenderPassDescriptor else {

 

return

 

   }

 

let commandBuffer = commandQueue.makeCommandBuffer()

 

        

 

let commandEncoder = commandBuffer?.makeRenderCommandEncoder(descriptor: descriptor)

 

        

 

commandEncoder?.setRenderPipelineState(pipelineState)

 

commandEncoder?.setVertexBuffer(vertexBuffer, offset: 0, index: 0)

 

commandEncoder?.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: vertices.count)

 

commandEncoder?.endEncoding()

 

commandBuffer?.present(drawable)

 

commandBuffer?.commit()

 

}

 

반응형