using UnityEngine; using Shapes; using System.Collections.Generic; [ExecuteAlways] public class LakeVisualizer : ImmediateModeShapeDrawer { [Header("网格设置")] public float fieldSize = 20f; public int pointCount = 30; public float pointSize = 0.15f; public float lineWidth = 0.03f; [Header("波动参数")] public float noiseScale = 0.3f; public float waveHeight = 1.5f; public float waveSpeed = 1f; public float timeScale = 1f; [Header("涟漪参数")] public float rippleStrength = 2f; public float rippleDuration = 1.5f; public float rippleSpreadSpeed = 6f; public float rippleSharpness = 2f; [Header("目标设置")] public Vector2 targetPosition = Vector2.zero; public float shapeChangeRadius = 4f; // 控制形状混合的范围 private Vector3[] points; private float time; private struct Ripple { public Vector2 position; public float startTime; } private List ripples = new List(); private void Update() { time = Application.isPlaying ? Time.time * timeScale : 0f; if (Application.isPlaying && Input.GetMouseButtonDown(0)) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out RaycastHit hit)) { ripples.Add(new Ripple { position = new Vector2(hit.point.x, hit.point.z), startTime = Time.time }); } } ripples.RemoveAll(r => Time.time - r.startTime > rippleDuration); } private float GetNoiseHeight(float x, float z, float currentTime) { float noise = 0f; float amp = 1f; float freq = 1f; for (int i = 0; i < 3; i++) { float nx = x * freq * noiseScale; float nz = z * freq * noiseScale; float nt = currentTime * waveSpeed * freq; noise += Mathf.PerlinNoise(nx + nt, nz + nt) * amp; amp *= 0.5f; freq *= 2f; } return noise * waveHeight; } public override void DrawShapes(Camera cam) { using (Draw.Command(cam)) { Draw.ResetAllDrawStates(); Draw.LineGeometry = LineGeometry.Volumetric3D; Draw.Thickness = lineWidth; float step = fieldSize / (pointCount - 1); float halfSize = fieldSize * 0.5f; if (points == null || points.Length != pointCount * pointCount) points = new Vector3[pointCount * pointCount]; for (int i = 0; i < pointCount; i++) { for (int j = 0; j < pointCount; j++) { float x = -halfSize + j * step; float z = -halfSize + i * step; Vector2 pos2D = new Vector2(x, z); float baseY = GetNoiseHeight(x, z, time); float rippleY = 0f; float brightness = 0f; float shapeBlend = 0f; foreach (var ripple in ripples) { float elapsed = Time.time - ripple.startTime; float spread = elapsed * rippleSpreadSpeed; float dist = Vector2.Distance(pos2D, ripple.position); float ease = Mathf.Sin(Mathf.Clamp01(elapsed / rippleDuration) * Mathf.PI); float spike = Mathf.Exp(-Mathf.Pow(dist - spread, 2f) * rippleSharpness); float bright = Mathf.Exp(-Mathf.Pow((dist - spread) * 0.5f, 2f)); rippleY += spike * rippleStrength * ease; brightness += bright * ease; // 目标点接近程度影响形状混合程度 float targetDist = Vector2.Distance(ripple.position, targetPosition); float shapeFactor = Mathf.Clamp01(1f - targetDist / shapeChangeRadius); shapeBlend = Mathf.Max(shapeBlend, shapeFactor * ease); } float finalY = baseY + rippleY; Vector3 worldPos = new Vector3(x, finalY, z); points[i * pointCount + j] = worldPos; float depth = (finalY + waveHeight) / (waveHeight * 2f); float brightnessScale = Mathf.Clamp01(1f + brightness); Color pointColor = Color.Lerp(new Color(0.5f, 1f, 1f), new Color(0f, 0.5f, 1f), depth); pointColor *= brightnessScale; float scale = pointSize * (1f - depth * 0.5f); // 形状混合逻辑(近似插值) if (shapeBlend < 0.1f) { Draw.Sphere(worldPos, scale, pointColor); } else if (shapeBlend < 0.3f) { Draw.Torus(worldPos, scale * 0.6f, scale * 0.2f, pointColor); // 环形 } else if (shapeBlend < 0.6f) { Draw.Cube(worldPos, scale * 1.4f, pointColor); // 立方体 } else if (shapeBlend < 0.9f) { Draw.Cone(worldPos, scale * 1.6f, scale * 0.5f, pointColor); // 锥体 } else { Vector3 a = worldPos + Vector3.up * scale; Vector3 b = worldPos + new Vector3(scale, -scale, 0); Vector3 c = worldPos + new Vector3(-scale, -scale, 0); Draw.Triangle(a, b, c, pointColor); // 三角形 } } } // 连接线条(可选) for (int i = 0; i < pointCount; i++) { for (int j = 0; j < pointCount; j++) { int index = i * pointCount + j; Vector3 current = points[index]; if (j < pointCount - 1) { Vector3 next = points[index + 1]; DrawLine(current, next); } if (i < pointCount - 1) { Vector3 next = points[index + pointCount]; DrawLine(current, next); } } } } } void DrawLine(Vector3 a, Vector3 b) { float avgY = (a.y + b.y) * 0.5f; float lineDepth = (avgY + waveHeight) / (waveHeight * 2f); Color lineColor = Color.Lerp(Color.cyan, new Color(0, 0.5f, 1f, 0.3f), lineDepth); Draw.Line(a, b, lineWidth * (1f - lineDepth * 0.5f), lineColor); } }