LoginSignup
4
2

More than 5 years have passed since last update.

SwiftでMetalを使用して色加算をしよう

Last updated at Posted at 2018-12-03

ブレンドモードで色加算を実現する覚書
「SwiftでMetalを使用してテクスチャを表示しよう」を参照
https://qiita.com/sanoh/items/98f52e3e71351bbcbc89

■Setp1:MetalRenderer.mを編集

色加算のブレンドモードを設定します。

MetalRenderer.swift
import MetalKit

let maxBuffersInFlight = 3

class MetalRenderer: NSObject, MTKViewDelegate {
    let _device: MTLDevice
    let _command_queue: MTLCommandQueue
    let _in_flight_semaphore = DispatchSemaphore(value: maxBuffersInFlight)

    let _buffer_position : MTLBuffer!
    let _render_pipeline_state: MTLRenderPipelineState

    let _color_image: MTLTexture
    init?(metalKitView: MTKView) {
        let vertices_array:[Float] =
            [
                +0.0, +1.0, 0.0, 0.0,
                -1.0, -1.0, 1.0, 0.0,
                +1.0, -1.0, 1.0, 1.0,
                ]
        _device = metalKitView.device!
        metalKitView.colorPixelFormat = MTLPixelFormat.bgra8Unorm
        _command_queue = _device.makeCommandQueue()!
        //  頂点情報の登録
        let size = vertices_array.count * MemoryLayout<Float>.size
        _buffer_position = _device.makeBuffer(bytes: vertices_array, length: size)
        //  シェーダーの登録
        guard let library = _device.makeDefaultLibrary() else { fatalError() }
        let descriptor = MTLRenderPipelineDescriptor()
        descriptor.vertexFunction=library.makeFunction(name: "myVertexShader")
        descriptor.fragmentFunction=library.makeFunction(name: "myFragmentShader")
        descriptor.colorAttachments[0].pixelFormat = metalKitView.colorPixelFormat
        //  ブレンドモードの設定(色加算)<新規>
        descriptor.colorAttachments[0].isBlendingEnabled = true
        descriptor.colorAttachments[0].rgbBlendOperation = .add
        descriptor.colorAttachments[0].alphaBlendOperation = .add
        descriptor.colorAttachments[0].sourceRGBBlendFactor = .one
        descriptor.colorAttachments[0].sourceAlphaBlendFactor = .one
        descriptor.colorAttachments[0].destinationRGBBlendFactor = .one
        descriptor.colorAttachments[0].destinationAlphaBlendFactor = .one

        _render_pipeline_state = try! _device.makeRenderPipelineState(descriptor: descriptor)
        //  テクスチャ読込+登録
        let textureLoader = MTKTextureLoader(device: _device)
        let textureLoaderOptions = [
            MTKTextureLoader.Option.textureUsage: NSNumber(value: MTLTextureUsage.shaderRead.rawValue),
            MTKTextureLoader.Option.textureStorageMode: NSNumber(value: MTLStorageMode.`private`.rawValue)
        ]
        _color_image    = try! textureLoader.newTexture(name: "colorImage",
                                                        scaleFactor: 1.0,
                                                        bundle: nil,
                                                        options: textureLoaderOptions)
        super.init()
    }

    func draw(in view: MTKView) {
        _ = _in_flight_semaphore.wait(timeout: DispatchTime.distantFuture)
        if let command_buffer = _command_queue.makeCommandBuffer() {
            let semaphore = _in_flight_semaphore
            command_buffer.addCompletedHandler { (_ command_buffer)-> Swift.Void in
                semaphore.signal()
            }
            let render_pass_descriptor = view.currentRenderPassDescriptor
            render_pass_descriptor?.colorAttachments[0].loadAction=MTLLoadAction.clear
            render_pass_descriptor?.colorAttachments[0].storeAction=MTLStoreAction.store
            render_pass_descriptor?.colorAttachments[0].clearColor=MTLClearColorMake(1.0, 0.0, 0.0, 1.0) // 背景色
            if let render_pass_descriptor = render_pass_descriptor {
                if let render_encoder = command_buffer.makeRenderCommandEncoder(descriptor: render_pass_descriptor) {
                    //  テクスチャの設定
                    render_encoder.setFragmentTexture(_color_image,
                                                      index: TextureIndex.color.rawValue)
                    //  モデルの設定
                    render_encoder.setRenderPipelineState(_render_pipeline_state)
                    render_encoder.setVertexBuffer(_buffer_position,
                                                   offset: 0,
                                                   index: 0)
                    render_encoder.drawPrimitives(type: MTLPrimitiveType.triangle,
                                                  vertexStart: 0,
                                                  vertexCount: 3)

                    render_encoder.endEncoding()
                    if let drawable = view.currentDrawable {
                        command_buffer.present(drawable)
                    }
                }
            }
            command_buffer.commit()
        }
    }

    func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
    }
}

■解説
なにも設定しないと、アルファは「false」の設定

        descriptor.colorAttachments[0].isBlendingEnabled = true
        descriptor.colorAttachments[0].rgbBlendOperation = .add
        descriptor.colorAttachments[0].alphaBlendOperation = .add
        descriptor.colorAttachments[0].sourceRGBBlendFactor = .one
        descriptor.colorAttachments[0].sourceAlphaBlendFactor = .one
        descriptor.colorAttachments[0].destinationRGBBlendFactor = .one
        descriptor.colorAttachments[0].destinationAlphaBlendFactor = .one

■Step2:実行

iOsは実機で実行してくださいMacの場合は以下のようになります。
もとはこれが
スクリーンショット 2018-11-30 12.30.01.png

こうなります
スクリーンショット 2018-12-03 18.28.37.png

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2