using Sirenix.OdinInspector; using UnityEngine; using UnityEngine.Splines; #if UNITY_EDITOR using System.IO; using UnityEditor; #endif namespace DanieleMarotta.RiversongCodeShowcase { [RequireComponent(typeof(SplineContainer))] public class WaterFlowMapBaker : MonoBehaviour { #if UNITY_EDITOR public int WorldSize = 100; public int MapSize = 512; public float InfluenceRadius = 10; public Texture2D OutputTexture; [Button(ButtonSizes.Large)] [GUIColor("cyan")] public void BakeFlowMap() { var splineContainer = GetComponent(); var texture = new Texture2D(MapSize, MapSize, TextureFormat.RGBA32, false, true) { wrapMode = TextureWrapMode.Clamp, filterMode = FilterMode.Bilinear }; for (var y = 0; y < MapSize; y++) for (var x = 0; x < MapSize; x++) { var c = new Color(0.5f, 0.5f, 0, 0); var uv = new Vector2((x + 0.5f) / MapSize, (y + 0.5f) / MapSize); var world = new Vector3(uv.x * WorldSize, 0, uv.y * WorldSize); var distance = SplineUtility.GetNearestPoint(splineContainer.Spline, world, out _, out var t); if (distance <= InfluenceRadius) { var tangent = splineContainer.Spline.EvaluateTangent(t); var direction = new Vector2(tangent.x, tangent.z); if (direction.sqrMagnitude > 0.0001f) direction.Normalize(); var influence = Mathf.Clamp01(1 - distance / InfluenceRadius); c.r = direction.x * 0.5f + 0.5f; c.g = direction.y * 0.5f + 0.5f; c.b = influence; } texture.SetPixel(x, y, c); } texture.Apply(false, false); var textureDirty = false; if (!OutputTexture) { var path = EditorUtility.SaveFilePanelInProject("Save Flow Map", "WaterFlowMap", "asset", string.Empty); if (!string.IsNullOrEmpty(path)) { texture.name = Path.GetFileNameWithoutExtension(path); AssetDatabase.CreateAsset(texture, path); OutputTexture = AssetDatabase.LoadAssetAtPath(path); textureDirty = true; } } else { texture.name = OutputTexture.name; EditorUtility.CopySerialized(texture, OutputTexture); textureDirty = true; } if (textureDirty) { EditorUtility.SetDirty(OutputTexture); AssetDatabase.SaveAssets(); } } #endif } }