コード例 #1
0
        public Serializable2DFloatArray GetArrayFromMask(WorldStampCreator parent)
        {
            GridSize = WorldStampCreator.GetMinGridSize(parent.Template.Bounds, parent.Template.Terrain);
            var bounds = parent.Template.Bounds;
            var width  = Mathf.CeilToInt(bounds.size.x / GridSize);
            var height = Mathf.CeilToInt(bounds.size.z / GridSize);
            var array  = new Serializable2DFloatArray(width, height);

            for (var u = 0; u < width; u++)
            {
                for (var v = 0; v < height; v++)
                {
                    var pos     = new Vector3((u / (float)width) * bounds.size.x, bounds.size.y / 2, (v / (float)height) * bounds.size.z);
                    var cell    = GridManager.GetCell(pos);
                    var cellMax = GridManager.GetCellMax(cell).x0z() + bounds.min;
                    var cellMin = GridManager.GetCellCenter(cell).x0z() + bounds.min;
                    if (!bounds.Contains(cellMax) || !bounds.Contains(cellMin))
                    {
                        continue;
                    }

                    var val = Mask.GetValue(cell);
                    array[u, v] = val;
                }
            }
            return(array);
        }
コード例 #2
0
ファイル: MMTerrainLayer.cs プロジェクト: cowtrix/Mad-Maps
        public override Serializable2DFloatArray GetHeights(int x, int z, int xSize, int zSize, int hRes)
        {
            if (Heights == null || Heights.Width != hRes || Heights.Height != hRes)
            {
                return(null);
            }
            var h = new Serializable2DFloatArray(xSize, zSize);

            for (var u = x; u < x + xSize; ++u)
            {
                for (var v = z; v < z + zSize; ++v)
                {
                    var hx = u - x;
                    var hz = v - z;
                    try
                    {
                        var baseHeight = Heights[u, v];
                        h[hx, hz] = baseHeight;
                    }
                    catch (IndexOutOfRangeException e)
                    {
                        Debug.LogError(string.Format("x {0} y {1}", hx, hz));
                        throw e;
                    }
                }
            }
            return(h);
        }
コード例 #3
0
        private void FillMaskFromMinY(Bounds bounds, Terrain terrain, Serializable2DFloatArray heights, Vector2 minY)
        {
            Mask.Clear();
            GridSize = WorldStampCreator.GetMinGridSize(bounds, terrain);
            for (var u = GridSize / 2f; u < bounds.size.x; u += GridSize)
            {
                for (var v = GridSize / 2f; v < bounds.size.z; v += GridSize)
                {
                    var cell    = GridManager.GetCell(new Vector3(u, 0, v));
                    var cellMax = GridManager.GetCellMax(cell).x0z() + bounds.min;
                    var cellMin = GridManager.GetCellCenter(cell).x0z() + bounds.min;
                    if (!bounds.Contains(cellMax) || !bounds.Contains(cellMin))
                    {
                        continue;
                    }

                    var h = heights.BilinearSample(new Vector2(u / bounds.size.z, v / bounds.size.x)) * bounds.size.y;
                    if (h < minY.x)
                    {
                        Mask.SetValue(cell, 0);
                    }
                    else if (h <= minY.y)
                    {
                        Mask.SetValue(cell, (h - minY.x) / (minY.y - minY.x));
                    }
                    else
                    {
                        Mask.SetValue(cell, 1);
                    }
                }
            }
        }
コード例 #4
0
        public static void AbsStencil(Serializable2DFloatArray stencil, int stencilKey = 0)
        {
            for (var u = 0; u < stencil.Width; ++u)
            {
                for (var v = 0; v < stencil.Height; ++v)
                {
                    int   key;
                    float strength;
                    var   rawValue = stencil[u, v];
                    if (rawValue == 0)
                    {
                        continue;
                    }

                    DecompressStencil(rawValue, out key, out strength, false);

                    if (stencilKey != 0 && Mathf.Abs(key) != stencilKey)
                    {
                        continue;
                    }

                    var newValue = CompressStencil(Mathf.Abs(key), strength);
                    stencil[u, v] = newValue;
                }
            }
        }
コード例 #5
0
ファイル: MMTerrainLayer.cs プロジェクト: cowtrix/Mad-Maps
        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));
        }
コード例 #6
0
        public static void StencilBilinearSample(this Serializable2DFloatArray array, Vector2 normalizedCoord, out float strength, bool ignoreNegativeKeys = true)
        {
            if (normalizedCoord.x < 0 || normalizedCoord.x > 1 || normalizedCoord.y < 0 || normalizedCoord.y > 1)
            {
                strength = 0;
                return;
            }
            normalizedCoord = new Vector2(normalizedCoord.x * array.Width, normalizedCoord.y * array.Height);

            int xMin = Mathf.FloorToInt(normalizedCoord.x);
            int xMax = Mathf.CeilToInt(normalizedCoord.x);
            int yMin = Mathf.FloorToInt(normalizedCoord.y);
            int yMax = Mathf.CeilToInt(normalizedCoord.y);

            xMin = Mathf.Clamp(xMin, 0, array.Width - 1);
            xMax = Mathf.Clamp(xMax, 0, array.Width - 1);
            yMin = Mathf.Clamp(yMin, 0, array.Height - 1);
            yMax = Mathf.Clamp(yMax, 0, array.Height - 1);

            float v1 = array[xMin, yMin];
            float v2 = array[xMin, yMax];
            float v3 = array[xMax, yMin];
            float v4 = array[xMax, yMax];

            int v1Index;
            int v2Index;
            int v3Index;
            int v4Index;

            MiscUtilities.DecompressStencil(v1, out v1Index, out v1);
            MiscUtilities.DecompressStencil(v2, out v2Index, out v2);
            MiscUtilities.DecompressStencil(v3, out v3Index, out v3);
            MiscUtilities.DecompressStencil(v4, out v4Index, out v4);

            if (ignoreNegativeKeys)
            {
                v1 = v1Index > 0 ? v1 : 0;
                v2 = v1Index > 0 ? v2 : 0;
                v3 = v1Index > 0 ? v3 : 0;
                v4 = v1Index > 0 ? v4 : 0;
            }

            if (Math.Abs(v1 + v2 + v3 + v4) < .01f)
            {
                strength = 0;
                return;
            }

            float xFrac = normalizedCoord.x.Frac();
            float yFrac = normalizedCoord.y.Frac();

            v1 *= (1 - xFrac) * (1 - yFrac);
            v2 *= (1 - xFrac) * (/*1 - */ yFrac);
            v3 *= (/*1 - */ xFrac) * (1 - yFrac);
            v4 *= (/*1 - */ xFrac) * (/*1 -*/ yFrac);

            strength = Mathf.Clamp01(v1 + v2 + v3 + v4);
        }
コード例 #7
0
ファイル: MMTerrainLayer.cs プロジェクト: cowtrix/Mad-Maps
        public override void Clear(TerrainWrapper wrapper)
        {
            Dispose(wrapper, false);

            Trees.Clear();
            TreeRemovals.Clear();

            if (Heights != null)
            {
                var tRes = wrapper.Terrain.terrainData.heightmapResolution;
                if (Heights.Width == tRes && Heights.Height == tRes)
                {
                    Heights.Clear();
                }
                else
                {
                    Heights = new Serializable2DFloatArray(tRes, tRes);
                }
            }
            SplatData.Clear();

            Objects.Clear();
            ObjectRemovals.Clear();
            if (DetailData != null)
            {
                DetailData.Clear();
            }


            if (Stencil != null)
            {
                var tRes = wrapper.Terrain.terrainData.heightmapResolution;
                if (Stencil.Width == tRes && Stencil.Height == tRes)
                {
                    Stencil.Clear();
                }
                else
                {
                    Stencil = new Stencil(tRes, tRes);
                }
            }

#if VEGETATION_STUDIO
            VSInstances.Clear();
            VSRemovals.Clear();
#endif

            GC.Collect();

#if UNITY_EDITOR
            UnityEditor.EditorUtility.SetDirty(this);
#endif
        }
コード例 #8
0
        public static float BilinearSample(this Serializable2DFloatArray array,
                                           Vector2 normalizedCoord)
        {
            if (array == null)
            {
                return(0);
            }

            if (array.Width == 0 && array.Height == 0)
            {
                return(0);
            }

            if (normalizedCoord.x < 0 || normalizedCoord.x > 1 || normalizedCoord.y < 0 || normalizedCoord.y > 1)
            {
                return(0);
            }
            normalizedCoord = new Vector2(normalizedCoord.x * array.Width, normalizedCoord.y * array.Height);

            int xMin = Mathf.FloorToInt(normalizedCoord.x);
            int xMax = Mathf.CeilToInt(normalizedCoord.x);
            int yMin = Mathf.FloorToInt(normalizedCoord.y);
            int yMax = Mathf.CeilToInt(normalizedCoord.y);

            xMin = Mathf.Clamp(xMin, 0, array.Width - 1);
            xMax = Mathf.Clamp(xMax, 0, array.Width - 1);
            yMin = Mathf.Clamp(yMin, 0, array.Height - 1);
            yMax = Mathf.Clamp(yMax, 0, array.Height - 1);

            float v1 = array[xMin, yMin];
            float v2 = array[xMin, yMax];
            float v3 = array[xMax, yMin];
            float v4 = array[xMax, yMax];

            if (Math.Abs(v1 + v2 + v3 + v4) < Single.Epsilon)
            {
                return(0);
            }

            float xFrac = normalizedCoord.x.Frac();
            float yFrac = normalizedCoord.y.Frac();

            v1 *= (1 - xFrac) * (1 - yFrac);
            v2 *= (1 - xFrac) * (/*1 - */ yFrac);
            v3 *= (/*1 - */ xFrac) * (1 - yFrac);
            v4 *= (/*1 - */ xFrac) * (/*1 -*/ yFrac);

            return(v1 + v2 + v3 + v4);
        }
コード例 #9
0
        protected override void CaptureInternal(Terrain terrain, Bounds bounds)
        {
            var min = terrain.WorldToHeightmapCoord(bounds.min, TerrainX.RoundType.Floor);
            var max = terrain.WorldToHeightmapCoord(bounds.max, TerrainX.RoundType.Floor);

            int width  = max.x - min.x;
            int height = max.z - min.z;

            float avgMarginHeight = 0; // If we want, we can have the stamp try to automatically find a good zero level by averaging the heights around the edge of the stamp
            int   marginCount     = 0;

            Heights = new Serializable2DFloatArray(width, height);
            float maxHeight     = float.MinValue;
            var   sampleHeights = terrain.terrainData.GetHeights(min.x, min.z, width, height);

            for (var dx = 0; dx < width; ++dx)
            {
                for (var dz = 0; dz < height; ++dz)
                {
                    var sample = sampleHeights[dz, dx];
                    Heights[dx, dz] = sample;

                    if (sample > maxHeight)
                    {
                        maxHeight = sample;
                    }

                    if (dx == 0 || dx == width - 1 || dz == 0 || dz == height - 1)
                    {
                        avgMarginHeight += sample;
                        marginCount++;
                    }
                }
            }
            if (AutoZeroLevel)
            {
                ZeroLevel = avgMarginHeight / marginCount;
            }
            for (var dx = 0; dx < width; ++dx)
            {
                for (var dz = 0; dz < height; ++dz)
                {
                    Heights[dx, dz] -= ZeroLevel;
                }
            }
            HeightSize = maxHeight - ZeroLevel;
            _dirty     = true;
        }
コード例 #10
0
ファイル: MMTerrainLayer.cs プロジェクト: cowtrix/Mad-Maps
        public void SetHeights(int x, int z, Serializable2DFloatArray heights, int heightRes, Serializable2DFloatArray stencil = null)
        {
            if (heights == null)
            {
                return;
            }
            if (Heights == null || Heights.Width != heightRes || Heights.Height != heightRes)
            {
                Heights = new Serializable2DFloatArray(heightRes, heightRes);
            }
            var width  = heights.Width;
            var height = heights.Height;

            for (var u = x; u < x + width; ++u)
            {
                for (var v = z; v < z + height; ++v)
                {
                    var hx = u - x;
                    var hz = v - z;
                    try
                    {
                        var heightsSample = heights[hx, hz];
                        heightsSample = Mathf.Clamp01(heightsSample);
                        if (stencil == null)
                        {
                            Heights[u, v] = heightsSample;
                        }
                        else
                        {
                            float val;
                            int   key;
                            MiscUtilities.DecompressStencil(stencil[u, v], out key, out val);
                            Heights[u, v] = Mathf.Lerp(Heights[u, v], heightsSample, val);
                        }
                    }
                    catch (IndexOutOfRangeException e)
                    {
                        Debug.LogError(string.Format("x {0} y {1}", hx, hz));
                        throw e;
                    }
                }
            }

#if UNITY_EDITOR
            UnityEditor.EditorUtility.SetDirty(this);
#endif
        }
コード例 #11
0
 public static void InvertStencil(Serializable2DFloatArray stencil)
 {
     for (var u = 0; u < stencil.Width; ++u)
     {
         for (var v = 0; v < stencil.Height; ++v)
         {
             int   key;
             float strength;
             var   rawValue = stencil[u, v];
             if (rawValue == 0)
             {
                 continue;
             }
             DecompressStencil(rawValue, out key, out strength, false);
             var newValue = CompressStencil(-key, strength);
             stencil[u, v] = newValue;
         }
     }
 }
コード例 #12
0
 public static void ColoriseStencil(Serializable2DFloatArray stencil)
 {
     for (var u = 0; u < stencil.Width; ++u)
     {
         for (var v = 0; v < stencil.Height; ++v)
         {
             int   key;
             float strength;
             DecompressStencil(stencil[u, v], out key, out strength);
             if (strength > 0 && key > 0)
             {
                 stencil[u, v] = MiscUtilities.CompressStencil(key, 1);
             }
             else
             {
                 stencil[u, v] = 0;
             }
         }
     }
 }
コード例 #13
0
 public static void ClampStencil(Serializable2DFloatArray stencil)
 {
     if (stencil == null)
     {
         return;
     }
     for (var u = 0; u < stencil.Width; ++u)
     {
         for (var v = 0; v < stencil.Height; ++v)
         {
             int   key;
             float strength;
             DecompressStencil(stencil[u, v], out key, out strength);
             if (key < 1)
             {
                 stencil[u, v] = 0;
             }
         }
     }
 }
コード例 #14
0
 public void SetMaskFromArray(WorldStampCreator parent, Serializable2DFloatArray mask)
 {
     GridSize = WorldStampCreator.GetMinGridSize(parent.Template.Bounds, parent.Template.Terrain);
     Mask.Clear();
     for (var u = GridSize / 2f; u < parent.Template.Bounds.size.x; u += GridSize)
     {
         for (var v = GridSize / 2f; v < parent.Template.Bounds.size.z; v += GridSize)
         {
             var cell    = GridManager.GetCell(new Vector3(u, 0, v));
             var cellMax = GridManager.GetCellMax(cell).x0z() + parent.Template.Bounds.min;
             var cellMin = GridManager.GetCellCenter(cell).x0z() + parent.Template.Bounds.min;
             if (!parent.Template.Bounds.Contains(cellMax) || !parent.Template.Bounds.Contains(cellMin))
             {
                 continue;
             }
             var val = mask.BilinearSample(new Vector2(u / parent.Template.Bounds.size.x, v / parent.Template.Bounds.size.z));
             Mask.SetValue(cell, val);
         }
     }
 }
コード例 #15
0
ファイル: LayerBase.cs プロジェクト: cowtrix/Mad-Maps
 public virtual Serializable2DFloatArray BlendHeights(int x, int z, int width, int height, int heightRes, Serializable2DFloatArray result)
 {
     return(result);
 }
コード例 #16
0
        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);
        }
コード例 #17
0
        public void Invalidate(Serializable2DFloatArray heights,
                               Func <Vector3> displaySizeGetter,
                               Func <Vector3> positionGetter,
                               Func <Vector3> scaleGetter,
                               Func <Quaternion> rotationGetter,
                               Func <Vector3> dataSizeGetter, bool flipHeights,
                               WorldStampMask mask, Common.Painter.GridManagerInt gridManager,
                               Func <bool> existenceHook, int res)
        {
            _dataSize      = dataSizeGetter;
            _displaySize   = displaySizeGetter;
            _existenceHook = existenceHook;
            _position      = positionGetter;
            _scale         = scaleGetter;
            _rotation      = rotationGetter;

            if (_mesh == null)
            {
                _mesh = new Mesh();
            }
            if (_material == null)
            {
                _material = Resources.Load <Material>("MadMaps/WorldStamp/WorldStampPreviewMaterial");
            }
            var verts    = new Vector3[(res + 1) * (res + 1)];
            var uv       = new Vector2[verts.Length];
            var colors   = new Color[verts.Length];
            int counter  = 0;
            var dataSize = dataSizeGetter();

            for (int u = 0; u <= res; u++)
            {
                var uF = u / (float)res;
                for (int v = 0; v <= res; v++)
                {
                    var vF          = v / (float)res;
                    var samplePoint = flipHeights ? new Vector2(uF, vF) : new Vector2(vF, uF);
                    var height      = heights.BilinearSample(samplePoint);

                    var pos = new Vector3(uF * dataSize.x, height * dataSize.y, vF * dataSize.z) - dataSize.xz().x0z() / 2;

                    float val = 1;
                    if (mask != null && gridManager != null)
                    {
                        val    = mask.GetBilinear(gridManager, new Vector3(pos.x, 0, pos.z) + dataSize.xz().x0z() / 2);
                        pos.y *= val;
                    }

                    verts[counter]  = pos;
                    uv[counter]     = new Vector2(uF, vF);
                    colors[counter] = Color.Lerp(Color.clear, Color.white, val);
                    counter++;
                }
            }

            _mesh.vertices = verts;
            _mesh.uv       = uv;
            _mesh.colors   = colors;

            var tris = new int[((res + 1) * (res)) * 6];

            for (var i = 0; i < tris.Length; i += 6)
            {
                var vIndex = i / 6;

                var t1 = vIndex + 0;
                var t2 = vIndex + 1;
                var t3 = vIndex + 2 + (res - 1);

                var t1r = t1 / (res + 1);
                var t2r = t2 / (res + 1);
                var t3r = (t3 / (res + 1)) - 1;

                if (t1r == t2r && t2r == t3r && t3r == t1r)
                {
                    tris[i + 0] = t1;
                    tris[i + 1] = t2;
                    tris[i + 2] = t3;
                }

                var t4 = vIndex + 2 + (res - 1);
                var t5 = vIndex + 1 + (res - 1);
                var t6 = vIndex + 0;

                var t4r = (t4 / (res + 1)) - 1;
                var t5r = (t5 / (res + 1)) - 1;
                var t6r = t6 / (res + 1);

                if (t4r == t5r && t5r == t6r && t6r == t4r)
                {
                    tris[i + 3] = t4;
                    tris[i + 4] = t5;
                    tris[i + 5] = t6;
                }
            }

            _mesh.triangles = tris;
            _mesh.RecalculateNormals(0);
            _mesh.RecalculateBounds();

#if UNITY_EDITOR
            UnityEditor.SceneView.onSceneGUIDelegate -= OnSceneGUIDelegate;
            UnityEditor.SceneView.onSceneGUIDelegate += OnSceneGUIDelegate;
#endif
        }
コード例 #18
0
        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);
        }
コード例 #19
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);
            }
        }
コード例 #20
0
ファイル: MMTerrainLayer.cs プロジェクト: cowtrix/Mad-Maps
        public void SetDetailMap(DetailPrototypeWrapper prototype, int x, int z, Serializable2DByteArray details, int dRes, Serializable2DFloatArray stencil = null)
        {
            if (DetailData == null)
            {
                DetailData = new CompressedDetailDataLookup();
            }

            Serializable2DByteArray existingDetails;

            if (!DetailData.TryGetValue(prototype, out existingDetails) || existingDetails.Width != dRes ||
                existingDetails.Height != dRes)
            {
                existingDetails       = new Serializable2DByteArray(dRes, dRes);
                DetailData[prototype] = existingDetails;
            }

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

            for (var u = x; u < x + width; ++u)
            {
                for (var v = z; v < z + height; ++v)
                {
                    var hx = u - x;
                    var hz = v - z;

                    try
                    {
                        var splatSample = details[hx, hz];
                        if (stencil != null)
                        {
                            existingDetails[u, v] = (byte)Mathf.Clamp(Mathf.Lerp(existingDetails[u, v], splatSample, stencil[hx, hz]), 0, 255);
                        }
                        else
                        {
                            existingDetails[u, v] = (byte)splatSample;
                        }
                    }
                    catch (Exception)
                    {
                        throw;
                    }
                }
            }


#if UNITY_EDITOR
            UnityEditor.EditorUtility.SetDirty(this);
#endif
        }
コード例 #21
0
ファイル: MMTerrainLayer.cs プロジェクト: cowtrix/Mad-Maps
        public void SetSplatmap(SplatPrototypeWrapper prototype, int x, int z,
                                float[,] splats, int splatRes, Serializable2DFloatArray stencil = null)
        {
            if (splats == null || prototype == null)
            {
                return;
            }
            if (SplatData == null)
            {
                SplatData = new CompressedSplatDataLookup();
            }

            Serializable2DByteArray existingSplats;

            if (!SplatData.TryGetValue(prototype, out existingSplats) || existingSplats.Width != splatRes ||
                existingSplats.Height != splatRes)
            {
                existingSplats       = new Serializable2DByteArray(splatRes, splatRes);
                SplatData[prototype] = existingSplats;
            }

            var width  = splats.GetLength(0);
            var height = splats.GetLength(1);

            for (var u = x; u < x + width; ++u)
            {
                if (u < 0 || u >= splatRes)
                {
                    continue;
                }
                for (var v = z; v < z + height; ++v)
                {
                    if (v < 0 || v >= splatRes)
                    {
                        continue;
                    }

                    var hx = u - x;
                    var hz = v - z;

                    try
                    {
                        var splatSample = splats[hx, hz] * 255f;

                        if (stencil != null)
                        {
                            var stencilVal = stencil[hx, hz];
                            splatSample = (byte)Mathf.Clamp(Mathf.Lerp(existingSplats[u, v], splatSample, stencilVal), 0, 255);
                        }

                        existingSplats[u, v] = (byte)Mathf.Clamp(splatSample, 0, 255);
                    }
                    catch (Exception)
                    {
                        throw;
                    }
                }
            }


#if UNITY_EDITOR
            UnityEditor.EditorUtility.SetDirty(this);
#endif
        }
コード例 #22
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);
            }
        }
コード例 #23
0
ファイル: MMTerrainLayer.cs プロジェクト: cowtrix/Mad-Maps
 public static bool IsValidStencil(Serializable2DFloatArray stencil)
 {
     return(stencil != null && stencil.Width > 0 && stencil.Height > 0);
 }
コード例 #24
0
ファイル: MMTerrainLayer.cs プロジェクト: cowtrix/Mad-Maps
        public override Serializable2DFloatArray BlendHeights(int x, int z, int width, int height, int heightRes, Serializable2DFloatArray result)
        {
            var layerHeights = GetHeights(x, z, width, height, heightRes);
            var stencil      = IsValidStencil(Stencil) ? Stencil : null;

            BlendMMTerrainLayerUtility.BlendArray(ref result,
                                                  layerHeights,
                                                  stencil,
                                                  BlendMode,
                                                  new Common.Coord(x, z),
                                                  new Common.Coord(x + width, z + height),
                                                  new Common.Coord(heightRes, heightRes));
            return(result);
        }