How to draw this gradient?

I need to draw gradients like this one

I would like to be able to change the color1 and the color2.
And I would like the result to look smooth on all screens.

I can draw the gradients in a graphics editor, but I think that there is a better solution.
Maybe OpenGL?

Any advice is very appreciated. Maybe some sample code?

1 Like

Hi. Shader can do it easy.
But shader and stuff sometimes hard to use. but in my example it is very simple. Just do this step by step:
1- Create one dummy sprite

auto s = Sprite::create("notImportantImage.png");
addChild(s);

2- write this lines for shader attaching to this sprite.

auto fileUtiles = cocos2d::FileUtils::getInstance();
auto fragmentFullPath = fileUtiles->fullPathForFilename("gradient.fsh");
auto fragSource = fileUtiles->getStringFromFile(fragmentFullPath);   
cocos2d::GLProgramState* glState=GLProgramState::getOrCreateWithGLProgram(cocos2d::GLProgram::createWithByteArrays(cocos2d::ccPositionTextureColor_noMVP_vert, fragSource.c_str()));
s->setGLProgramState(glState);

3- create fragment shader file and name it gradient.fsh and put this file in resource folder of your project.
4- In gradient.fsh write this code:

varying vec4 v_fragmentColor;
varying vec2 v_texCoord;

void main()
{
 float a = 2.0 * abs(v_texCoord.x - 0.5);
 vec4 color1 = vec4(1.0,0.0,0.0,1.0);
 vec4 color2 = vec4(0.0,0.0,1.0,1.0);
 gl_FragColor = color1 * a + color2 * (1.0 - a);
}

I can’t check now if it’s works or not but you know the concept.

1 Like

It is awesome!!

And it works like a charm.

A little bit different gradient, but good enough for me.

Some modifications

varying vec4 v_fragmentColor;
varying vec2 v_texCoord;

void main()
{
 float a = 1.8 * abs(v_texCoord.x - 0.5);
 vec4 color1 = vec4(1.0,0.215,0.725,1.0);
 vec4 color2 = vec4(0.5,0.925,1.0,1.0);
 gl_FragColor = color1 * a + color2 * (1.0 - a) * 1.1;
}

And I got

Thank you! Thank you! Thank you!

Only one moment. Now I am using a white image (540x960) to create the sprite. I am wondering if I can create the image by the code instead? I looked in the API reference, but did not find anything.

I played with it a little.

auto back = Sprite::create("0.png");
back->setPosition(origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 2);

this->addChild(back);

const char* fShader = R"(
uniform vec4 color1;
uniform vec4 color2;

varying vec4 v_fragmentColor;
varying vec2 v_texCoord;

void main()
{
float a = 1.5 * abs(v_texCoord.x - 0.5);
gl_FragColor = color1 * a + color2 * (1.0 - a);
}
)";

auto color1 = Vec4(1.0, 0.215, 0.725, 1.0);
auto color2 = Vec4(0.5, 0.925, 1.0, 1.0);

auto glState = GLProgramState::create(GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fShader));
glState->setUniformVec4("color1", color1);
glState->setUniformVec4("color2", color2);

back->setGLProgramState(glState);

I really hope that I did not break anything. :slight_smile:

Glad to help you.
My code is linear distribution between two colour. you can use non linear for some cool effects.
Try to use colours as uniform in shader and then you can animate your colours and that’s the power of shaders.

1 Like

I think that v_texCoord is the normalized coordinate of each fragment (correct me if I am wrong). Although it took me a while to figure it out. :smile:

So I think that the easiest way to get a smooth color transition in the center is to use

float a = - 4 * v_texCoord.x * v_texCoord.x + 4 * v_texCoord.x;

I already used uniform in my code in the previous post and it seems that it works. I just thought that it is better to have a set colors than a set of shaders. But it is a cool idea to try to animate it.

Another newbie question.
If I create a sprite using a 10x10 image, then how many times will the fragment shader be called? 100?

@slackmoehrle Could you help please?

We have a new “LayerGradient” class in v3.16.

I do not see how I can get this gradient with LayerGradient.
Or do you suggest using two gradients one by one?

And I looked in the source code of CCLayer.cpp and it is interesting that LayerColor (and LayerGradient) does not use the image. Although I am still too newbie to fully understand the code.

Apparently I need to study the manual on the opengl.org carefully and for a long time, because now I kind of fell in love with shaders. :smile:

p.s.
@slackmoehrle We still do not have the 3.16 api reference on the site.