Sign in to follow this  
Followers 0
MadJik

Donut distortion Effect Plugin

11 posts in this topic

Donut distortion Effect Plugin

What's this?

It would be more handy if I can find some good math skills to help me with sinus & co. formulas. Don't hesitate to PM if you like to solve my problem!

I'm not really happy with this distortion effect as I've not find the correct formula to apply what I had in mind.

But for now it gives some good results enough to be published.

How does it works?

The initial idea was to distort the image by a rotation between 2 circles and so create something like a Donut aspect. This is to illustrate the idea:

DonutSettings.png

The red Arc should be the distortion of the green segment.

The result for now is just a distortion between 2 circles... and I named it the Donut effect!

Before:

rays.jpg

After:

rays1.jpg

I've found 4 modes of distortions:

DonutModes.png

This is a test of the modes on lightrays:

DonutModes2.png

Download the DLL

Plugin Donut.dll

ar.pngHere is the DLLal.png

The source will be available soon with the plugins package!

How to install?

Close Paint.net

Unzip and place the DLL in your Effect folder usually: C:/Program Files/Paint.NET/Effects

The User interface

This plugin is added to the menu Effects, submenu Distort.

DonutUI.png

External radius (0,1000, dft 300)

Set the size of the donut by choosing its radius.

Internal radius (0,1000, dft 100)

Set the size of the hole of the donut.

Unit (checkbox, dft unchecked)

unchecked: External and internal raduis values are in pixels

checked: The values are in 1/1000 based on the smallest size of the selection.

- ex: for a 800x600 image, 1000 represents the full raduis of 600 = 300px

This is usefull to redo the effect over the image with a small selection here and there:

wooden.gif

Distortion angle (-360,+360, dft 10)

This value is issued to set the "strength" of the distortion.

Quality

Increasing the quality is slowering the rendering a bit, and should reduce the pixelisation.

Effect Mix

This is a slider to mix the final image with the orignal image to make the effect more or less subtile.

Mode

Choose the distortion mode (Soft, medium, hard, distroy).

Some examples:

Donut11.jpgDonut12.jpg

Donut21.jpgDonut22.jpg

Donut31.jpgDonut32.jpg

0

Share this post


Link to post
Share on other sites

This is an interesting idea. However, I think this effect can be used similar to Twist plug-in (there's two, one of them by pyrochild), and I could achieve similar effect using pyrochild's liquifying plug-in. I'm not knocking your effort. It seem there's more option in this one than with Twist.

0

Share this post


Link to post
Share on other sites

Hello,

i really loved your plugin , very cool results, Nice concept and design .. good job there ! keep it up.any way , i tried to do some tricks with this plugin + my Lines Fractal plugin , look what i got ! 784033588.png

by rendering Lines Fractal 2 times each on a layer, Then flipping one of them horizontally , then applying Donut to them several times.

Thanks for your effort :)

Ahmed

0

Share this post


Link to post
Share on other sites

I do like this "downloads" although it is simular to pyrochilds plugins, It is an interesting alternative :)

0

Share this post


Link to post
Share on other sites

Missed this is my sweeps. I can see the distinction clearly Madjik.

Especially in the distinction it will leave the center of the zone un affected which requires masking with swirl and is harder to control. Single pass approach. Overlapping this effect, as you've demonstrated lends a far more complex distortion than simple swirls and it avoid the hard center point that will occur from that approach.

Because of the matching distortion similar to Ripples, etc. it may even be nice to see a highlight added to this one. (Cursory overview request/suggestion and I've not seen the code to know if this is possible or not with this implementation.)

Thanks again Madjik for another wonderful tool in the arsenal. (Or first thanks in writing. Tons of thanks in my head while using PDN so far ... :mrgreen: )

Example of overlapping distortions that I was seeing before downloading. Only other thing that came from this was that I had to use a selection box/bounding box approach to position the distortion. Would love to have the positional box included (not sure that that thing is called in the interface programming.)

th_donuttest.png

And another example of what you absolutely cannot do with just swirling:

th_donut_not_swirl.png

Edited by delpart
0

Share this post


Link to post
Share on other sites
...it may even be nice to see a highlight added to this one.
Could you tell me more about this ?
Would love to have the positional box included (not sure that that thing is called in the interface programming.)
You just called it: interface! No chance for me to create such interface like for liquify or custom brushes. And this plugin isn't enough popular (due to its similarity) to spend too much effort on it.
2

Share this post


Link to post
Share on other sites

I knew I should have played with it more before posting that. =O And thought of learning a few part names and screen-shot examples. Here's some screen shots of the controls I was thinking of.

Could you tell me more about this ?

Ripple and drop ripple both have this highlight function. It can be used to create gradient effects and not just as a distortion. A similar approach could be applied to this plugin with that feature.

Obviously here I may be lacking the knowledge of how these other distorts function, but the use of highlight in both of them will change the outcome. Sometimes dramatically.

Brief example of drop ripple on a white canvas using the highlight to create the pattern and a gradient with no highlight showing the distortion it is creating. Also note the centering/positional control in the interface as that's what I was thinking the Donut needed.

th_ripple_example.jpg

And the function pointed out (since I made this screenshot might as well use it):

th_highlight_function.jpg

You just called it: interface! No chance for me to create such interface like for liquefy or custom brushes. And this plugin isn't enough popular (due to its similarity) to spend too much effort on it.

Sorry for the confusion here. While that would be wonderful to see a liquefy-like interface, I was just thinking of this control:

th_POSITION_CONTROL-1.jpg

I hope that helps explain my ramblings. Thanks again Madjik and I'm not wishing to demand those changes. Just my feedback from a user's point of view.

Edited by delpart
0

Share this post


Link to post
Share on other sites

The highlight is like a shadow or a light that could give some kind of volume aspect. I'll give it a try...

The offset control isn't too difficult to add but I think it isn't suitable for this effect as you should use the selection area for that. Maybe...

Your suggestions are good ideas. Thanks a lot for them!

0

Share this post


Link to post
Share on other sites

Thanks Madjik for the nice plugin, the Effect Mix feature is not functioning well with me, this happens only on transparent layer (shape/object on a 100% transparent layer) the orginal shape stays there, not sure how to get rid of it.

Thanks

0

Share this post


Link to post
Share on other sites

Thanks Madjik for the nice plugin, the Effect Mix feature is not functioning well with me, this happens only on transparent layer (shape/object on a 100% transparent layer) the orginal shape stays there, not sure how to get rid of it.

Thanks

You could fill the layer with a white color and use blend mode or

use a transparent background not at 0 but at 1... Full transparancy is not handled.

This is the source code you could adapt with the codelab.

 

// Title: Donut distortion
// Name: Donut
// Author: 2012 MadJik (Jean-Claude Jay)
// Submenu: Distort
// URL: http://forums.getpaint.net/index.php?showtopic=7186
// Version 1.2

#region UICode
	int Amount1 = 300; // [0,1000] External radius
	int Amount2 = 100; // [0,1000] Internal Radius
	bool Amount3 = false; // [0,1] Unit : Off=pixels, On=x/1000 of smallest side
	double Amount4 = 10; // [-360,360] Distortion angle
	int Amount5 = 2;   // [0,5] Quality (AntiAlias) 
	int Amount6 = 0; // [0,100] Highlight
	double Amount7 = 0; // [-1,1] Phase
	Pair<double, double> Amount8 = Pair.Create( 0.0 , 0.0 ); // Offset Blue
	int Amount9 = 100; // [0,100] Effect Mix
	byte Amount10=0;  // Mode|Soft|Medium|Hard|Distroy
#endregion
public const double FULL_PI = 3.14159265358979323846;
public const double DEUX_PI = FULL_PI * 2.0;
public const double DEGR_PI = FULL_PI / 180.0;
public float t = 0;
public float ph = 0;

ColorBgra EffectMix(ColorBgra dstpix, ColorBgra srcpix, double intensity)
{
	dstpix.R = (byte)(dstpix.R * intensity + (1.0 - intensity) * srcpix.R);
	dstpix.G = (byte)(dstpix.G * intensity + (1.0 - intensity) * srcpix.G);
	dstpix.B = (byte)(dstpix.B * intensity + (1.0 - intensity) * srcpix.;	
	return dstpix;
}

float Inlight(float x, float y, float ri, float re, float rm, float d)
{
	if ((d >= ri) || (d <= re))
	{
		d -= ri;
		float dist = (float)Math.Sqrt(d);
		float angle = dist * t - ph;
		float z = (float)(Math.Cos(angle) * (rm - dist)) ;
		return z;
	}
	return 0;
}


void Render(Surface dst, Surface src, Rectangle rect)
{
	Rectangle selection = EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt();
	int sL = selection.Left;
	int sR = selection.Right;
	int sT = selection.Top;
	int sB = selection.Bottom;
	int sW = sR - sL;
	int sH = sB - sT;
	int CenterX = (int)(sW * (1.0 + Amount8.First) / 2.0) + sL;
	int CenterY = (int)(sH * (1.0 + Amount8.Second) / 2.0)+ sT;

	// check the smallest amount
	float radE = Amount1; if (Amount2 > radE) radE= Amount2;
	float radI = Amount2; if (Amount1 < radI) radI= Amount1;
	float lm = (float)Amount6 * 0.05f;

	// radius in ?/00
	if (Amount3)
	{
		float fullval = sW; if (sH < sW) fullval = sH;
		float ratio = fullval / 2000.0f;
		radE = radE * ratio;
		radI = radI * ratio;
	}

	// amount must be different
	if (radE == radI) radE++;
	
	// Light
	float radM = radE - radI;
	t = (float)FULL_PI / radM;	
	ph = (float)(Amount7 * DEUX_PI);
	
	// calculate the squares
	float radE2 = radE * radE;
	float radI2 = radI * radI;
	
	// gap between radius
	float radM2 = radE2 - radI2;

	//distortion angle (strength)
	float angle = (float)(Amount4 * DEGR_PI); // Angle

	int r,g,b,a;
	double mix = Amount9 / 100.0;
	ColorBgra tmppix;

	// Variables for Anti-Aliasing 
	int aaLevel = Amount5; //Anti-Alias level 
	int aaSamples = aaLevel * aaLevel + 1;
	PointF[] aaPoints = new PointF[aaSamples];

	// Init table for AA (don't ask me how it works)  
	for (int s = 0; s < aaSamples; ++s)
	{
		double x = (s * aaLevel) / (double)aaSamples;
		double y = s / (double)aaSamples;
		x -= (int)x;
		// RGSS + rotation to maximize AA quality
		aaPoints[s] = new PointF((float)x - 0.5f, (float)y - 0.5f );
	}

	for (int y = rect.Top; y < rect.Bottom; y++)
	{
		for (int x = rect.Left; x < rect.Right; x++)
		{
			tmppix = src[x,y];
			float rX = (float)(x - CenterX);
			float rY = (float)(y - CenterY);
			b = 0; g = 0; r = 0; a = 0;
			int cptaa = 0;

			foreach (PointF pt in aaPoints)
			{
				float xaa = (float)(pt.X + rX);
				float yaa = (float)(pt.Y + rY);
				float tmpR = xaa * xaa + yaa * yaa;
				if ((tmpR >= radI2) && (tmpR <= radE2))
				{
					float tmp1 = radE2 - radI2;
					float tmp2 = (tmpR - radI2) / tmp1;

					// formula on selected mode	
					float w_angle =0;
					switch (Amount10)
					{
						case 0:
							w_angle = (float)((Math.Cos((1.0f - 2.0f * tmp2) * FULL_PI) + 1.0f) / 2.0f);
							break;
						case 1:
							w_angle = (float)(Math.Sin(tmp2 * FULL_PI));
							break;
						case 2:
						// circle
							float tmp3 = (tmp2 - 0.5f) * 2.0f;
							if (tmp3 == 1.0f)
								w_angle = 0;
							else
								w_angle = (float)(Math.Sqrt(1.0f - tmp3 * tmp3));
							break;
						case 3:
						// cos
							w_angle = (float)(Math.Cos(tmp2 * FULL_PI));
							break;
					}

					float c_angle = (float)Math.Cos(angle * w_angle);
					float s_angle = (float)Math.Sin(angle * w_angle);
					
					float srcX = (float)(CenterX + xaa * c_angle - yaa * s_angle);
					float srcY = (float)(CenterY + xaa * s_angle + yaa * c_angle);
					tmppix = src.GetBilinearSampleWrapped(srcX, srcY);
					if (tmppix.A == 0) tmppix = src[x,y];

					float Z = Inlight(xaa, yaa, radI, radE, radM, tmpR);
					if (Z != 0)
					{
						if (Z > 0)
						{
							int Light = (int) ((lm * Z) + 0.499f);
							if (Light > 0)
							{
								if (Light > 0xff)
								{
									Light = 0xff;
								}
								tmppix = ColorBgra.Blend(tmppix, ColorBgra.White, (byte) Light);
							}
						}
						else 
						{
							int Light = (int) ((lm * -Z) + 0.499f);
							if (Light > 0)
							{
								if (Light > 0xff)
								{
									Light = 0xff;
								}
								tmppix = ColorBgra.Blend(tmppix, ColorBgra.Black, (byte) Light);
							}
						}
					}

					cptaa++;
					r += tmppix.R;
					g += tmppix.G;
					b += tmppix.B;
					a += tmppix.A;						
				}
			}
			if (cptaa != 0)
			{
				tmppix.R = (byte)(r / cptaa);
				tmppix.G = (byte)(g / cptaa);
				tmppix.B = (byte)(b / cptaa);
				tmppix.A = (byte)(a / cptaa);
			}
			if (Amount9 < 100)
				dst[x,y] = EffectMix(tmppix, src[x,y], mix);
			else
				dst[x,y] = tmppix;
		}
	}
}
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0