public void SetHeights(int x, int z, Serializable2DFloatArray heights, int heightRes, Serializable2DFloatArray stencil = null) { if (heights == null) { return; } if (Heights == null || Heights.Width != heightRes || Heights.Height != heightRes) { Heights = new Serializable2DFloatArray(heightRes, heightRes); } var width = heights.Width; var height = heights.Height; for (var u = x; u < x + width; ++u) { for (var v = z; v < z + height; ++v) { var hx = u - x; var hz = v - z; try { var heightsSample = heights[hx, hz]; heightsSample = Mathf.Clamp01(heightsSample); if (stencil == null) { Heights[u, v] = heightsSample; } else { float val; int key; MiscUtilities.DecompressStencil(stencil[u, v], out key, out val); Heights[u, v] = Mathf.Lerp(Heights[u, v], heightsSample, val); } } catch (IndexOutOfRangeException e) { Debug.LogError(string.Format("x {0} y {1}", hx, hz)); throw e; } } } #if UNITY_EDITOR UnityEditor.EditorUtility.SetDirty(this); #endif }
public override Texture2D ToTexture2D(bool normalise, Texture2D tex = null) { if (tex == null || tex.width != Width || tex.height != Height) { tex = new Texture2D(Width, Height); } var colors = new Color32[Width * Height]; OnBeforeSerialize(); for (int i = 0; i < Data.Length; i++) { int stencilKey; float value; MiscUtilities.DecompressStencil(Data[i], out stencilKey, out value); colors[i] = Color.Lerp(Color.black, ColorUtils.GetIndexColor(stencilKey), value); } tex.SetPixels32(colors); tex.Apply(); return(tex); }
public void Process(global::MapMagic.CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func <float, bool> stop = null) { if (stop != null && stop(0)) { return; } Matrix result = new Matrix(rect); foreach (MadMapsStencilOutput gen in gens.GeneratorsOfType <MadMapsStencilOutput>(onlyEnabled: true, checkBiomes: true)) { Matrix input = (Matrix)gen.input.GetObject(results); if (input == null) { continue; } //loading biome matrix Matrix biomeMask = null; if (gen.biome != null) { object biomeMaskObj = gen.biome.mask.GetObject(results); if (biomeMaskObj == null) { continue; //adding nothing if biome has no mask } biomeMask = (Matrix)biomeMaskObj; if (biomeMask == null) { continue; } if (biomeMask.IsEmpty()) { continue; //optimizing empty biomes } } //adding to final result if (gen.biome == null) { result.Add(input); } else if (biomeMask != null) { result.Add(input, biomeMask); } } //creating 2d array if (stop != null && stop(0)) { return; } int heightSize = terrainSize.resolution; var stencil = new Stencil(heightSize, heightSize); int key = 1; for (int x = 0; x < heightSize - 1; x++) { for (int z = 0; z < heightSize - 1; z++) { float strength; int disposableKey; MiscUtilities.DecompressStencil(stencil[x, z], out disposableKey, out strength); var writeValue = result[x + results.heights.rect.offset.x, z + results.heights.rect.offset.z]; stencil[x, z] = MiscUtilities.CompressStencil(key, strength + writeValue); } } //pushing to apply if (stop != null && stop(0)) { return; } results.apply.CheckAdd(typeof(MadMapsStencilOutput), stencil, replace: true); }
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 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); } } }