美文网首页
OpenGL笔记十六:CAEmitterLayer粒子效果

OpenGL笔记十六:CAEmitterLayer粒子效果

作者: 御雪飞斐 | 来源:发表于2019-06-24 17:12 被阅读0次

    前言

    期待您移步上篇:OpenGL笔记十五:GLSL光照计算

    简述

    核心动画Core Animation 中的粒子效果所用到的特殊图层就是CAEmitterLayer。
    CAEmitterLayer是CALayer的一个常用子类,CALayer的子类有很多,CAEmitterLayer就是其中之一,CAEmitterLayer是用于实现基于Core Animation的高性能粒子引擎系统。
    粒子系统使用到两个类CAEmitterLayer与CAEmitterCell,CAEmitterLayer是粒子发射源,用来发射粒子的,它所发射的粒子就是CAEmitterCell(当然粒子也可以发射粒子,也就是CAEmitterCell也可以发射CAEmitterCell)。可以认为CAEmitterLayer是CAEmitterCell的发射源,通过不同的参数设置就会不断的产生不同的粒子。


    CALayer.png

    CAEmitterLayer属性

    @property(nullable, copy) NSArray<CAEmitterCell *> *emitterCells; // 用来装粒子种类的数组, 通过给数组赋值,来支持多个cell
    @property float birthRate; //粒子产生系数(倍数),默认1.0
    @property float lifetime; // 粒子的生命周期系数, 默认1.0
    @property CGPoint emitterPosition; // 决定粒子发射位置的中心点
    @property CGFloat emitterZPosition; //立体中 Z轴 位置
    @property CGSize emitterSize; // 发射源的尺寸大小
    @property CGFloat emitterDepth; // 立体中 发射源的深度
    @property(copy) NSString *emitterShape; // 发射源的形状,默认是点point,(还有line,rectangle,circle,cuboid,sphere).
    @property(copy) NSString *emitterMode; // 发射模式,默认是volume,(还有points,outline,surface).
    @property(copy) NSString *renderMode; // 渲染模式,默认是unordered,还有oldestFirst,oldestLast,backToFront,additive
    @property BOOL preservesDepth; //是否需要深度
    @property float velocity; // 粒子基本速度系数, 默认1.0
    @property float scale; // 粒子缩放比例系数, 默认1.0
    @property float spin; // 粒子自旋转速度系数, 默认1.0
    @property unsigned int seed; // 随机数发生器
    
    • 常用属性
    • emitterPosition :发射源的中心点
    • emitterSize:发射源的尺寸大小
    • emitterShape:发射源的形状
    • kCAEmitterLayerPoint 点形状,发射源的形状就是一个点
    • kCAEmitterLayerLine 线形状,发射源的形状是一条线
    • kCAEmitterLayerRectangle 矩形状,发射源的形状是一个矩形
    • kCAEmitterLayerCuboid 立体矩形形状(3D),发射源是一个立体矩形,这里要生效的话需要设置z方向的数据,如果不设置就同矩形状
    • kCAEmitterLayerCircle 圆形形状,发射源是一个圆形
    • kCAEmitterLayerSphere 立体圆形(3D),三维的圆形,同样需要设置z方向数据,不设置则如同二维的圆
    • emitterMode:发射粒子的模式
    • kCAEmitterLayerPoints 点模式,发射器以点模式发射粒子。发射点就是发射形状的某个特殊的点,如shap是kCAEmitterLayerPoint,发射点就是中心点,如是kCAEmitterLayerLine,发射点就是线的中心点,如是kCAEmitterLayerRectangle,那发射点就是四个顶点,如是kCAEmitterLayerCircle,那发射点就是圆心
    • kCAEmitterLayerOutline 轮廓模式,从形状的边界上发射粒子
    • kCAEmitterLayerSurface 表面模式,从形状的表面上发射粒子
    • kCAEmitterLayerVolume 是相对于3D形状的物体内部发射
    • renderMode:渲染模式

    粒子是以怎么一种形式进行渲染的:

    • kCAEmitterLayerUnordered 粒子是无序出现的
    • kCAEmitterLayerOldestFirst 声明时间长的粒子会被渲染在最上层
    • kCAEmitterLayerOldestLast 声明时间短的粒子会被渲染在最上层
    • kCAEmitterLayerBackToFront 粒子的渲染按照Z轴的前后顺序进行
    • kCAEmitterLayerAdditive 进行粒子混合

    CAEmitterCell属性

    @property(nullable, copy) NSString *name; // 粒子名字, 默认为nil,有了名字才能找到对应的粒子
    @property(getter=isEnabled) BOOL enabled; 
    @property float birthRate; // 粒子的产生率,默认0
    @property float lifetime; // 粒子的生命周期,默认0,以秒为单位。
    @property float lifetimeRange; // 粒子的生命周期的范围,默认0,以秒为单位。
    @property CGFloat emissionLatitude;// 指定纬度,纬度角代表了在x-z轴平面坐标系中与x轴与z轴之间的夹角,默认0
    @property CGFloat emissionLongitude; // 指定经度,经度角代表了在x-y轴平面坐标系中与x轴与y轴之间的夹角,默认0
    @property CGFloat emissionRange; //发射角度范围,默认0
    @property CGFloat velocity; // 速度,默认是0
    @property CGFloat velocityRange; //速度范围,默认是0
    @property CGFloat xAcceleration; // 在x方向上的重力加速度分量,默认是0
    @property CGFloat yAcceleration;// 在y方向上的重力加速度分量,默认是0
    @property CGFloat zAcceleration;// 在z方向上的重力加速度分量,默认是0
    @property CGFloat scale; // 粒子在生命周期范围内的缩放比例, 默认是1
    @property CGFloat scaleRange; // 缩放比例范围,默认是0
    @property CGFloat scaleSpeed; // 在生命周期内的缩放速度,默认是0,负数缩小,正数放大;
    @property CGFloat spin; // 粒子的平均旋转速度,默认是0
    @property CGFloat spinRange; // 自旋转角度范围,弧度制,默认是0
    @property(nullable) CGColorRef color; // 粒子的颜色,默认白色
    @property float redRange; // 粒子的颜色red,green,blue,alpha能改变的范围,默认0
    @property float greenRange;
    @property float blueRange;
    @property float alphaRange;
    @property float redSpeed; // 粒子速度red,green,blue,alpha在生命周期内的改变的速度,默认都是0
    @property float greenSpeed;
    @property float blueSpeed;
    @property float alphaSpeed;
    @property(nullable, strong) id contents; // 粒子的内容,设置为CGImageRef的对象
    @property CGRect contentsRect;//粒子内容的位置
    @property CGFloat contentsScale; //粒子内容的缩放比例
    @property(copy) NSString *minificationFilter;//缩小的过滤器(基本不用)
    @property(copy) NSString *magnificationFilter;//放大的过滤器(基本不用)
    @property float minificationFilterBias;
    @property(nullable, copy) NSArray<CAEmitterCell *> *emitterCells; // 粒子里面的粒子
    @property(nullable, copy) NSDictionary *style;
    
    • 粒子生命周期属性
    • lifetime:粒子在系统上的生命周期,即存活时间,单位是秒
    • lifetimeRange:让粒子生命周期均匀变化,以便可以让粒子的出现和消失显得更加离散
    • birthRate:粒子产生数量的决定参数,它表示CAEmitterLayer上每秒产生的粒子数量,是浮点数。对于这个数量为浮点数,在测试的时候可以灵活使用它。比如你想看粒子的运动状态,但是太多了可能会很迷糊,这时候你把birthRate 设置成0.1f,把lifetime设置时间较长,就能看到单个粒子的运动状态
    • 粒子内容属性
    • contents:为CGImageRef的对象。关于contents会联想到CALayer了,在CALayer中展示静态的图片是需要用到这个属性。在CAEmitterCell上它的意义也是一样的。但是因为粒子系统可以给粒子上色,为了做出好的颜色变换效果,通常提供的图片为白色的纯色的图片
    • name:粒子的名字,当CAEmitterLayer里面有很多个cell的时候,可以给每个cell设置好名字,要修改一些属性以达到动画效果的改变等,就可以通过KVC拿到这个cell的某个属性
    • 粒子颜色状态属性
    • color:是粒子的颜色属性,这个属性的作用是给粒子上色,color 会结合contents内容来改变我们的CAEmitterCell,它的实现原理很简单,就是将contents自身的颜色的RGBA值 * color的RGBA值,得到最终的粒子颜色。如果想完全通过color属性来控制CAEmitterCell 粒子的颜色,那就选用一张(255.0,255.0,255.0)的白色图片作为CAEmitterCell 的contents,就可以了。
    • redRange、greenRange、blueRange、alphaRange:这些是对应的color的RGBA的取值范围,默认为0,取值范围为0~1。
      假如:colorBallCell.color = [[UIColor colorWithRed:0.5 green:0.f blue:0.5 alpha:0.4.f] CGColor];
      colorBallCell.redRange = 0.8f;
      colorBallCell.greenRange = 0.1f;
      colorBallCell.alphaRange = 1.0f;
      则在产生粒子时,粒子的颜色对。应的取值范围是:R(0.5, 0.8),G(0.1, 0.5),B(0.0, 0.5),A(0.4, 1.0)。
    • redSpeed、greenSpeed、blueSpeed、alphaSpeed:这些是对应的是粒子的RGBA的变化速度,默认为0,取值范围为0~1。粒子颜色R,G,B,A在生命周期内,在上面的取值范围内,每秒钟改变速度(此值*255)。
    • 运行轨迹属性
    • emissionLongitude:表示粒子飞行方向跟水平坐标轴(x轴)之间的夹角,默认是0,顺时针方向是正向。默认为0,为弧度值,粒子顺着x轴飞行。
    • emissionLatitude:表示粒子飞行方向,在x-z轴平面坐标系中与x轴之间的夹角,默认是0,为弧度值。
    • emissionRange:粒子的发射角度范围,为弧度值。以粒子飞行的经纬度,为顶点的扇形范围。
    • velocity、velocityRange:粒子的初速度和初速度的范围。
    • xAcceleration 、yAcceleration、zAcceleration:分别是在x、y、z轴方向的加速度。
    • spin、spinRange:粒子的自转属性,表示每秒钟粒子自转的弧度数。粒子的自转是以弧度制来计算的,表示每秒钟粒子自转的弧度数。spin为正数代表粒子是顺时针旋转的,为负数的话就是逆时针旋转。spinRange为自转弧度数的范围。

    CAEmitterCell子粒子的属性

    emitterCells:CAEmitterCell的emitterCells跟CAEmitterLayer的一样,也是一个CAEmitterCell的数组。我们基本可以按照操作CAEmitterLayer的emitterCells一样来设置我们粒子的emitterCells。

    • CAEmitterCell是服从CAMediatiming协议的,我们通过控制子CAEmitterCell的beginTime来控制子CAEmitterCell的出现时机。当子CAEmitterCell的beginTime为0时,表示你的粒子从CAEmitterLayer上发射出来后就会立即开始发射子CAEmitterCell,而且子CAEmitterCell的beginTime是不能大于你的粒子的lifetime的。
    • 无论粒子是从什么样的形状上发射出来的,当它要发射子CAEmitterCell的时候,子CAEmitterCell总是从kCAEmitterLayerPoint形状上由父粒子的中心发射出来的。

    案例

    • 主代码
    @interface ViewController ()
    @property (nonatomic, strong) CAEmitterLayer * colorBallLayer;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        self.view.backgroundColor = [UIColor blackColor];
        [self setupEmitter];
        
    }
    - (void)setupEmitter{
        
        UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake(0, 100, self.view.bounds.size.width, 50)];
        [self.view addSubview:label];
        label.textColor = [UIColor whiteColor];
        label.text = @"轻点或拖动来改变发射源位置";
        label.textAlignment = NSTextAlignmentCenter;
        
        // 1. 设置CAEmitterLayer
        CAEmitterLayer * colorBallLayer = [CAEmitterLayer layer];
        [self.view.layer addSublayer:colorBallLayer];
        self.colorBallLayer = colorBallLayer;
        
        //发射源的尺寸大小
        colorBallLayer.emitterSize = CGSizeMake(self.view.frame.size.width * 0.5, self.view.frame.size.height * 0.5);
        //发射源的形状
        colorBallLayer.emitterShape = kCAEmitterLayerRectangle;
        //发射模式
        colorBallLayer.emitterMode = kCAEmitterLayerPoints;
        //粒子发射形状的中心点
        colorBallLayer.emitterPosition = CGPointMake(self.view.layer.bounds.size.width * 0.5, self.view.frame.size.height * 0.5);
        
        // 2. 配置CAEmitterCell
        CAEmitterCell * colorBallCell = [CAEmitterCell emitterCell];
        //粒子名称
        colorBallCell.name = @"colorBallCell";
        //粒子产生率,默认为0
        colorBallCell.birthRate = 20.f;
        //粒子生命周期
        colorBallCell.lifetime = 10.f;
        //粒子速度,默认为0
        colorBallCell.velocity = 0.f;
        //粒子速度平均量
        colorBallCell.velocityRange = 00.f;
        //x,y,z方向上的加速度分量,三者默认都是0
        colorBallCell.yAcceleration = 15.f;
        //指定纬度,纬度角代表了在x-z轴平面坐标系中与x轴之间的夹角,默认0:
        colorBallCell.emissionLongitude = M_PI_4; // 向左
        //发射角度范围,默认0,以锥形分布开的发射角度。角度用弧度制。粒子均匀分布在这个锥形范围内;
        colorBallCell.emissionRange = M_PI_4; // 围绕X轴向左90度
        // 缩放比例, 默认是1
        colorBallCell.scale = 0.2;
        // 缩放比例范围,默认是0
        colorBallCell.scaleRange = 0.1;
        // 在生命周期内的缩放速度,默认是0
        colorBallCell.scaleSpeed = 0.02;
        // 粒子的内容,为CGImageRef的对象
        colorBallCell.contents = (id)[[UIImage imageNamed:@"circle_white"] CGImage];
        //颜色
        colorBallCell.color = [[UIColor colorWithRed:0.5 green:0.f blue:0.5 alpha:1.f] CGColor];
        // 粒子颜色red,green,blue,alpha能改变的范围,默认0
        colorBallCell.redRange = 1.f;
        colorBallCell.greenRange = 1.f;
        colorBallCell.alphaRange = 0.8;
        // 粒子颜色red,green,blue,alpha在生命周期内的改变速度,默认都是0
        colorBallCell.blueSpeed = 1.f;
        colorBallCell.alphaSpeed = -0.1f;
        
        // 添加
        colorBallLayer.emitterCells = @[colorBallCell];
    }
    
    • 手指触摸事件
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        CGPoint point = [self locationFromTouchEvent:event];
        [self setBallInPsition:point];
    }
    
    - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        CGPoint point = [self locationFromTouchEvent:event];
        [self setBallInPsition:point];
    }
    
    /**
     * 获取手指所在点
     */
    - (CGPoint)locationFromTouchEvent:(UIEvent *)event{
        UITouch * touch = [[event allTouches] anyObject];
        return [touch locationInView:self.view];
    }
    
    • 移动动画发射源
    - (void)setBallInPsition:(CGPoint)position{
        
        //创建基础动画
        CABasicAnimation * anim = [CABasicAnimation animationWithKeyPath:@"emitterCells.colorBallCell.scale"];
        //fromValue
        anim.fromValue = @0.2f;
        //toValue
        anim.toValue = @0.5f;
        //duration
        anim.duration = 1.f;
        //线性起搏,使动画在其持续时间内均匀地发生
        anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
        
        // 用事务包装隐式动画
        [CATransaction begin];
        //设置是否禁止由于该事务组内的属性更改而触发的操作。
        [CATransaction setDisableActions:YES];
        //为colorBallLayer 添加动画
        [self.colorBallLayer addAnimation:anim forKey:nil];
        //为colorBallLayer 指定位置添加动画效果
        [self.colorBallLayer setValue:[NSValue valueWithCGPoint:position] forKeyPath:@"emitterPosition"];
        //提交动画
        [CATransaction commit];
    }
    

    相关文章

      网友评论

          本文标题:OpenGL笔记十六:CAEmitterLayer粒子效果

          本文链接:https://www.haomeiwen.com/subject/imvwqctx.html