Environment :
cocos2d-x 3.14.1
The code is very simple first create a cc.DrawNode instance and draw a something in a empty scene:
var drawNode = new cc.DrawNode();
this.addChild(drawNode);
drawNode.setPosition(cc.winSize.width / 2, cc.winSize.height / 2);
drawNode.drawDot(cc.p(0, 0), 150, cc.color(255, 0, 0, 255));
and there will be a dot at the center of the screen in red and this works correctly on both web and native:
Then, apply a custom shader to the cc.DrawNode instance:
var shaderProgram = new cc.GLProgram(
"res/shader/shader_vert_drawnode.vsh",
"res/shader/shader_frag_drawnode.fsh"
);
shaderProgram.link();
shaderProgram.updateUniforms();
drawNode.setShaderProgram(shaderProgram);
and the shader is very simple:
// .vert
attribute vec4 a_position;
void main()
{
gl_Position = CC_PMatrix * CC_MVMatrix * a_position;
}
// .frag
void main()
{
gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
}
After doing this, the red dot will become a blue rect and this alse works correctly on both web and native:
And the last step, add a uniform
to the frag shader named u_test
and set the value from the code:
// .frag
uniform float u_testValue;
void main()
{
gl_FragColor = vec4(0.0, u_testValue, 0.0, 1.0);
}
and set the value from code :
var shaderProgram = new cc.GLProgram(
"res/shader/shader_vert_drawnode.vsh",
"res/shader/shader_frag_drawnode.fsh"
);
shaderProgram.link();
shaderProgram.updateUniforms();
drawNode.setShaderProgram(shaderProgram);
shaderProgram.use();
shaderProgram.setUniformLocationWith1f(
shaderProgram.getUniformLocationForName("u_testValue"),
1.0
);
But, this time, only in web I can get a green rect as expected :
In native, there will be nothing drawn on the screen and the reason is the rect is black which means the u_test
value is not passed to the frag shader.
I found a post on this topic here:
And two issues on github that are already fixed:
I debugged the demo on native a little bit and here is what I think is weird :
[1] the onDraw function in DrawNode calls
getGLProgramState()->apply(transform);
[2] the apply function handle the uniforms
applyUniforms();
[3] where the uniforms will be applied:
void GLProgramState::applyUniforms()
{
// set uniforms
updateUniformsAndAttributes();
for(auto& uniform : _uniforms) {
uniform.second.apply();
}
}
[4] and in my demo, there is one uniform in _uniforms that is u_test that need to be set and the code continues to
void UniformValue::apply()
{
// ...
case GL_FLOAT:
_glprogram->setUniformLocationWith1f(_uniform->location, _value.floatValue);
break;
}
[5] And I thinks here is where the issue happens, the updated value is true after calling the updateUniformLocation function but the value of f1 is 0 which I think should be 1.
void GLProgram::setUniformLocationWith1f(GLint location, GLfloat f1)
{
bool updated = updateUniformLocation(location, &f1, sizeof(f1)*1);
if (updated)
{
glUniform1f( (GLint)location, f1);
}
}
This is where I get so far the issue I still can not figure out what went wrong here , any suggestion will be appreciated, thanks