中间版本存档
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using Shapes;
|
||||
|
||||
public class GridGenerator
|
||||
{
|
||||
private float fieldSize;
|
||||
private int pointCount;
|
||||
private float pointSize;
|
||||
private float lineWidth;
|
||||
private float edgeLineLength;
|
||||
|
||||
public GridGenerator(float fieldSize, int pointCount, float pointSize, float lineWidth, float edgeLineLength)
|
||||
{
|
||||
this.fieldSize = fieldSize;
|
||||
this.pointCount = pointCount;
|
||||
this.pointSize = pointSize;
|
||||
this.lineWidth = lineWidth;
|
||||
this.edgeLineLength = edgeLineLength;
|
||||
}
|
||||
|
||||
public List<Vector3> GenerateGridPoints()
|
||||
{
|
||||
List<Vector3> points = new List<Vector3>();
|
||||
float step = fieldSize / (pointCount - 1);
|
||||
float halfSize = fieldSize / 2f;
|
||||
|
||||
for (int i = 0; i < pointCount; i++)
|
||||
{
|
||||
for (int j = 0; j < pointCount; j++)
|
||||
{
|
||||
float x = j * step - halfSize;
|
||||
float z = i * step - halfSize;
|
||||
points.Add(new Vector3(x, 0f, z));
|
||||
}
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
public void DrawGridPoint(Vector3 position, float size, Color color)
|
||||
{
|
||||
Draw.Sphere(position, size, color);
|
||||
}
|
||||
|
||||
public void DrawGridLine(Vector3 start, Vector3 end, float width, Color color)
|
||||
{
|
||||
Draw.Line(start, end, width, color);
|
||||
}
|
||||
|
||||
public void DrawEdgeLine(Vector3 start, Vector3 end, float width, Color color)
|
||||
{
|
||||
Vector3 direction = (end - start).normalized;
|
||||
Vector3 normal = Vector3.Cross(direction, Vector3.up).normalized;
|
||||
Vector3 offset = normal * edgeLineLength;
|
||||
|
||||
Draw.Line(start + offset, end + offset, width, color);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 98172966e69290c4d9bd44ac3ee8b2d1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,30 +1,77 @@
|
||||
using UnityEngine;
|
||||
using Shapes;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.UI;
|
||||
|
||||
[ExecuteAlways]
|
||||
public class LakeLineDrawer : ImmediateModeShapeDrawer
|
||||
{
|
||||
[Header("场设置")]
|
||||
public float fieldSize = 20f;
|
||||
public int pointCount = 30;
|
||||
public float pointSize = 0.15f;
|
||||
public float fieldSize = 80f;
|
||||
public Vector2 fieldOffset = Vector2.zero;
|
||||
public int pointCount = 80;
|
||||
public float pointSize = 0.1f;
|
||||
public float lineWidth = 0.03f;
|
||||
|
||||
[Header("波动参数")]
|
||||
[Header("颜色设置")]
|
||||
public Color lakeDarkColor = new Color(0f, 0.5f, 1f); // 湖面低处颜色
|
||||
public Color lakeLightColor = new Color(0.5f, 1f, 1f, 0.3f); // 湖面高处颜色
|
||||
public Color edgeDarkColor = new Color(0f, 0.5f, 1f); // 边缘低处颜色
|
||||
public Color edgeLightColor = new Color(0.5f, 1f, 1f, 0.3f); // 边缘高处颜色
|
||||
public float edgeLineLength = 1f; // 边缘线的长度
|
||||
|
||||
[Header("UI控制")]
|
||||
public Slider xOffsetSlider;
|
||||
public Slider zOffsetSlider;
|
||||
public float maxOffset = 20f;
|
||||
|
||||
[Header("目标点设置")]
|
||||
public List<TargetPoint> targetPoints = new List<TargetPoint>();
|
||||
public float targetSize = 0.5f;
|
||||
public float rotationSpeed = 30f; // 旋转速度(度/秒)
|
||||
public float floatAmplitude = 0.2f; // 起伏幅度
|
||||
public float floatFrequency = 2f; // 起伏频率
|
||||
public float targetLineWidth = 0.02f; // 目标点线框的宽度
|
||||
public float targetHeightOffset = 0.5f; // 目标点距离湖面的高度偏移
|
||||
public Color targetFillColor = Color.red; // 目标点实体颜色
|
||||
public Color targetWireColor = Color.white; // 目标点线框颜色
|
||||
public float wireScale = 1.05f; // 线框相对于实体的大小比例
|
||||
|
||||
[Header("可视区域")]
|
||||
public float visibleAreaSize = 20f;
|
||||
|
||||
// 波动参数,用于生成波动效果
|
||||
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; // 尖刺锐度
|
||||
public float rippleStrength = 2f; // 恢复原来的强度
|
||||
public float rippleDuration = 0.8f; // 适中的持续时间
|
||||
public float rippleSpreadSpeed = 4f; // 适中的传播速度
|
||||
public float rippleSharpness = 4f; // 适中的锐度
|
||||
public float rippleMaxRadius = 3f; // 新增:涟漪最大半径
|
||||
|
||||
private Vector3[] points;
|
||||
// 存储每个点是否在可视区域内的标记
|
||||
private bool[] validPoints;
|
||||
private float time;
|
||||
private List<Ripple> ripples = new List<Ripple>();
|
||||
|
||||
[System.Serializable]
|
||||
public class TargetPoint
|
||||
{
|
||||
public Vector2 gridPosition; // 网格位置(0到pointCount-1)
|
||||
public TargetType type;
|
||||
public Color color = Color.white;
|
||||
}
|
||||
|
||||
public enum TargetType
|
||||
{
|
||||
Sphere,
|
||||
Cube,
|
||||
Torus
|
||||
}
|
||||
|
||||
private struct Ripple
|
||||
{
|
||||
@@ -38,18 +85,38 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer
|
||||
public float brightnessBoost;
|
||||
}
|
||||
|
||||
private List<Ripple> ripples = new List<Ripple>();
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// 如果是播放状态,则更新时间;否则设为0
|
||||
time = Application.isPlaying ? Time.time * timeScale : 0f;
|
||||
|
||||
HandleMouseInput();
|
||||
HandleUIInput();
|
||||
CleanExpiredRipples();
|
||||
}
|
||||
|
||||
private void HandleUIInput()
|
||||
{
|
||||
if (xOffsetSlider != null && zOffsetSlider != null)
|
||||
{
|
||||
fieldOffset = new Vector2(
|
||||
xOffsetSlider.value * maxOffset,
|
||||
zOffsetSlider.value * maxOffset
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理鼠标点击,触发新的涟漪
|
||||
private void HandleMouseInput()
|
||||
{
|
||||
if (Application.isPlaying && Input.GetMouseButtonDown(0))
|
||||
{
|
||||
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
|
||||
|
||||
if (Physics.Raycast(ray, out RaycastHit hit))
|
||||
{
|
||||
Vector3 hitPos = hit.point;
|
||||
|
||||
ripples.Add(new Ripple
|
||||
{
|
||||
position = new Vector2(hitPos.x, hitPos.z),
|
||||
@@ -57,57 +124,74 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CleanExpiredRipples()
|
||||
{
|
||||
ripples.RemoveAll(r => Time.time - r.startTime > rippleDuration);
|
||||
}
|
||||
|
||||
// 计算涟漪对某个点的影响,返回该点的偏移量和亮度提升
|
||||
private RippleResult GetRippleEffect(float x, float z, float currentTime)
|
||||
{
|
||||
float rippleOffset = 0f;
|
||||
float brightness = 0f;
|
||||
|
||||
// 遍历所有涟漪,计算它们对当前点的影响
|
||||
foreach (var ripple in ripples)
|
||||
{
|
||||
// 计算涟漪已经存在的时间
|
||||
float elapsed = currentTime - ripple.startTime;
|
||||
float spread = elapsed * rippleSpreadSpeed;
|
||||
float dist = Vector2.Distance(new Vector2(x, z), ripple.position);
|
||||
float spread = elapsed * rippleSpreadSpeed; // 涟漪扩展的距离
|
||||
float dist = Vector2.Distance(new Vector2(x, z), ripple.position); // 当前点与涟漪中心的距离
|
||||
|
||||
// 如果距离超过最大半径,跳过这个涟漪的影响
|
||||
if (dist > rippleMaxRadius)
|
||||
continue;
|
||||
|
||||
// 计算涟漪的时间影响,t表示涟漪的衰减程度
|
||||
float t = Mathf.Clamp01(elapsed / rippleDuration);
|
||||
float ease = Mathf.Sin(t * Mathf.PI);
|
||||
float ease = Mathf.Sin(t * Mathf.PI); // 使用正弦函数使衰减效果平滑
|
||||
|
||||
// 计算涟漪对当前点的高度影响
|
||||
float spike = Mathf.Exp(-Mathf.Pow(dist - spread, 2f) * rippleSharpness);
|
||||
rippleOffset += spike * rippleStrength * ease;
|
||||
|
||||
// 计算涟漪对当前点的亮度提升
|
||||
float bright = Mathf.Exp(-Mathf.Pow((dist - spread) * 0.5f, 2f));
|
||||
brightness += bright * ease;
|
||||
}
|
||||
|
||||
return new RippleResult
|
||||
{
|
||||
heightOffset = rippleOffset,
|
||||
brightnessBoost = brightness
|
||||
heightOffset = rippleOffset, // 高度偏移
|
||||
brightnessBoost = brightness // 亮度提升
|
||||
};
|
||||
}
|
||||
|
||||
// 计算某个点的基础高度,基于噪声函数模拟波浪
|
||||
private float GetHeight(float x, float z, float currentTime)
|
||||
{
|
||||
float noise = 0;
|
||||
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;
|
||||
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))
|
||||
@@ -117,63 +201,246 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer
|
||||
Draw.Thickness = lineWidth;
|
||||
|
||||
float step = fieldSize / (pointCount - 1);
|
||||
float halfSize = fieldSize * 0.5f;
|
||||
float halfField = fieldSize * 0.5f;
|
||||
float halfVisible = visibleAreaSize * 0.5f;
|
||||
|
||||
if (points == null || points.Length != pointCount * pointCount)
|
||||
points = new Vector3[pointCount * pointCount];
|
||||
if (validPoints == null || validPoints.Length != pointCount * pointCount)
|
||||
validPoints = new bool[pointCount * pointCount];
|
||||
|
||||
for (int i = 0; i < pointCount; i++)
|
||||
CalculatePointPositions(step, halfField, halfVisible);
|
||||
DrawPointsAndLines(step, halfField, halfVisible);
|
||||
DrawEdgeLines(halfField, halfVisible);
|
||||
DrawTargetPoints(); // 添加目标点的绘制
|
||||
}
|
||||
}
|
||||
|
||||
// 计算每个点的位置和涟漪效果
|
||||
private void CalculatePointPositions(float step, float halfField, float halfVisible)
|
||||
{
|
||||
// 遍历每个点,计算其位置和涟漪影响
|
||||
for (int i = 0; i < pointCount; i++)
|
||||
{
|
||||
for (int j = 0; j < pointCount; j++)
|
||||
{
|
||||
for (int j = 0; j < pointCount; j++)
|
||||
{
|
||||
float x = -halfSize + j * step;
|
||||
float z = -halfSize + i * step;
|
||||
// 计算当前点的位置(x,z)
|
||||
float x = -halfField + j * step + fieldOffset.x;
|
||||
float z = -halfField + i * step + fieldOffset.y;
|
||||
|
||||
float baseHeight = GetHeight(x, z, time);
|
||||
RippleResult ripple = GetRippleEffect(x, z, Time.time);
|
||||
float finalY = baseHeight + ripple.heightOffset;
|
||||
// 判断该点是否在可视区域内
|
||||
bool inside = Mathf.Abs(x) <= halfVisible && Mathf.Abs(z) <= halfVisible;
|
||||
int index = i * pointCount + j; // 计算当前点的索引
|
||||
validPoints[index] = inside; // 设置该点是否有效
|
||||
|
||||
Vector3 pos = new Vector3(x, finalY, z);
|
||||
if (!inside)
|
||||
continue;
|
||||
|
||||
points[i * pointCount + j] = pos;
|
||||
// 获取基础波浪高度,并计算涟漪影响
|
||||
float baseHeight = GetHeight(x, z, time);
|
||||
RippleResult ripple = GetRippleEffect(x, z, Time.time);
|
||||
float finalY = baseHeight + ripple.heightOffset;
|
||||
|
||||
float depth = (finalY + waveHeight) / (waveHeight * 2f);
|
||||
float brightness = Mathf.Clamp01(1f + ripple.brightnessBoost);
|
||||
float pointScale = pointSize * (1f - depth * 0.5f);
|
||||
// 创建点的坐标
|
||||
Vector3 pos = new Vector3(x, finalY, z);
|
||||
points[index] = pos; // 存储计算得到的点
|
||||
|
||||
Color baseColor = Color.Lerp(new Color(0.5f, 1f, 1f), new Color(0f, 0.5f, 1f), depth);
|
||||
baseColor *= brightness;
|
||||
// 计算亮度:基于高度,越高越亮
|
||||
float heightT = Mathf.InverseLerp(-waveHeight, waveHeight, finalY);
|
||||
float brightness = Mathf.Clamp01(1f + ripple.brightnessBoost); // 计算亮度,防止超出范围
|
||||
Color baseColor = Color.Lerp(lakeDarkColor, lakeLightColor, heightT);
|
||||
baseColor *= brightness;
|
||||
|
||||
Draw.Sphere(pos, pointScale, baseColor);
|
||||
}
|
||||
// 绘制当前点
|
||||
Draw.Sphere(pos, pointSize * (1f - heightT * 0.5f), baseColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < pointCount; i++)
|
||||
// 绘制点与点之间的连线
|
||||
private void DrawPointsAndLines(float step, float halfField, float halfVisible)
|
||||
{
|
||||
for (int i = 0; i < pointCount; i++)
|
||||
{
|
||||
for (int j = 0; j < pointCount; j++)
|
||||
{
|
||||
for (int j = 0; j < pointCount; j++)
|
||||
int index = i * pointCount + j;
|
||||
if (!validPoints[index])
|
||||
continue;
|
||||
|
||||
Vector3 current = points[index];
|
||||
|
||||
if (j < pointCount - 1 && validPoints[index + 1])
|
||||
{
|
||||
int index = i * pointCount + j;
|
||||
Vector3 current = points[index];
|
||||
Vector3 next = points[index + 1];
|
||||
DrawLineBetweenPoints(current, next, halfField, halfVisible);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
// 绘制与下边点的连线
|
||||
if (i < pointCount - 1 && validPoints[index + pointCount])
|
||||
{
|
||||
Vector3 next = points[index + pointCount];
|
||||
DrawLineBetweenPoints(current, next, halfField, halfVisible);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制两点之间的连线,加入深度和颜色的渐变
|
||||
private void DrawLineBetweenPoints(Vector3 current, Vector3 next, float halfField, float halfVisible)
|
||||
{
|
||||
// 计算连线的平均高度
|
||||
float avgY = (current.y + next.y) * 0.5f;
|
||||
float heightT = Mathf.InverseLerp(-waveHeight, waveHeight, avgY);
|
||||
|
||||
// 计算连线的颜色,依赖于高度
|
||||
Color lineColor = Color.Lerp(lakeDarkColor, lakeLightColor, heightT);
|
||||
lineColor.a *= 0.8f; // 设置透明度
|
||||
|
||||
// 绘制连线
|
||||
Draw.Line(current, next, lineWidth * (1f - heightT * 0.5f), lineColor);
|
||||
}
|
||||
|
||||
private void DrawEdgeLine(float x, float z, float halfVisible)
|
||||
{
|
||||
// 检查点是否在可视区域内
|
||||
if (Mathf.Abs(x) > halfVisible || Mathf.Abs(z) > halfVisible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算湖面高度作为起始点的Y坐标
|
||||
float startY = GetHeight(x, z, time); // 获取湖面高度
|
||||
|
||||
// 设置边缘线的起始点
|
||||
Vector3 start = new Vector3(x, startY, z);
|
||||
|
||||
// 设置边缘线的终止点,向下延伸一定的长度
|
||||
Vector3 end = new Vector3(x, startY - edgeLineLength, z); // 向下延伸的线条
|
||||
|
||||
// 设置颜色,基于高度
|
||||
float heightT = Mathf.InverseLerp(-waveHeight, waveHeight, startY);
|
||||
Color lineColor = Color.Lerp(edgeDarkColor, edgeLightColor, heightT);
|
||||
lineColor.a *= 0.8f; // 设置透明度
|
||||
|
||||
// 绘制边缘线
|
||||
Draw.Line(start, end, lineWidth * 0.5f, lineColor);
|
||||
}
|
||||
|
||||
private void DrawEdgeLines(float halfField, float halfVisible)
|
||||
{
|
||||
// 绘制湖面边缘的向下线条(无扰动)
|
||||
float step = fieldSize / (pointCount - 1);
|
||||
float halfEdgeLineLength = edgeLineLength * 0.5f; // 设置边缘线长度
|
||||
|
||||
// 只在field边界处绘制线条,且仅当边界在可视区域内时绘制
|
||||
// 1. 绘制 X 轴的边缘线(左边和右边)
|
||||
for (float z = -halfField; z <= halfField; z += step)
|
||||
{
|
||||
// 检查边界点是否在可视区域内
|
||||
if (Mathf.Abs(z) <= halfVisible)
|
||||
{
|
||||
float x = halfField; // 右边
|
||||
DrawEdgeLine(x, z, halfVisible);
|
||||
x = -halfField; // 左边
|
||||
DrawEdgeLine(x, z, halfVisible);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 绘制 Z 轴的边缘线(上边和下边)
|
||||
for (float x = -halfField; x <= halfField; x += step)
|
||||
{
|
||||
// 检查边界点是否在可视区域内
|
||||
if (Mathf.Abs(x) <= halfVisible)
|
||||
{
|
||||
float z = halfField; // 上边
|
||||
DrawEdgeLine(x, z, halfVisible);
|
||||
z = -halfField; // 下边
|
||||
DrawEdgeLine(x, z, halfVisible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制目标点
|
||||
private void DrawTargetPoints()
|
||||
{
|
||||
float step = fieldSize / (pointCount - 1);
|
||||
float halfField = fieldSize * 0.5f;
|
||||
float halfVisible = visibleAreaSize * 0.5f;
|
||||
|
||||
foreach (var target in targetPoints)
|
||||
{
|
||||
// 将网格位置转换为世界坐标
|
||||
float x = -halfField + target.gridPosition.x * step + fieldOffset.x;
|
||||
float z = -halfField + target.gridPosition.y * step + fieldOffset.y;
|
||||
|
||||
// 检查是否在可视区域内
|
||||
if (Mathf.Abs(x) > halfVisible || Mathf.Abs(z) > halfVisible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取该点的高度
|
||||
float height = GetHeight(x, z, time);
|
||||
|
||||
// 添加额外的起伏效果和高度偏移
|
||||
float floatOffset = Mathf.Sin(time * floatFrequency) * floatAmplitude;
|
||||
Vector3 position = new Vector3(x, height + floatOffset + targetHeightOffset, z);
|
||||
|
||||
// 计算旋转
|
||||
float rotation = time * rotationSpeed;
|
||||
Quaternion rot = Quaternion.Euler(0, rotation, 0);
|
||||
|
||||
// 绘制外层立方体线框
|
||||
DrawWireCube(position, rot, targetSize * wireScale, targetWireColor);
|
||||
|
||||
// 根据类型绘制内部形状
|
||||
switch (target.type)
|
||||
{
|
||||
case TargetType.Sphere:
|
||||
Draw.Sphere(position, targetSize * 0.8f, targetFillColor);
|
||||
break;
|
||||
case TargetType.Cube:
|
||||
Draw.Cube(position, rot, targetSize * 0.8f, targetFillColor);
|
||||
break;
|
||||
case TargetType.Torus:
|
||||
Draw.Torus(position, rot, targetSize * 0.8f, targetSize * 0.3f, targetFillColor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawWireCube(Vector3 position, Quaternion rotation, float size, Color color)
|
||||
{
|
||||
Vector3[] vertices = new Vector3[]
|
||||
{
|
||||
new Vector3(-size, -size, -size),
|
||||
new Vector3(size, -size, -size),
|
||||
new Vector3(size, size, -size),
|
||||
new Vector3(-size, size, -size),
|
||||
new Vector3(-size, -size, size),
|
||||
new Vector3(size, -size, size),
|
||||
new Vector3(size, size, size),
|
||||
new Vector3(-size, size, size)
|
||||
};
|
||||
|
||||
// 应用旋转
|
||||
for (int i = 0; i < vertices.Length; i++)
|
||||
{
|
||||
vertices[i] = rotation * vertices[i] + position;
|
||||
}
|
||||
|
||||
// 绘制边
|
||||
int[] edges = new int[]
|
||||
{
|
||||
0,1, 1,2, 2,3, 3,0, // 底面
|
||||
4,5, 5,6, 6,7, 7,4, // 顶面
|
||||
0,4, 1,5, 2,6, 3,7 // 连接线
|
||||
};
|
||||
|
||||
for (int i = 0; i < edges.Length; i += 2)
|
||||
{
|
||||
Draw.Line(vertices[edges[i]], vertices[edges[i+1]], targetLineWidth, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Shapes;
|
||||
|
||||
public class LakeUIController : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private LakeLineDrawer lakeDrawer;
|
||||
public Slider xOffsetSlider;
|
||||
public Slider zOffsetSlider;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// 设置滑动条的初始值
|
||||
if (xOffsetSlider != null && zOffsetSlider != null)
|
||||
{
|
||||
xOffsetSlider.minValue = -1f;
|
||||
xOffsetSlider.maxValue = 1f;
|
||||
xOffsetSlider.value = 0f;
|
||||
|
||||
zOffsetSlider.minValue = -1f;
|
||||
zOffsetSlider.maxValue = 1f;
|
||||
zOffsetSlider.value = 0f;
|
||||
|
||||
// 将滑动条引用传递给LakeLineDrawer
|
||||
lakeDrawer.xOffsetSlider = xOffsetSlider;
|
||||
lakeDrawer.zOffsetSlider = zOffsetSlider;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6709e527ba5cd1a43802e44a9de467d8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,195 @@
|
||||
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<Ripple> ripples = new List<Ripple>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 874c4686e7644b74f83e1c0a58b26b34
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,79 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public struct Ripple
|
||||
{
|
||||
public Vector3 position;
|
||||
public float startTime;
|
||||
public float strength;
|
||||
}
|
||||
|
||||
public struct RippleResult
|
||||
{
|
||||
public float height;
|
||||
public float brightness;
|
||||
}
|
||||
|
||||
public class RippleManager
|
||||
{
|
||||
private List<Ripple> ripples = new List<Ripple>();
|
||||
private float rippleStrength;
|
||||
private float rippleDuration;
|
||||
private float rippleSpreadSpeed;
|
||||
private float rippleSharpness;
|
||||
private float rippleMaxRadius;
|
||||
|
||||
public RippleManager(float strength, float duration, float spreadSpeed, float sharpness, float maxRadius)
|
||||
{
|
||||
rippleStrength = strength;
|
||||
rippleDuration = duration;
|
||||
rippleSpreadSpeed = spreadSpeed;
|
||||
rippleSharpness = sharpness;
|
||||
rippleMaxRadius = maxRadius;
|
||||
}
|
||||
|
||||
public void AddRipple(Vector3 position)
|
||||
{
|
||||
ripples.Add(new Ripple
|
||||
{
|
||||
position = position,
|
||||
startTime = Time.time,
|
||||
strength = rippleStrength
|
||||
});
|
||||
}
|
||||
|
||||
public void CleanupRipples()
|
||||
{
|
||||
ripples.RemoveAll(r => Time.time - r.startTime > rippleDuration);
|
||||
}
|
||||
|
||||
public RippleResult GetRippleEffect(Vector3 position, float currentTime)
|
||||
{
|
||||
float totalHeight = 0f;
|
||||
float totalBrightness = 0f;
|
||||
|
||||
foreach (var ripple in ripples)
|
||||
{
|
||||
float timeSinceStart = currentTime - ripple.startTime;
|
||||
if (timeSinceStart > rippleDuration) continue;
|
||||
|
||||
float distance = Vector3.Distance(position, ripple.position);
|
||||
float maxDistance = rippleSpreadSpeed * timeSinceStart;
|
||||
|
||||
if (distance > maxDistance || distance > rippleMaxRadius) continue;
|
||||
|
||||
float distFactor = Mathf.Exp(-distance * rippleSharpness);
|
||||
float timeFactor = 1f - (timeSinceStart / rippleDuration);
|
||||
float strength = ripple.strength * distFactor * timeFactor;
|
||||
|
||||
totalHeight += strength;
|
||||
totalBrightness += strength;
|
||||
}
|
||||
|
||||
return new RippleResult
|
||||
{
|
||||
height = totalHeight,
|
||||
brightness = totalBrightness
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea17c12f760878e4dadd86d12ad6ca8a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,112 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using Shapes;
|
||||
|
||||
public enum TargetType
|
||||
{
|
||||
Sphere,
|
||||
Cube,
|
||||
Torus
|
||||
}
|
||||
|
||||
public class TargetPointManager
|
||||
{
|
||||
private List<Vector3> targetPoints = new List<Vector3>();
|
||||
private List<TargetType> targetTypes = new List<TargetType>();
|
||||
private float targetSize;
|
||||
private float wireScale;
|
||||
private float heightOffset;
|
||||
private Color entityColor;
|
||||
private Color wireColor;
|
||||
private float rotationSpeed;
|
||||
private float floatSpeed;
|
||||
private float floatHeight;
|
||||
|
||||
public TargetPointManager(float size, float wireScale, float height, Color entity, Color wire, float rotSpeed, float floatSpeed, float floatHeight)
|
||||
{
|
||||
this.targetSize = size;
|
||||
this.wireScale = wireScale;
|
||||
this.heightOffset = height;
|
||||
this.entityColor = entity;
|
||||
this.wireColor = wire;
|
||||
this.rotationSpeed = rotSpeed;
|
||||
this.floatSpeed = floatSpeed;
|
||||
this.floatHeight = floatHeight;
|
||||
}
|
||||
|
||||
public void AddTargetPoint(Vector3 position, TargetType type)
|
||||
{
|
||||
targetPoints.Add(position);
|
||||
targetTypes.Add(type);
|
||||
}
|
||||
|
||||
public void ClearTargetPoints()
|
||||
{
|
||||
targetPoints.Clear();
|
||||
targetTypes.Clear();
|
||||
}
|
||||
|
||||
public void DrawTargetPoints(float currentTime)
|
||||
{
|
||||
for (int i = 0; i < targetPoints.Count; i++)
|
||||
{
|
||||
Vector3 pos = targetPoints[i];
|
||||
TargetType type = targetTypes[i];
|
||||
|
||||
// 计算浮动效果
|
||||
float floatOffset = Mathf.Sin(currentTime * floatSpeed) * floatHeight;
|
||||
Vector3 finalPos = pos + Vector3.up * (heightOffset + floatOffset);
|
||||
|
||||
// 绘制外框(立方体)
|
||||
DrawWireCube(finalPos, targetSize * wireScale, wireColor);
|
||||
|
||||
// 绘制内部形状
|
||||
switch (type)
|
||||
{
|
||||
case TargetType.Sphere:
|
||||
Draw.Sphere(finalPos, targetSize * 0.8f, entityColor);
|
||||
break;
|
||||
case TargetType.Cube:
|
||||
Draw.Cube(finalPos, Quaternion.Euler(0, currentTime * rotationSpeed, 0), targetSize * 0.8f, entityColor);
|
||||
break;
|
||||
case TargetType.Torus:
|
||||
Draw.Torus(finalPos, Quaternion.Euler(0, currentTime * rotationSpeed, 0), targetSize * 0.8f, targetSize * 0.2f, entityColor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawWireCube(Vector3 position, float size, Color color)
|
||||
{
|
||||
float halfSize = size / 2f;
|
||||
Vector3[] points = new Vector3[]
|
||||
{
|
||||
position + new Vector3(-halfSize, -halfSize, -halfSize),
|
||||
position + new Vector3(halfSize, -halfSize, -halfSize),
|
||||
position + new Vector3(halfSize, -halfSize, halfSize),
|
||||
position + new Vector3(-halfSize, -halfSize, halfSize),
|
||||
position + new Vector3(-halfSize, halfSize, -halfSize),
|
||||
position + new Vector3(halfSize, halfSize, -halfSize),
|
||||
position + new Vector3(halfSize, halfSize, halfSize),
|
||||
position + new Vector3(-halfSize, halfSize, halfSize)
|
||||
};
|
||||
|
||||
// 绘制底面
|
||||
Draw.Line(points[0], points[1], 0.1f, color);
|
||||
Draw.Line(points[1], points[2], 0.1f, color);
|
||||
Draw.Line(points[2], points[3], 0.1f, color);
|
||||
Draw.Line(points[3], points[0], 0.1f, color);
|
||||
|
||||
// 绘制顶面
|
||||
Draw.Line(points[4], points[5], 0.1f, color);
|
||||
Draw.Line(points[5], points[6], 0.1f, color);
|
||||
Draw.Line(points[6], points[7], 0.1f, color);
|
||||
Draw.Line(points[7], points[4], 0.1f, color);
|
||||
|
||||
// 绘制连接线
|
||||
Draw.Line(points[0], points[4], 0.1f, color);
|
||||
Draw.Line(points[1], points[5], 0.1f, color);
|
||||
Draw.Line(points[2], points[6], 0.1f, color);
|
||||
Draw.Line(points[3], points[7], 0.1f, color);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8d5ffa5489c71c48951644fc2c52117
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class WaveGenerator
|
||||
{
|
||||
private float noiseScale;
|
||||
private float waveHeight;
|
||||
private float waveSpeed;
|
||||
|
||||
public WaveGenerator(float noiseScale, float waveHeight, float waveSpeed)
|
||||
{
|
||||
this.noiseScale = noiseScale;
|
||||
this.waveHeight = waveHeight;
|
||||
this.waveSpeed = waveSpeed;
|
||||
}
|
||||
|
||||
public float GetHeight(float x, float z, float time)
|
||||
{
|
||||
float noise = Mathf.PerlinNoise(x * noiseScale + time * waveSpeed, z * noiseScale + time * waveSpeed);
|
||||
return Mathf.Lerp(-waveHeight, waveHeight, noise);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed485db0b6bd66943af4f7b138357992
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user