Crater generation script

 avatar
unknown
csharp
2 years ago
3.8 kB
62
Indexable
    /// <summary>
    /// Generates a crater at a given world position, of a diameter X meters and a depth of X meters and some dirt all around (percentage of crater's full diameter)
    /// </summary>
    /// <param name="p_worldPos"></param>
    /// <param name="p_holeDiameter"></param>
    /// <param name="p_depth"></param>
    void SpawnCrater(Vector3 p_worldPos, float p_holeDiameter, float p_depth, float p_dirtPercentageOnEdges)
    {
        float fullCraterSize = p_holeDiameter + (p_holeDiameter * p_dirtPercentageOnEdges); // Base hole diameter + dirt edges

        // Setting the dirt height on the edges of the crater
        float dirtHeight = p_holeDiameter > 1 ? 0.25f * p_depth : 0f; // Doing the edges of the crater only if the crater is big enough, otherwise looks pretty bad

        // Converting real world size (meters) in heightmap size and taking into account resolution
        fullCraterSize = (_heightMapResolution * fullCraterSize) / _terrainData.size.x;

        // Converting the real world depth asked in scaled height of the terrain, so that 1m depth is always 1m depth, regardless of the terrain's Y scale / max height
        p_depth /= _terrainData.size.y;
        dirtHeight /= _terrainData.size.y;

        // Converting world coordinates into terrain coordinates
        int xBase = (int)(((p_worldPos.x - _terrainPos.x) / _terrainData.size.x) * _heightMapResolution);
        int zBase = (int)(((p_worldPos.z - _terrainPos.z) / _terrainData.size.x) * _heightMapResolution);

        // Clamping the terrainX and terrainZ values so we don't get errors
        // Also moving the area to be centered on the real world point (center of our crater to be on the world point)
        xBase = (int)Mathf.Clamp((float)xBase - fullCraterSize / 2f, 0, _heightMapResolution);
        zBase = (int)Mathf.Clamp((float)zBase - fullCraterSize / 2f, 0, _heightMapResolution);

        // Rounding the crater's size to the nearest integer because the terrain array only takes integers
        int roundedCraterSize = (int)Mathf.Ceil(fullCraterSize);

        float[,] heights = _terrainData.GetHeights(xBase, zBase, roundedCraterSize, roundedCraterSize); // Getting the heights values we want to modify

        float radius = fullCraterSize / 2f; // Radius is half of the crater's diameter, useful to get some distance stuff

        // Cache
        float tempHeight;
        float distanceToCenter;
        float percDistanceToCenter;
        for (int x = 0; x < roundedCraterSize; x++)
            for (int z = 0; z < roundedCraterSize; z++)
            {
                distanceToCenter = Vector2.Distance(new Vector2(x, z), new Vector2(radius, radius));

                if (distanceToCenter <= radius)
                {
                    percDistanceToCenter = distanceToCenter / radius; // How far from the center this terrain node is

                    // Dirt edge
                    if (percDistanceToCenter >= 1f - p_dirtPercentageOnEdges) tempHeight = heights[x, z] + (p_depth * _craterDirtShape.Evaluate(1f - percDistanceToCenter)); // Smoothing
                                                                                                                                                                             // Crater's hole
                    else tempHeight = heights[x, z] - (p_depth * _craterDepthShape.Evaluate(percDistanceToCenter)); // Smoothing

                    heights[x, z] = Mathf.Clamp(tempHeight, 0, 1); // Setting the new height
                }
            }

        // Using SetHeightsDelayLOD doesn't help at all, doesn't change a thing
        //_terrainData.SetHeightsDelayLOD(xBase, zBase, heights);
        //_terrainData.SyncHeightmap();

        _terrainData.SetHeights(xBase, zBase, heights);
    }
Editor is loading...