public static void SnapshotSplats(this MMTerrainLayer layer, Terrain terrain) { var rawSplats = terrain.terrainData.GetAlphamaps(0, 0, terrain.terrainData.alphamapWidth, terrain.terrainData.alphamapHeight); layer.SplatData.Clear(); var splatWrapperLookup = ResolvePrototypes(terrain.terrainData.splatPrototypes); for (var k = 0; k < rawSplats.GetLength(2); ++k) { var prototype = terrain.terrainData.splatPrototypes[k]; SplatPrototypeWrapper wrapper; if (!splatWrapperLookup.TryGetValue(prototype, out wrapper)) { continue; } var data = new Serializable2DByteArray(terrain.terrainData.alphamapResolution, terrain.terrainData.alphamapResolution); float sum = 0; for (var u = 0; u < rawSplats.GetLength(0); ++u) { for (var v = 0; v < rawSplats.GetLength(1); ++v) { var sample = (byte)Mathf.Clamp(rawSplats[u, v, k] * 255f, 0, 255); data[v, u] = sample; sum += sample; } } if (sum > 0) { layer.SplatData[wrapper] = data; } } }
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(); }
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 }
public override Serializable2DByteArray BlendDetails(DetailPrototypeWrapper detailWrapper, int x, int z, int width, int height, int dRes, Serializable2DByteArray result) { var layerDetails = GetDetailMap(detailWrapper, x, z, width, height, dRes); if (layerDetails == null) { return(result); } var stencil = IsValidStencil(Stencil) ? Stencil : null; BlendMMTerrainLayerUtility.BlendArray(ref result, layerDetails, stencil, BlendMode, Common.Coord.Zero, new Common.Coord(dRes, dRes)); return(result); }
/* * public static float BilinearSample(this Serializable2DIntArray array, Vector2 normalizedCoord) * { * if (array == null) * { * 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) * (yFrac); * v3 *= (xFrac) * (1 - yFrac); * v4 *= (xFrac) * (yFrac); * * return v1 + v2 + v3 + v4; * } */ public static float BilinearSample(this Serializable2DByteArray array, Vector2 normalizedCoord) { if (array == null) { 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); }
public override Serializable2DByteArray BlendSplats(SplatPrototypeWrapper splat, int x, int z, int width, int height, int aRes, Serializable2DByteArray result) { var layerSplats = GetSplatmap(splat, x, z, width, height, aRes); if (layerSplats == null) { return(result); } var stencil = BlendMode == EMMTerrainLayerBlendMode.Stencil && IsValidStencil(Stencil) ? Stencil : null; BlendMMTerrainLayerUtility.BlendArray(ref result, layerSplats, stencil, BlendMode, new Common.Coord(x, z), new Common.Coord(aRes, aRes)); return(result); }
public override Serializable2DByteArray GetDetailMap(DetailPrototypeWrapper detailWrapper, int x, int z, int width, int height, int detailResolution) { if (DetailData == null) { return(null); } Serializable2DByteArray data; if (!DetailData.TryGetValue(detailWrapper, out data)) { return(null); } if (data.Width != detailResolution || data.Height != detailResolution) { DetailData.Remove(detailWrapper); return(null); } var detailMap = new Serializable2DByteArray(width, 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 detail = data[u, v]; detailMap[hx, hz] = detail; } catch (Exception) { throw; } } } return(detailMap); }
public override Serializable2DByteArray GetSplatmap(SplatPrototypeWrapper prototype, int x, int z, int width, int height, int splatResolution) { if (SplatData == null) { return(null); } Serializable2DByteArray data; if (!SplatData.TryGetValue(prototype, out data)) { return(null); } if (data.Width != splatResolution || data.Height != splatResolution) { SplatData.Remove(prototype); return(null); } var splats = new Serializable2DByteArray(width, 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 = data[u, v]; splats[hx, hz] = splatSample; } catch (Exception) { throw; } } } return(splats); }
public static void SnapshotDetails(this MMTerrainLayer layer, Terrain terrain) { layer.DetailData.Clear(); var prototypes = terrain.terrainData.detailPrototypes; var dRes = terrain.terrainData.detailResolution; var wrapperLookup = ResolvePrototypes(prototypes); for (var i = 0; i < prototypes.Length; i++) { DetailPrototypeWrapper wrapper; var prototype = prototypes[i]; if (!wrapperLookup.TryGetValue(prototype, out wrapper)) { continue; } var data = new Serializable2DByteArray(dRes, dRes); var detailMap = terrain.terrainData.GetDetailLayer(0, 0, terrain.terrainData.detailWidth, terrain.terrainData.detailHeight, i); int sum = 0; for (var u = 0; u < detailMap.GetLength(0); u++) { for (var v = 0; v < detailMap.GetLength(1); v++) { var sample = (byte)detailMap[u, v]; data[v, u] = sample; sum += sample; } } if (sum > 0) { layer.DetailData.Add(wrapper, data); } } }
public virtual Serializable2DByteArray BlendDetails(DetailPrototypeWrapper detail, int x, int z, int width, int height, int dRes, Serializable2DByteArray result) { // throw new NotImplementedException(); //Debug.LogErrorFormat("BlendDetails is not implemented for {0} ({1})", name, GetType()); return(result); }
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 }
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(); }
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 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); }
public static void BlendArray(ref Serializable2DByteArray baseData, Serializable2DByteArray blendingData, Serializable2DFloatArray stencil, MMTerrainLayer.EMMTerrainLayerBlendMode blendMode, Common.Coord offset, Common.Coord size) { 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/BlendIntArray"); int kernelHandle = blendShader.FindKernel("BlendInts"); var baseAsInt = baseData.Data.ConvertToIntArray(); // TODO hmmmmm var blendAsInt = blendingData.Data.ConvertToIntArray(); //var baseBuffer = new ComputeBuffer(baseData.Width * baseData.Height, sizeof(float)); var baseBuffer = ComputeShaderPool.GetBuffer(baseData.Width * baseData.Height, sizeof(float)); baseBuffer.SetData(baseAsInt); 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(blendAsInt); 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, 0, 0)); blendShader.Dispatch(kernelHandle, baseData.Width, baseData.Height, 1); baseBuffer.GetData(baseAsInt); for (int i = 0; i < baseAsInt.Length; i++) { baseData.Data[i] = (byte)baseAsInt[i]; } /*baseBuffer.Release(); * baseBuffer.Dispose(); * blendBuffer.Release(); * blendBuffer.Dispose();*/ ComputeShaderPool.ReturnBuffer(baseBuffer); ComputeShaderPool.ReturnBuffer(blendBuffer); if (stencilBuffer != null) { ComputeShaderPool.ReturnBuffer(stencilBuffer); //stencilBuffer.Release(); //stencilBuffer.Dispose(); } //Resources.UnloadAsset(blendShader); UseCount++; } else { for (int dx = 0; dx < width; dx++) { for (int dz = 0; dz < height; dz++) { var blendingVal = blendingData[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 = (offset.x + dx) / (float)size.x; var zF = (offset.z + dz) / (float)size.z; float strength; stencil.StencilBilinearSample(new Vector2(xF, zF), out strength); if (strength > 0) { var existingValue = baseData[dx, dz]; var newValue = (byte)Mathf.RoundToInt(Mathf.Clamp(Mathf.Lerp(existingValue, blendingVal, strength), 0, 255)); baseData[dx, dz] = newValue; } break; } } } } GC.Collect(3, GCCollectionMode.Forced); }