使用ARKit+CAEmitterLayer粒子发射器放个烟花

7,196 阅读3分钟

PK创意闹新春,我正在参加「春节创意投稿大赛」,详情请看:春节创意投稿大赛

前言

马上就要过年了,在这里提前祝大家新年快乐。还记得小时候放鞭炮、放烟花的快乐时光吗,在大城市里面不让放烟花,就算在农村,有的地方也不让放了。现在我们就使用ARKit+CAEmitterLayer粒子发射器给大家放个烟花吧。

fire.gif

下面我们就来实现这个效果:

1、创建AR项目

1.1、 打开XCode,新建项目,选择Augmented Reality App

截屏2022-01-07 10.40.58.png

1.2、设置项目名称,bundle id,选择渲染引擎SceneKit,语言使用Swift

截屏2022-01-07 10.41.28.png

创建完成之后,你会发现系统自动创建了一个飞机的场景

class ViewController: UIViewController, ARSCNViewDelegate {

    @IBOutlet var sceneView: ARSCNView!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Set the view's delegate
        sceneView.delegate = self
        
        // Show statistics such as fps and timing information
        sceneView.showsStatistics = true
        
        // Create a new scene
        let scene = SCNScene(named: "art.scnassets/ship.scn")!
        
        // Set the scene to the view
        sceneView.scene = scene
    }
    
    // 其他代码省略...
}

1.3、将飞机的场景删除,然后创建一个平面几何形状SCNPlane

override func viewDidLoad() {
    super.viewDidLoad()

    // Set the view's delegate
    sceneView.delegate = self

    // 创建一个平面几何形状SCNPlane 宽为0.5米,高为1米
    let plane = SCNPlane(width: 0.5, height: 1)
    // 基于几何图形创建节点,节点的创建不仅仅可以基于平面,长方体、圆球、圆锥、圆环、金字塔形 等等都可以创建
    let node = SCNNode(geometry: plane)
    node.position = SCNVector3Make(0, 0.1, -1)
    // 添加节点
    sceneView.scene.rootNode.addChildNode(node)
}

这样一个平面场景就创建好了,下面看看效果:

RPReplay_Final1641540665.GIF

2、CAEmitterLayer粒子发射器实现烟花

实现烟花效果,我们需要使用CAEmitterLayer结合CAEmitterCell。烟花需要三个cell,一个提供发射的,一个用于爆炸的,一个用于爆炸后飞溅的火花

下面是代码:

extension ViewController {

    // 烟花View
    private func createFireWorksView() -> UIView {
    
        let fireworksBgView = UIView()
        fireworksBgView.isOpaque = false
        fireworksBgView.frame = CGRect(x: 0, y: 0, width: 500, height: 1000)
        let viewSize = fireworksBgView.bounds.size
        
        // 设置CAEmitterLayer
        let fireworksEmitter = CAEmitterLayer()
        fireworksEmitter.preservesDepth = true
        // 1、设置发射的位置
        fireworksEmitter.emitterPosition = CGPoint(x: viewSize.width/2, y: viewSize.height)
        // 发射源的size 决定了发射源的大小
        fireworksEmitter.emitterSize = CGSize(width: viewSize.width/2, height: 0)
        // 发射模式
        fireworksEmitter.emitterMode = .outline
        // 发射形状
        fireworksEmitter.emitterShape = .line
        // 渲染模式
        fireworksEmitter.renderMode = .additive
        // 用于初始化随机函数的种子
        fireworksEmitter.seed = arc4random()%100 + 1
        // 每秒产生的粒子数量的系数
        fireworksEmitter.birthRate = 1
        
        // 2、发射
        let rocket = CAEmitterCell()
        // 粒子参数的速度乘数因子
        rocket.birthRate = 1
        // 发射角度
        rocket.emissionRange = 0
        // 速度
        rocket.velocity = 500
        // 速度范围
        rocket.velocityRange = 100
        // y方向的加速度分量
        rocket.yAcceleration = 70
        rocket.lifetime = 1.02
        // 粒子要展示的图片
        rocket.contents = UIImage(named: "01")?.cgImage
        // 缩放比例
        rocket.scale = 1
        // 粒子颜色
        rocket.color = UIColor.red.cgColor
        rocket.greenRange = 1
        rocket.redRange = 1
        rocket.blueRange = 1
        // 粒子旋转角度范围
        rocket.spinRange = 0

        // 3、爆炸
        let burst = CAEmitterCell()
        // 粒子参数的速度乘数因子
        burst.birthRate = 1.0
        // 速度
        burst.velocity = 10
        burst.scale = 1
        burst.redSpeed = -1.5
        burst.blueSpeed = 1.5
        burst.greenSpeed = 1.0
        burst.lifetime = 0.1

        // 4、爆炸后飞溅的火花
        let spark = CAEmitterCell()
        spark.birthRate = 400
        spark.velocity = 300
        spark.emissionRange = 2 * CGFloat.pi
        spark.yAcceleration = 200
        // 生命周期范围
        spark.lifetime = 1.5
        // 粒子内容
        spark.contents = UIImage(named: "01")?.cgImage
        spark.scaleSpeed = -0.4
        spark.greenSpeed = -0.1
        spark.redSpeed = 0.4
        spark.blueSpeed = -0.1
        spark.alphaSpeed = -0.25
        spark.spin = 2 * CGFloat.pi
        spark.spinRange = 2 * CGFloat.pi

        // 粒子添加到CAEmitterLayer上
        fireworksEmitter.emitterCells = [rocket]
        rocket.emitterCells = [burst]
        burst.emitterCells = [spark]
        fireworksBgView.layer.addSublayer(fireworksEmitter)
        return fireworksBgView
    }
}

3、创建SCNMaterial渲染器,将烟花View添加到里面

以下代码都是在 1.3 步里面

3.1、创建渲染器

// 创建渲染器
let material = SCNMaterial()
// 将`烟花View`设置给contents,这个 contents 属性可以设置很多东西,UILabel,UIImage,甚至 AVPlayer 都可以
material.diffuse.contents = createFireWorksView()

3.2、用渲染器对几何图形进行渲染

// 用渲染器对几何图形进行渲染
node.geometry?.materials = [material]

到此整个功能就结束了,demo地址

参考:
CAEmitterLayer粒子发射器的神奇效果