Radial Gradient

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.

That’s interesting, but can I achieve same results like with currently implementated gradient?

Thanks, works perfectly :slight_smile:

But i can see the png with correct result. I tested on iOS simulator.

@Joseph39 good job, it is smart to do it like this.

Tested on simulator too. Thats strange, but when using another color:
LayerRadialGradient::create(Color4B(179, 232, 184, 89), Color4B(0, 90, 128, 0), 600,center, 0.0f);

Image will be blank, but on simulator it’s ok.

Did you mean it can not work on device? What device did you test on?

No, I’m testing on simulator only. Just try that another color. Also, disable code for other gradients on the scene…

Ok, i will test i tomorrow.

Yep, this color will make image blank. It is strange.

@anon98020523 the effect is ok, we can not see the same result as simulator is because the background color of simulator is black, and render texture’s background color is white. If you do it like this:

LayerRadialGradient *gradient = LayerRadialGradient::create(Color4B(179, 232, 184, 89), Color4B(0, 90, 128, 0), 200, Vec2(200, 200), 0.0f);
    addChild(gradient);
    RenderTexture* render = RenderTexture::create((int)Director::getInstance()->getWinSize().width,
                                                  (int)Director::getInstance()->getWinSize().height, Texture2D::PixelFormat::RGBA8888);
    
    render->beginWithClear(0, 0, 0, 255);
    gradient->visit();
    render->end();
    render->saveToFile("ololo.png",Image::Format::PNG);

Then the effect is the same.

Thats again strange, but when bg is black, image is ok. It’s full and bright. But I need a transparent bg color, so I’m doing render->beginWithClear(0, 0, 0, 0); and with it - image is very poor.

render->beginWithClear(0, 0, 0, 255);

output this image(not edited):

But, changing bg opacity to 0:

render->beginWithClear(0, 0, 0, 0);

output this (I edited file in Photoshop afterwards - just added black background under rendered image):

And if you take a look carefully - on the top of this image there are a little bit some color…

@zhangxm I get back to this now. Problem with render my gradient is because of this bug renderTexture saveToFile artifacts can you please take a look? Bug already created on github.

Could you please paste the github issue link? I will take a look after releasing v3.16.

@anon98020523 thanks.

Also, Just take code and images from zip file to test from this post - renderTexture saveToFile artifacts it’s reproduced easily.

@Joseph39 Hey, I’m trying to use your super smart solution and match with my gradient:
LayerRadialGradient::create( Color4B(179, 232, 184, 89), Color4B(0, 90, 128, 0), 200, Vec2(200, 200), 0.0f);

With it I get current result:

07

But I’m trying your method using same colors from this post and get:

06

Color looks cool :slight_smile: but it’s really different from what I specified:

Color4B borderColor1(Color4B(179, 232, 184, 89));
Color4B centerColor1(Color4B(0, 90, 128, 0));