コード例 #1
0
    /// <summary>
    /// Reconstructs the sample points after save file load.
    /// </summary>
    /// <param name="name">Name of planet.</param>
    public void reconstructSamplePoints(string name)
    {
        SystemLogger.write ("Reconstructing sample points");

        int i = 0;

        while(i < serializedSamplePointsByPlanet[name].samplePointLocations.Count)
        {
            long key = serializedSamplePointsByPlanet[name].samplePointKeys[i];
            if(!samplePoints.ContainsKey(key))
            {
                samplePoints.Add(key, new List<ProceduralGenerationPoint>());
            }

            ProceduralGenerationPoint p = new ProceduralGenerationPoint(serializedSamplePointsByPlanet[name].samplePointLocations[i]);
            p.objectName = serializedSamplePointsByPlanet[name].samplePointObjects[i];
            p.size = serializedSamplePointsByPlanet[name].samplePointSizes[i];
            p.triangleIndex = serializedSamplePointsByPlanet[name].triangleIndexes[i];
            samplePoints[key].Add (p);
            i++;
        }
    }
コード例 #2
0
    /// <summary>
    /// Checks the neighboring grid locations to see if there's an object that is too close to a certain point.
    /// </summary>
    /// <returns><c>true</c> if it is too close to something <c>false</c> otherwise.</returns>
    /// <param name="grid">Grid.</param>
    /// <param name="point">Point.</param>
    /// <param name="minDistance">Minimum distance.</param>
    /// <param name="cellSize">Cell size.</param>
    /// <param name="triangle">Triangle.</param>
    public bool overlappingPoint(Dictionary<long, ProceduralGenerationPoint> grid, ProceduralGenerationPoint point, float minDistance, float cellSize, int triangle)
    {
        Vector2 newPoint = point.uvPosition;
        long gridPoint = point.gridPosition;
        int y = (int) gridPoint / gridOffset;
        int x = (int) gridPoint - (y * gridOffset);

        int gridSpaces = Mathf.CeilToInt(minDistance / cellSize);
        long key;

        for(int i = x - gridSpaces; i < gridSpaces + x; ++i)
        {
            for(int j = y - gridSpaces; j < gridSpaces + y; ++j)
            {
                if( i != x && j != y)
                {
                    key = i + j * gridOffset;

                    if(grid.ContainsKey(key))
                    {
                        if(inRange(grid[key].uvPosition, newPoint, minDistance + grid[key].size))
                        {
                            return true;
                        }
                    }
                }
            }
        }

        return false;
    }
コード例 #3
0
    /// <summary>
    /// Turns a Vector3 position on the mesh to a Vector2 uv point.
    /// </summary>
    /// <returns>The Vector2 uv point.</returns>
    /// <param name="point">Point.</param>
    public Vector2 meshPointToUv(ProceduralGenerationPoint point)
    {
        Vector3 toP1 = triangles[point.triangleIndex][0] - point.position;
        Vector3 toP2 = triangles[point.triangleIndex][1] - point.position;
        Vector3 toP3 = triangles[point.triangleIndex][2] - point.position;

        float triangleArea = Vector3.Cross (toP1 - toP2, toP1 - toP3).magnitude;
        float a1 = Vector3.Cross (toP2, toP3).magnitude / triangleArea;
        float a2 = Vector3.Cross (toP3, toP1).magnitude / triangleArea;
        float a3 = Vector3.Cross (toP1, toP2).magnitude / triangleArea;

        Vector2 uv = uvsToTriangles[point.triangleIndex][0] * a1 + uvsToTriangles[point.triangleIndex][1] * a2 + uvsToTriangles[point.triangleIndex][2] * a3;

        return uv;
    }
コード例 #4
0
 /// <summary>
 /// Gets the color at a location.
 /// </summary>
 /// <returns>The color at location on the me.</returns>
 /// <param name="point">Point.</param>
 public Color getColorAtTriangle(ProceduralGenerationPoint point)
 {
     int x = Mathf.FloorToInt(point.uvPosition.x * heatmapColors.width);
     int y = Mathf.FloorToInt(point.uvPosition.y * heatmapColors.height);
     return heatmapColors.GetPixel(x, y);
 }
コード例 #5
0
    /// <summary>
    /// Generates the random point around an existing point.
    /// </summary>
    /// <returns>A point.</returns>
    /// <param name="triangleIndex">Triangle index.</param>
    /// <param name="triangles">Triangles.</param>
    /// <param name="uvsToTriangles">Uvs to triangles.</param>
    /// <param name="minDistance">Minimum distance.</param>
    public ProceduralGenerationPoint generateRandomPointAround(int triangleIndex, List<Vector3[]> triangles, List<Vector2[]> uvsToTriangles, float minDistance)
    {
        // the range of triangle index values away that a point can be generated
        int range = Mathf.CeilToInt (minDistance / triangleArea * 3f);

        // the actual index value away of the triangle used to generate a new point
        int x = 0;

        if (Random.Range (0, 2) == 0)
        {
            x = Random.Range (range, 2*range);
        }
        else
        {
            x = Random.Range (-2 * range, -range);
        }

        while((triangleIndex + x) >= triangles.Count || (triangleIndex + x) < 0)
        {
            if (Random.Range (0, 2) == 0)
            {
                x = Random.Range (range, 2*range);
            }
            else
            {
                x = Random.Range (-2 * range, -range);
            }
        }

        ProceduralGenerationPoint p = new ProceduralGenerationPoint(getInterpolation (triangles [triangleIndex + x]));

        p.triangleIndex = triangleIndex + x;
        p.uvPosition = meshPointToUv (p);

        p.size = getSize(getColorChance(getColorAtTriangle(p)));
        p.c = getColorAtTriangle (p);
        return p;
    }
コード例 #6
0
    /// <summary>
    /// Generates the poisson sampling points that can be used to determine where to place objects.
    /// </summary>
    /// <returns>The poisson sampling point.</returns>
    /// <param name="minDistance">Minimum distance.</param>
    /// <param name="newPointsCount">Number of new points that should be generated around an existing point.</param>
    public Dictionary<long, List<ProceduralGenerationPoint>> generatePoisson(float minDistance, int newPointsCount)
    {
        SystemLogger.write ("Began generating poisson sample points");
        // gets triangle indices from first submesh
        int[] triangleIndices = mesh.GetTriangles (0);

        Vector3[] vertices = mesh.vertices;
        Vector2[] uvs = mesh.uv;
        Vector3[] normals = mesh.normals;
        Dictionary<long, List<ProceduralGenerationPoint>> samplePoints = new Dictionary<long, List<ProceduralGenerationPoint>> ();

        List<ProceduralGenerationPoint> processList = new List<ProceduralGenerationPoint> ();

        ProceduralGenerationPoint point;

        int rand;
        long gridPoint;
        float minDis;

        int tries = 0;

        for(int i =  0; i < triangleIndices.Length - 2; i+=3)
        {
            Vector3[] triangleVertices = new Vector3[3];
            triangleVertices[0] = vertices[triangleIndices[i]];
            triangleVertices[1] = vertices[triangleIndices[i+1]];
            triangleVertices[2] = vertices[triangleIndices[i+2]];

            triangles.Add (triangleVertices);

            Vector2[] triangleUVs = new Vector2[3];
            triangleUVs[0] = uvs[triangleIndices[i]];
            triangleUVs[1] = uvs[triangleIndices[i + 1]];
            triangleUVs[2] = uvs[triangleIndices[i + 2]];

            uvsToTriangles.Add(triangleUVs);

            faceNormals.Add ((normals[triangleIndices[i]] + normals[triangleIndices[i + 1]] + normals[triangleIndices[i + 2]])/3);
        }

        // calculates the ratio of a distance on the 3d mesh to a distance on the 2d uv by getting the distance from the same 2 points on both the mesh
        // and on the uv

        ProceduralGenerationPoint temp = new ProceduralGenerationPoint (getInterpolation (triangles [0]));
        temp.triangleIndex = 0;
        temp.uvPosition = meshPointToUv (temp);

        ProceduralGenerationPoint temp2 = new ProceduralGenerationPoint (getInterpolation (triangles [1]));
        temp2.triangleIndex = 1;
        temp2.uvPosition = meshPointToUv (temp2);

        uvToMeshRatio = Vector2.Distance (temp.uvPosition, temp2.uvPosition) / Vector3.Distance (temp.position, temp2.position);

        // size of cells in the mesh grid for generation
        cellSize = (minDistance / Mathf.Sqrt (2f)) * uvToMeshRatio;

        // calculates the area of a triangle on the mesh

        Vector3 side1 = triangles [0] [0] - triangles [0] [1];
        Vector3 side2 = triangles [0] [1] - triangles [0] [2];
        Vector3 side3 = triangles [0] [2] - triangles [0] [0];

        triangleArea = Vector3.Cross (side1 - side2, side1 - side3).magnitude;

        // the number to offset the y value from the x to create a unique index for vector2 hashes in the dictionary
        int initialNumber = Mathf.CeilToInt ((triangleArea * uvToMeshRatio) / cellSize) * triangles.Count;
        int power = Mathf.CeilToInt (Mathf.Log10 (initialNumber));
        gridOffset = Mathf.RoundToInt(Mathf.Pow (10, power));
        power = Mathf.CeilToInt (Mathf.Log10(planetSections));
        chunkGridOffset = Mathf.RoundToInt (Mathf.Pow (10, power));

        SystemLogger.write ("Creating starting seeds...");
        // creates the starting seeds from which points will be generated around
        for (int i = 0; i < startingSeeds; ++i)
        {
            rand = Random.Range (0, triangles.Count);
            ProceduralGenerationPoint firstPoint = new ProceduralGenerationPoint (getInterpolation (triangles [rand]));
            firstPoint.triangleIndex = rand;
            firstPoint.uvPosition = meshPointToUv(firstPoint);

            // the color at that location
            Color c = getColorAtTriangle(firstPoint);

            firstPoint.size = getSize(getColorChance(c));
            firstPoint.c = c;

            gridPoint = toGrid (firstPoint.uvPosition, chunkCellSize, chunkGridOffset);
            firstPoint.chunkGridPosition = gridPoint;
            firstPoint.gridPosition = toGrid (firstPoint.uvPosition, cellSize, gridOffset);
            // the minimum distance of generation taking into acount the minimum distance allowed between objects, the density of the region, and the size of
            // the object being generated around, all multiplied by the uvToMeshRatio so that the measurement is given in terms of uv distance

            minDis = (minDistance + distanceVariance * getDensity(c) + firstPoint.size) * uvToMeshRatio;
            tries = 0;

            // if there is already a point within that cell then it is automatically too close to another point
            // otherwise it will check with overlappingPoint whether or not it is too close to any cells in its neighborhood
            // if either are true then that means the point is invalid and another point is generated as an attemp

            while ((1- getDensity(firstPoint.c)) < startingSeedsDensityThreshold || chunkGrid.ContainsKey(gridPoint)
                   || grid.ContainsKey(firstPoint.gridPosition)|| overlappingPoint(grid, firstPoint, minDis, cellSize, firstPoint.triangleIndex))
            {
                rand = Random.Range (0, triangles.Count);
                firstPoint.position = getInterpolation (triangles [rand]);
                firstPoint.triangleIndex = rand;
                firstPoint.uvPosition = meshPointToUv(firstPoint);

                gridPoint = toGrid(firstPoint.uvPosition, chunkCellSize, chunkGridOffset);
                firstPoint.chunkGridPosition = gridPoint;
                firstPoint.gridPosition = toGrid (firstPoint.uvPosition, cellSize, gridOffset);

                minDis = (minDistance + distanceVariance * getDensity(c) + firstPoint.size) * uvToMeshRatio;

                // it will only keep generating new points in an attempt at generating a valid point as many times as the maxAttempts allows
                if(tries < maxAttempts)
                {
                    tries ++;
                }
                else
                {
                    break;
                }
            }

            // tries < maxAttempts that means it exited the while loop because there was a valid point and not because there were too many
            // atempts taken

            if (tries < maxAttempts)
            {
                // uses grid location as key in sample points dictionary for access later
                long key = firstPoint.chunkGridPosition;
                firstPoint.gridPosition = toGrid (firstPoint.uvPosition, cellSize, gridOffset);
                if(!samplePoints.ContainsKey(key))
                {
                    samplePoints.Add(key, new List<ProceduralGenerationPoint>());
                }

                // registers a chunk to mark it as having objects if chunk is not already registered
                if(!chunkStatus.ContainsKey(key))
                {
                    chunkStatus.Add(key, false);
                }

                if(!chunkGrid.ContainsKey(key))
                {
                    chunkGrid.Add(key, new List<EnvironmentOrienter>());
                }

                samplePoints[key].Add (firstPoint);
                processList.Add (firstPoint);

                // add point to grid

                grid.Add (firstPoint.gridPosition, firstPoint);
            }
        }

        currentObjects = startingSeeds;

        // not based on those seeds, generate objects around them

        SystemLogger.write ("Creating the surrounding points....");

        while (currentObjects < maxObjects && processList.Count != 0)
        {
            point = processList[processList.Count - 1];
            processList.RemoveAt(processList.Count - 1);
            tries = 0;
            for(int i = 0; i < newPointsCount; ++i)
            {
                // generate a random point around an existing point
                ProceduralGenerationPoint newPoint = generateRandomPointAround (point.triangleIndex, triangles, uvsToTriangles, minDistance + distanceVariance + large);

                Color c = getColorAtTriangle(newPoint);
                newPoint.size = getSize(getColorChance(c));
                newPoint.c = c;
                gridPoint = toGrid (newPoint.uvPosition, cellSize, gridOffset);
                newPoint.gridPosition = gridPoint;
                minDis = (minDistance + distanceVariance * getDensity(c) + newPoint.size) * uvToMeshRatio;

                while ((1- getDensity(newPoint.c)) < generationDensityThreshold  || grid.ContainsKey(gridPoint) || overlappingPoint(grid, newPoint, minDis,cellSize, newPoint.triangleIndex))
                {
                    newPoint = generateRandomPointAround (point.triangleIndex, triangles, uvsToTriangles, minDistance + distanceVariance + large);

                    minDis = (minDistance + distanceVariance * getDensity(c) + newPoint.size) * uvToMeshRatio;
                    gridPoint = toGrid (newPoint.uvPosition, cellSize, gridOffset);
                    newPoint.gridPosition = gridPoint;

                    if(tries < maxAttempts)
                    {
                        tries ++;
                    }
                    else
                    {
                        break;
                    }
                }

                if (tries < maxAttempts)
                {
                    long key = toGrid(newPoint.uvPosition, chunkCellSize, chunkGridOffset);
                    if(!samplePoints.ContainsKey(key))
                    {
                        samplePoints.Add(key, new List<ProceduralGenerationPoint>());
                    }

                    samplePoints[key].Add (newPoint);
                    processList.Add(newPoint);

                    if(!chunkStatus.ContainsKey(key))
                    {
                        chunkStatus.Add(key, false);
                    }

                    if(!chunkGrid.ContainsKey(key))
                    {
                        chunkGrid.Add(key, new List<EnvironmentOrienter>());
                    }

                    currentObjects++;
                    grid.Add(gridPoint, newPoint);

                    newPoint.chunkGridPosition = key;

                    tries = 0;
                }
                else
                {
                    break;
                }

                if(currentObjects >= maxObjects)
                {
                    break;
                }
            }

        }

        return samplePoints;
    }