Skip to content

Latest commit

 

History

History
149 lines (126 loc) · 5.14 KB

noise.md

File metadata and controls

149 lines (126 loc) · 5.14 KB

Noise

Flax contains various utilities for sampling different noise functions such as:

Noise Preview
Perlin Perlin Noise
Simplex Simplex Noise
Worley Worley Noise
Voronoi Voronoi Noise
Custom Custom Noise

Those can be accessed via scripting FlaxEngine.Utilities.Noise static class and used to enrich procedurally generated worlds and content.

Noise in Materials/Particles

Material Graph Noise Nodes

All visual graphs (materials, particles, animations) can sample noise functions both on CPU and GPU to enrich the content. All noise functions return normalized results in the range 0-1. Some of them return more noise components, such as Voronoi Noise where X=minDistToCell, Y=randomColor, Z=minEdgeDistance. Depending on the context only one or even all components can be used. Follow the tooltip with documentation for every node.

Noise preview control

Below is a sample code for custom UI Control that can be added to the scene for debugging or testing different noise types visually. Simply create UI Canvas, add UI Control to it, set control type to NoisePreview, and use NoiseType with NoiseScale properties to analyze noises.

public class NoisePreview : ContainerControl
{
    private GPUTexture _tempTexture;
    private byte[] _data;
    private Noises _noise = Noises.None;
    private float _scale;

    public enum Noises
    {
        [HideInEditor]
        None,
        Perlin,
        Simplex,
        Voronoi,
        Worley,
        Custom,
    }

    /// <summary>
    /// Noise to preview.
    /// </summary>
    public Noises NoiseType = Noises.Perlin;

    /// <summary>
    /// Noise scale.
    /// </summary>
    [Limit(0.001f)]
    public float NoiseScale = 10.0f;

    /// <inheritdoc />
    public NoisePreview()
    {
        Size = new Float2(64);
    }

    /// <inheritdoc />
    public override void DrawSelf()
    {
        base.DrawSelf();

        if (!_tempTexture)
        {
            // Create new GPU texture
            var texture = new GPUTexture();
            _tempTexture = texture;
            var desc = GPUTextureDescription.New2D(64, 64, PixelFormat.R8G8B8A8_UNorm, GPUTextureFlags.ShaderResource);
            if (texture.Init(ref desc))
                return;
        }

        if (_noise != NoiseType || _scale != NoiseScale)
        {
            // Update noise texture
            _noise = NoiseType;
            _scale = NoiseScale;
            UpdateTexture();
        }

        // Draw noise texture
        Render2D.DrawTexture(_tempTexture, new Rectangle(Float2.Zero, Size));
    }

    /// <inheritdoc />
    public override void OnDestroy()
    {
        // Ensure to cleanup resources
        _tempTexture?.ReleaseGPU();
        FlaxEngine.Object.Destroy(ref _tempTexture);

        base.OnDestroy();
    }

    private unsafe void UpdateTexture()
    {
        var desc = _tempTexture.Description;
        var size = desc.Width * desc.Height * PixelFormatExtensions.SizeInBytes(desc.Format);
        if (_data == null || _data.Length != size)
            _data = new byte[size];
        fixed (byte* dataPtr = _data)
        {
            // Generate pixels data
            Float2 uv;
            var colorsPtr = (Color32*)dataPtr;
            for (int y = 0; y < desc.Height; y++)
            {
                uv.Y = (float)y / desc.Height * _scale;
                for (int x = 0; x < desc.Width; x++)
                {
                    uv.X = (float)x / desc.Width * _scale;

                    // Sample noise at uv location
                    var noise = Vector3.Zero;
                    switch (_noise)
                    {
                    case Noises.Perlin:
                        noise = new Vector3(FlaxEngine.Utilities.Noise.PerlinNoise(uv));
                        break;
                    case Noises.Simplex:
                        noise = new Vector3(FlaxEngine.Utilities.Noise.SimplexNoise(uv));
                        break;
                    case Noises.Voronoi:
                        noise = FlaxEngine.Utilities.Noise.VoronoiNoise(uv);
                        break;
                    case Noises.Worley:
                        noise = new Vector3(FlaxEngine.Utilities.Noise.WorleyNoise(uv), 0.0f);
                        break;
                    case Noises.Custom:
                        noise = new Vector3(FlaxEngine.Utilities.Noise.CustomNoise(new Float3(uv, 0.0f)));
                        break;
                    }

                    colorsPtr[y * desc.Width + x] = (Color32)(Color)noise;
                }
            }

            // Update texture data on a GPU (send data)
            uint rowPitch = (uint)size / (uint)desc.Height;
            uint slicePitch = (uint)size;
            GPUDevice.Instance.MainContext.UpdateTexture(_tempTexture, 0, 0, new IntPtr(dataPtr), rowPitch, slicePitch);
            _tempTexture.ResidentMipLevels = 1; // Mark mip-map as available (required for standard textures only - other than render textures)
        }
    }
}