PixelsForGlory / VoronoiDiagram

Library to create voronoi diagrams in Unity3D.
MIT License
37 stars 3 forks source link

Issue with Get1DSampleArray, Get2DSampleArray #2

Open Ownezx opened 3 years ago

Ownezx commented 3 years ago

As I was trying to use the library I came across two problems as I was using those function. First, the first column and line are always empty and uninitialized as can be seen on this image (although the unity background is grey, we can clearly see a black line and column on the quad):

Screenshot 2020-11-15 at 20 12 26

Second, with a low amount of points sometimes the whole array is not set resulting in the following result when displaying it (This time the black region is not limited to the line and column):

Screenshot 2020-11-15 at 20 12 07

The error was produced by attaching the following mono behaviour code attached below to a 100x100 scaled quad with settings {numberOfPoints = 4 or 5, relaxation = 1, seed = 130}:

If I do end up fixing the issues I will put a pull request.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using PixelsForGlory.ComputationalSystem;
using System.Linq;
using UnityEditor;

/// <summary>
/// This is a test monobehavior to show how the voronoi diagram work
/// To use attach this script to a newly created quad.
/// Make sure your quad has a scale of around 1000x1000 as that will be the number
/// of pixels on the texture.
/// 
/// Additionnaly, since the creation of the texture is very slow an editor
/// script allows to generate the diagram on the press of a button on the editor.
/// </summary>
public class VoronoiExample : MonoBehaviour
{
    /// <summary>
    /// Total number of points
    /// </summary>
    [Tooltip("Total number of points")]
    [Range(0, 500)]
    public int numberOfPoints = 10;

    /// <summary>
    /// Relaxation of the diagram, if you just want to generate the diagram and
    /// not affect the points use 1 as a value.
    /// </summary>
    [Tooltip("Relaxation of the diagram, if you just want to generate the" +
        " diagram and not affect the points use 1 as a value.")]
    [Range(1, 50)]
    public int relaxation = 1;

    /// <summary>
    /// Random seed in order to 
    /// </summary>
    public int seed = 0;

    [Tooltip("Radius of the gizmos that show the points")]
    public float gizmoRadius = 1;

    /// <summary>
    /// Saved site in order to display them with gizmos
    /// </summary>
    List<VoronoiDiagramSite<Color>> sites = new List<VoronoiDiagramSite<Color>>();

    /// <summary>
    /// Saved size of the quad so we can move the gizmos in the correct place
    /// </summary>
    private Vector2 size;

    public void Generate()
    {
        MeshRenderer renderer = gameObject.GetComponent<MeshRenderer>();
        int width = (int)gameObject.transform.localScale.x;
        int height = (int)gameObject.transform.localScale.y;
        size = gameObject.transform.localScale;

        var voronoiDiagram = new VoronoiDiagram<Color>(new Rect(0f, 0f, width, height));

        Random.InitState(seed);

        // Clear and generate new points
        sites.Clear();
        while (sites.Count < numberOfPoints)
        {
            int randX = Random.Range(0, width - 1);
            int randY = Random.Range(0, height - 1);

            var point = new Vector2(randX, randY);
            Debug.Log(point);
            if (!sites.Any(item => item.Coordinate == point))
            {
                sites.Add(new VoronoiDiagramSite<Color>(point, new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f))));
            }
        }

        // Add the sites to the diagram
        voronoiDiagram.AddSites(sites);
        // Generate voronoi diagram
        voronoiDiagram.GenerateSites(relaxation);

        // Generate 2D unity texture
        var texture = new Texture2D(width, height);
        renderer.sharedMaterial.mainTexture = texture;

        texture.SetPixels(voronoiDiagram.Get1DSampleArray());
        texture.anisoLevel = 0;
        texture.filterMode = FilterMode.Point;
        texture.Apply();

        // Set the material of the quad
        renderer.sharedMaterial.mainTexture = texture;
    }

    /// <summary>
    /// As long as the quad is not rotated the center will be shown correctly
    /// </summary>
    private void OnDrawGizmos()
    {
        foreach (var p in sites)
        {
            Gizmos.DrawSphere(gameObject.transform.position + (Vector3)(p.Coordinate - size / 2), gizmoRadius);
        }
    }
}
Ownezx commented 3 years ago

Given another situation with {numberOfPoints = 10, relaxation = 1, seed = 188} some pixels are not considered in any sites (see the black pixel between dark pink and dark blue on the bottom left of the image) :

Screenshot 2020-11-15 at 21 26 05

This was found while trying to make a function that would find the site of the current position.

afuzzyllama commented 3 years ago

Thanks for bringing this up. I haven't looked at the code in quite sometime and I'm sure there are bugs here and there. If you manage to fix them, please submit a pull request. Otherwise in the future I might be able to revisit and fix!