But it does not work. It shows a black screen with 2 draw calls. What is wrong? Did I pass all uniforms and attributes normally to the fragment shader. Did I initialize the program correctly?
@mmvlad It did not help me. I suspect I have done something wrong while passing uniforms of attributes to the shader.
@toojuice I don’t understand why I need to use a custom command. I assign a shader to a node so that the shader was used during the rendering of that node. Shouldn’t it be just fine?
@naghekyan - No, you’re right. I shouldn’t be so quick to reply when I’m sleep deprived.
But, doing a quick test… changing the color value the fragment shader returns to a constant, causes the screen to be set to that color. So the output side works. It seems the input side is not working, as you suggested. I’ll play around a little more and report back if I find anything out.
@naghekyan - Hey sorry, I haven’t had much time to look into it and probably won’t have more time until next week.
I did download the original tutorial’s project and tested it out and saw that it work. I don’t see anything off the bat that’s different in your port, so I’m guessing there’s a setting or operational difference between the two engines (cocos2d-x and cocos2d).
Using Xcode’s OpenGL debugger, I see an error and a warning:
ERROR: Mipmapping enabled without a complete mip-chain Texture #0 has mipmapping enabled, but is missing levels of the mip-chain
WARNING: Uninitialized texture data Texture #0 is being used for a drawing call while it contains uninitialized data
I’d guess these are causing the problem. Will look more into it later
Here you can see how he explains why we need CustomCommand and also there is a good link about cocos2d-x 3 rendering pipeline: http://cocos2d-x.org/wiki/Cocos2d_v30_renderer_pipeline_roadmap. So I start to think, that the cocos2d/cocos2d-x-2.2.x approach is obsolete. And this is my mistake. I need to think in therms of rendering commands.
Ok, it’s taken me a while to get back to this, but I have an answer, of sorts. Some things that I learned along the way:
You don’t need to wrap the code in a custom command
It seems to be easier to use GLProgramState to interface with the shader
First, here’s the code I used:
// add "HelloWorld" splash screen"
auto sprite = Sprite::create("HelloWorld.png");
sprite->getTexture()->setAntiAliasTexParameters();
// position the sprite on the center of the screen
sprite->setPosition(_visibleSize / 2);
// add the sprite as a child to this layer
this->addChild(sprite);
const GLchar * fragmentSource = FileUtils::getInstance()->getStringFromFile("CSEColorRamp.fsh").c_str();
GLProgram* p = GLProgram::createWithByteArrays(ccPositionTextureA8Color_vert, fragmentSource);
p->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
p->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORD);
p->link();
CHECK_GL_ERROR_DEBUG();
p->updateUniforms();
CHECK_GL_ERROR_DEBUG();
sprite->setGLProgram(p);
Texture2D *_colorRampTexture = Director::getInstance()->getTextureCache()->addImage("colorRamp.png");
_colorRampTexture->setAliasTexParameters();
_colorRampTexture->retain();
// Here we set up which textures are associated with which shader variables
auto glProgramState = GLProgramState::getOrCreateWithGLProgram(p);
sprite->setGLProgramState(glProgramState);
glProgramState->setUniformTexture("u_texture", sprite->getTexture());
glProgramState->setUniformTexture("u_colorRampTexture", _colorRampTexture);
sprite->getGLProgram()->use();
Here are screenshots of with and without the shader:
You may have noticed that using the shader translates the position of the image for some reason I have not looked into why this is, but I hope it’s not terribly hard to debug.
Thank you very much @toojuice ! One difference I see is that I do sprite->setGLProgram(p); right after creating the program, but you have done that after binding attribute locations. Is this important?
Also you call sprite->getGLProgram()->use(); which is missing in my case and you use GLProgramState, which, indeed makes easier to pass uniforms to the program!
@naghekyan - sorry for the late reply. I’ve been really busy lately and completely missed it. I don’t think the location of sprite->setGLProgram(p); is very important. But you can experiment if you feel like it
CC_PMatrix is the projection matrix, where as the CC_MVPMatrix is the model, view, projection matrix. Since in 2d we are using ortho camera CC_PMatrix is enough to do calculations. I understand this way, if wrong correct me guys.