interpolate Perlin Noise

I’ve been tinkering around with noise textures recently (with the end goal being random terrain generation.) I had some pretty good progress today, actually getting a random noise texture to render on a quad object in Unity. The next step, as I understand, is to “smooth” out the noise so that the texture looks more like your standard height map texture. However, when I get to that stage, it leaves the texture looking very boxy and Jagged. I don’t know if this is due to some weirdness in the Texture class, or if my “smoothing” methods are flawed. Could use some help going in the right direction from here.

using UnityEngine;
using System.Collections;

public class TextureCreator : MonoBehaviour
{
    public int resolution = 128;

    [Range(2,64)]
    public int turbulence = 16;

    Color32 _color;
    Texture2D texture;

    int Width, Height;
    double[,] Noise;

    private void Awake()
    {
        Width = resolution;
        Height = resolution;
        Noise = new double[Width, Height];
       
        texture = new Texture2D(Width, Height, TextureFormat.RGB24, true);
        texture.name = "Perlin Noise Texture";
        texture.wrapMode = TextureWrapMode.Clamp;
        GetComponent<MeshRenderer>().material.mainTexture = texture;
        GenerateNoise();
        DisplayTurbulenceNoise();
        }
    }

    //Generates Random noise array
    private void GenerateNoise()
    {
        for (int x = 0; x < Width; x++)
        {
            for (int y = 0; y < Width; y++)
            {
                Noise[x, y] = Random.Range(0, 32768) / 32768.0;

            }
        }
    }

    //Interpolates or "smooths" the noise
    private double SmoothNoise(double x, double y)
    {
        double fractX = x - (int)x;
        double fractY = y - (int)y;

        int x1 = ((int)x + Width) % Width;
        int y1 = ((int)y + Height) % Height;

        int x2 = (x1 + Width - 1) % Width;
        int y2 = (y1 + Height - 1) % Height;
        double Value = 0.0;
        Value += fractX * fractY * Noise[x1, y1];
        Value += (1 - fractX) * fractY * Noise[x1, y2];
        Value += fractX * (1 - fractY) * Noise[x2, y1];
        Value += (1 - fractX) * (1 - fractY) * Noise[x2, y2];

        return Value;
    }

    //Calculates Noise Turbulence (Adding Noise Values together at different zoom levels)
    private double GenerateTurbulence(double x,double y,double size)
    {
        double value = 0.0;
        double initSize = size;
        while(size >= 1)
        {
            value += (SmoothNoise(x / size, y / size) * size);
            size /= 2.0;
        }
        return(128.0 * value / initSize);
    }

    //Draws the Noise Texture
    private void DisplayTurbulenceNoise()
    {
        for (int x = 0; x < Width; x++)
        {
            for (int y = 0; y < Height; y++)
            {
                _color.r = _color.g = _color.b = (byte)(GenerateTurbulence(x,y,turbulence));
                texture.SetPixel(x, y,_color);
            }
        }
        texture.Apply();
    }
}

66696-capture.png

Fixed My problem! The issue was in my smoothing algorithm, and after much tinkering around with different methods I resolved it. The changes from this code from the last code are the addition of the “Interpolate” and “InterpolateNoise” functions, as well as a change in “GenerateTurbulence” to use the new “InterpolateNoise” function instead of the “SmoothNoise” function


Note: There are also a few syntax differences in this code, as I wrote this in Windows Form C# in order to just create a bitmap image, instead of applying the noise to a texture in unity.

    private PictureBox picBox;
    private Bitmap _bitmap;
    private Graphics bitGraphics;
    private Color _color;

    private int Width, Height;
    private Double[,] Noise;
    private Random rand;
    private Random seed = new Random();
    private int _seed;
    private int Zoom = 1;
    private int octave = 64;

    private void GenerateNoise()
    {
            rand = new Random();
            for (int x = 0; x < Width; x++)
            {
                for (int y = 0; y < Width; y++)
                {
                    Noise[x, y] = (rand.Next() % 32768) / 32768.0;

                }
            }
        }
        private double Interpolate(double _x, double _y, double v)
        {
            double ft = v * 3.1415927;
            double f = (1 - Math.Cos(ft))*0.5;

            return _x * (1 - f) + _y * f;
        }
        private double InterpolateNoise(double x,double y)
        {
            int intX = (int)x;
            double fractX = x - intX;

            int intY = (int)y;
            double fractY = y - intY;

            double v1 = SmoothNoise(intX, intY);
            double v2 = SmoothNoise(intX + 1, intY);
            double v3 = SmoothNoise(intX, intY + 1);
            double v4 = SmoothNoise(intX + 1, intY + 1);

            double i1 = Interpolate(v1, v2, fractX);
            double i2 = Interpolate(v3, v4, fractX);

            return Interpolate(i1, i2, fractY);

        }
        private double SmoothNoise(double x, double y)
        {
            
            int intX = (int)x;
            double fractX = x - intX;

            int intY = (int)y;
            double fractY = y - intY;

            int x1 = (intX + Width) % Width;
            int y1 = (intY + Height) % Height;

            int x2 = (x1 + Width - 1) % Width;
            int y2 = (y1 + Height - 1) % Height;

            double Value = 0.0;
            Value += fractX * fractY * Noise[x1,y1];
            Value += (1 - fractX) * fractY * Noise[x1,y2];
            Value += fractX * (1 - fractY) * Noise[x2,y1];
            Value += (1 - fractX) * (1 - fractY) * Noise[x2,y2];
            return Value;
        }
        private double GenerateTurbulence(double x, double y, double size)
        {
            double value = 0.0;
            double initSize = size;
            while (size >= 1)
            {
                value += (InterpolateNoise(x / size, y / size) * size);
                size /= 2.0;
            }
            return (128.0 * value / initSize);
        }
        private void DisplayNormalNosie()
        {
            for(int x = 0;x< Width;x++)
            {
                for(int y = 0; y < Height;y++)
                {
                    byte value = (byte)(256 * Noise[x/Zoom, y/Zoom]);
                    _color = Color.FromArgb(value, value, value);
                    _bitmap.SetPixel(x, y, _color);
                }
            }
        }


        private void DisplayTurbulenceNoise()
        {
            for (int x = 0; x < Width; x++)
            {
                for (int y = 0; y < Height; y++)
                {
                    byte value = (byte)(GenerateTurbulence(x/Zoom,y/Zoom,octave));
                    _color = Color.FromArgb(value, value, value);
                    _bitmap.SetPixel(x, y, _color);
                }
            }
        }