public void ApplyStampsToTerrain(TerrainWrapper wrapper) { wrapper.OnPostFinalise -= ApplyStampsToTerrain; if (!ApplyStamps) { return; } //Debug.Log("ApplyStampsToTerrain"); if (!wrapper.ObjectContainer) { return; } var ws = wrapper.ObjectContainer.transform.FindTransformInChildren(LayerName); if (!ws) { return; } var stamps = ws.GetComponentsInChildren <WorldStamp>(); List <string> layers = new List <string>(); foreach (var s in stamps) { if (layers.Contains(s.LayerName)) { continue; } layers.Add(s.LayerName); } layers = layers.OrderBy((x) => wrapper.Layers.FindIndex(0, (y) => x == y.name)).ToList(); for (var i = 0; i < layers.Count; ++i) { LayerComponentApplyManager.ApplyAllLayerComponents(wrapper, layers[i]); } }
public static void WeldToNextX (ref float[,] heights, TerrainWrapper neig, int margin) { #if WDEBUG Profiler.BeginSample("Weld Height"); #endif //Debug.Log("NextX"); int heightSize = heights.GetLength(0); var nStrip = neig.GetCompoundHeights(null,0,0,heightSize,1,heightSize); for (int z=0; z<heightSize; z++) { float thisHeight = Mathf.Clamp01(nStrip[z,0]); for (int x=heightSize-margin; x<heightSize; x++) { float percent = 1 - 1f*(heightSize-x-1)/margin; //percent = 3*percent*percent - 2*percent*percent*percent; //heights[z,x] += delta*percent; //float prevValue = Mathf.Clamp01(heights[z,x]) ; heights[z,x] = Mathf.Lerp(heights[z,x], thisHeight, percent); //Debug.Log(string.Format("Set ({0}, {1}) from {2} to {3} ({4}% to {5})", x, z, prevValue, heights[z,x], percent, thisHeight)); } } #if WDEBUG Profiler.EndSample(); #endif }
public static void WeldToPrevZ (ref float[,] heights, TerrainWrapper neig, int margin) { #if WDEBUG Profiler.BeginSample("Weld Height"); #endif //Debug.Log("PrevZ"); int heightSize = heights.GetLength(0); var nStrip = neig.GetCompoundHeights(null,heightSize-1,0,1,heightSize,heightSize); for (int x=0; x<heightSize; x++) { var delta = nStrip[0,x] - heights[0,x]; //float percentFromSide = Mathf.Min( Mathf.Clamp01(1f*x/margin), Mathf.Clamp01(1 - 1f*(x-(heightSize-1-margin))/margin) ); //float invPercentFromSide = 2000000000; if (percentFromSide > 0.0001f) invPercentFromSide = 1f/percentFromSide; for (int z=0; z<margin; z++) { float percent = 1-1f*z/margin; // if (percentFromSide < 0.999f) percent = Mathf.Pow(percent, invPercentFromSide); //percent = 3*percent*percent - 2*percent*percent*percent; heights[z,x] += delta*percent; //heights[z,x] = 1; } } #if WDEBUG Profiler.EndSample(); #endif }
public static void WeldToPrevX (ref float[,] heights, TerrainWrapper neig, int margin) { #if WDEBUG Profiler.BeginSample("Weld Height"); #endif int heightSize = heights.GetLength(0); //Debug.Log("PrevX:" + heightSize); var nStrip = neig.GetCompoundHeights(null,0,heightSize-1,heightSize,1,heightSize); //var nStrip = neig.GetCompoundHeights(null,0,0,heightSize,1,heightSize); for (int x=0; x<heightSize; x++) { float delta = nStrip[x,0] - heights[x,0]; for (int z=0; z<margin; z++) { float percent = 1-1f*z/margin; //percent = 3*percent*percent - 2*percent*percent*percent; heights[x,z] += delta*percent; //heights[z,x] = 1; } } #if WDEBUG Profiler.EndSample(); #endif }
public override void ProcessTrees(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) { return; } var spline = NodeConnection.GetSpline(); var rand = new Random(NodeConnection.ThisNode.Seed); var length = spline.Length; var step = config.StepDistance; var tSize = wrapper.Terrain.terrainData.size; for (var i = 0f; i < length; i += step.GetRand(rand)) { var roll = rand.NextDouble(); var randroll = (float)rand.NextDouble(); var eval = config.ProbablityThroughCurve.Evaluate(randroll); //Debug.Log(randroll + " " + eval); var offsetDist = eval * config.OffsetMultiplier; var uniformT = i / length; var naturalT = spline.UniformToNaturalTime(uniformT); var offset = (spline.GetTangent(naturalT).normalized *offsetDist); var probability = config.ProbablityAlongCurve.Evaluate(uniformT) * config.ProbabilityMultiplier; if (probability < roll) { continue; } // Place tree var randIndex = Mathf.FloorToInt((float)rand.NextDouble() * config.Trees.Count); var prefab = config.Trees[randIndex]; var wPos = spline.GetUniformPointOnSpline(uniformT) + offset; //var h - //wPos.y = wrapper.GetCompoundHeight(layer, wPos)*tSize.y; wPos.y = config.YOffset; //Debug.DrawLine(wPos, wPos + Vector3.up *10, Color.red, 10); var tPos = wrapper.Terrain.WorldToTreePos(wPos); layer.Trees.Add(new MadMapsTreeInstance(tPos, Vector2.one * config.Size.GetRand(rand), prefab, config.Color.GetRand(rand))); } }
public void Snap() { if (!Network || Configuration.SnappingMode == NodeConfiguration.ESnappingMode.None || Vector3.Distance(_lastSnapPosition, transform.position) < .01f) { return; // Do nothing in this case } if (Configuration.SnappingMode == NodeConfiguration.ESnappingMode.Wrapper) { var pos = transform.position; var wrapper = TerrainWrapper.GetWrapper(pos); if (wrapper != null) { if (wrapper.Layers.Count > 0) { var newY = wrapper.GetCompoundHeight(Network.GetLayer(wrapper), pos) * wrapper.Terrain.terrainData.size.y + wrapper.Terrain.GetPosition().y + Configuration.SnapOffset; transform.position = new Vector3(transform.position.x, newY, transform.position.z); } else { Debug.LogWarning("Node with a Wrapper snap setting on a terrain, but wrapper has no layers - this won't work.", this); } } else { Debug.LogWarning("Node with a Wrapper snap setting on a terrain without a TerrainWrapper component - this won't work.", this); } _lastSnapPosition = transform.position; } if (Configuration.SnappingMode == NodeConfiguration.ESnappingMode.Terrain) { var terrain = TerrainX.FindEncompassingTerrain(transform.position); var newY = terrain.SampleHeight(transform.position) + terrain.GetPosition().y + Configuration.SnapOffset; transform.position = new Vector3(transform.position.x, newY, transform.position.z); _lastSnapPosition = transform.position; } if (Configuration.SnappingMode == NodeConfiguration.ESnappingMode.Raycast) { RaycastHit hitInfo; if (Physics.Raycast( new Ray(transform.position + Vector3.up * Configuration.SnapDistance / 2, Vector3.down), out hitInfo, Configuration.SnapDistance, Configuration.SnapMask)) { transform.position = hitInfo.point + Vector3.up * Configuration.SnapOffset; } _lastSnapPosition = transform.position; } var exitNode = GetComponent <StampExitNode>(); if (exitNode) { exitNode.Update(); } }
void OnEnable() { var wrappers = FindObjectsOfType <TerrainWrapper>(); if (wrappers.Length > 0) { Context = wrappers[0]; } Sort(); }
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); } }
public override void ProcessTrees(TerrainWrapper terrainWrapper, LayerBase baseLayer, int stencilKey) { if (!RemoveTrees) { 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; } var objectBounds = GetObjectBounds(); stencilKey = GetPriority(); var trees = terrainWrapper.GetCompoundTrees(layer, true); objectBounds = new ObjectBounds(objectBounds.center, new Vector3(objectBounds.extents.x, 50000, objectBounds.extents.z), objectBounds.Rotation); foreach (var hurtTreeInstance in trees) { if (IgnoredTrees.Contains(hurtTreeInstance.Prototype)) { //Debug.DrawLine(worldPos, worldPos + Vector3.up * 10, Color.red, 50); continue; } var worldPos = terrainWrapper.Terrain.TreeToWorldPos(hurtTreeInstance.Position); worldPos = new Vector3(worldPos.x, objectBounds.center.y, worldPos.z); if (!objectBounds.Contains(new Vector3(worldPos.x, objectBounds.center.y, worldPos.z))) { //Debug.DrawLine(worldPos, worldPos + Vector3.up * 10, Color.red, 50); 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)); //DebugHelper.DrawPoint(worldPos, 1, Color.white, 5); if (falloff > .5f) { layer.TreeRemovals.Add(hurtTreeInstance.Guid); //Debug.DrawLine(worldPos, worldPos + Vector3.up * 10, Color.red, 50); } /*else{ * Debug.DrawLine(worldPos, worldPos + Vector3.up * 10, Color.green, 50); * }*/ } }
void OnSelectionChange() { if (!Selection.activeGameObject) { return; } var wrapper = Selection.activeGameObject.GetComponent <TerrainWrapper>(); if (wrapper) { Context = wrapper; NeedsResort = true; } }
public MMTerrainLayer GetLayer(TerrainWrapper terrainWrapper, bool createIfMissing = false) { MMTerrainLayer snapshot; if ((!LayerMapping.TryGetValue(terrainWrapper, out snapshot) || snapshot == null) && createIfMissing) { snapshot = ScriptableObject.CreateInstance <MMTerrainLayer>(); snapshot.name = "Road Network"; LayerMapping[terrainWrapper] = snapshot; terrainWrapper.Layers.Insert(0, snapshot); snapshot.BlendMode = MMTerrainLayer.EMMTerrainLayerBlendMode.Stencil; } return(snapshot); }
public override void ProcessObjects(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; } var regex = new Regex(IgnoredObjectsRegex ?? string.Empty); var objectBounds = GetObjectBounds(); stencilKey = GetPriority(); var objects = terrainWrapper.GetCompoundObjects(layer); objectBounds = new ObjectBounds(objectBounds.center, new Vector3(objectBounds.extents.x, 5000, objectBounds.extents.z), objectBounds.Rotation); foreach (var prefabObjectData in objects) { if (!string.IsNullOrEmpty(IgnoredObjectsRegex) && regex.IsMatch(prefabObjectData.Prefab.name)) { continue; } var worldPos = terrainWrapper.Terrain.TreeToWorldPos(prefabObjectData.Position); worldPos = new Vector3(worldPos.x, objectBounds.center.y, worldPos.z); if (!objectBounds.Contains(new Vector3(worldPos.x, objectBounds.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 (falloff > .5f) { layer.ObjectRemovals.Add(prefabObjectData.Guid); } } }
public override void ProcessObjects(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) { return; } if (Configuration == null) { return; } var config = Configuration.GetConfig <Config>(); if (config == null) { Debug.LogError("Invalid configuration! Expected ConnectionTerrainHeightConfiguration"); return; } var spline = NodeConnection.GetSpline(); var bounds = spline.GetApproximateXZObjectBounds(); bounds.Expand(new Vector3(config.ObjectRemoveDistance, 1000, config.ObjectRemoveDistance)); var tPos = wrapper.transform.position; var tSize = wrapper.Terrain.terrainData.size; var regex = new Regex(config.RegexMatch ?? string.Empty); var objects = wrapper.GetCompoundObjects(layer, true); foreach (var data in objects) { if (data.Prefab == null || !regex.IsMatch(data.Prefab.name)) { continue; } var wPos = tPos + new Vector3(data.Position.x * tSize.x, data.Position.y, data.Position.z * tSize.z); if (!bounds.Contains(wPos)) { //Debug.DrawLine(wPos, wPos + Vector3.up * 10, Color.cyan, 20); continue; } var ut = spline.GetClosestUniformTimeOnSplineXZ(wPos.xz()); var pointOnSpline = spline.GetUniformPointOnSpline(ut); var dist = (pointOnSpline.xz() - wPos.xz()).magnitude; if (dist < config.ObjectRemoveDistance) { if (!layer.ObjectRemovals.Contains(data.Guid)) { layer.ObjectRemovals.Add(data.Guid); } if (ShowDebug) { Debug.DrawLine(pointOnSpline, wPos, Color.red, 20); } } else { if (ShowDebug) { Debug.DrawLine(pointOnSpline, wPos, Color.green, 20); } } } }
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 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); } } }
public override void ProcessVegetationStudio(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; } var config = Configuration.GetConfig <Config>(); var spline = NodeConnection.GetSpline(); var rand = new Random(NodeConnection.ThisNode.Seed); if (config.Prototypes.SelectedIDs.Count == 0 || config.Prototypes.Package == null) { return; } var length = spline.Length; var step = config.StepDistance; var tSize = wrapper.Terrain.terrainData.size; for (var i = 0f; i < length; i += step.GetRand(rand)) { var roll = rand.NextDouble(); var randroll = (float)rand.NextDouble(); var eval = config.ProbablityThroughCurve.Evaluate(randroll); //Debug.Log(randroll + " " + eval); var offsetDist = eval * config.OffsetMultiplier; var uniformT = i / length; var naturalT = spline.UniformToNaturalTime(uniformT); var offset = (spline.GetTangent(naturalT).normalized *offsetDist); var probability = config.ProbablityAlongCurve.Evaluate(uniformT) * config.ProbabilityMultiplier; if (probability < roll) { continue; } // Place tree var randIndex = Mathf.FloorToInt((float)rand.NextDouble() * config.Prototypes.SelectedIDs.Count); var id = config.Prototypes.SelectedIDs[randIndex]; var wPos = spline.GetUniformPointOnSpline(uniformT) + offset; //Debug.DrawLine(wPos, wPos + Vector3.up *10, Color.red, 10); var tPos = wrapper.Terrain.WorldToTreePos(wPos); tPos.y = config.YOffset; var size = Vector3.one * config.Size.GetRand(rand); var newInstance = new VegetationStudioInstance() { Guid = System.Guid.NewGuid().ToString(), VSID = id, Position = tPos, Scale = size, Rotation = config.Rotation.GetRand(rand), Package = config.Prototypes.Package, }; layer.VSInstances.Add(newInstance); } }
public override void ProcessVegetationStudio(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; } var tSize = terrainWrapper.Terrain.terrainData.size; var tPos = terrainWrapper.transform.position; var wrapperBounds = new Bounds(terrainWrapper.Terrain.GetPosition() + terrainWrapper.Terrain.terrainData.size / 2, terrainWrapper.Terrain.terrainData.size); wrapperBounds.Expand(Vector3.up * 5000); if (RemoveExistingVSData) { var stampBounds = new ObjectBounds(transform.position, Size / 2, transform.rotation); stampBounds.Expand(Vector3.up * 5000); var compoundVSData = terrainWrapper.GetCompoundVegetationStudioData(layer, true); foreach (var vsdataInstance in compoundVSData) { if (layer.VSRemovals.Contains(vsdataInstance.Guid)) { continue; } if (IgnoredVSPrototypes.Contains(vsdataInstance.VSID)) { continue; } var wPos = vsdataInstance.Position; wPos = new Vector3(wPos.x * tSize.x, wPos.y, wPos.z * tSize.z); wPos += tPos; if (stampBounds.Contains(wPos)) { var stencilPos = wPos - tPos; stencilPos = new Vector2(stencilPos.x / tSize.x, stencilPos.z / tSize.z); var stencilAmount = layer.GetStencilStrength(stencilPos, stencilKey); if (stencilAmount > 0.5f) { layer.VSRemovals.Add(vsdataInstance.Guid); //Debug.DrawLine(wPos, wPos + Vector3.up * stencilAmount * 20, Color.red, 30); } } } } if (!VegetationStudioEnabled) { UnityEngine.Profiling.Profiler.EndSample(); return; } for (var i = 0; i < Data.VSData.Count; i++) { var vsInstance = Data.VSData[i].Clone(); var maskPos = new Vector3(vsInstance.Position.x * Data.Size.x, 0, vsInstance.Position.z * Data.Size.z) /* + (Data.Size/2)*/; var maskValue = GetMask().GetBilinear(Data.GridManager, maskPos); if (maskValue <= 0.25f) { continue; } var wPos = transform.position + transform.rotation * (new Vector3(vsInstance.Position.x * Size.x, vsInstance.Position.y, vsInstance.Position.z * Size.z) - (Size.xz().x0z() / 2)); if (!wrapperBounds.Contains(wPos)) { continue; } if (StencilVSData) { var stencilPos = new Vector2((wPos.x - tPos.x) / tSize.x, (wPos.z - tPos.z) / tSize.z); var stencilVal = layer.GetStencilStrength(stencilPos, stencilKey); if (stencilVal <= 0.25f) { continue; } } vsInstance.Guid = Guid.NewGuid().ToString(); //var height = terrainWrapper.GetCompoundHeight(layer, wPos, true) * tSize.y * Vector3.up; vsInstance.Position = wPos - terrainWrapper.transform.position; vsInstance.Position.y = Data.VSData[i].Position.y; vsInstance.Position = new Vector3(vsInstance.Position.x / tSize.x, vsInstance.Position.y, vsInstance.Position.z / tSize.z); layer.VSInstances.Add(vsInstance); } UnityEngine.Profiling.Profiler.EndSample(); }
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 override void ProcessObjects(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 (Configuration == null || !Network) { return; } var config = Configuration.GetConfig <Config>(); if (config == null) { Debug.LogError("Invalid config for ConnectionObjectComponent " + name, this); return; } if (config.Objects == null || config.Objects.Count == 0) { return; } var seed = NodeConnection.ThisNode.Seed; var rand = new Random(seed); var spline = NodeConnection.GetSpline(); var length = spline.Length; var step = config.Distance; var tSize = wrapper.Terrain.terrainData.size; for (var i = config.InitialOffset; i < length; i += step.GetRand(rand)) { var randIndex = Mathf.FloorToInt((float)rand.NextDouble() * config.Objects.Count); var prefab = config.Objects[randIndex]; var roll = (float)rand.NextDouble(); if (roll > config.Chance) { continue; } var offset = config.LocalOffset.GetRand(rand); var scale = config.Scale.GetRand(rand); if (config.UniformScale) { scale = Vector3.one * scale.x; } var uniformT = i / length; var splineOffset = config.SplineOffset.GetRand(rand) * (rand.Flip() ? -1 : 1); var tangent = spline.GetTangent(uniformT).normalized; var rotation = Quaternion.LookRotation(tangent) * Quaternion.Euler(config.Rotation.GetRand(rand)); var worldPos = spline.GetUniformPointOnSpline(uniformT); worldPos += tangent * splineOffset; worldPos += offset; if (!config.AbsoluteHeight) { worldPos.y = offset.y; } var tPos = worldPos - wrapper.transform.position; tPos = new Vector3(tPos.x / tSize.x, tPos.y, tPos.z / tSize.z); var prefabObject = new PrefabObjectData() { AbsoluteHeight = config.AbsoluteHeight, Guid = Guid.NewGuid().ToString(), Position = tPos, Scale = scale, Rotation = rotation.eulerAngles, Prefab = prefab, ContainerMetadata = layer.name, }; layer.Objects.Add(prefabObject); } }
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); } }
void OnGUI() { titleContent = new GUIContent("WS Priorities"); EditorGUILayout.BeginHorizontal(); EditorGUILayout.BeginVertical(); Context = (TerrainWrapper)EditorGUILayout.ObjectField("Terrain Wrapper", Context, typeof(TerrainWrapper), true); Filter = EditorGUILayout.TextField("Layer Filter", Filter); EditorGUILayout.EndVertical(); GUI.enabled = Context; if (GUILayout.Button(EditorGUIUtility.IconContent("TreeEditor.Refresh"), GUILayout.Width(32), GUILayout.Height(32))) { NeedsResort = true; } GUI.enabled = true; EditorGUILayout.EndHorizontal(); if (Context == null) { EditorGUILayout.HelpBox("Please Select a Terrain Wrapper", MessageType.Info); return; } if (NeedsResort) { NeedsResort = false; Sort(); } if ((_list == null || _list.Count == 0)) { EditorGUILayout.HelpBox("No Eligible Layer Components Found In Scene", MessageType.Info); return; } _scroll = EditorGUILayout.BeginScrollView(_scroll); foreach (var mapping in _list) { EditorExtensions.Seperator(); EditorGUILayout.LabelField(string.Format("[{0}] Layer '{1}'", mapping.LayerIndex, mapping.LayerName)); foreach (var stamp in mapping.Components) { EditorGUILayout.BeginHorizontal(); if (GUILayout.Button(string.Format(" {0}", stamp.name), EditorStyles.boldLabel)) { Selection.activeGameObject = stamp.gameObject; } EditorGUILayout.LabelField("Priority", GUILayout.Width(50)); var currentPriority = stamp.GetPriority(); currentPriority = EditorGUILayout.DelayedIntField(currentPriority, GUILayout.Width(100)); if (currentPriority != stamp.GetPriority()) { stamp.SetPriority(currentPriority); NeedsResort = true; } EditorGUILayout.EndHorizontal(); } EditorGUILayout.Space(); } EditorGUILayout.EndScrollView(); }
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 ProcessVegetationStudio(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) { Debug.LogError("Unable to find network! " + name, this); return; } if (Configuration == null) { return; } var config = Configuration.GetConfig <Config>(); if (config == null) { Debug.LogError("Invalid configuration! Expected ConnectionTerrainHeightConfiguration"); return; } var mainSpline = NodeConnection.GetSpline(); var radius = config.InstanceRemoveDistance; // 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); var flatCullbounds = objectBounds.ToAxisBounds(); //DebugHelper.DrawCube(flatCullbounds.center, flatCullbounds.extents, Quaternion.identity, Color.yellow, 20); //DebugHelper.DrawCube(objectBounds.center, objectBounds.extents, objectBounds.Rotation, Color.cyan, 20); Plane startPlane, endPlane; GenerateSplinePlanes(0, mainSpline, out startPlane, out endPlane); var vsData = wrapper.GetCompoundVegetationStudioData(layer, true, flatCullbounds); for (int i = vsData.Count - 1; i >= 0; i--) { var vsInstance = vsData[i]; if (config.IgnoredPrototypes.Contains(vsInstance.VSID)) { continue; } var wPos = wrapper.Terrain.TreeToWorldPos(vsInstance.Position); if (!objectBounds.Contains(wPos) || !GeometryExtensions.BetweenPlanes(wPos, startPlane, endPlane)) { continue; } var ut = mainSpline.GetClosestUniformTimeOnSplineXZ(wPos.xz()); var splinePos = mainSpline.GetUniformPointOnSpline(ut); var d = splinePos.xz() - wPos.xz(); if (d.sqrMagnitude < config.InstanceRemoveDistance * config.InstanceRemoveDistance && !layer.VSRemovals.Contains(vsInstance.Guid)) { layer.VSRemovals.Add(vsInstance.Guid); //DebugHelper.DrawPoint(wPos, .5f, Color.red, 20); } } }