Jump to content

Perlin Waves


pascal
 Share

Recommended Posts

Hello.

It has been a while, but I'm back with another plugin: Perlin Waves.

This plugin uses Perlin noise to generate a wave texture. It comes with a lot of configurable options.

I hope you like it!

 

Download: perlinwaves.zip

11-11-2021 update: bug fix and changed alpha settings

Effect can be found in Effects > Render > Perlin Waves

 

Preview:

demo2.jpg.09948a522b9287bdb44a8401aeb7a044.jpg

 

Code:

A part of the code comes from this Perlin noise implementation

Spoiler
// Name: Perlin Waves
// Submenu: Render
// Author: pascal
// Title: Generate Perlin Waves
// Version: 1.0
// Desc:
// Keywords:
// URL:
// Help:
#region UICode
ColorWheelControl col1 = ColorBgra.FromBgr(0, 0, 0); // Line Color
ColorWheelControl col2 = ColorBgra.FromBgr(255, 255, 255); // Background Color
IntSliderControl zoom = 50; // [1,200] Zoom
IntSliderControl rotate = 0; // [0,1000] Move
IntSliderControl width = 10; // [1,1000] Thickness
IntSliderControl seed = 1; // [1,1000] Seed
IntSliderControl smooth = 2; // [0,2] Interpolation
IntSliderControl height = 50; // [0,100] Height
IntSliderControl contr = 0; // [0,100] Contrast
ListBoxControl alpha = 0; // Alpha Mode|Overlay|Preserve|Preserve Inverted|Transparent|Transparent Inverted|Blend|Blend Inverted|Clip|Clip Inverted
#endregion


class vector{
    public float x;
    public float y;
}


void Render(Surface dst, Surface src, Rectangle rect)
{
    for(int y = rect.Top; y < rect.Bottom; y++)
    {
        for(int x = rect.Left; x < rect.Right; x++)
        {
            if(IsCancelRequested) return;

            float val = (perlin(x / (float)zoom, y / (float)zoom) + 1) / 2f;
            float col = 0;
            float w = width / 1000f;
            float h = contrastR(height / 100f, 2);

            if(val > h - w && val < h + w)
            {
                if(val < h)
                {
                    col = contrast(map(val, h - w, h, 0, 1), contr * contr / 100f);
                }
                else
                {
                    col = contrast(map(val, h + w, h, 0, 1), contr * contr / 100f);
                }
            }

            ColorBgra cp = new ColorBgra();
            cp.R = limit(col * col1.R + (1 - col) * col2.R);
            cp.G = limit(col * col1.G + (1 - col) * col2.G);
            cp.B = limit(col * col1.B + (1 - col) * col2.B);

            switch(alpha)
            {
                case 1:
                cp.A = src[x, y].A;
                break;
                case 2:
                cp.A = limit(255-src[x, y].A);
                break;
                case 3:
                cp = col1;
                cp.A = limit(col * 255);
                break;
                case 4:
                cp = col2;
                cp.A = limit((1 - col) * 255);
                break;
                case 5:
                cp = col1;
                cp.A = limit(col * 255);
                cp = blend(cp, src[x, y]);
                break;
                case 6:
                cp = col2;
                cp.A = limit((1 - col) * 255);
                cp = blend(cp, src[x, y]);
                break;
                case 7:
                cp = col1;
                cp.A = limit(col * src[x, y].A);
                break;
                case 8:
                cp = col2;
                cp.A = limit((1 - col) * src[x, y].A);
                break;
                default:
                cp.A = (byte)255;
                break;
            }

            dst[x, y] = cp;
        }
    }
}


byte limit(float x)
{
    return (byte)Math.Max(0, Math.Min(255, x));
}


float map(float val, float min0, float max0, float min1, float max1)
{
    return min1 + (val - min0) / (max0 - min0) * (max1 - min1);
}


float contrast(float val, float con)
{
    if(val < 0.5)
    {
        return (float)(Math.Pow(2 * val, 1 + con) / 2);
    }
    else
    {
        return (float)(1 - Math.Pow(-2 * val + 2, 1 + con) / 2);
    }

}


float contrastR(float val, float con)
{
    if(con == 0f) return val;
    if(val < 0.5)
    {
        return (float)(0.5 - Math.Pow(-2 * val + 1, 1 + con) / 2);
    }
    else
    {
        return (float)(0.5 + Math.Pow(2 * val - 1, 1 + con) / 2);
    }
}


ColorBgra blend(ColorBgra a, ColorBgra b)
{
    if(a.A == 0 && b.A == 0) return ColorBgra.FromBgra(0, 0, 0, 0);

    float alpha = a.A / 255f;
    float alphaB = b.A / 255f;
    float alpha0 = alpha + alphaB * (1 - alpha);

    byte R = limit((a.R * alpha + b.R * alphaB * (1 - alpha)) / alpha0);
    byte G = limit((a.G * alpha + b.G * alphaB * (1 - alpha)) / alpha0);
    byte B = limit((a.B * alpha + b.B * alphaB * (1 - alpha)) / alpha0);
    byte A = limit(alpha0 * 255);

    return ColorBgra.FromBgra(B, G, R, A);
}


vector randomGradient(int ix, int iy)
{
    uint w = (uint)seed;
    uint s = w / 2;
    uint a = (uint)ix; uint b = (uint)iy;
    a *= 3284157443; b ^= a << (int) s | a >> (int)(w - s);
    b *= 1911520717; a ^= b << (int) s | b >> (int)(w - s);
    a *= 2048419325;
    float random = (float)(a * (3.14159265 / ~(~0u >> 1)) + rotate / 1000f * Math.Tau);
    vector v = new vector();
    v.x = (float)Math.Sin(random);
    v.y = (float)Math.Cos(random);
    return v;
}


float dotGridGradient(int ix, int iy, float x, float y)
{
    vector gradient = randomGradient(ix, iy);
    float dx = x - (float)ix;
    float dy = y - (float)iy;
    return (dx*gradient.x + dy*gradient.y);
}


float interpolate(float a0, float a1, float w)
{
    if (0.0 > w) return a0;
    if (1.0 < w) return a1;
    switch(smooth){
        case 0:
            return (float)((a1 - a0) * w + a0);
        case 1:
            return (float)((a1 - a0) * (3.0 - w * 2.0) * w * w + a0);
        default:
            return (float)((a1 - a0) * ((w * (w * 6.0 - 15.0) + 10.0) * w * w * w) + a0);
    } 
}


float perlin(float x, float y)
{
    int x0 = (int)x;
    int x1 = x0 + 1;
    int y0 = (int)y;
    int y1 = y0 + 1;

    float sx = x - (float)x0;
    float sy = y - (float)y0;

    float n0, n1, ix0, ix1, value;

    n0 = dotGridGradient(x0, y0, x, y);
    n1 = dotGridGradient(x1, y0, x, y);
    ix0 = interpolate(n0, n1, sx);

    n0 = dotGridGradient(x0, y1, x, y);
    n1 = dotGridGradient(x1, y1, x, y);
    ix1 = interpolate(n0, n1, sx);

    value = interpolate(ix0, ix1, sy);
    return value;
}

 

Edited by pascal
moved code into spoiler
  • Like 3
  • Thanks 1
  • Upvote 3
Link to comment
Share on other sites

This is very cool @pascal!  Thank you for sharing with us.  I already have a few ideas... 😁

 

Perlin Waves with Diffuse:

perlinwaves_01.png

Image from an idea:

perlinwaves_02.png

 

 

 

Edited by lynxster4
added idea image
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...