Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
6
Help us understand the problem. What is going on with this article?

More than 1 year has passed since last update.

@fuziki

Swift+MetalでEmitter

Swift+MetalでEmitter

Swift+Metalでエミッター(粒子放出器)のサンプルです。
某ガンダムのGNドライブ風です。
炎や煙も同じ仕組みで再現できます。
完成形↓
IMG_5738.PNG

表現するコツ

1.アルファブレンディングを有効にする。
2.depth stencilへの書き込みを禁止する。
3. Metalのpointを使って描画する。

コード

1. アルファブレンディング

半透明(透明)を有効にするにはアルファブレンディングを有効にします。
結果色 = sourceBlendFactor * 描画色 (BlendOperation) destinationAlphaBlendFactor * 元々の色
今回は単純な加算合成に設定します。

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

2.depth stencilへの書き込みを禁止する。

通常、depth stencilへ書き込みをします。
しかし、エフェクトを表示するときは書き込みを禁止した方が都合がいいです。
書き込みをした場合と、禁止した場合の結果は以下の通りです。
書き込みした場合↓
IMG_5738.PNG

書き込みを禁止した場合↓
IMG_5737.PNG

書き込みをした場合は、後ろのオブジェクトが表示されないため、透明色でも後ろにオブジェクトが描画されません。
しかし、depth stencilは深度情報に書き込まないため、遠いモノから描画する必要があります。

MetalEz.swift
        //depth stencilに書き込むとき
        let depthDescriptor = MTLDepthStencilDescriptor()
        depthDescriptor.depthCompareFunction = .less
        depthDescriptor.isDepthWriteEnabled = true
        depthStencilState = device.makeDepthStencilState(descriptor: depthDescriptor)

        //depth stencilに書き込まないとき
        let depthDescriptorForBlending = MTLDepthStencilDescriptor()
        depthDescriptorForBlending.depthCompareFunction = .less
        depthDescriptorForBlending.isDepthWriteEnabled = false
        depthStencilStateForBlending = device.makeDepthStencilState(descriptor: depthDescriptorForBlending)

3. Metalのpointを使って描画する。

OpenGLの場合は正方形を描画するために三角形が2枚必要でしたが、Metalはpointを使うことで、正方形が描画できるみたいです。
データ削減になっていいですね。

MetalEzRender.swift
    func draw(vaertex: MTLBuffer, frameUniformBuffer: MTLBuffer, texure: MTLTexture, count: Int) {
        mtlEz.mtlRenderCommandEncoder.setVertexBuffer(vaertex, offset: 0, index: 0)
        mtlEz.mtlRenderCommandEncoder.setVertexBuffer(frameUniformBuffer, offset: 0, index: 1)
        mtlEz.mtlRenderCommandEncoder.setFragmentTexture(texure, index: 0)
        mtlEz.mtlRenderCommandEncoder.drawPrimitives(type: .point, vertexStart: 0, vertexCount: count, instanceCount: 1)
    }
6
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
6
Help us understand the problem. What is going on with this article?