반응형
이 글에서는 Metal에서 이미지를 MTKView에 올리는 방법에 대해 알아보겠습니다.
1. 이미지 로드하기
Metal에서 이미지를 사용하기 위해서는 이미지를 로드해야 합니다.
guard let image = UIImage(named: "{이미지 파일 이름}") else {
fatalError("이미지를 로드하는 데 실패했습니다.")
}
2. Texture 생성하기
이미지를 로드했다면, 이제 해당 이미지를 Metal에서 사용할 수 있는 Texture로 변환해야 합니다.
guard let texture = try? MTLTextureLoader(device: device).newTexture(cgImage: image.cgImage!, options: nil) else {
fatalError("Texture를 생성하는 데 실패했습니다.")
}
3. Pipeline 생성하기
Pipeline은 GPU에서 동작하는 코드를 구성하는데 필요한 정보를 담고 있는 객체입니다. 이번 예제에서는 Vertex와 Fragment Shader를 작성하여 Pipeline을 생성합니다.
3-1. Vertex Shader 작성하기
Vertex Shader는 입력 데이터를 변환하는 역할을 합니다. 이번 예제에서는 2D 이미지를 출력하기 때문에, 2D 좌표값을 입력으로 받아 3D 좌표값으로 변환하는 작업을 수행하도록 작성합니다.
#include <metal_stdlib>
using namespace metal;
struct VertexIn {
float2 position;
};
struct VertexOut {
float4 position [[position]];
float2 textureCoordinate;
};
vertex VertexOut vertexShader(VertexIn vertexIn [[stage_in]]) {
VertexOut vertexOut;
vertexOut.position = float4(vertexIn.position, 0.0, 1.0);
vertexOut.textureCoordinate = float2((vertexIn.position.x + 1.0) / 2.0, (1.0 - vertexIn.position.y) / 2.0);
return vertexOut;
}
3-2. Fragment Shader 작성하기
Fragment Shader는 Vertex Shader에서 출력된 값을 이용하여 색상 정보를 생성합니다. 이번 예제에서는 Texture를 이용하여 색상 정보를 생성하도록 작성합니다.
#include <metal_stdlib>
using namespace metal;
struct FragmentIn {
float2 textureCoordinate;
};
fragment half4 fragmentShader(FragmentIn fragmentIn [[stage_in]],
texture2d<half> texture [[texture(0)]]) {
constexpr sampler textureSampler(mag_filter::linear, min_filter::linear);
return half4(texture.sample(textureSampler, fragmentIn.textureCoordinate).rgb, 1.0);
}
3-3. Pipeline 생성하기
Vertex Shader와 Fragment Shader를 이용하여 Pipeline을 생성합니다.
let library = try! device.makeLibrary(source: "{위에서 작성한 MSL 코드}", options: nil)
let vertexFunction = library.makeFunction(name: "vertexShader")
let fragmentFunction = library.makeFunction(name: "fragmentShader")
let pipelineDescriptor = MTLRenderPipelineDescriptor()
pipelineDescriptor.vertexFunction = vertexFunction
pipelineDescriptor.fragmentFunction = fragmentFunction
pipelineDescriptor.colorAttachments[0].pixelFormat = mtkView.colorPixelFormat
let pipelineState = try! device.makeRenderPipelineState(descriptor: pipelineDescriptor)
4. MTKView에 Texture 출력하기
Texture를 생성하고, Pipeline을 생성했다면, 이제 해당 Texture를 MTKView에 출력할 수 있습니다.
mtkView.drawableSize = view.bounds.size
guard let commandBuffer = commandQueue.makeCommandBuffer(),
let drawable = mtkView.currentDrawable else {
fatalError("MTKView 설정에 실패했습니다.")
}
let renderPassDescriptor = mtkView.currentRenderPassDescriptor
renderPassDescriptor?.colorAttachments[0].texture = drawable.texture
let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor!)
renderEncoder.setRenderPipelineState(pipelineState)
renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
renderEncoder.setFragmentTexture(texture, index: 0)
renderEncoder.drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: 4)
renderEncoder.endEncoding()
commandBuffer.present(drawable)
commandBuffer.commit()
위 코드에서 renderEncoder.drawPrimitives() 메소드에서는 출력할 도형의 형태를 지정합니다. 위 코드에서는 삼각형 스트립을 출력하는 예제입니다.
이제 위 코드를 사용하여 Metal에서 이미지를 MTKView에 출력할 수 있습니다.
반응형
'iOS > 라이브러리' 카테고리의 다른 글
[Library, Metal] shader 사용방법 (0) | 2023.02.06 |
---|---|
[Library, Metal] vertex를 index로 메모리 절약하기 (0) | 2023.02.03 |
[Library, Metal] 삼각형 그리기 (pipeline) (0) | 2023.02.03 |
[Library, Metal] MetalView 그리기 (0) | 2023.02.03 |