Radial Gradient

Anyone? @zhangxm ? Any official comments? Can you add radial type of gradient?

Bump, please help :worried:

Use this

Thats not even answer…/ I need for some GradientLayer (radial…) from cocos2d-x. Is cocos2d devs able to do so? Or anyone?

try this. Call it with something like this:

void yourclass::layerSetup (){

//random colors, change for what you need

auto gCb = [](){
    GLubyte val = RandomHelper::random_int(0, 255);
    return val;
};

auto pmI = [](){
    int val = RandomHelper::random_int(-1, 1);
    return val;
};


Color4B startColor = Color4B(gCb(),gCb(),gCb(),(gCb()+128)/2);
Color4B endColor = Color4B(gCb(),gCb(),gCb(),(gCb()+128)/2);

auto dirVec = Vec2(pmI()*(RandomHelper::random_real(s_origin.x, s_visibleSize.width)),
                   (pmI())*(RandomHelper::random_real(s_origin.y, s_visibleSize.height)));

auto levelGradient = LayerGradient::create(startColor, endColor, dirVec);

levelGradient->setContentSize(s_visibleSize);
levelGradient->setPosition(s_origin);
levelGradient->setName("levelGradient");
addChild(levelGradient,-9999);

auto shaderLayer = ShaderLayer::create("game.glsl");
addChild(shaderLayer);

}

hope it helps. Ended up my tricks, man

Thanks. Thats looks very promising, but it’s not radial. How this can be modified to radial, like this:

I don’t know. Maybe you could use a clipping node like in cocos2dx 3.6 How to Mask sprite in circle

Nope, I mean that I need radial gradient, currently it’s linear gradient with direction… Clipping gives nothing, but just cut corers…
I believe that shader should be modified to something like here - https://github.com/SFML/SFML/wiki/Source:-Radial-Gradient-Shader but I have no idea how to implement this…

Is there some chance of official responce from cocos2d-x devs? @slackmoehrle this thread totally ignored, no help, why? I feels like when I post something on the forum it’s a really low chance get official response…

I can ask someone to take a look at this thread. GDC was a primary focus for us these last few weeks.

Also, remember that these forums are for everyone to participate. We don’t staff these forums as a dedicated support mechanism. We also participate as much as possible but each day varies with our other responsibilities. An official response to each thread would take full-time resources we don’t have,

1 Like

Thanks, looking forward for radial gradient layer… :slight_smile:

@zhangxm looks like I’ve got some bug with RadialGradient.
Could you please take a look(last comment in this issue): https://github.com/cocos2d/cocos2d-x/issues/17480#issuecomment-306922153

I think i fixed it, and i added comment in the issue.

Hey @zhangxm. I have two questions about radial again :slight_smile:

  1. how I can use RenderTexture to get LayerRadialGradient just as sprite? Using just radial->visit(); gives me zero image…
  2. when I’m adding at same position on same node one radial gradient on top of another - I’ve got fps drop from 60fps to 30-45fps. And really lagging gameplay. What can it be? Any ideas? As soon as I remove one of any gradients, fps goes to solid 60. (for some reason I can’t re-create same situation in cpp-test, to show).

Actually if 1st will be solved… I probably just will render once my radial gradient and use it as static image, to improve performance.

Hi @anon98020523. About question 1), could you please show a the codes?
About question 2), radial gradient is cost because the fragment shader will loop each pixel, so you’d better don’s use it frequently.

Sure, but it’s just standard.

Vec2 pos = posByScreen(0.5, 1.0);
    LayerRadialGradient *gradient = LayerRadialGradient::create(Color4B(145, 106, 209, 140), Color4B(0, 0, 0, 0), 600, pos, 0.0f);
    addChild(gradient);
    RenderTexture* render = RenderTexture::create((int)Director::getInstance()->getWinSize().width,
                                                  (int)Director::getInstance()->getWinSize().height, Texture2D::PixelFormat::RGBA8888);

    render->begin();
    gradient->visit();
    render->end();
    render->saveToFile("ololo.png",Image::Format::PNG);

I see, so it’s ideal for me to just create a static sprite from it.

I can see the result, how did you check the result png?

Ok how about a procedurally generated texture like this:

static float smoothstep(float edge0, float edge1, float x) {
	float t = clampf((x - edge0) / (edge1 - edge0), 0.0, 1.0);
	return t * t * (3.0 - 2.0 * t);
}

static Texture2D* generateRadialGradientTexture(int size) {

	auto colors = new (std::nothrow) GLubyte[size * size * 4];
	Color4B color(Color4B::WHITE);// change it to whatever you want

	for (int y = 0; y < size; y++)
	{
		for (int x = 0; x < size; x++)
		{
			auto uv = Vec2(x, y) / size;

			float distance = uv.distance(Vec2(0.5, 0.5));
			float alpha = smoothstep(0.5, 0.0, distance) * 0.3;

			int idx = (y * size + x) * 4;
			colors[idx + 0] = color.r;
			colors[idx + 1] = color.g;
			colors[idx + 2] = color.b;

			//alpha
			colors[idx + 3] = clampf(alpha * 256.f + 0.5f, 0.f, 255.f);
		}
	}

	auto txt = new Texture2D();
	txt->initWithData(colors, size * size * 4, Texture2D::PixelFormat::RGBA8888, size, size, Size(size, size));

	delete[] colors;
	return txt;
}

then simply this:

auto tex = generateRadialGradientTexture(256);
auto spr = Sprite::createWithTexture(tex);
spr->setPosition(winSize / 2);
this->addChild(spr);
1 Like

or what about this:

// with translucent edges
static Texture2D* generateRadialGradientTexture(int size) {
	auto radius = size / 2;
	auto colors = new (std::nothrow) GLubyte[size * size * 4];

	Vec3 col = Vec3(1, 1, 0);

	Vec2 center(radius, radius);
	for (int y = 0; y < size; y++)
	{
		for (int x = 0; x < size; x++)
		{
			// background
			Vec3 color = Vec3(1, 1, 1);

			float dist = (Vec2(x, y) - center).length();
			float f = dist / radius;

			f = sqrt(clampf(1.f - f*f, 0., 1.0));
			float step = smoothstep(radius, radius, dist);
			auto val = 1.f - step;

			color -= col * val * f;

			int idx = (y * size + x) * 4;
			float r = clampf(color.x * 256.f + 0.5f, 0.f, 255.f);
			float g = clampf(color.y * 256.f + 0.5f, 0.f, 255.f);
			float b = clampf(color.z * 256.f + 0.5f, 0.f, 255.f);
			float a = clampf(f * 256.f + 0.5f, 0.f, 255.f);

			///////////////////////////////
			colors[idx + 0] = std::abs(r);
			colors[idx + 1] = std::abs(g);
			colors[idx + 2] = std::abs(b);
			colors[idx + 3] = std::abs(a);
		}
	}

	auto txt = new Texture2D();
	txt->initWithData(colors, size * size * 4, Texture2D::PixelFormat::RGBA8888, size, size, Size(size, size));

	delete[] colors;
	return txt;
}
1 Like

or even this:

static Color4B Lerp(const Color4B& value1, const Color4B& value2, float amount)
{
	amount = clampf(amount, 0.0f, 1.0f);
	return Color4B(
		(int)MathUtil::lerp(value1.r, value2.r, amount),
		(int)MathUtil::lerp(value1.g, value2.g, amount),
		(int)MathUtil::lerp(value1.b, value2.b, amount),
		(int)MathUtil::lerp(value1.a, value2.a, amount)
	);
}

static float Falloff(float distance, float maxDistance, float scalingFactor)
{
	if (distance <= maxDistance / 3)
	{
		return scalingFactor * (1 - 3 * distance * distance / (maxDistance * maxDistance));
	}
	else if (distance <= maxDistance)
	{
		float x = 1 - distance / maxDistance;
		return (3.f / 2.f) * scalingFactor * x * x;
	}
	else
		return 0;
}

static float Falloff(float distance, float maxDistance)
{
	return Falloff(distance, maxDistance, 1.f);
}

static Texture2D* generateRadialGradientTexture(int size) {
	auto radius = size / 2;
	auto colors = new (std::nothrow) GLubyte[size * size * 4];

	Color4B borderColor(Color4B::RED);
	Color4B centerColor(Color4B::YELLOW);

	for (int y = 0; y < size; y++)
	{
		for (int x = 0; x < size; x++)
		{
			float distance = Vec2::ONE.distance(Vec2(x, y) / radius);
			float alpha = Falloff(distance, 1, 1);

			int idx = (y * size + x) * 4;
			float innerGradient = Falloff(distance, 0.6f, 0.8f);
			auto color = Lerp(borderColor, centerColor, innerGradient);

			colors[idx + 0] = color.r;
			colors[idx + 1] = color.g;
			colors[idx + 2] = color.b;

			//alpha
			colors[idx + 3] = (GLbyte)clampf(alpha * 256.f + 0.5f, 0.f, 255.f);
		}
	}

	auto txt = new Texture2D();
	txt->initWithData(colors, size * size * 4, Texture2D::PixelFormat::RGBA8888, size, size, Size(size, size));

	delete[] colors;
	return txt;
}
        // color presets
    	Color4B borderColor1(Color4B::RED);
    	Color4B centerColor1(Color4B::YELLOW);

    	Color4B borderColor2(Color4B::BLUE);
    	Color4B centerColor2(Color4B(0, 255, 255, 255));

    	Color4B borderColor3(Color4B::GREEN);
    	Color4B centerColor3(Color4B::YELLOW);

    	Color4B borderColor4(Color4B::MAGENTA);
    	Color4B centerColor4(Color4B::WHITE);

    	Color4B borderColor5(Color4B::RED);
    	Color4B centerColor5(Color4B::RED);
2 Likes

I just opened it and it was just blank.