158 lines
5.3 KiB
C#
158 lines
5.3 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using Shapes;
|
|
|
|
[ExecuteAlways]
|
|
[RequireComponent(typeof(MeshCollider))]
|
|
public class LakeLineDrawer : 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 = 1.5f;
|
|
public float rippleRadius = 2f;
|
|
public float rippleDuration = 2f;
|
|
|
|
private Vector3[] points;
|
|
private float time;
|
|
|
|
// 涟漪记录
|
|
private List<Vector2> rippleCenters = new List<Vector2>();
|
|
private List<float> rippleTimes = new List<float>();
|
|
|
|
private void Update()
|
|
{
|
|
// 运行中才响应点击
|
|
if (Application.isPlaying && Input.GetMouseButtonDown(0))
|
|
{
|
|
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
|
|
if (Physics.Raycast(ray, out RaycastHit hit))
|
|
{
|
|
// 将点击点转换为局部坐标
|
|
Vector3 localPos = transform.InverseTransformPoint(hit.point);
|
|
rippleCenters.Add(new Vector2(localPos.x, localPos.z));
|
|
rippleTimes.Add(time);
|
|
}
|
|
}
|
|
|
|
// 清除过时涟漪
|
|
if (Application.isPlaying)
|
|
{
|
|
for (int i = rippleCenters.Count - 1; i >= 0; i--)
|
|
{
|
|
if (time - rippleTimes[i] > rippleDuration)
|
|
{
|
|
rippleCenters.RemoveAt(i);
|
|
rippleTimes.RemoveAt(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private float GetNoise(float x, float z, float t)
|
|
{
|
|
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 = t * waveSpeed * freq;
|
|
noise += Mathf.PerlinNoise(nx + nt, nz + nt) * amp;
|
|
amp *= 0.5f;
|
|
freq *= 2f;
|
|
}
|
|
|
|
float ripple = 0f;
|
|
for (int i = 0; i < rippleCenters.Count; i++)
|
|
{
|
|
Vector2 center = rippleCenters[i];
|
|
float rippleTime = t - rippleTimes[i];
|
|
if (rippleTime > rippleDuration) continue;
|
|
|
|
float dist = Vector2.Distance(new Vector2(x, z), center);
|
|
if (dist > rippleRadius) continue;
|
|
|
|
float nd = dist / rippleRadius;
|
|
float rippleVal = Mathf.Sin((1f - nd) * Mathf.PI * 2f - rippleTime * 4f) * (1f - nd);
|
|
ripple += rippleVal * rippleStrength * (1f - rippleTime / rippleDuration);
|
|
}
|
|
|
|
return (noise + ripple) * waveHeight;
|
|
}
|
|
|
|
public override void DrawShapes(Camera cam)
|
|
{
|
|
using (Draw.Command(cam))
|
|
{
|
|
time = Application.isPlaying ? Time.time * timeScale : 0f;
|
|
|
|
Draw.ResetAllDrawStates();
|
|
Draw.LineGeometry = LineGeometry.Volumetric3D;
|
|
Draw.Thickness = lineWidth;
|
|
Draw.Color = Color.cyan;
|
|
|
|
float step = fieldSize / (pointCount - 1);
|
|
float half = 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 = -half + j * step;
|
|
float z = -half + i * step;
|
|
float y = GetNoise(x, z, time);
|
|
points[i * pointCount + j] = new Vector3(x, y, z);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < pointCount; i++)
|
|
{
|
|
for (int j = 0; j < pointCount; j++)
|
|
{
|
|
int index = i * pointCount + j;
|
|
Vector3 current = points[index];
|
|
|
|
float depth = (current.y + waveHeight) / (waveHeight * 2f);
|
|
float scale = pointSize * (1f - depth * 0.5f);
|
|
Color pointColor = Color.Lerp(new Color(0.5f, 1f, 1f), new Color(0f, 0.3f, 1f, 0.5f), depth);
|
|
|
|
Draw.Sphere(current, scale, pointColor);
|
|
|
|
if (j < pointCount - 1)
|
|
{
|
|
Vector3 next = points[index + 1];
|
|
float avgY = (current.y + next.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(current, next, lineWidth * (1f - lineDepth * 0.5f), lineColor);
|
|
}
|
|
|
|
if (i < pointCount - 1)
|
|
{
|
|
Vector3 next = points[index + pointCount];
|
|
float avgY = (current.y + next.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(current, next, lineWidth * (1f - lineDepth * 0.5f), lineColor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|