1. 程式人生 > >(cocos2d-x) 背景模糊化以及效率優化

(cocos2d-x) 背景模糊化以及效率優化

在遊戲中有時了為了突顯前景元素,需要對背景進行一些模糊化處理,如下圖所示

雖然cocos2d-x 3.x提供了新的使用者模糊化的shader指令碼,但根據實現方式的不同仍然會有很大區別。

方案0:對所有背景上所有精靈進行模糊化

最不可取的方案,多數情況下並不能達到預期效果,而且效率低,原因見以下兩圖:

第1張黑色背景是引擎示例中的效果,第2張是我在示例程式碼中加了一個白色背景後的效果。

這裡的問題是,實際上3.x版本提供shader指令碼無法很好的處理帶有透明度的圖片,由於示例預設都是黑色背景,因此無法看出問題,而在白色背景下,所有透明的地方都被處理成了黑色。相信現在遊戲中即使背景也會有大量帶有透明區域的圖片,況且當我們我們模糊處理的時候經常也需要處理前景圖片,那麼這個問題完全不能忽視了。

我本人對shader指令碼並不太熟悉,不過猜測應該可以靠修改shader指令碼解決。但即使如此,對場景中多個精靈進行模糊化,效率如何呢?我們來看方案1。

方案1:擷取螢幕生成一個精靈作為臨時背景,並對此精靈進行模糊化

基本思路是使用渲染到紋理技術生成一個臨時的圖片精靈,將此精靈置於場景最上層(即Zorder高於其他精靈),成為一個假背景,而把需要突顯的元素,再置於這個精靈之上。實現很容易,效果如圖:

粗略看貌似沒問題,但請注意左下角的幀率。實際上即使只對一個960x640尺寸的精靈進行模糊化,效率也非常低,長期保持在20幀以下。雖然這裡我的執行環境是整合顯示卡,這也是造成幀率的低的原因之一,但桌上型電腦尚且如此,移動裝置上很難表現的更好,況且移動裝置還要耗電和發熱問題,效率問題必須重視。於是便有了方案2。

方案2:用模糊化後的精靈生成一個普通精靈作為臨時背景

效果如圖:

幀數恢復到了60左右,經我在手機上測試,對1280x720的圖片進行這樣的處理,也幾乎沒有問題,僅僅會在生成模糊圖的一刻會瞬間降到40幀左右,之後會迅速恢復至60幀。

以下是實現程式碼:

#include "HelloWorldScene.h"

USING_NS_CC;

//////////////////////////////////////////////////////////////////////////
//精靈模糊類
//////////////////////////////////////////////////////////////////////////
class SpriteBlur : public cocos2d::Sprite
{
public:
    SpriteBlur();
    ~SpriteBlur();
    static SpriteBlur* create(cocos2d::Sprite* pSprite, const float fRadius = 8.0f, const float fSampleNum = 8.0f);
    bool initWithTexture(cocos2d::Texture2D* pTexture, const cocos2d::Rect&  rRect);
    void initGLProgram();

    void setBlurRadius(float fRadius);
    void setBlurSampleNum(float fSampleNum);

protected:
    float fBlurRadius_;
    float fBlurSampleNum_;
};

SpriteBlur::SpriteBlur()
    : fBlurRadius_(0.0f)
    , fBlurSampleNum_(0.0f)
{

}

SpriteBlur::~SpriteBlur()
{

}

SpriteBlur* SpriteBlur::create(cocos2d::Sprite* pSprite, const float fRadius, const float fSampleNum)
{
    SpriteBlur* pRet = new (std::nothrow) SpriteBlur();
    if (nullptr == pRet)
        return nullptr;
    pRet->fBlurRadius_ = fRadius;
    pRet->fBlurSampleNum_ = fSampleNum;
    if (pRet->initWithSpriteFrame(pSprite->getSpriteFrame()))
        pRet->autorelease();
    else
        CC_SAFE_DELETE(pRet);
    return pRet;
}

bool SpriteBlur::initWithTexture(cocos2d::Texture2D* texture, const cocos2d::Rect& rect)
{
    if (Sprite::initWithTexture(texture, rect))
    {
#if CC_ENABLE_CACHE_TEXTURE_DATA
        auto listener = EventListenerCustom::create(EVENT_RENDERER_RECREATED, [this](EventCustom* event){
            setGLProgram(nullptr);
            initGLProgram();
        });

        _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
#endif
        initGLProgram();
        return true;
    }
    return false;
}

void SpriteBlur::initGLProgram()
{
    GLchar * fragSource = (GLchar*)cocos2d::String::createWithContentsOfFile(
        cocos2d::FileUtils::getInstance()->fullPathForFilename("shaders/blur.fsh").c_str())->getCString();
    auto program = cocos2d::GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource);

    auto glProgramState = cocos2d::GLProgramState::getOrCreateWithGLProgram(program);
    setGLProgramState(glProgramState);

    auto size = getTexture()->getContentSizeInPixels();
    getGLProgramState()->setUniformVec2("resolution", size);
    getGLProgramState()->setUniformFloat("blurRadius", fBlurRadius_);
    getGLProgramState()->setUniformFloat("sampleNum", fBlurSampleNum_);
}


void SpriteBlur::setBlurRadius(float radius)
{
    fBlurRadius_ = radius;
    getGLProgramState()->setUniformFloat("blurRadius", fBlurRadius_);
}

void SpriteBlur::setBlurSampleNum(float num)
{
    fBlurSampleNum_ = num;
    getGLProgramState()->setUniformFloat("sampleNum", fBlurSampleNum_);
}

//////////////////////////////////////////////////////////////////////////
//精靈模糊化函式
//////////////////////////////////////////////////////////////////////////
cocos2d::RenderTexture* SpriteBlurer(cocos2d::Sprite* pSprite, const float fRadius = 8.0f, const float fSampleNum = 8.0f)
{
    //模糊化的臨時精靈
    auto pSptBlur = SpriteBlur::create(pSprite, fRadius, fSampleNum);
    pSptBlur->setRotationSkewX(180.0f);
    pSptBlur->setPositionX(pSptBlur->getContentSize().width / 2);
    pSptBlur->setPositionY(pSptBlur->getContentSize().height / 2);
    //使用精靈尺寸初始化一個空的渲染紋理物件
    cocos2d::RenderTexture* textureScreen =
        cocos2d::RenderTexture::create(pSptBlur->getContentSize().width, pSptBlur->getContentSize().height);
    //開始獲取
    textureScreen->beginWithClear(0.0f, 0.0f, 0.0f, 0.0f);
    //遍歷節點物件,填充紋理到texure中
    pSptBlur->visit();
    //結束獲取
    textureScreen->end();
    return textureScreen;
}

//////////////////////////////////////////////////////////////////////////
//截圖函式
//////////////////////////////////////////////////////////////////////////
cocos2d::RenderTexture* ScreenShot(const bool bIsSave, std::function<void(cocos2d::RenderTexture*, const std::string&)> pFuncCallback)

{
    //使用螢幕尺寸初始化一個空的渲染紋理物件
    Size sizeWin = Director::getInstance()->getWinSize();
    cocos2d::RenderTexture* textureScreen =
        cocos2d::RenderTexture::create(sizeWin.width, sizeWin.height);
    //清除資料並開始獲取
    textureScreen->beginWithClear(0.0f, 0.0f, 0.0f, 0.0f);
    //遍歷場景節點物件,填充紋理到texure中
    cocos2d::Director::getInstance()->getRunningScene()->visit();
    //結束獲取
    textureScreen->end();
    //儲存為PNG圖
    if (bIsSave)
    {
        static int s_iSerialNumber = 0;
        textureScreen->saveToFile(
            cocos2d::CCString::createWithFormat("ScreenShot_%04d.png", ++s_iSerialNumber)->getCString(),
            cocos2d::Image::Format::PNG,
            true,
            pFuncCallback);
    }
    else
    {
        if (nullptr != pFuncCallback)
        {
            pFuncCallback(textureScreen, "");
        }
    }
    return textureScreen;
}


//////////////////////////////////////////////////////////////////////////
//示例
//////////////////////////////////////////////////////////////////////////
Scene* HelloWorld::createScene()
{
    auto scene = Scene::create();
    auto layer = HelloWorld::create();
    scene->addChild(layer);
    return scene;
}

bool HelloWorld::init()
{
    if ( !Layer::init() )
    {
        return false;
    }
    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();
    auto closeItem = MenuItemImage::create(
                                           "CloseNormal.png",
                                           "CloseSelected.png",
                                           CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
    closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
                                origin.y + closeItem->getContentSize().height/2));
    auto menu = Menu::create(closeItem, NULL);
    menu->setPosition(Vec2::ZERO);
    this->addChild(menu, 1);
    auto label = Label::createWithTTF("Hello World", "fonts/Marker Felt.ttf", 24);
    label->setPosition(Vec2(origin.x + visibleSize.width/2,
                            origin.y + visibleSize.height - label->getContentSize().height));
    this->addChild(label, 1);
    auto sprite = Sprite::create("HelloWorld.png");
    sprite->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
    this->addChild(sprite, 0);

    //////////////////////////////////////////////////////////////////////////
    //背景模糊
    //////////////////////////////////////////////////////////////////////////
    //新增按鍵用於觸發背景模糊
    auto blurItem = MenuItemImage::create(
        "CloseNormal.png",
        "CloseSelected.png",
        [&](Ref* pSender){

            //擷取螢幕(不儲存圖片,不設定回撥函式)
            auto textureScreen = ScreenShot(false, nullptr);
            
            //方案1:直接對背景精靈進行模糊化操作(效率低)
            //使用擷取後獲得的截圖精靈,生成一個帶模糊效果的精靈
            //SpriteBlur* spriteBlur = SpriteBlur::create(textureScreen->getSprite(), 8.0f, 8.0f);
            //spriteBlur->setRotationSkewX(180.0f);

            //方案2:將模糊化後的精靈儲存成一張圖片
            //將擷取的螢幕進行模糊化
            auto textureBlur = SpriteBlurer(textureScreen->getSprite());
            //將模糊化後的圖片儲存成一張圖片
            auto spriteBlur = Sprite::createWithSpriteFrame(textureBlur->getSprite()->getSpriteFrame());
            spriteBlur->setPosition(Vec2(visibleSize.width, visibleSize.height));

            Size size = Director::getInstance()->getWinSize();
            spriteBlur->setRotationSkewX(180.0f);
            spriteBlur->setPosition(Vec2(size.width / 2, size.height / 2));

            //將此精靈覆蓋在原有層之上,成為一個臨時背景
            this->addChild(spriteBlur, 4);

            //新增一個新的圖片作為前景元素以便進行比較
            auto sprite = Sprite::create("HelloWorld.png");
            sprite->setPosition(Vec2(size.width / 2, size.height / 2));
            sprite->setScale(0.5f);
            this->addChild(sprite, 5);
            
        }
    );
    blurItem->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
    menu->addChild(blurItem);

    return true;
}


void HelloWorld::menuCloseCallback(Ref* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
    MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
    return;
#endif

    Director::getInstance()->end();

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
}

HelloWorldScene.h未做任何修改,因此此處不再貼出。

class SpriteBlur用於生成可被shader處理的精靈,注意將cocos2d-x的shader指令碼拷入自己的專案中。得到的精靈每一幀都會進行畫素渲染,可以動態調節模糊效果。建構函式中的除了需要模糊化的精靈之外,另外兩個引數:fRadius為模糊半徑,此引數越大,模糊效果越明顯;fSampleNum為模糊取樣,此引數越大,模糊效果越細膩。這兩個引數越高,效率也就越低。並且當高過一定數值後,在手機上有可能出現異常,建議兩個引數設定均不要超過8。

ScreenShot為截圖函式,相關教程很多,此處不再展開。

SpriteBlurer為精靈模糊化函式,將一個普通精靈傳入,即可返回一個被模糊化處理後的紋理,使用此紋理即可生成普通精靈。即把用shader處理過的精靈截圖,生成普通精靈,此精靈不再需要進行畫素渲染,因此保證了效率。

 此方案的缺點:SpriteBlurer函式生成的紋理,既不能再次調整模糊程度的強弱,也不能改變顯示內容。但如果作為一個背景來用,這個方案已經足夠了。 

相關推薦

(cocos2d-x) 背景模糊以及效率優化

在遊戲中有時了為了突顯前景元素,需要對背景進行一些模糊化處理,如下圖所示 雖然cocos2d-x 3.x提供了新的使用者模糊化的shader指令碼,但根據實現方式的不同仍然會有很大區別。 方案0:對所有背景上所有精靈進行模糊化 最不可取的方案,多數情況下並不能達到預期效

Windows平臺cocos2d-x 3.2下載以及建立新專案過程

首先,有關於cocos2d-x在windows下Android環境的搭建, 這裡簡單列一下所需工具的下載地址: 1、JDK 下載地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html 2

Cocos2d-x中Vector容器以及例項介紹

Vector<T> 是Cocos2d-x 3.x推出的列表容器,因此它所能容納的是Ref及子類所建立的物件指標,其中的T是模板,表示能夠放入到容器中的型別,在Cocos2d-x 3.x中T表

如何實現Android 佈局背景模糊處理

在模仿 IOS 密碼輸入頁面的時候發現其背景有模糊處理,於是瞭解了一下並記錄下來,以便使用.在Android 中具體實現方法如下查考 http://www.cnblogs.com/lipeil/p/3997992.htmlprivate void applyBlur() { // 獲取桌布管理器

SparkStreaming讀取kafka資料進行反序列以及mapPartition優化例項

val monitorWrappedMessage1 =  KafkaUtils.createStream[String,  Array[Byte], StringDecoder, DefaultDecoder](       ssc, kafkaParams, topic

Cocos2d-x優化中關於背景圖片優化

指針 text .cpp 互動出版網 沒有 tde white 實現 origin 因為背景圖片長時間在場景中保存,並且圖片非常多,我們能夠對其進行一些優化。我們通過例如以下幾個方面考慮優化:1、不要Alpha通道背景圖片的特點是不須要透明的,所以紋理格式能夠採用不帶有A

UIKit和Cocos2d-x的整合使用;設定CCEAGLView背景為透明,來顯示背後的UIView; 以及整合中遇到的問題的解決方案

UIKit和Cocos2d-x的整合使用 原來我們的專案通過原始的UIKit來實現應用開發,但是現在需要往應用中增加禮物特效動畫,而禮物特效需要通過cocos2d-x來實現。晚上的方法大多都是通過建立初始的cocos2d工程,再在工程中增加UIKit的實現。最著名的介紹這個

Cocos2d-x中Vector&lt;T&gt;容器以及實例介紹

top 宋體 hello 操作符 模板類 log ins bsp main Vector<T> 是Cocos2d-x 3.x推出的列表容器,因此它所能容納的是Ref及子類所創建的對象指針,其中的T是模板,表示能夠放入到容器中的類型,在Cocos2d-x 3.x

Cocos2d-x v3.1.1 創建以及編譯項目

耐心 以及 系統 content win 3.1 包名 安裝路徑 ont 1.安裝python, 並將安裝路徑增加系統環境變量中; 2. 執行cocos2d-x根文件夾下的setup.py; 3. 進入cmd, 輸入: cocos new 項目名稱 -p 包名 -l 語

quick-cocos2d-x教程9:實例之加上背景圖片

nbsp mod work .text eight zip function 大小 dto 在梳理完quick-cocos2d-x框架的各個文件夾後,我們開始我們的實例教程,在helloworld後面。加上一張圖片,lua編輯器,我用的lua editor。還不錯。

我學cocos2d-x (三) Node:一切可視對象的祖先

父類 顯示 fine rtu cocos2 static trac 坐標 ati 在cocos2d-x中一切可視化的對象都繼承自Node(如文字(label)、精靈(sprite)、場景(scene)、布局(layer))。這是一個純虛類。主要負責決定元素顯示的位置

Cocos2d-x Lua遊戲開發Mac環境搭建以及一點點感悟

感覺 慢慢 怎樣 tid lease 人生 第三方 什麽 增強 接觸Cocos2d-x 最近由於公司項目的需要,自己開始接觸Cocos,開始做一些簡單的輕量級的遊戲,以前沒有接觸過這一塊的東西,也是借助這個機會學習一下遊戲的開發,由於以前自己

cocos2d-x 圖片紋理優化 資源加載方案

context 24* fad 對話 一個bug mipmap cocos 依靠 ast 原文地址:http://blog.sina.com.cn/s/blog_64d591e80101me1y.html 文章主要解決了我一直以來疑惑的幾個問題 1.到底用不用2的N次冪的圖

改善深層神經網路:超引數除錯、正則以及優化_課程筆記_第一、二、三週

所插入圖片仍然來源於吳恩達老師相關視訊課件。仍然記錄一下一些讓自己思考和關注的地方。 第一週 訓練集與正則化 這周的主要內容為如何配置訓練集、驗證集和測試集;如何處理偏差與方差;降低方差的方法(增加資料量、正則化:L2、dropout等);提升訓練速度的方法:歸一化訓練集;如何合理的初始化權

吳恩達改善深層神經網路引數:超引數除錯、正則以及優化——優化演算法

機器學習的應用是一個高度依賴經驗的過程,伴隨著大量的迭代過程,你需要訓練大量的模型才能找到合適的那個,優化演算法能夠幫助你快速訓練模型。 難點:機器學習沒有在大資料發揮最大的作用,我們可以利用巨大的資料集來訓練網路,但是在大資料下訓練網路速度很慢; 使用快速的優化演算法大大提高效率

改善深層神經網路:超引數除錯、正則以及優化 優化演算法 第二週

改善深層神經網路:超引數除錯、正則化以及優化  優化演算法 第二課 1. Mini-batch Batch vs Mini-batch gradient descent Batch就是將所有的訓練資料都放到網路裡面進行訓練,計算量大,硬體要求高。一次訓練只能得到一個梯

吳恩達 改善深層神經網路:超引數除錯、正則以及優化 第一週

吳恩達 改善深層神經網路:超引數除錯、正則化以及優化 課程筆記  第一週 深度學習裡面的實用層面 1.1 測試集/訓練集/開發集        原始的機器學習裡面訓練集,測試集和開發集一般按照6:2:2的比例來進行劃分。但是傳統的機器學習

cocos2d-x v3.0各個環境下建立專案以及編譯、執行官方DEMO

如何建立一個新專案 How to start a new game Runsetup.pyRun thecocosscriptExample: $ cd cocos2d-x $ ./setup.py $ source FILE_TO_SAVE_SYSTEM_VARIAB

Mysql模糊查詢like效率以及更高效的寫法

原文來自:https://www.cnblogs.com/chaobest/p/6737901.html在使用msyql進行模糊查詢的時候,很自然的會用到like語句,通常情況下,在資料量小的時候,不容易看出查詢的效率,但在資料量達到百萬級,千萬級的時候,查詢的效率就很容易顯

吳恩達《深度學習-改善深層神經網路》3--超引數除錯、正則以及優化

1. 系統組織超參除錯Tuning process1)深度神經網路的超參有學習速率、層數、隱藏層單元數、mini-batch大小、學習速率衰減、β(優化演算法)等。其重要性各不相同,按重要性分類的話:   第一類:最重要的引數就是學習速率α    第二類:隱藏層單元數、min