如何使用cocos2d-x 3.1片段着色器?

时间:2014-08-23 17:27:10

标签: cocos2d-x cocos2d-x-3.0

以下代码来自本教程:http://www.raywenderlich.com/10862/how-to-create-cool-effects-with-custom-shaders-in-opengl-es-2-0-and-cocos2d-2-x

这是一个非常酷的教程,但我不知道如何在cocos2d-x 3中做到这一点。我已经翻译了下面的代码

- (id)init
{
  self = [super init];
  if (self) {
    // 1
    sprite = [CCSprite spriteWithFile:@"Default.png"];
    sprite.anchorPoint = CGPointZero;
    sprite.rotation = 90;
    sprite.position = ccp(0, 320);
    [self addChild:sprite];

    // 2
    const GLchar * fragmentSource = (GLchar*) [[NSString stringWithContentsOfFile:[CCFileUtils fullPathFromRelativePath:@"CSEColorRamp.fsh"] encoding:NSUTF8StringEncoding error:nil] UTF8String];
    sprite.shaderProgram = [[CCGLProgram alloc] initWithVertexShaderByteArray:ccPositionTextureA8Color_vert
                                       fragmentShaderByteArray:fragmentSource];
    [sprite.shaderProgram addAttribute:kCCAttributeNamePosition index:kCCVertexAttrib_Position];
    [sprite.shaderProgram addAttribute:kCCAttributeNameTexCoord index:kCCVertexAttrib_TexCoords];
    [sprite.shaderProgram link];
    [sprite.shaderProgram updateUniforms];

    // 3
    colorRampUniformLocation = glGetUniformLocation(sprite.shaderProgram->program_, "u_colorRampTexture");
    glUniform1i(colorRampUniformLocation, 1);

    // 4
    colorRampTexture = [[CCTextureCache sharedTextureCache] addImage:@"colorRamp.png"];
    [colorRampTexture setAliasTexParameters];

    // 5
    [sprite.shaderProgram use];
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, [colorRampTexture name]);
    glActiveTexture(GL_TEXTURE0);
  }
  return self;
}

并获得了这个:

Vec2 origin = Director::getInstance()->getVisibleOrigin();


sprite = Sprite::create("HelloWorld.png");
sprite->setAnchorPoint(Vec2(0, 0));
sprite->setRotation(3);
sprite->setPosition(origin);
addChild(sprite);

const GLchar * fragmentSource = FileUtils::getInstance()->getStringFromFile("CSEColorRamp.fsh").c_str();
GLProgram* p = GLProgram::createWithByteArrays(ccPositionTextureA8Color_vert, fragmentSource);
sprite->setGLProgram(p);
p->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
p->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORD);
p->link();
p->updateUniforms();


// 3
colorRampUniformLocation = glGetUniformLocation(sprite->getGLProgram()->getProgram(), "u_colorRampTexture");
glUniform1i(colorRampUniformLocation, 1);

// 4
colorRampTexture = Director::getInstance()->getTextureCache()->addImage("colorRamp.png");
colorRampTexture->setAliasTexParameters();

// 5
sprite->getGLProgram()->use();
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, colorRampTexture->getName());
glActiveTexture(GL_TEXTURE0);

但它不起作用。它显示一个带有2个绘制调用的黑屏。怎么了?我是否将所有制服和属性正常传递给片段着色器。我是否正确初始化了程序?

1 个答案:

答案 0 :(得分:1)

以下是如何在cocos2d-x 3.1中使用着色器的示例:

.h文件

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"

using namespace cocos2d;

class HelloWorld : public cocos2d::Layer
{
public:
    // there's no 'id' in cpp, so we recommend returning the class instance pointer
    static cocos2d::Scene* createScene();

    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();  

    virtual void visit(Renderer *renderer, const Mat4 &transform, bool transformUpdated) override;
    //we call our actual opengl commands here
    void onDraw();

    // implement the "static create()" method manually
    CREATE_FUNC(HelloWorld);

private:
    CustomCommand _customCommand;

    GLuint vao;
    GLuint vertexVBO;
    GLuint colorVBO;
};

#endif // __HELLOWORLD_SCENE_H__

.cpp文件

#include "HelloWorldScene.h"

USING_NS_CC;


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

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

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

    // return the scene
    return scene;
}

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

    //create my own program
    auto program = new GLProgram;
    program->initWithFilenames("myVertextShader.vert", "myFragmentShader.frag");
    program->link();
    //set uniform locations
    program->updateUniforms();


    //    this->setGLProgram(GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_COLOR));
    this->setGLProgram(program);

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



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

    //    auto size = Director::getInstance()->getVisibleSize();
    Vertex data[] =
    {
        {{-1,-1},{0,1,0,1}},

        {{1,-1},{1,0,0,1}},

        { {-1,1},{0,0,1,1}},

        {{1,1},{0,1,0,1}}
    };

    GLubyte indices[] = { 0,1,2,  //第一个三角形索引
        2,3,1}; //第二个三角形索引

    glGenBuffers(1, &vertexVBO);
    glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
    GLuint positionLocation = glGetAttribLocation(program->getProgram(), "a_position");
    //    CCLOG("position =%d", positionLocation);
    glEnableVertexAttribArray(positionLocation);


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

    //set for color
    //    glGenBuffers(1, &colorVBO);
    //    glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
    //    glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);

    GLuint colorLocation = glGetAttribLocation(program->getProgram(), "a_color");
    glEnableVertexAttribArray(colorLocation);
    glVertexAttribPointer(colorLocation,
        4,
        GL_FLOAT,
        GL_FALSE,
        sizeof(Vertex),
        (GLvoid*)offsetof(Vertex,Color));

    GLuint indexVBO;
    glGenBuffers(1, &indexVBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices) , indices, GL_STATIC_DRAW);

    program->autorelease();

    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // 使用vao    http://blog.sina.com.cn/s/blog_4a657c5a01016f8s.html
    return true;
}

void HelloWorld::visit(cocos2d::Renderer *renderer, const Mat4 &transform, bool transformUpdated)
{
    Layer::draw(renderer, transform, transformUpdated);

    //send custom command to tell the renderer to call opengl commands
    _customCommand.init(_globalZOrder);
    _customCommand.func = CC_CALLBACK_0(HelloWorld::onDraw, this);
    renderer->addCommand(&_customCommand);


}

void HelloWorld::onDraw()
{
    //question1: why the triangle goes to the up side
    //如果使用对等矩阵,则三角形绘制会在最前面
    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);


    auto glProgram = getGLProgram();

    glProgram->use();

    //set uniform values, the order of the line is very important
    glProgram->setUniformsForBuiltins();



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

    //use vao
    glBindVertexArray(vao);

    GLuint uColorLocation = glGetUniformLocation(glProgram->getProgram(), "u_color");

    float uColor[] = {1.0, 0.0, 0.0, 1.0};
    glUniform4fv(uColorLocation,1, uColor);

    //    glDrawArrays(GL_TRIANGLES, 0, 6);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE,(GLvoid*)0);

    glBindVertexArray(0);

    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, 6);
    CHECK_GL_ERROR_DEBUG();

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

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

}

myVertextShader.vert顶点着色器

attribute vec4 a_position;
attribute vec4 a_color;

varying vec4 v_fragmentColor;

uniform vec4 u_color;

void main()
{
    gl_Position = CC_MVPMatrix * a_position;
    v_fragmentColor = a_color * u_color;
}

myFragmentShader.frag片段着色器

varying vec4 v_fragmentColor;

void main()
{
    gl_FragColor = v_fragmentColor;
}

我使用过这个来源:http://4gamers.cn/blog/categories/opengl-es/