欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OpenGL ES ---粒子效果的制作

程序员文章站 2022-05-29 07:52:25
...

一、简单介绍

在这里简单的介绍下学到的粒子效果的制作的核心概念,下载地址:案例地址  其实这边主要就是利用了一个纹理粒子,然后我们通过设置它的x,y,z轴的速度,然后做出不一样的效果。然后在着色器程序中针对每个点进行处理,根据受力,位移这些进行处理,这里就简单的介绍下顶点着色器的内容,和实现四种效果所用的block。

先看下效果

OpenGL ES ---粒子效果的制作

OpenGL ES ---粒子效果的制作

OpenGL ES ---粒子效果的制作

OpenGL ES ---粒子效果的制作

二、代码实战

第一种效果

void(^blockA)() = ^{
        
        //设置开始的时间
        self.autoSpawnDelta=0.5f;
        
        //设置重力
        self.particleEffect.gravity = CCDefaultGravity;
        
        //设置X轴上的随机速度,RAND_MAX是0x7fffffff (2147483647)
        
        //-0.5f的意思就是说让物体既可以往左边弹,也可以往右边弹
        float randomXVelocity = -0.5f+1.0f*(float)random()/(float)RAND_MAX;
        
        /*
         Position:出发位置
         velocity:速度
         force:抛物线
         size:大小
         lifeSpanSeconds:耗时
         fadeDurationSeconds:渐逝时间
         */
        //添加粒子
        [self.particleEffect addParticleAtPosition:GLKVector3Make(0.0f, 0.0f, 0.9f) velocity:GLKVector3Make
(randomXVelocity, 1.0f, -1.0f) force:GLKVector3Make(0.0f, 9.0f, 0.0f) size:8.0f lifeSpanSeconds:3.2f fadeDurationSeconds:0.5f];
        
    };

第二种效果

void(^blockB)() = ^{
        
        //设置开始时间
        self.autoSpawnDelta=0.05f;
        
        //设置重力
        self.particleEffect.gravity = GLKVector3Make(0.0f, 0.5f, 0.0f);
        
        //设置一次性创建多少个粒子
        int n=50;
        
        for(int i=0;i<n;i++)
        {
            //X轴的速度
            float randomXVelocity = -0.1f+0.2f*(float)random()/(float)RAND_MAX;
            
            //Z轴速度
            float randomZVelocity = 0.1f +0.2f * (float)random()/(float)RAND_MAX;
            //位置在(0.0f,-0.5f,0.0f) 有x轴方向和Z方向的速度
           [self.particleEffect addParticleAtPosition:GLKVector3Make(0.0f, -0.5f, 0.0f) velocity:GLKVector3Make
            (randomXVelocity, 0.0, randomZVelocity) force:GLKVector3Make(0.0f, 0.0f, 0.0f) size:16.0f lifeSpanSeconds:2.2f
            fadeDurationSeconds:3.0f];
            
            
        }
    };

如果我们把速度仅仅设置为X轴和Y轴,而不是X轴和Z轴的话是这样的效果,也就是例子完全是往上的也就是说如果说我们把速度设置为这样的话,就是下面的效果

velocity:GLKVector3Make(randomXVelocity,randomZVelocity ,0.0f )

OpenGL ES ---粒子效果的制作

而如果是设置X轴和Z轴的速度,就有往外的效果

velocity:GLKVector3Make (randomXVelocity, 0.0, randomZVelocity)
OpenGL ES ---粒子效果的制作

第三种效果

  void(^blockC)() = ^{
      
        //设置开始时间
        self.autoSpawnDelta = 0.5f;
        
        //设置重力
        self.particleEffect.gravity = GLKVector3Make(0.0f, 0.0f, 0.0f);
        
        //设置创建粒子的数量
        int n = 100;
        for(int i = 0; i < n; i++)
        {
            //X,Y,Z速度
            float randomXVelocity = -0.5f + 1.0f * (float)random() / (float)RAND_MAX;
            float randomYVelocity = -0.5f + 1.0f * (float)random() / (float)RAND_MAX;
            float randomZVelocity = -0.5f + 1.0f * (float)random() / (float)RAND_MAX;
            
            //创建粒子
            [self.particleEffect
             addParticleAtPosition:GLKVector3Make(0.0f, 0.0f, 0.0f)
             velocity:GLKVector3Make(
                                     randomXVelocity,
                                     randomYVelocity,
                                     randomZVelocity)
             force:GLKVector3Make(0.0f, 0.0f, 0.0f)
             size:4.0f
             lifeSpanSeconds:3.2f
             fadeDurationSeconds:0.5f];
        }

        
    };

第四种效果

void(^blockD)() = ^{
        
        //开始的时间
        self.autoSpawnDelta = 3.2f;
        
        //重力
        self.particleEffect.gravity = GLKVector3Make(0.0f, 0.0f, 0.0f);
        
        int n = 100;
        for(int i = 0; i < n; i++)
        {
            //X,Y速度
            float randomXVelocity = -0.5f + 1.0f * (float)random() / (float)RAND_MAX;
            float randomYVelocity = -0.5f + 1.0f * (float)random() / (float)RAND_MAX;
            
            
            //GLKVector3Normalize 计算法向量
            //计算速度与方向
            GLKVector3 velocity = GLKVector3Normalize( GLKVector3Make(
                                                                      randomXVelocity,
                                                                      randomYVelocity,
                                                                      0.0f));
            
            [self.particleEffect
             addParticleAtPosition:GLKVector3Make(0.0f, 0.0f, 0.0f)
             velocity:velocity
             force:GLKVector3MultiplyScalar(velocity, -1.5f)
             size:4.0f
             lifeSpanSeconds:3.2f
             fadeDurationSeconds:0.1f];
        }
        
    };

顶点着色器

//位置
attribute vec3 a_emissionPosition;
//速度
attribute vec3 a_emissionVelocity;
//受力大小
attribute vec3 a_emissionForce;
//大小
attribute vec2 a_size;
//发射时间和销毁时间
attribute vec2 a_emissionAndDeathTimes;
//MVP变化矩阵
uniform highp mat4 u_mvpMatrix;
//纹理
uniform sampler2D u_samplers2D[1];
//重力
uniform highp vec3 u_gravity;
//当前时间
uniform highp float u_elapsedSeconds;

//varying
//粒子透明度
varying lowp float v_particleOpacity;

void main()
{
   //流逝时间 = 当前时间 - 发射的时间,就是用于计算加速的消耗
    highp float elaspedTime = u_elapsedSeconds-a_emissionAndDeathTimes.x;
    
    //假设质量为1.0的话,加速度 = 力,因为F=ma
    //v= v0+at;
    //v:表示当前速度 v0:表示初速度 a:表示加速度 t:表示时间
    
    highp vec3 velocity = a_emissionVelocity+((a_emissionForce+u_gravity)*elaspedTime);
    
    /*
     设物体做匀加速直线运动,加速度为a,经时间t速度由V0(初速度)大到vt(末速度)
     1、匀加加速平均速度公式V平均=(Vt+V0)/2................1
     2、位移公式S=V平均*t=(Vt+V0)t/2....................2
     
     s=s0 + 0.5 * (v0 + v) * t;
     s表示的是当前的位置 s0表示初始位置 v0表示初始速度 V表示当前速度 t表示的是时间
     */
    highp vec3 untransformedPositon = a_emissionPosition + 0.5 * (a_emissionVelocity+velocity)*elaspedTime;
    
    //得出点的位置
    gl_Position = u_mvpMatrix*vec4(untransformedPositon,1.0);
    //gl_Position.w相当于一个缩放因子了,去除一下,gl_PointSize。这个值控制了点精灵顶点的大小,是像素数值 栅格化点的直径
    gl_PointSize = a_size.x/gl_Position.w;
    
    //消失时间影响的是透明度
    //粒子消失的时间减去当前的时间,所得到的是当前的寿命,除以fade也就是渐隐时间,如果当剩余的时间是小于渐隐的时间也就是Fade的时候,
    //就会得到一个从1到0变化的值
    //最后的0.00001是因为分母不能为0,所以取0.00001
    v_particleOpacity = max(0.0,min(1.0,(a_emissionAndDeathTimes.y-u_elapsedSeconds)/max(a_size.y,0.00001)));
}

片元着色器

//纹理
uniform sampler2D u_samplers2D[1];

//粒子透明度
varying lowp float v_particleOpacity;

void main()
{
   /*
    纹理映射的坐标是bottom left为00点,这里是top left为00点。那么片段着色器看起来就是这样的。
    gl_FragColor = texture2D(uSampler2D,gl_PointCoord);
    现在这个值是默认提供的,从左上角开始的坐标。片段着色器在每个像素上执行,就会把一个默认的纹理绘制到顶点上。
    */
    lowp vec4 textureColor = texture2D(u_samplers2D[0],gl_PointCoord);
    
    textureColor.a = textureColor.a * v_particleOpacity;
    
    gl_FragColor = textureColor;
    
}