示例#1
0
        private void WriteHeightsToTerrain(TerrainWrapper wrapper, Bounds bounds)
        {
            var heightmapRes = wrapper.Terrain.terrainData.heightmapResolution;

            if (Heights == null || Heights.Width != heightmapRes || Heights.Height != heightmapRes)
            {
                if (Heights != null && Heights.Width > 0 && Heights.Height > 0)
                {
                    Debug.LogWarning(
                        string.Format(
                            "Failed to write heights for layer '{0}' as it was the wrong resolution. Expected {1}x{1}, got {2}x{2}",
                            name, heightmapRes, Heights.Width), wrapper);
                }
                return;
            }

            var terrain         = wrapper.Terrain;
            var existingHeights = wrapper.CompoundTerrainData.Heights;

            if (existingHeights == null || existingHeights.Width != heightmapRes ||
                existingHeights.Height != heightmapRes)
            {
                existingHeights = new Serializable2DFloatArray(heightmapRes, heightmapRes);
                wrapper.CompoundTerrainData.Heights = existingHeights;
            }
            var min = terrain.WorldToHeightmapCoord(bounds.min, TerrainX.RoundType.Floor);
            var max = terrain.WorldToHeightmapCoord(bounds.max, TerrainX.RoundType.Floor);

            min = new Common.Coord(Mathf.Clamp(min.x, 0, heightmapRes), Mathf.Clamp(min.z, 0, heightmapRes));
            max = new Common.Coord(Mathf.Clamp(max.x, 0, heightmapRes), Mathf.Clamp(max.z, 0, heightmapRes));

            BlendMMTerrainLayerUtility.BlendArray(ref existingHeights, Heights, IsValidStencil(Stencil) ? Stencil : null,
                                                  BlendMode, min, max, new Common.Coord(heightmapRes, heightmapRes));
        }
示例#2
0
        private void WriteSplatsToTerrain(TerrainWrapper wrapper, Bounds bounds)
        {
            if (SplatData == null || SplatData.Count == 0)
            {
                return;
            }

            if (BlendMode == EMMTerrainLayerBlendMode.Set)
            {
                wrapper.CompoundTerrainData.SplatData.Clear();
            }

            var terrain     = wrapper.Terrain;
            var splatRes    = terrain.terrainData.alphamapResolution;
            var stencilSize = new Common.Coord(Stencil.Width, Stencil.Height);

            if (BlendMode == EMMTerrainLayerBlendMode.Stencil)
            {
                // Remove Stencil Values
                foreach (var pair in wrapper.CompoundTerrainData.SplatData)
                {
                    var data = pair.Value;
                    BlendMMTerrainLayerUtility.StencilEraseArray(ref data, Stencil, Common.Coord.Zero, new Common.Coord(splatRes, splatRes),
                                                                 stencilSize, false, false);
                }
            }

            foreach (var keyValuePair in SplatData)
            {
                var splatPrototypeWrapper = keyValuePair.Key;
                var readData = keyValuePair.Value;

                if (readData == null || readData.Width != splatRes || readData.Height != splatRes)
                {
                    Debug.LogWarning(
                        string.Format(
                            "Failed to write splat layer {0} for layer '{3}' as it was the wrong resolution. Expected {1}x{1}, got {2}x{2}",
                            splatPrototypeWrapper.name, splatRes, readData.Width, name), wrapper);
                    continue;
                }

                Serializable2DByteArray data;
                if (!wrapper.CompoundTerrainData.SplatData.TryGetValue(splatPrototypeWrapper, out data) ||
                    data.Width != splatRes || data.Height != splatRes)
                {
                    data = new Serializable2DByteArray(splatRes, splatRes);
                }

                BlendMMTerrainLayerUtility.BlendArray(ref data, readData,
                                                      IsValidStencil(Stencil) ? Stencil : null,
                                                      BlendMode, Common.Coord.Zero, stencilSize);

                wrapper.CompoundTerrainData.SplatData[splatPrototypeWrapper] = data;
            }
            GC.Collect();
        }
示例#3
0
        public override void ProcessDetails(TerrainWrapper terrainWrapper, LayerBase baseLayer, int stencilKey)
        {
            if (!RemoveGrass)
            {
                return;
            }
            var layer = baseLayer as MMTerrainLayer;

            if (layer == null)
            {
                Debug.LogWarning(string.Format("Attempted to write {0} to incorrect layer type! Expected Layer {1} to be {2}, but it was {3}", name, baseLayer.name, GetLayerType(), baseLayer.GetType()), this);
                return;
            }
            stencilKey = GetPriority();
            var objectBounds = GetObjectBounds();
            var dRes         = terrainWrapper.Terrain.terrainData.detailResolution;
            var axisBounds   = objectBounds.Flatten().ToAxisBounds();

            var matrixMin = terrainWrapper.Terrain.WorldToDetailCoord(axisBounds.min);

            matrixMin = new Common.Coord(Mathf.Clamp(matrixMin.x, 0, dRes), Mathf.Clamp(matrixMin.z, 0, dRes));

            var matrixMax = terrainWrapper.Terrain.WorldToDetailCoord(axisBounds.max);

            matrixMax = new Common.Coord(Mathf.Clamp(matrixMax.x, 0, dRes), Mathf.Clamp(matrixMax.z, 0, dRes));

            var arraySize = new Common.Coord(matrixMax.x - matrixMin.x, matrixMax.z - matrixMin.z);

            var details = layer.GetDetailMaps(matrixMin.x, matrixMin.z, arraySize.x, arraySize.z, dRes);

            for (var dx = 0; dx < arraySize.x; ++dx)
            {
                var xF = dx / (float)arraySize.x;
                for (var dz = 0; dz < arraySize.z; ++dz)
                {
                    var zF      = dz / (float)arraySize.z;
                    var falloff = GetFalloff(new Vector2(xF, zF));
                    foreach (var serializable2DByteArray in details)
                    {
                        if (IgnoredDetails.Contains(serializable2DByteArray.Key))
                        {
                            continue;
                        }
                        var readValue  = serializable2DByteArray.Value[dx, dz] / 255f;
                        var newValue   = readValue * (1 - falloff);
                        var writeValue = (byte)Mathf.Clamp(newValue * 255, 0, 255);
                        serializable2DByteArray.Value[dx, dz] = writeValue;
                    }
                }
            }
            foreach (var serializable2DByteArray in details)
            {
                layer.SetDetailMap(serializable2DByteArray.Key, matrixMin.x, matrixMin.z, serializable2DByteArray.Value, dRes);
            }
        }
示例#4
0
        private void WriteDetailsToTerrain(TerrainWrapper wrapper, Bounds bounds)
        {
            if (DetailData == null || DetailData.Count == 0)
            {
                return;
            }

            var terrain          = wrapper.Terrain;
            var detailResolution = terrain.terrainData.detailResolution;

            var detailCoordMin = terrain.WorldToDetailCoord(bounds.min);
            var detailCoordMax = terrain.WorldToDetailCoord(bounds.max);

            detailCoordMin = new Common.Coord(Mathf.Clamp(detailCoordMin.x, 0, detailResolution - 1),
                                              Mathf.Clamp(detailCoordMin.z, 0, detailResolution - 1));
            detailCoordMax = new Common.Coord(Mathf.Clamp(detailCoordMax.x, 0, detailResolution - 1),
                                              Mathf.Clamp(detailCoordMax.z, 0, detailResolution - 1));

            if (BlendMode == EMMTerrainLayerBlendMode.Set)
            {
                wrapper.CompoundTerrainData.DetailData.Clear();
            }

            foreach (var keyValuePair in DetailData)
            {
                var detailPrototypeWrapper = keyValuePair.Key;
                var readData = keyValuePair.Value;

                if (readData == null || readData.Width != detailResolution || readData.Height != detailResolution)
                {
                    Debug.LogWarning(
                        string.Format(
                            "Failed to write detail layer {0} for layer '{3}' as it was the wrong resolution. Expected {1}x{1}, got {2}x{2}",
                            detailPrototypeWrapper.name, detailResolution, readData.Width, name), wrapper);
                    continue;
                }

                Serializable2DByteArray data;
                if (!wrapper.CompoundTerrainData.DetailData.TryGetValue(detailPrototypeWrapper, out data) ||
                    data.Width != detailResolution || data.Height != detailResolution)
                {
                    data = new Serializable2DByteArray(detailResolution, detailResolution);
                }

                for (var u = detailCoordMin.x; u < detailCoordMax.x; ++u)
                {
                    var uF = u / (float)detailResolution;
                    //var arrayU = u - detailCoordMin.x;
                    for (var v = detailCoordMin.z; v < detailCoordMax.z; ++v)
                    {
                        var vF = v / (float)detailResolution;
                        //var arrayV = v - detailCoordMin.x;

                        if (BlendMode == EMMTerrainLayerBlendMode.Set)
                        {
                            data[u, v] = readData[u, v];
                        }
                        else if (BlendMode == EMMTerrainLayerBlendMode.Additive)
                        {
                            data[u, v] += readData[u, v];
                        }
                        else if (BlendMode == EMMTerrainLayerBlendMode.Stencil)
                        {
                            var stencil = this.GetStencilStrength(new Vector2(uF, vF));
                            if (stencil > 0)
                            {
                                var dataVal = data[u, v];
                                var readVal = readData[u, v];
                                var newVal  = (byte)
                                              Mathf.RoundToInt(Mathf.Clamp(Mathf.Lerp(dataVal, readVal, stencil), 0, 255));
                                data[u, v] = newVal;
                            }
                        }
                    }
                }

                /*BlendArrayUtility.BlendArray(ref data, readData,
                 *      Stencil != null ? Stencil.Select(0, 0, detailResolution, detailResolution) : null,
                 *      BlendMode, TerrainCoord.Zero, new TerrainCoord(detailResolution - 1, detailResolution - 1));*/
                wrapper.CompoundTerrainData.DetailData[detailPrototypeWrapper] = data;
            }
            GC.Collect();
        }
示例#5
0
        public override void ProcessDetails(TerrainWrapper wrapper, LayerBase baseLayer, int stencilKey)
        {
            var layer = baseLayer as MMTerrainLayer;

            if (layer == null)
            {
                Debug.LogWarning(string.Format("Attempted to write {0} to incorrect layer type! Expected Layer {1} to be {2}, but it was {3}", name, baseLayer.name, GetLayerType(), baseLayer.GetType()), this);
                return;
            }
            if (!Network || Configuration == null)
            {
                return;
            }
            var config = Configuration.GetConfig <Config>();

            if (config == null)
            {
                Debug.LogError("Invalid configuration! Expected ConnectionTerrainHeightConfiguration");
                return;
            }

            var terrain      = wrapper.Terrain;
            var dRes         = terrain.terrainData.detailResolution;
            var mainSpline   = NodeConnection.GetSpline();
            var radius       = config.Radius;
            var falloffCurve = config.GrassFalloff;

            // Create bounds to encapsulate spline (axis aligned)
            var bounds = mainSpline.GetApproximateBounds();

            bounds.Expand(radius * 2 * Vector3.one);

            // Create object bounds
            var objectBounds = mainSpline.GetApproximateXZObjectBounds();

            objectBounds.Expand(radius * 2 * Vector3.one);
            objectBounds.Expand(Vector3.up * 10000);

            // Early cull
            var axisBounds    = objectBounds.ToAxisBounds();
            var terrainBounds = terrain.GetComponent <Collider>().bounds;

            if (!terrainBounds.Intersects(axisBounds))
            {
                return;
            }

            // Get matrix space min/max
            var matrixMin = terrain.WorldToDetailCoord(bounds.min);

            matrixMin = new Common.Coord(Mathf.Clamp(matrixMin.x, 0, dRes), Mathf.Clamp(matrixMin.z, 0, dRes));
            var matrixMax = terrain.WorldToDetailCoord(bounds.max);

            matrixMax = new Common.Coord(Mathf.Clamp(matrixMax.x, 0, dRes), Mathf.Clamp(matrixMax.z, 0, dRes));

            var floatArraySize = new Common.Coord(matrixMax.x - matrixMin.x, matrixMax.z - matrixMin.z);
            var layerDetails   = layer.GetDetailMaps(matrixMin.x, matrixMin.z, floatArraySize.x, floatArraySize.z, dRes);

            var writeStencil = new Serializable2DFloatArray(floatArraySize.x, floatArraySize.z);

            for (var dx = 0; dx < floatArraySize.x; ++dx)
            {
                for (var dz = 0; dz < floatArraySize.z; ++dz)
                {
                    var coordX = matrixMin.x + dx;
                    var coordZ = matrixMin.z + dz;

                    var worldPos = terrain.DetailCoordToWorldPos(new Common.Coord(coordX, coordZ));
                    worldPos = new Vector3(worldPos.x, objectBounds.center.y, worldPos.z);

                    if (!terrain.ContainsPointXZ(worldPos) || !objectBounds.Contains(worldPos))
                    {
                        continue;
                    }

                    var uniformT        = mainSpline.GetClosestUniformTimeOnSplineXZ(worldPos.xz()); // Expensive!
                    var closestOnSpline = mainSpline.GetUniformPointOnSpline(uniformT);

                    var normalizedFlatDistToSpline = (worldPos - closestOnSpline).xz().magnitude / radius;
                    var maskValue = Mathf.Clamp01(falloffCurve.Evaluate(normalizedFlatDistToSpline));
                    if (maskValue <= 0 || normalizedFlatDistToSpline < 0 || normalizedFlatDistToSpline > 1)
                    {
                        //DebugHelper.DrawPoint(worldPos, 1, Color.yellow, 20);
                        continue;
                    }

                    //DebugHelper.DrawPoint(worldPos, .2f, Color.green, 20);
                    //Debug.DrawLine(worldPos, worldPos + Vector3.up * maskValue, Color.green, 20);
                    writeStencil[dx, dz]          = 1;
                    layer.Stencil[coordX, coordZ] = MiscUtilities.CompressStencil(GetPriority(), 1);
                    foreach (var data in layerDetails)
                    {
                        float readValue = data.Value[dx, dz];
                        readValue /= 16;

                        var writeValue     = readValue * (1 - maskValue);
                        var writeByteValue = (byte)Mathf.Clamp(writeValue * 16, 0, 16);
                        data.Value[dx, dz] = writeByteValue;
                    }
                }
            }

            foreach (var serializable2DByteArray in layerDetails)
            {
                layer.SetDetailMap(serializable2DByteArray.Key, matrixMin.x, matrixMin.z, serializable2DByteArray.Value, dRes, writeStencil);
            }
        }
示例#6
0
        public override void ProcessHeights(TerrainWrapper wrapper, LayerBase baseLayer, int stencilKey)
        {
            var layer = baseLayer as MMTerrainLayer;

            if (layer == null)
            {
                Debug.LogWarning(string.Format("Attempted to write {0} to incorrect layer type! Expected Layer {1} to be {2}, but it was {3}", name, baseLayer.name, GetLayerType(), baseLayer.GetType()), this);
                return;
            }
            if (!Network || Configuration == null)
            {
                return;
            }
            var config = Configuration.GetConfig <Config>();

            if (config == null)
            {
                Debug.LogError("Invalid configuration! Expected ConnectionTerrainHeightConfiguration");
                return;
            }
            var terrain     = wrapper.Terrain;
            var terrainPos  = wrapper.Terrain.GetPosition();
            var terrainSize = wrapper.Terrain.terrainData.size;
            var heightRes   = terrain.terrainData.heightmapResolution;

            var mainSpline   = NodeConnection.GetSpline();
            var radius       = config.Radius;
            var falloffCurve = config.Falloff;
            var heightCurve  = config.Height;

            // Create bounds to encapsulate spline (axis aligned)
            var bounds = mainSpline.GetApproximateBounds();

            bounds.Expand(radius * 2 * Vector3.one);

            // Create object bounds
            var objectBounds = mainSpline.GetApproximateXZObjectBounds();

            objectBounds.Expand(radius * 2 * Vector3.one);
            objectBounds.Expand(Vector3.up * 10000);

            // Early cull
            var axisBounds    = objectBounds.ToAxisBounds();
            var terrainBounds = terrain.GetComponent <Collider>().bounds;

            terrainBounds.Expand(Vector3.up * 10000);
            if (!terrainBounds.Intersects(axisBounds))
            {
                return;
            }

            // Get matrix space min/max
            var matrixMin = terrain.WorldToHeightmapCoord(bounds.min, TerrainX.RoundType.Floor) - Coord.One;

            matrixMin = matrixMin.Clamp(0, heightRes);
            var matrixMax = terrain.WorldToHeightmapCoord(bounds.max, TerrainX.RoundType.Ceil) + Coord.One;

            matrixMax = matrixMax.Clamp(0, heightRes);

            var xDelta = matrixMax.x - matrixMin.x;
            var zDelta = matrixMax.z - matrixMin.z;

            var floatArraySize = new Common.Coord(
                Mathf.Min(xDelta, terrain.terrainData.heightmapResolution - matrixMin.x),
                Mathf.Min(zDelta, terrain.terrainData.heightmapResolution - matrixMin.z));

            float planeGive = (wrapper.Terrain.terrainData.size.x / wrapper.Terrain.terrainData.heightmapResolution) * 0;
            Plane startPlane, endPlane;

            GenerateSplinePlanes(planeGive, mainSpline, out startPlane, out endPlane);

            var layerHeights = layer.GetHeights(matrixMin.x, matrixMin.z, floatArraySize.x, floatArraySize.z, heightRes) ??
                               new Serializable2DFloatArray(floatArraySize.x, floatArraySize.z);

            stencilKey = GetStencilKey();
            if (layer.Stencil == null || layer.Stencil.Width != heightRes || layer.Stencil.Height != heightRes)
            {
                layer.Stencil = new Stencil(heightRes, heightRes);
            }

            for (var dz = 0; dz < floatArraySize.z; ++dz)
            {
                for (var dx = 0; dx < floatArraySize.x; ++dx)
                {
                    var coordX = matrixMin.x + dx;
                    var coordZ = matrixMin.z + dz;

                    var worldPos = terrain.HeightmapCoordToWorldPos(new Common.Coord(coordX, coordZ));
                    worldPos = new Vector3(worldPos.x, objectBounds.center.y, worldPos.z);
                    if (!terrain.ContainsPointXZ(worldPos) ||
                        !objectBounds.Contains(worldPos) ||
                        !GeometryExtensions.BetweenPlanes(worldPos, startPlane, endPlane))
                    {
                        // Cull if we're outside of the approx bounds
                        continue;
                    }

                    var uniformT                   = mainSpline.GetClosestUniformTimeOnSplineXZ(worldPos.xz()); // Expensive!
                    var closestOnSpline            = mainSpline.GetUniformPointOnSpline(uniformT);
                    var normalizedFlatDistToSpline = (worldPos - closestOnSpline).xz().magnitude / (radius);
                    if (normalizedFlatDistToSpline >= 1)
                    {
                        continue;
                    }

                    var maskValue   = Mathf.Clamp01(falloffCurve.Evaluate(normalizedFlatDistToSpline));
                    var heightDelta = heightCurve.Evaluate(normalizedFlatDistToSpline);

                    float existingStencilStrength;
                    int   existingStencilKey;
                    MiscUtilities.DecompressStencil(layer.Stencil[coordX, coordZ], out existingStencilKey, out existingStencilStrength);

                    if (existingStencilKey != stencilKey &&
                        existingStencilKey > stencilKey &&
                        !(existingStencilStrength < maskValue && maskValue > 0))
                    {
                        continue;
                    }

                    // Refine our worldposition to be on the same XZ plane as the spline point
                    worldPos = new Vector3(worldPos.x, closestOnSpline.y, worldPos.z);

                    // Find the point on the spline closest to this given point
                    var naturalT = mainSpline.UniformToNaturalTime(uniformT);

                    // Get the upvec from the natural time
                    var up = mainSpline.GetUpVector(naturalT).normalized;

                    // Create a plane and cast against it
                    var plane = new Plane(up, closestOnSpline);

                    float dist    = 0;
                    var   castRay = new Ray(worldPos, Vector3.down);
                    plane.Raycast(castRay, out dist);
                    var castPoint     = castRay.GetPoint(dist);
                    var heightAtPoint = (castPoint.y + heightDelta);

                    heightAtPoint -= terrainPos.y;
                    heightAtPoint /= terrainSize.y;
                    heightAtPoint  = MiscUtilities.FloorToUshort(heightAtPoint);

                    var existingHeight = layerHeights[dx, dz];
                    var newHeight      = Mathf.Lerp(existingHeight, heightAtPoint, Mathf.Clamp01(maskValue));

                    layerHeights[dx, dz] = newHeight;

                    var key = maskValue > existingStencilStrength ? stencilKey : existingStencilKey;
                    var newRawStencilValue = MiscUtilities.CompressStencil(key, /*stencilKey == existingStencilKey ?*/ Mathf.Max(maskValue, existingStencilStrength) /* : maskValue + existingStencilStrength*/);
                    //newRawStencilValue = MiscUtilities.CompressStencil(key, 1);

                    layer.Stencil[coordX, coordZ] = newRawStencilValue;
                }
            }

            layer.SetHeights(matrixMin.x, matrixMin.z,
                             layerHeights, wrapper.Terrain.terrainData.heightmapResolution);
        }
示例#7
0
        public override void ProcessSplats(TerrainWrapper wrapper, LayerBase baseLayer, int stencilKey)
        {
            var layer = baseLayer as MMTerrainLayer;

            if (layer == null)
            {
                Debug.LogWarning(string.Format("Attempted to write {0} to incorrect layer type! Expected Layer {1} to be {2}, but it was {3}", name, baseLayer.name, GetLayerType(), baseLayer.GetType()), this);
                return;
            }
            if (!Network || Configuration == null)
            {
                return;
            }
            var config = Configuration.GetConfig <Config>();

            if (config == null)
            {
                Debug.LogError("Invalid configuration! Expected ConnectionTerrainHeightConfiguration");
                return;
            }

            var terrain    = wrapper.Terrain;
            var splatRes   = wrapper.Terrain.terrainData.alphamapResolution;
            var mainSpline = NodeConnection.GetSpline();
            var radius     = config.Radius;

            // Create bounds to encapsulate spline (axis aligned)
            var bounds = mainSpline.GetApproximateBounds();

            bounds.Expand(radius * 2 * Vector3.one);

            // Create object bounds
            var objectBounds = mainSpline.GetApproximateXZObjectBounds();

            objectBounds.Expand(radius * 2 * Vector3.one);
            objectBounds.Expand(Vector3.up * 10000);

            // Early cull
            var axisBounds    = objectBounds.ToAxisBounds();
            var terrainBounds = wrapper.Terrain.GetComponent <Collider>().bounds;

            if (!terrainBounds.Intersects(axisBounds))
            {
                return;
            }

            float planeGive = -(wrapper.Terrain.terrainData.size.x / wrapper.Terrain.terrainData.alphamapResolution) * SplatOffset;
            Plane startPlane, endPlane;

            GenerateSplinePlanes(planeGive, mainSpline, out startPlane, out endPlane);

            // Get matrix space min/max
            var matrixMin = terrain.WorldToSplatCoord(bounds.min, TerrainX.RoundType.Floor);
            var matrixMax = terrain.WorldToSplatCoord(bounds.max, TerrainX.RoundType.Ceil);

            matrixMin = new Common.Coord(Mathf.Clamp(matrixMin.x, 0, terrain.terrainData.alphamapResolution), Mathf.Clamp(matrixMin.z, 0, terrain.terrainData.alphamapResolution));
            matrixMax = new Common.Coord(Mathf.Clamp(matrixMax.x, 0, terrain.terrainData.alphamapResolution), Mathf.Clamp(matrixMax.z, 0, terrain.terrainData.alphamapResolution));

            var floatArraySize = new Common.Coord(matrixMax.x - matrixMin.x, matrixMax.z - matrixMin.z);

            // Get all the existing compound splats
            var currentPrototypes = wrapper.GetCompoundSplatPrototypes(layer, true);
            var baseData          = layer.GetSplatMaps(matrixMin.x, matrixMin.z, floatArraySize.x, floatArraySize.z, splatRes);

            stencilKey = GetStencilKey();
            Serializable2DFloatArray thisPatchStencil = new Serializable2DFloatArray(floatArraySize.x,
                                                                                     floatArraySize.z);

            foreach (var splatConfiguration in config.SplatConfigurations)
            {
                var splatPrototypeWrapper = splatConfiguration.SplatPrototype;
                Serializable2DByteArray baseLayerSplat;
                if (!baseData.TryGetValue(splatPrototypeWrapper, out baseLayerSplat))
                {
                    baseLayerSplat = new Serializable2DByteArray(floatArraySize.x, floatArraySize.z);
                    baseData[splatPrototypeWrapper] = baseLayerSplat;
                }

                for (var dz = 0; dz < floatArraySize.z; ++dz)
                {
                    for (var dx = 0; dx < floatArraySize.x; ++dx)
                    {
                        var coordX   = matrixMin.x + dx;
                        var coordZ   = matrixMin.z + dz;
                        var worldPos = terrain.SplatCoordToWorldPos(new Common.Coord(coordX, coordZ));
                        worldPos = new Vector3(worldPos.x, objectBounds.center.y, worldPos.z);

                        if (terrain.ContainsPointXZ(worldPos) &&
                            objectBounds.Contains(worldPos) &&
                            GeometryExtensions.BetweenPlanes(worldPos, startPlane, endPlane))
                        {
                            var uniformT                   = mainSpline.GetClosestUniformTimeOnSplineXZ(worldPos.xz()); // Expensive!
                            var closestOnSpline            = mainSpline.GetUniformPointOnSpline(uniformT);
                            var normalizedFlatDistToSpline = (worldPos - closestOnSpline).xz().magnitude / (config.Radius);
                            if (normalizedFlatDistToSpline != Mathf.Clamp01(normalizedFlatDistToSpline))
                            {
                                continue;
                            }
                            var maskValue       = config.SplatFalloff.Evaluate(normalizedFlatDistToSpline);
                            var writeFloatValue = splatConfiguration.SplatStrength * maskValue;
                            var writeValue      = (byte)Mathf.RoundToInt(Mathf.Clamp(writeFloatValue * 255f, 0, 255));
                            var mainRead        = baseLayerSplat[dx, dz];
                            var newVal          = (byte)Mathf.Clamp(Mathf.Max(writeValue, mainRead), 0, 255);
                            var delta           = newVal - mainRead;

                            if (delta < 1 / 255f)
                            {
                                continue;
                            }

                            foreach (var currentPrototype in currentPrototypes)
                            {
                                if (!baseData.ContainsKey(currentPrototype))
                                {
                                    continue;
                                }
                                if (currentPrototype == splatPrototypeWrapper)
                                {
                                    continue;
                                }
                                var otherSplatFloatValue    = baseData[currentPrototype][dx, dz] / 255f;
                                var otherSplatFloatWriteVal = (otherSplatFloatValue * (1 - (delta / 255f)));
                                var write = (byte)Mathf.Clamp(Mathf.RoundToInt(otherSplatFloatWriteVal * 255), 0, 255);
                                baseData[currentPrototype][dx, dz] = write;
                            }
                            //DebugHelper.DrawPoint(worldPos, 1, Color.red, 10);
                            baseLayerSplat[dx, dz]        = newVal;
                            layer.Stencil[coordX, coordZ] = MiscUtilities.CompressStencil(stencilKey, 1);
                            thisPatchStencil[dx, dz]      = 1;
                        }
                        else
                        {
                            thisPatchStencil[dx, dz] = 0;
                        }
                    }
                }
            }

            foreach (var existingSplatPrototype in baseData)
            {
                var splat = existingSplatPrototype.Key;
                var data  = existingSplatPrototype.Value;
                layer.SetSplatmap(splat, matrixMin.x, matrixMin.z, data, wrapper.Terrain.terrainData.alphamapResolution, thisPatchStencil);
            }
        }
        public static void BlendArray(ref Serializable2DFloatArray baseData,
                                      Serializable2DFloatArray blendingData,
                                      Serializable2DFloatArray stencil,
                                      MMTerrainLayer.EMMTerrainLayerBlendMode blendMode,
                                      Common.Coord offset, Common.Coord max, Common.Coord originalSize)
        {
            if (blendingData == null)
            {
                return;
            }
            if (baseData == null)
            {
                baseData = blendingData;
                return;
            }

            var width  = baseData.Width;
            var height = baseData.Height;

            if (TerrainWrapper.ComputeShaders && ShouldCompute(baseData))
            {
                var blendShader  = ComputeShaderPool.GetShader("MadMaps/WorldStamp/ComputeShaders/BlendFloatArray");
                int kernelHandle = blendShader.FindKernel("BlendFloats");

                //var baseBuffer = new ComputeBuffer(baseData.Width * baseData.Height, sizeof(float));
                var baseBuffer = ComputeShaderPool.GetBuffer(baseData.Width * baseData.Height, sizeof(float));
                baseBuffer.SetData(baseData.Data);
                blendShader.SetBuffer(kernelHandle, "_Base", baseBuffer);
                blendShader.SetVector("_BaseSize", new Vector4(baseData.Width, baseData.Height));

                //var blendBuffer = new ComputeBuffer(blendingData.Width * blendingData.Height, sizeof(float));
                var blendBuffer = ComputeShaderPool.GetBuffer(blendingData.Width * blendingData.Height, sizeof(float));
                blendBuffer.SetData(blendingData.Data);
                blendShader.SetBuffer(kernelHandle, "_Blend", blendBuffer);
                blendShader.SetVector("_BlendSize", new Vector4(blendingData.Width, blendingData.Height));

                ComputeBuffer stencilBuffer = null;
                if (stencil != null && stencil.Width > 0 && stencil.Height > 0)
                {
                    //stencilBuffer = new ComputeBuffer(stencil.Width * stencil.Height, sizeof(float));
                    stencilBuffer = ComputeShaderPool.GetBuffer(stencil.Width * stencil.Height, sizeof(float));
                    stencilBuffer.SetData(stencil.Data);
                    blendShader.SetBuffer(kernelHandle, "_Stencil", stencilBuffer);
                    blendShader.SetVector("_StencilSize", new Vector4(stencil.Width, stencil.Height));
                }
                else
                {
                    stencilBuffer = ComputeShaderPool.GetBuffer(1, sizeof(float));
                    blendShader.SetBuffer(kernelHandle, "_Stencil", stencilBuffer);
                    blendShader.SetVector("_StencilSize", new Vector4(0, 0));
                }

                blendShader.SetInt("_BlendMode", (int)blendMode);
                blendShader.SetVector("_MinMax", new Vector4(offset.x, offset.z, max.x, max.z));
                blendShader.SetVector("_TotalSize", new Vector4(originalSize.x, originalSize.z, 0, 0));

                blendShader.Dispatch(kernelHandle, baseData.Width, baseData.Height, 1);

                baseBuffer.GetData(baseData.Data);

                /*baseBuffer.Release();
                 * baseBuffer.Dispose();
                 * blendBuffer.Release();
                 * blendBuffer.Dispose();*/
                ComputeShaderPool.ReturnBuffer(baseBuffer);
                ComputeShaderPool.ReturnBuffer(blendBuffer);
                if (stencilBuffer != null)
                {
                    /*stencilBuffer.Release();
                    *  stencilBuffer.Dispose();*/
                    ComputeShaderPool.ReturnBuffer(stencilBuffer);
                }
                //Resources.UnloadAsset(blendShader);
                UseCount++;
            }
            else
            {
                for (int dx = 0; dx < width; dx++)
                {
                    for (int dz = 0; dz < height; dz++)
                    {
                        var blendingVal = blendingData[dx, dz];
                        var baseValue   = baseData[dx, dz];
                        switch (blendMode)
                        {
                        case MMTerrainLayer.EMMTerrainLayerBlendMode.Set:
                            baseData[dx, dz] = blendingVal;
                            break;

                        case MMTerrainLayer.EMMTerrainLayerBlendMode.Additive:
                            baseData[dx, dz] += blendingVal;
                            break;

                        case MMTerrainLayer.EMMTerrainLayerBlendMode.Stencil:
                            var   xF = (dx + offset.x) / (float)originalSize.x;
                            var   zF = (dz + offset.z) / (float)originalSize.z;
                            float strength;
                            stencil.StencilBilinearSample(new Vector2(xF, zF), out strength);
                            //strength  = 1;
                            if (strength > 0)
                            {
                                baseData[dx, dz] = Mathf.Lerp(baseValue, blendingVal, strength);
                            }
                            break;
                        }
                    }
                }
            }
            GC.Collect(3, GCCollectionMode.Forced);
        }
        public static void StencilEraseArray(
            ref Serializable2DByteArray baseData,
            Serializable2DFloatArray stencil,
            Common.Coord min, Common.Coord max, Common.Coord size,
            bool invert, bool absolute)
        {
            if (baseData == null || stencil == null)
            {
                return;
            }

            var width  = baseData.Width;
            var height = baseData.Height;

            if (TerrainWrapper.ComputeShaders && ShouldCompute(baseData))
            {
                var blendShader  = ComputeShaderPool.GetShader("MadMaps/WorldStamp/ComputeShaders/StencilIntArray");
                int kernelHandle = blendShader.FindKernel("StencilInts");

                var dataAsInt = baseData.Data.ConvertToIntArray();

                //var baseBuffer = new ComputeBuffer(baseData.Width * baseData.Height, sizeof(float));
                var baseBuffer = ComputeShaderPool.GetBuffer(baseData.Width * baseData.Height, sizeof(float));
                baseBuffer.SetData(dataAsInt);
                blendShader.SetBuffer(kernelHandle, "_Base", baseBuffer);
                blendShader.SetVector("_BaseSize", new Vector4(baseData.Width, baseData.Height));
                blendShader.SetVector("_MinMax", new Vector4(min.x, min.z, max.x, max.z));
                blendShader.SetVector("_TotalSize", new Vector4(size.x, size.z));

                //ComputeBuffer stencilBuffer= new ComputeBuffer(stencil.Width * stencil.Height, sizeof(float));
                var stencilBuffer = ComputeShaderPool.GetBuffer(stencil.Width * stencil.Height, sizeof(float));
                stencilBuffer.SetData(stencil.Data);
                blendShader.SetBuffer(kernelHandle, "_Stencil", stencilBuffer);
                blendShader.SetVector("_StencilSize", new Vector4(stencil.Width, stencil.Height));
                blendShader.SetBool("_Invert", invert);
                blendShader.SetBool("_Absolute", absolute);

                blendShader.Dispatch(kernelHandle, baseData.Width, baseData.Height, 1);

                baseBuffer.GetData(dataAsInt);

                for (int i = 0; i < dataAsInt.Length; i++)
                {
                    var val = dataAsInt[i];
                    baseData.Data[i] = (byte)Mathf.Clamp(val, 0, 255);
                }

                /*baseBuffer.Release();
                 * baseBuffer.Dispose();
                 * stencilBuffer.Release();
                 * stencilBuffer.Dispose();
                 * Resources.UnloadAsset(blendShader);*/

                ComputeShaderPool.ReturnBuffer(baseBuffer);
                ComputeShaderPool.ReturnBuffer(stencilBuffer);
                UseCount++;
            }
            else
            {
                for (var u = 0; u < width; ++u)
                {
                    var uF = (u + min.x) / (float)size.x;
                    for (var v = 0; v < height; ++v)
                    {
                        var vF = (v + min.z) / (float)size.z;

                        float value;
                        stencil.StencilBilinearSample(new Vector2(uF, vF), out value);
                        var existingValue = baseData[u, v];
                        var newValue      = existingValue;
                        if (absolute)
                        {
                            newValue = (byte)(value > 0 ? existingValue : 0);
                        }
                        else
                        {
                            newValue = (byte)Mathf.Clamp(existingValue * (1 - value), 0, 255);
                            if (invert)
                            {
                                newValue = (byte)Mathf.Clamp(existingValue * value, 0, 255);
                            }
                        }
                        baseData[u, v] = newValue;
                    }
                }
            }
            GC.Collect(3, GCCollectionMode.Forced);
        }
示例#10
0
        public override void ProcessSplats(TerrainWrapper terrainWrapper, LayerBase baseLayer, int stencilKey)
        {
            var layer = baseLayer as MMTerrainLayer;

            if (layer == null)
            {
                Debug.LogWarning(string.Format("Attempted to write {0} to incorrect layer type! Expected Layer {1} to be {2}, but it was {3}", name, baseLayer.name, GetLayerType(), baseLayer.GetType()), this);
                return;
            }
            if (!SetSplat || Splat == null || SplatStrength == 0)
            {
                return;
            }
            stencilKey = GetPriority();
            var objectBounds = GetObjectBounds();
            var aRes         = terrainWrapper.Terrain.terrainData.alphamapResolution;
            var axisBounds   = objectBounds.Flatten().ToAxisBounds();

            var matrixMin = terrainWrapper.Terrain.WorldToSplatCoord(axisBounds.min);

            matrixMin = new Common.Coord(Mathf.Clamp(matrixMin.x, 0, aRes), Mathf.Clamp(matrixMin.z, 0, aRes));

            var matrixMax = terrainWrapper.Terrain.WorldToSplatCoord(axisBounds.max);

            matrixMax = new Common.Coord(Mathf.Clamp(matrixMax.x, 0, aRes), Mathf.Clamp(matrixMax.z, 0, aRes));

            var arraySize = new Common.Coord(matrixMax.x - matrixMin.x, matrixMax.z - matrixMin.z);

            var existingSplats = layer.GetSplatMaps(matrixMin.x, matrixMin.z, arraySize.x, arraySize.z, aRes);

            for (var dx = 0; dx < arraySize.x; ++dx)
            {
                var xF = dx / (float)arraySize.x;
                for (var dz = 0; dz < arraySize.z; ++dz)
                {
                    var zF      = dz / (float)arraySize.z;
                    var falloff = GetFalloff(new Vector2(xF, zF));

                    float splatStrength = falloff * SplatStrength;
                    if (!existingSplats.ContainsKey(Splat))
                    {
                        existingSplats.Add(Splat, new Serializable2DByteArray(arraySize.x, arraySize.z));
                    }
                    var existingbaseVal = existingSplats[Splat][dx, dz] / 255f;
                    var newBaseVal      = Mathf.Max(existingbaseVal, splatStrength);
                    var writeBaseValue  = (byte)Mathf.Clamp(newBaseVal * 255, 0, 255);
                    existingSplats[Splat][dx, dz] = writeBaseValue;

                    foreach (var serializable2DByteArray in existingSplats)
                    {
                        if (serializable2DByteArray.Key == Splat)
                        {
                            continue;
                        }

                        var readValue  = serializable2DByteArray.Value[dx, dz] / 255f;
                        var newValue   = readValue * (1 - newBaseVal);
                        var writeValue = (byte)Mathf.Clamp(newValue * 255, 0, 255);
                        serializable2DByteArray.Value[dx, dz] = writeValue;
                    }
                }
            }
            foreach (var serializable2DByteArray in existingSplats)
            {
                layer.SetSplatmap(serializable2DByteArray.Key, matrixMin.x, matrixMin.z, serializable2DByteArray.Value, aRes);
            }
        }
示例#11
0
        public override void ProcessStencil(TerrainWrapper terrainWrapper, LayerBase baseLayer, int stencilKey)
        {
            var layer = baseLayer as MMTerrainLayer;

            if (layer == null)
            {
                Debug.LogWarning(string.Format("Attempted to write {0} to incorrect layer type! Expected Layer {1} to be {2}, but it was {3}", name, baseLayer.name, GetLayerType(), baseLayer.GetType()), this);
                return;
            }
            stencilKey = GetPriority();
            var objectBounds  = GetObjectBounds();
            var flatObjBounds = objectBounds.Flatten();
            var flatBounds    = flatObjBounds.ToAxisBounds();
            var terrainSize   = terrainWrapper.Terrain.terrainData.size;
            var hRes          = terrainWrapper.Terrain.terrainData.heightmapResolution;

            var matrixMin = terrainWrapper.Terrain.WorldToHeightmapCoord(flatBounds.min,
                                                                         TerrainX.RoundType.Floor);
            var matrixMax = terrainWrapper.Terrain.WorldToHeightmapCoord(flatBounds.max,
                                                                         TerrainX.RoundType.Ceil);

            matrixMin = new Common.Coord(Mathf.Clamp(matrixMin.x, 0, hRes), Mathf.Clamp(matrixMin.z, 0, hRes));
            matrixMax = new Common.Coord(Mathf.Clamp(matrixMax.x, 0, hRes), Mathf.Clamp(matrixMax.z, 0, hRes));

            var floatArraySize = new Common.Coord(matrixMax.x - matrixMin.x, matrixMax.z - matrixMin.z);


            layer.BlendMode = MMTerrainLayer.EMMTerrainLayerBlendMode.Stencil;

            if (layer.Stencil == null || layer.Stencil.Width != hRes || layer.Stencil.Height != hRes)
            {
                layer.Stencil = new Stencil(hRes, hRes);
            }
            var layerHeights = layer.GetHeights(matrixMin.x, matrixMin.z, floatArraySize.x, floatArraySize.z, hRes) ??
                               new Serializable2DFloatArray(floatArraySize.x, floatArraySize.z);

            var objectBoundsPlane = new Plane((objectBounds.Rotation * Vector3.up).normalized, objectBounds.center);

            for (var dz = 0; dz < floatArraySize.z; ++dz)
            {
                for (var dx = 0; dx < floatArraySize.x; ++dx)
                {
                    var coordX = matrixMin.x + dx;
                    var coordZ = matrixMin.z + dz;

                    int   existingStencilKey;
                    float existingStencilVal;
                    MiscUtilities.DecompressStencil(layer.Stencil[coordX, coordZ], out existingStencilKey,
                                                    out existingStencilVal);

                    var worldPos = terrainWrapper.Terrain.HeightmapCoordToWorldPos(new Common.Coord(coordX, coordZ));
                    worldPos = new Vector3(worldPos.x, objectBounds.center.y, worldPos.z);
                    if (!flatObjBounds.Contains(new Vector3(worldPos.x, flatObjBounds.center.y, worldPos.z)))
                    {
                        continue;
                    }

                    var localPos = Quaternion.Inverse(objectBounds.Rotation) * (worldPos - objectBounds.min);
                    var xDist    = localPos.x / objectBounds.size.x;
                    var zDist    = localPos.z / objectBounds.size.z;

                    float falloff = GetFalloff(new Vector2(xDist, zDist));
                    if (Mathf.Approximately(falloff, 0))
                    {
                        continue;
                    }

                    var   planeRay = new Ray(worldPos, Vector3.up);
                    float dist;

                    objectBoundsPlane.Raycast(planeRay, out dist);

                    var heightAtPoint  = (planeRay.GetPoint(dist) - terrainWrapper.transform.position).y / terrainSize.y;
                    var blendedHeight  = heightAtPoint;
                    var existingHeight = layerHeights[dx, dz];

                    if (SetHeights)
                    {
                        if (BlendMode == HeightBlendMode.Max && existingHeight > heightAtPoint)
                        {
                            layer.Stencil[matrixMin.x + dx, matrixMin.z + dz] = MiscUtilities.CompressStencil(0, 0);
                            continue;
                        }
                        if (BlendMode == HeightBlendMode.Min && existingHeight < heightAtPoint)
                        {
                            layer.Stencil[matrixMin.x + dx, matrixMin.z + dz] = MiscUtilities.CompressStencil(0, 0);
                            continue;
                        }
                    }

                    switch (BlendMode)
                    {
                    case HeightBlendMode.Set:
                        blendedHeight = Mathf.Lerp(existingHeight, blendedHeight, falloff);
                        break;

                    case HeightBlendMode.Max:
                        blendedHeight = Mathf.Max(existingHeight, blendedHeight);
                        break;

                    case HeightBlendMode.Min:
                        blendedHeight = Mathf.Min(existingHeight, blendedHeight);
                        break;

                    case HeightBlendMode.Average:
                        blendedHeight = (existingHeight + blendedHeight) / 2;
                        break;
                    }

                    layer.Stencil[matrixMin.x + dx, matrixMin.z + dz] = MiscUtilities.CompressStencil(stencilKey, 1);
                }
            }
        }