天天看點

cocos2dx3.x繪制自己的node

3.x最大的變化就是繪制,通過繪制指令添加到渲染隊列中,優化相鄰兩個渲染命中,如果使用的是同一張紋理,則會并到一個批次中繪制出來,具體流程可以看看之前的文章,cocos動畫系統及繪制

下面的例子還順帶開了vbo,vao的話opengles2.0還不支援,是以都被我注釋了

h

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"

using namespace cocos2d;

class HelloWorld : public cocos2d::Layer
{
public:
    virtual ~HelloWorld();
    static cocos2d::Scene* createScene();
    virtual bool init() override;  
    //重寫這個方法很重要,node節點遞歸visit完後就會調這個draw函數,是以我們在這裡添加繪制指令綁定自己的繪制函數OnDraw
    virtual void draw(Renderer *renderer, const Mat4 &transform, bool transformUpdated) override;
    //自己的繪制函數
    void onDraw();
    void menuCloseCallback4(cocos2d::Ref* pSender);
    CREATE_FUNC(HelloWorld);

private:
    CustomCommand _customCommand;

    //GLuint vao;
    GLuint vertexVBO; //緩沖區對象句柄 - 頂點
    GLuint indexVBO; //緩沖區對象句柄 - 頂點索引
    //當然,你可以可以Gluint vbo[2]用數組去裝
};

#endif // __HELLOWORLD_SCENE_H__
           

cpp

#include "HelloWorldScene.h"
#include "MySprite.h"
#include "CubeTexture.h"

USING_NS_CC;


Scene* HelloWorld::createScene()
{
    // \'scene\' is an autorelease object
    auto scene = Scene::create();

    Size size = Director::getInstance()->getWinSize();

    auto layer2 = Layer::create();
    Sprite* sp = Sprite::create("HelloWorld.png");
    //MoveTo* move = MoveTo::create(5.0f, Vec2(400, 400));
    //sp->runAction(move);

    sp->setPosition(size.width / , size.height / );
    //sp->setScale(2.0f);

    FontDefinition fd;
    fd._fontSize = ;
    FontShadow fs;
    fs._shadowEnabled = true;
    fs._shadowBlur = ;
    fs._shadowOffset = Size(, );
    fs._shadowOpacity = ;
    fd._shadow = fs;
    LabelTTF* lb = LabelTTF::createWithFontDefinition("Hello world", fd);
    lb->setPosition(size.width / , size.height / );
    layer2->addChild(sp);
    layer2->addChild(lb);
    //scene->addChild(layer2);

    // \'layer\' is an autorelease object
    auto layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}


void HelloWorld::menuCloseCallback4(cocos2d::Ref* pSender)
{
    auto scene = CubeTexture::createScene();
    Director::getInstance()->replaceScene(scene);
}


// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //
    // 1. super init first
    if ( !Layer::init() )
    {
        return false;
    }

    auto closeItem4 = MenuItemImage::create(
        "CloseNormal.png",
        "CloseSelected.png",
        CC_CALLBACK_1(HelloWorld::menuCloseCallback4, this));
    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();
    closeItem4->setPosition(Vec2(origin.x + visibleSize.width /  - closeItem4->getContentSize().width / ,
        origin.y + visibleSize.height /  + closeItem4->getContentSize().height / ));

    // create menu, it\'s an autorelease object
    auto menu = Menu::create(closeItem4, NULL);
    menu->setPosition(Vec2::ZERO);
    this->addChild(menu, );

    //create my own program
    auto glprogram = new GLProgram;
    glprogram->initWithFilenames("myVertextShader.vert", "myFragmentShader.frag");
    glprogram->link();
    //set uniform locations
    glprogram->updateUniforms();
    setGLProgram(glprogram); //設定為自己的shader

    //glGenVertexArrays(1, &vao);
    //glBindVertexArray(vao);


    glGenBuffers(, &vertexVBO); //建立緩沖區句柄
    glGenBuffers(, &indexVBO);

    return true;
}

void HelloWorld::draw(cocos2d::Renderer *renderer, const Mat4 &transform, bool transformUpdated)
{
    _customCommand.init(_globalZOrder); //繪制優先級
    _customCommand.func = CC_CALLBACK_0(HelloWorld::onDraw, this);//綁定自定義繪制函數,由于是用自己定于的頂點資料,是以沒用矩陣資訊
    renderer->addCommand(&_customCommand); //把渲染指令丢進繪制隊列
}

void HelloWorld::onDraw()
{
    //如果使用對等矩陣,則三角形繪制會在最前面
    Director::getInstance()->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    Director::getInstance()->loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    Director::getInstance()->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
    Director::getInstance()->loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);


    Mat4 modelViewMatrix;
    Mat4::createLookAt(Vec3(,,), Vec3(,,), Vec3(,,), &modelViewMatrix);
    modelViewMatrix.translate(, , -);

    //static float move = 0;
    //modelViewMatrix.translate(sinf(move*0.05)*2, 2, -5);
    //move++;

    //static float rotation = 0;
    //modelViewMatrix.rotate(Vec3(1,1,1),CC_DEGREES_TO_RADIANS(rotation));
    //rotation++;
    //if (rotation > 360) {
    //    rotation = 0;
    //}

    Mat4 projectionMatrix;
    Mat4::createPerspective(, /, , , &projectionMatrix);

    Director::getInstance()->multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, projectionMatrix);
    Director::getInstance()->multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, modelViewMatrix);

    auto glProgram = getGLProgram();
    glProgram->use();
    glProgram->setUniformsForBuiltins();

    Director::getInstance()->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
    Director::getInstance()->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);

    typedef struct {
        float Position[];
        float Color[];
    } Vertex;

    //    auto size = Director::getInstance()->getVisibleSize();
    Vertex data[] =
    {
        // Front
        { { , -,  }, { , , ,  } },
        { { , ,  }, { , , ,  } },
        { { -, ,  }, { , , ,  } },
        { { -, -,  }, { , , ,  } },
        // Back
        { { , , - }, { , , ,  } },
        { { -, -, - }, { , , ,  } },
        { { , -, - }, { , , ,  } },
        { { -, , - }, { , , ,  } },
        // Left
        { { -, -,  }, { , , ,  } },
        { { -, ,  }, { , , ,  } },
        { { -, , - }, { , , ,  } },
        { { -, -, - }, { , , ,  } },
        // Right
        { { , -, - }, { , , ,  } },
        { { , , - }, { , , ,  } },
        { { , ,  }, { , , ,  } },
        { { , -,  }, { , , ,  } },
        // Top
        { { , ,  }, { , , ,  } },
        { { , , - }, { , , ,  } },
        { { -, , - }, { , , ,  } },
        { { -, ,  }, { , , ,  } },
        // Bottom
        { { , -, - }, { , , ,  } },
        { { , -,  }, { , , ,  } },
        { { -, -,  }, { , , ,  } },
        { { -, -, - }, { , , ,  } }
    };

    GLubyte indices[] = {
        // Front
        , , ,
        , , ,
        // Back
        , , ,
        , , ,
        // Left
        , , ,
        , , ,
        // Right
        , , ,
        , , ,
        // Top
        , , ,
        , , ,
        // Bottom
        , , ,
        , , 
    };

    glBindBuffer(GL_ARRAY_BUFFER, vertexVBO); //綁定這個緩沖區句柄為頂點類型
    glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); //申請記憶體大小和綁定資料,靜态繪制,有幾種枚舉類型這裡就不說了,自行百度

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBO);//綁定這個緩沖區句柄為索引類型
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    GLuint positionLocation = glGetAttribLocation(glProgram->getProgram(), "a_position"); //擷取自定義shader中的屬性變量的位址
    GLuint colorLocation = glGetAttribLocation(glProgram->getProgram(), "a_color");

    glEnableVertexAttribArray(positionLocation);//激活
    glEnableVertexAttribArray(colorLocation);

    glVertexAttribPointer(positionLocation, , GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Position));
    glVertexAttribPointer(colorLocation, , GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Color));



    // 0 ~ 1 之間波動
    static float colorCount = ;
    float tmp = sinf(colorCount*);
    tmp = tmp <  ? -tmp : tmp;
    colorCount++;

    /* ---------------------- test1, 為一個float指派 */
    //GLuint uColorLocation1 = glGetUniformLocation(glProgram->getProgram(), "specIntensity");
    //float specIntensity = tmp;
    //glUniform1f(uColorLocation1, specIntensity);

    /* ---------------------- test2, 為1個由4個float組成的vec4指派 */
    //GLuint uColorLocation2 = glGetUniformLocation(glProgram->getProgram(), "u_color");
    //float uColor2[] = { tmp, tmp, tmp, tmp };
    //glUniform4fv(uColorLocation2, 1, uColor2);

    /* ---------------------- test3, 為float[]數組中的兩個元素指派 */
    //GLuint uColorLocation3 = glGetUniformLocation(glProgram->getProgram(), "threshold");
    //float threshold[2] = { 0.5, tmp };
    //glUniform1fv(uColorLocation3, 2, threshold);

    /* ---------------------- test4, 為vec4[]數組中的3個元素指派 */
    //GLuint uColorLocation4 = glGetUniformLocation(glProgram->getProgram(), "colors");
    //float colors[12] = { 0.4, 0.4, 0.8, 1.0,
    //  0.2, 0.2, 0.4, 1.0,
    //  1.0, 1.0, 1.0, tmp };
    //glUniform4fv(uColorLocation4, 3, colors);

    /* ---------------------- test5, 為float[]數組中的某個元素指派,根據下标索引 */
    GLuint uColorLocation5 = glGetUniformLocation(glProgram->getProgram(), "threshold[0]"); //傳入自定shader中的uniform變量,控制alpha透明度
    float asd = tmp;
    glUniform1f(uColorLocation5, asd);

    glDrawElements(GL_TRIANGLES, , GL_UNSIGNED_BYTE,(GLvoid*)); //繪制三角形,由于索引也上傳到緩沖區了,是以這裡的索引直接傳0位址

    //解除激活的緩沖區
    glBindBuffer(GL_ARRAY_BUFFER, );
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, );

    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(, );
    CHECK_GL_ERROR_DEBUG();
}

HelloWorld::~HelloWorld()
{
    //清除緩沖區句柄
    glDeleteBuffers(, &vertexVBO);
    glDeleteBuffers(, &indexVBO);
}
           

myVertextShader.vert

attribute vec3 a_position;
attribute vec4 a_color;

varying vec4 v_fragmentColor;

varying vec3 normal;  

void main()
{
    gl_Position = CC_MVPMatrix * vec4(a_position.xyz,);
    v_fragmentColor = a_color;
}
           

myFragmentShader.frag

varying vec4 v_fragmentColor;

uniform float specIntensity;
uniform vec4 u_color;
uniform float threshold[];
uniform vec4 colors[];  

vec4 toonify(float intensity)  
{  
    vec4 color;  
    if (intensity < )  
       color = vec4(,  , , );  
    else if (intensity < )  
       color = vec4(,  , , );  
    else if (intensity < )  
       color = vec4(,  , , );  
    else  
    {
       color = vec4(, , , );   
       //discard; //最後的discard關鍵字隻能在片斷shader中使用,它将在不寫入幀緩存或者深度緩存的情況下,終止目前片斷的shader程式。
    }

    return(color);  
} 

void main()
{
    // ---------------------- test1
    // gl_FragColor = v_fragmentColor * vec4(1.0, 1.0, 1.0, specIntensity);

    // ---------------------- test2
    //gl_FragColor = v_fragmentColor * u_color;

    // ---------------------- test3
    //gl_FragColor = v_fragmentColor * vec4(1.0, 1.0, 1.0, threshold[1]);

    // ---------------------- test4
    //gl_FragColor = v_fragmentColor * colors[2];

    // ---------------------- test5
    gl_FragColor = v_fragmentColor * vec4(, , , threshold[]);

    // ---------------------- test6
    //gl_FragColor =  toonify(threshold[0]);
}
           

注釋中的其他uniform可以解開注釋,同時shader也解開

shader編寫需要注意的是

如果shader中定義了uniform屬性名但沒有使用,會在編譯shader時優化調,是以在c++中擷取uniform中的變量位址會是個空位址

其次就是類型需要嚴格一直,在windows平台展現不出來,應為win平台用的是opengl4.0的,而手機平台的是opengles2.0标準,類型不一緻在運作時導緻異常崩潰,崩潰資訊可以重eclipse中看到,比如 float a = 4.0 * 123就是錯的,float*int,應改為 float a = 4.0 * float(123)才正确

繼續閱讀