Apple Engine

Apple, iPhone, iOS, その周辺のことについて

iOS で SceneKit を試す(Swift 3) その75 - SceneKit Particle System File と パーティクルシステム の emitterShape

SceneKit Particle System File (scnp) は Particle System 専用のファイル。
Scene Editor 上で、Particle System の確認ができる。

scnp ファイルは Particle System のファイルではあるが、scn では参照ができないため、コード場で行う。

 

scnp ファイルを Scene Editor で見た場合

パーティクルシステムの情報しかないので、Scene Graph View は存在せず、Inspector のも少なくなっている。

Scene Editor の下の部分は scn ファイルと異なっている。

f:id:x67x6fx74x6f:20170822155920p:plain

 

ファイルの作成

Xcode のメニューバー、File > New > File… か、Command + N から「SceneKit Particle System File」を選ぶ。

f:id:x67x6fx74x6f:20170822154139p:plain

 

テンプレートの選択が出るので必要なものを選択すると、scnp ファイルと使用する画像ファイルができあがる。

f:id:x67x6fx74x6f:20170822154154p:plain

 

テンプレートの種類

以下のテンプレートが用意されている。

  • Bokeh
  • Confetti
  • Rain
  • Reactor
  • Smoke
  • Stars

 

Bokeh

円状のパーティクルの輪郭がボケながら消えてゆくテンプレート。

Attributes Inspector (Command + Option + 4) の Image の Color を変更すると色が変わる。

bokeh.png は 4x4 のアニメーションを並べたテクスチャで、例えば Initial frame の 0 にするとアニメーションが行われないため、ボケは行われず透過で消える。

f:id:x67x6fx74x6f:20170822155207p:plain

 

Confetti

紙吹雪の動きを模したテンプレート。

テンプレートのままだと Scene Editor で表示されないため、 コード上で設定を行う。

 

Fire

炎を模したテンプレート

f:id:x67x6fx74x6f:20170822155229p:plain

 

Rain

雨粒が下に落ちる雨を模したテンプレート。

重力の物理アニメーションで落としているの PhysicsWorld の重力値を変更する場合は注意。

f:id:x67x6fx74x6f:20170822155246p:plain

 

Reactor

バーナーのような炎を模したテンプレート

f:id:x67x6fx74x6f:20170822155308p:plain

 

Smoke

煙を模したアニメーション。

f:id:x67x6fx74x6f:20170822155319p:plain

 

Stars

小さな星が奥から手前に移動し、宇宙空間を慰労しているかのように見せるテンプレート。

薄い黄色から薄い青にアニメーションさせているため、 Scene Editor で若干ズームアウトすると見た目が変わる。

f:id:x67x6fx74x6f:20170822155341p:plain

 

 

任意の Shape にパーティクルを適応してみる。

普通にシーンにパーティクルを適応しても scn のパーティクルシステムとかわらないので emitterShape を使用してみる。

ひとまず、Xcode で SceneKit の Game テンプレート作成。

 

SCNP の作成

Command + N から「SceneKit Particle System File」を選美、Fire テンプレートを選択。
ここでは、ファイル名を Fire.scnp にしてプロジェクトに追加する。

 

GameViewController.swift の設定

GameViewController.swift を開く。

ship.scn を使用しないので、19行目を以下に変更。

let scene = SCNScene()

 

ship.scn を使用しなくなり、宇宙船のアニメーションはいらないので、 44、47行目を削除

let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!
ship.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)))

   

パーティクルの設定

GameViewController.swift の viewDidLoad() でビルトインジオメトリ SCNText でシェイプを作成。
そのシェイプからエミッターとしてパーティクルを吐き出す。

// シェイプ
let textShape = SCNText(string: "つぶ", extrusionDepth: 1)
textShape.flatness = 0.0

// パーティクルシステム
let particle = SCNParticleSystem(named: "Fire.scnp", inDirectory: "")
particle?.emitterShape = textShape
let particleShapePosition = particle?.emitterShape?.boundingSphere.center

// ノードにパーティクルシステムをピボット変更後して紐付ける
let particleNode = SCNNode()
particleNode.pivot = SCNMatrix4MakeTranslation(particleShapePosition!.x, particleShapePosition!.y, 0)
particleNode.addParticleSystem(particle!)

scene.rootNode.addChildNode(particleNode)

 

そのままでは大きいので、27行目の カメラの Z軸を 50 に変更

cameraNode.position = SCNVector3(x: 0, y: 0, z: 50)

 

ビルドすると以下のような感じになる

f:id:x67x6fx74x6f:20170822154217g:plain

 

GameViewController.swift のコード

import UIKit
import QuartzCore
import SceneKit

class GameViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let scene = SCNScene()
        
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 50)
        scene.rootNode.addChildNode(cameraNode)
        
        let lightNode = SCNNode()
        lightNode.light = SCNLight()
        lightNode.light!.type = .omni
        lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
        scene.rootNode.addChildNode(lightNode)
        
        let ambientLightNode = SCNNode()
        ambientLightNode.light = SCNLight()
        ambientLightNode.light!.type = .ambient
        ambientLightNode.light!.color = UIColor.darkGray
        scene.rootNode.addChildNode(ambientLightNode)
        
        let scnView = self.view as! SCNView
        scnView.scene = scene
        scnView.allowsCameraControl = true
        scnView.showsStatistics = true
        scnView.backgroundColor = UIColor.black
        
        // シェイプ
        let textShape = SCNText(string: "つぶ", extrusionDepth: 1)
        textShape.flatness = 0.0
        
        // パーティクルシステム
        let particle = SCNParticleSystem(named: "Fire.scnp", inDirectory: "")
        particle?.emitterShape = textShape
        let particleShapePosition = particle?.emitterShape?.boundingSphere.center
        
        // ノードにパーティクルシステムをピボット変更後して紐付ける
        let particleNode = SCNNode()
        particleNode.pivot = SCNMatrix4MakeTranslation(particleShapePosition!.x, particleShapePosition!.y, 0)
        particleNode.addParticleSystem(particle!)
        
        scene.rootNode.addChildNode(particleNode)
    }
    
    override var shouldAutorotate: Bool {
        return true
    }
    
    override var prefersStatusBarHidden: Bool {
        return true
    }
    
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if UIDevice.current.userInterfaceIdiom == .phone {
            return .allButUpsideDown
        } else {
            return .all
        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

 

今回はここまで。