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)); }
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 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); } }
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 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); } }
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); }
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); }
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); } }
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); } } }