音視頻開發(fā)之旅(16) OpenGL ES粒子效果-煙花爆炸

目錄

  1. 煙花爆竹場景和屬性
  2. 實踐以及遇到的問題
  3. 資料
  4. 收獲

通過該篇的實踐實現(xiàn)如下效果


一、煙花爆竹場景和屬性

在上一篇 音視頻開發(fā)之旅(15) OpenGL ES粒子系統(tǒng) - 噴泉 的基礎(chǔ)上 實現(xiàn)煙花爆炸效果。

在具體實踐之前宁仔,先來想一想坟瓢,煙花爆炸的場景和屬性
場景:從中心點開始爆炸卵洗,然后煙花粒子向各個方向炸開最铁,整體形狀也各有不同管跺,比如 北京奧運會的大腳印棵里,但是大部分還是圓形(因為設(shè)計實現(xiàn)相對簡單)润文,今天我們也實現(xiàn)一個圓形的煙花爆炸效果。
屬性:顏色殿怜、角度典蝌、運動矢量、形狀头谜。

實現(xiàn)流程和上一篇基本一致骏掀,不清晰整理的流程,建議先回看下

二柱告、實踐:煙花效果

在上篇的基礎(chǔ)上通過修改Render的onDrawFrame中的粒子發(fā)射器來逐步實現(xiàn)煙花爆炸效果截驮。

2.1 首先定義煙花爆炸對象
粒子的添加角度采用360度隨機的方式添加

public class ParticleFireworksExplosion {

    private float[] mDirectionVector = {0f, 0f, 0.5f, 1f};
    private float[] mResultVector = new float[4];
    private final Random mRandom = new Random();
    private float[] mRotationMatrix = new float[16];

    public void addExplosion(ParticleSystem particleSystem, Geometry.Point position, int color, float curTime) {

        Matrix.setRotateEulerM(mRotationMatrix, 0, mRandom.nextFloat() * 360, mRandom.nextFloat() * 360, mRandom.nextFloat() * 360);
        Matrix.multiplyMV(mResultVector, 0, mRotationMatrix, 0, mDirectionVector, 0);


        particleSystem.addParticle(
                position,
                color,
                new Geometry.Vector(mResultVector[0],
                        mResultVector[1],
                        mResultVector[2]),
                curTime);
    }
}

2.2 然后在Render中使用ParticleFireworksExplosion作為粒子發(fā)射器

public class ParticlesRender implements GLSurfaceView.Renderer {

    ...
    private ParticleFireworksExplosion particleFireworksExplosion;

 @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {

    ...
     particleFireworksExplosion = new ParticleFireworksExplosion();
    }


@Override
    public void onDrawFrame(GL10 gl) {
     ...

        //粒發(fā)射器添加粒子
//        mParticleShooter.addParticles(mParticleSystem,curTime,20);
                        int color = Color.rgb(255, 50, 5);

        //煙花爆炸粒子發(fā)生器 添加粒子
        particleFireworksExplosion.addExplosion(
                mParticleSystem,
                new Geometry.Point(
                        0,
                        0f ,
                        0),
                color,
                curTime);
        ...

    }

效果如下:


問題1: 這明顯不是煙花爆炸的效果

煙花爆炸是一個時間段只有一個爆炸,然后煙花顆粒向外圓形擴展開际度。而目前實現(xiàn)的效果是不斷的發(fā)射新的粒子葵袭。

為此需要在onDrawFrame中間隔一段時間才發(fā)射粒子,這樣讓“煙花飛一會”從而形成煙花爆炸效果乖菱;同時坡锡,為了同一時間段粒子的數(shù)量保持一致蓬网,我們多同一個時間點我們同發(fā)射寫粒子。具體實現(xiàn)如下:

public class ParticleFireworksExplosion {

    ...

    private final int mPreAddParticleCount = 100;

    public void addExplosion(ParticleSystem particleSystem, Geometry.Point position, int color, float curTime) {

        //不是OnDrawFrame就添加煙花爆炸粒子鹉勒,而是采用1/100的采樣率 帆锋,讓粒子飛一會,從而產(chǎn)生煙花爆炸效果
        if (mRandom.nextFloat() < 1.0f / mPreAddParticleCount) {

            //同一時刻添加100個方向360隨機的粒子
            for (int i = 0; i < mPreAddParticleCount; i++) {
                Matrix.setRotateEulerM(mRotationMatrix, 0, mRandom.nextFloat() * 360, mRandom.nextFloat() * 360, mRandom.nextFloat() * 360);
                Matrix.multiplyMV(mResultVector, 0, mRotationMatrix, 0, mDirectionVector, 0);


                particleSystem.addParticle(
                        position,
                        color,
                        new Geometry.Vector(mResultVector[0],
                                mResultVector[1],
                                mResultVector[2]),
                        curTime);
            }
        }
    }
}

效果如下:


問題2: 煙花擴散的效果不是圓形而是橢圓

這需要采用投影矩陣和視圖矩陣變換 把橢圓形狀投影到屏幕贸弥。

為此我們需要做如此處理

1.  頂點著色器中添加unifrom mat4窟坐,在gl_Position的賦值需要和改矩陣相乘。
2.  Program中解析該location以及進行數(shù)據(jù)的輸入
3.  Render中進行透視矩陣和試圖矩陣的定義和計算绵疲,生成matrix數(shù)據(jù)

具體實現(xiàn)如下:

1. 頂點著色器

uniform float u_Time;
uniform mat4 u_Matrix; //定義矩陣數(shù)據(jù)類型變量

attribute vec3 a_Position;
attribute vec3 a_Color;
attribute vec3 a_Direction;
attribute float a_PatricleStartTime;

varying vec3 v_Color;
varying float v_ElapsedTime;

void main(){
    v_Color = a_Color;
    //粒子已經(jīng)持續(xù)時間  當(dāng)前時間-開始時間
    v_ElapsedTime = u_Time - a_PatricleStartTime;
    //重力或者阻力因子哲鸳,隨著時間的推移越來越大
    float gravityFactor = v_ElapsedTime * v_ElapsedTime / 9.8;
    //當(dāng)前的運動到的位置 粒子起始位置+(運動矢量*持續(xù)時間)
    vec3 curPossition = a_Position + (a_Direction * v_ElapsedTime);
    //減去重力或阻力的影響
    curPossition.y -= gravityFactor;

    //把當(dāng)前位置通過內(nèi)置變量傳給片元著色器。
//    gl_Position =  vec4(curPossition,1.0); //注釋掉該實現(xiàn)盔憨,修改為下面的實現(xiàn)徙菠。

    //把當(dāng)前位置和MVP矩陣相乘后,通過內(nèi)置變量傳給片元著色器
    gl_Position = u_Matrix * vec4(curPossition, 1.0);

    gl_PointSize = 25.0;
}

2. Program中解析和賦值matrix

public class ParticleShaderProgram {

    ...
    private final String U_MATRIX = "u_Matrix";

    private final int uMatrixLocation;


    public ParticleShaderProgram(Context context) {
        ...

        //獲取uniform 和attribute的location

        uMatrixLocation = glGetUniformLocation(program, U_MATRIX);

        ...
    }

    /**
     * 設(shè)置Uniform變量
     * @param matrix
     * @param curTime
     */
    public void setUniforms(float[] matrix, float curTime, int textureId){
        GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, matrix, 0);

       ...

    }
}

3. Render中進行透視矩陣和試圖矩陣的定義和計算郁岩,生成matrix數(shù)據(jù)

public class ParticlesRender implements GLSurfaceView.Renderer {

    ...
    private final float[] projectionMatrix = new float[16];
    private final float[] viewMatrix = new float[16];
    private final float[] viewProjectionMatrix = new float[16];

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0,0,width,height);

        Matrix.perspectiveM(projectionMatrix, 0,45, (float) width
                / (float) height, 1f, 10f);

        setIdentityM(viewMatrix, 0);
        translateM(viewMatrix, 0, 0f, -1.5f, -5f);
        multiplyMM(viewProjectionMatrix, 0, projectionMatrix, 0,
                viewMatrix, 0);
    }


 @Override
    public void onDrawFrame(GL10 gl) {
      ...
        //設(shè)置Uniform變量 
        mProgram.setUniforms(viewProjectionMatrix,curTime,mTextureId);
    }
}

效果如下:


問題3婿奔、目前的煙花都是紅色的,如何實現(xiàn)多彩的煙花问慎?

只需要修改粒子的顏色即可萍摊,我們通過hsv顏色空間,隨機調(diào)節(jié)色調(diào)如叼,然后轉(zhuǎn)為rgb顏色空間的顏色值冰木,賦值給粒子,具體實現(xiàn)如下

public class ParticleFireworksExplosion {

    private float[] mDirectionVector = {0f, 0f, 0.3f, 1f};
    private float[] mResultVector = new float[4];
    private final Random mRandom = new Random();
    private float[] mRotationMatrix = new float[16];

    private final int mPreAddParticleCount = 100;
      // 定義hsv色彩空間值笼恰,色調(diào)值默認(rèn)為0(對應(yīng)角度范圍為0-360)踊沸,飽和度和亮度默認(rèn)為1(范圍為0-2)
    private final float[] hsv = {0f, 1f, 1f};


    public void addExplosion(ParticleSystem particleSystem, Geometry.Point position, float curTime) {


        //不是OnDrawFrame就添加煙花爆炸粒子,而是采用1/100的采樣率 社证,讓粒子飛一會逼龟,從而產(chǎn)生煙花爆炸效果
        if (mRandom.nextFloat() < 1.0f / mPreAddParticleCount) {

        //隨機生成顏色的色調(diào),
        hsv[0] = random.nextInt(360);
        //把hsv顏色空間轉(zhuǎn)位rgb顏色空間值
        int color = Color.HSVToColor(hsv);

            //同一時刻添加100*3個方向360隨機的粒子
            for (int i = 0; i < mPreAddParticleCount *3 ; i++) {
                Matrix.setRotateEulerM(mRotationMatrix, 0, mRandom.nextFloat() * 360, mRandom.nextFloat() * 360, mRandom.nextFloat() * 360);
                Matrix.multiplyMV(mResultVector, 0, mRotationMatrix, 0, mDirectionVector, 0);
                particleSystem.addParticle(
                        position,
                        color,
                        new Geometry.Vector(mResultVector[0],
                                mResultVector[1]+0.3f,//由于煙花彈向上的慣性追葡,爆炸時添加向上的偏移腺律,效果看起來更加逼真。
                                mResultVector[2]),
                        curTime);
            }
        }
    }
}

效果正如開篇展示


完整代碼已上傳至github

參考

《OpenGL ES 3.0 編程指南》
《OpenGL ES應(yīng)用開發(fā)實踐指南》

[粒子系統(tǒng)--煙花 [OpenGL-Transformfeedback]]
[Android制作粒子爆炸特效]
[Android超強大的粒子動畫庫辽俗,流星雨疾渣,爆炸,滿屏飛花崖飘,等粒子特效快速實現(xiàn)]
[OpenGL進階(六)-粒子系統(tǒng)]
[【OpenGL】Shader實例分析(七)- 雪花飄落效果]

收獲

通過對OpenGL ES粒子系統(tǒng)的學(xué)習(xí)實踐,發(fā)現(xiàn)通過粒子可以制作很多絢麗的效果杈女。也在學(xué)習(xí)實踐的過程中越來越發(fā)現(xiàn)路還很長朱浴,要不斷持續(xù)學(xué)習(xí)實踐才行吊圾。

具體到本篇收獲
分析煙花爆炸的場景與特性

通過實踐逐步實現(xiàn)多彩的煙花效果
遇到的問題解決

感謝你的閱讀

本來這個OpenGL ES系列計劃還要寫2-3篇,把天空盒翰蠢、光照等也逐步學(xué)習(xí)實踐项乒,但是感覺到應(yīng)用場景和整體方向目前來看關(guān)系性還不是很大。所以準(zhǔn)備放大后續(xù)環(huán)節(jié)學(xué)習(xí)實踐梁沧。下一篇我們開啟JNI和NDK系列的學(xué)習(xí)實踐檀何。歡迎關(guān)注公眾號“音視頻開發(fā)之旅”,一起學(xué)習(xí)成長廷支。

歡迎交流

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末频鉴,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子恋拍,更是在濱河造成了極大的恐慌垛孔,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件施敢,死亡現(xiàn)場離奇詭異周荐,居然都是意外死亡,警方通過查閱死者的電腦和手機僵娃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門概作,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人默怨,你說我怎么就攤上這事讯榕。” “怎么了先壕?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵瘩扼,是天一觀的道長。 經(jīng)常有香客問我垃僚,道長集绰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任谆棺,我火速辦了婚禮栽燕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘改淑。我一直安慰自己碍岔,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布朵夏。 她就那樣靜靜地躺著蔼啦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪仰猖。 梳的紋絲不亂的頭發(fā)上捏肢,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天奈籽,我揣著相機與錄音,去河邊找鬼鸵赫。 笑死衣屏,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的辩棒。 我是一名探鬼主播狼忱,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼一睁!你這毒婦竟也來了钻弄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤卖局,失蹤者是張志新(化名)和其女友劉穎斧蜕,沒想到半個月后示辈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體跳芳,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡蒸痹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年澡绩,在試婚紗的時候發(fā)現(xiàn)自己被綠了纷闺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筒扒。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡揽碘,死狀恐怖浦徊,靈堂內(nèi)的尸體忽然破棺而出单鹿,到底是詐尸還是另有隱情掀宋,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布仲锄,位于F島的核電站劲妙,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏儒喊。R本人自食惡果不足惜镣奋,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望怀愧。 院中可真熱鬧侨颈,春花似錦、人聲如沸芯义。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扛拨。三九已至耘分,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背陶贼。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工啤贩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留待秃,地道東北人拜秧。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像章郁,于是被迫代替她去往敵國和親枉氮。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容