GPU优化
This commit is contained in:
@@ -212,6 +212,7 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
var mainModule = particle.main;
|
||||
mainModule.prewarm = prewarm;
|
||||
mainModule.maxParticles = 500;
|
||||
}
|
||||
|
||||
public void SetSimulationSpace(ParticleSystemSimulationSpace simulationSpace)
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using Sirenix.OdinInspector;
|
||||
using UniRx;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
@@ -26,6 +27,7 @@ namespace Ichni.RhythmGame
|
||||
return track;
|
||||
}
|
||||
|
||||
[Button]
|
||||
public override void SetDefaultSubmodules()
|
||||
{
|
||||
transformSubmodule = new TransformSubmodule(this);
|
||||
@@ -34,7 +36,7 @@ namespace Ichni.RhythmGame
|
||||
trackTimeSubmodule = null;
|
||||
trackRendererSubmodule = null;
|
||||
}
|
||||
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!GameManager.instance.audioManager.isUpdating)
|
||||
@@ -56,7 +58,7 @@ namespace Ichni.RhythmGame
|
||||
public override void AfterInitialize()
|
||||
{
|
||||
base.AfterInitialize();
|
||||
|
||||
|
||||
if (trackPathSubmodule != null && trackPathSubmodule.pathNodeList.Count > 3)
|
||||
{
|
||||
trackPathSubmodule.ClosePath();
|
||||
@@ -64,17 +66,27 @@ namespace Ichni.RhythmGame
|
||||
|
||||
if(trackRendererSubmodule != null)
|
||||
{
|
||||
//var path = trackPathSubmodule!.path;
|
||||
|
||||
trackRendererSubmodule.meshGenerator.autoUpdate = false;
|
||||
/*path.ResampleTransform();
|
||||
path.Subscribe(trackRendererSubmodule.meshGenerator);
|
||||
path.EditorUpdateConnectedNodes();
|
||||
path.RebuildImmediate(true, true);*/
|
||||
//path.EditorAwake();
|
||||
}
|
||||
}
|
||||
|
||||
public override void BeforeStart()
|
||||
{
|
||||
switch (trackPathSubmodule.trackSpaceType)
|
||||
{
|
||||
case Track.TrackSpaceType.CatmullRom:
|
||||
trackPathSubmodule.GenerateCatmullRomSpline();
|
||||
break;
|
||||
case Track.TrackSpaceType.Linear:
|
||||
trackPathSubmodule.GenerateLinearSpline();
|
||||
break;
|
||||
case Track.TrackSpaceType.BSpline:
|
||||
trackPathSubmodule.GenerateBSpline();
|
||||
break;
|
||||
}
|
||||
base.BeforeStart();
|
||||
}
|
||||
|
||||
|
||||
public override void Refresh()
|
||||
{
|
||||
|
||||
@@ -60,8 +60,9 @@ namespace Ichni.RhythmGame
|
||||
trackPositioner.spline = trackListFolder.trackList[trackSwitch.value].trackPathSubmodule.path;
|
||||
}
|
||||
|
||||
trackPositioner.SetPercent(trackPercent.value);
|
||||
trackPositioner.RebuildImmediate();
|
||||
nowAttachedTrack?.trackPathSubmodule.UpdatePoint(transform, trackPercent.value);
|
||||
//trackPositioner.SetPercent(trackPercent.value);
|
||||
//trackPositioner.RebuildImmediate();
|
||||
|
||||
/*Debug.Log(trackSwitch.value + " " + trackPercent.value + " " +
|
||||
nowAttachedTrack.trackPathSubmodule.path.EvaluatePosition(trackPercent.value) + " " +
|
||||
|
||||
@@ -44,7 +44,8 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
if (track.timeDurationSubmodule.CheckTimeInDuration(GameManager.instance.songTime))
|
||||
{
|
||||
trackPositioner.SetPercent(trackTimeSubmoduleMovable.headPercent);
|
||||
track.trackPathSubmodule.UpdatePoint(transform, trackTimeSubmoduleMovable.headPercent);
|
||||
//trackPositioner.SetPercent(trackTimeSubmoduleMovable.headPercent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dreamteck.Splines;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
@@ -52,8 +53,8 @@ namespace Ichni.RhythmGame
|
||||
float finalValue = trackPercent.value;
|
||||
if (finalValue > 1 && finalValue > Mathf.Floor(finalValue)) finalValue -= Mathf.Floor(finalValue);
|
||||
|
||||
|
||||
trackPositioner.SetPercent(finalValue);
|
||||
track.trackPathSubmodule.UpdatePoint(transform, finalValue);
|
||||
//trackPositioner.SetPercent(finalValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,6 +70,11 @@ namespace Ichni.RhythmGame
|
||||
}
|
||||
}
|
||||
|
||||
public partial class TrackPercentPoint
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
namespace Beatmap
|
||||
{
|
||||
public class TrackPercentPoint_BM : GameElement_BM
|
||||
|
||||
@@ -3,14 +3,25 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Dreamteck.Splines;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using Sirenix.OdinInspector;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Splines;
|
||||
using Spline = Dreamteck.Splines.Spline;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
// 引入官方的 Splines 命名空间
|
||||
using UnitySpline = UnityEngine.Splines.Spline;
|
||||
using UnitySplineContainer = UnityEngine.Splines.SplineContainer;
|
||||
|
||||
public partial class TrackPathSubmodule : TrackSubmodule
|
||||
{
|
||||
public SplineComputer path;
|
||||
public Dreamteck.Splines.SplineComputer path;
|
||||
public List<PathNode> pathNodeList;
|
||||
|
||||
public Track.TrackSpaceType trackSpaceType;
|
||||
@@ -25,13 +36,13 @@ namespace Ichni.RhythmGame
|
||||
Track.TrackSamplingType trackSamplingType, bool isClosed, bool isShowingDisplay) : base(track)
|
||||
{
|
||||
this.path = track.AddComponent<SplineComputer>();
|
||||
|
||||
|
||||
this.pathNodeList = new List<PathNode>();
|
||||
this.trackSpaceType = trackSpaceType;
|
||||
this.trackSamplingType = trackSamplingType;
|
||||
this.isClosed = isClosed;
|
||||
|
||||
this.path.sampleRate = 16;
|
||||
this.path.sampleRate = 8;
|
||||
this.path.updateMode = SplineComputer.UpdateMode.LateUpdate;
|
||||
SetUpSplineComputer(this.trackSpaceType, this.trackSamplingType);
|
||||
//闭合路径在PathNode生成时执行,在初始化的情况下,PathNode数量为0,不会执行闭合操作
|
||||
@@ -42,6 +53,10 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
this.track.trackPathSubmodule = this;
|
||||
}
|
||||
|
||||
|
||||
this.container = track.AddComponent<UnitySplineContainer>();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +118,194 @@ namespace Ichni.RhythmGame
|
||||
}
|
||||
}
|
||||
|
||||
public partial class TrackPathSubmodule
|
||||
{
|
||||
public UnitySplineContainer container;
|
||||
public bool isSplineDirty = false; // 这个标记可以在外部被设置为 true 来触发表现层更新
|
||||
|
||||
public void GenerateCatmullRomSpline()
|
||||
{
|
||||
UnitySpline spline = new UnitySpline();
|
||||
int count = pathNodeList.Count;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
//使用Auto Knot模式,Unity会自动计算切线以实现Catmull-Rom样条的特性
|
||||
BezierKnot knot = new BezierKnot();
|
||||
knot.Position = pathNodeList[i].transformSubmodule.currentPosition;
|
||||
knot.Rotation = quaternion.identity; //初始旋转,后续可以根据需要
|
||||
spline.Add(knot);
|
||||
}
|
||||
|
||||
//必须设置为Auto Knot模式,让Unity自动计算切线以实现Catmull-Rom样条的特性
|
||||
spline.SetTangentMode(TangentMode.AutoSmooth);
|
||||
container.Splines = new UnitySpline[] { spline };
|
||||
}
|
||||
|
||||
public void GenerateLinearSpline()
|
||||
{
|
||||
UnitySpline spline = new UnitySpline();
|
||||
int count = pathNodeList.Count;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
BezierKnot knot = new BezierKnot();
|
||||
knot.Position = pathNodeList[i].transformSubmodule.currentPosition;
|
||||
knot.Rotation = quaternion.identity; //初始旋转,后续可以根据需要
|
||||
spline.Add(knot);
|
||||
}
|
||||
|
||||
//必须设置为Linear模式,让Unity不计算切线,保持线性插值
|
||||
spline.SetTangentMode(TangentMode.Linear);
|
||||
container.Splines = new UnitySpline[] { spline };
|
||||
}
|
||||
|
||||
[Button]
|
||||
public void GenerateBSpline()
|
||||
{
|
||||
//if(pathNodeList.Count < 3) return;
|
||||
|
||||
UnitySpline spline = new UnitySpline();
|
||||
int count = pathNodeList.Count;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
spline.Add(CalculateBSplineKnot(i));
|
||||
}
|
||||
|
||||
// 必须设置为 Broken 模式,因为我们已经手动用数学算出了完美平滑的 Tangent,不需要 Unity 再去插手
|
||||
spline.SetTangentMode(TangentMode.Broken);
|
||||
container.Splines = new UnitySpline[] { spline };
|
||||
}
|
||||
|
||||
private BezierKnot CalculateBSplineKnot(int i)
|
||||
{
|
||||
UnitySpline spline = new UnitySpline();
|
||||
int count = pathNodeList.Count;
|
||||
|
||||
Vector3 pPrev, pCurr, pNext;
|
||||
pCurr = pathNodeList[i].transformSubmodule.currentPosition;
|
||||
|
||||
// 1. 获取前后相邻点 (处理封闭与开放的拓扑逻辑)
|
||||
if (isClosed)
|
||||
{
|
||||
// 使用取模运算,让索引在首尾循环缠绕 (加 count 是为了防止负数)
|
||||
pPrev = pathNodeList[(i - 1 + count) % count].transformSubmodule.currentPosition;
|
||||
pNext = pathNodeList[(i + 1) % count].transformSubmodule.currentPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 开放状态下,首尾节点重复使用端点坐标
|
||||
pPrev = pathNodeList[Mathf.Max(0, i - 1)].transformSubmodule.currentPosition;
|
||||
pNext = pathNodeList[Mathf.Min(count - 1, i + 1)].transformSubmodule.currentPosition;
|
||||
}
|
||||
|
||||
BezierKnot knot = new BezierKnot();
|
||||
|
||||
// 2. 计算 B-Spline 等价的 Bezier 节点位置与切线
|
||||
if (!isClosed && (i == 0 || i == count - 1))
|
||||
{
|
||||
// 开放曲线的硬性端点锚定
|
||||
knot.Position = pCurr;
|
||||
if (i == 0)
|
||||
{
|
||||
knot.TangentIn = float3.zero;
|
||||
knot.TangentOut = (pNext - pCurr) / 3f;
|
||||
}
|
||||
else
|
||||
{
|
||||
knot.TangentIn = (pPrev - pCurr) / 3f;
|
||||
knot.TangentOut = float3.zero;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 标准 1/6 B-Spline 平滑换算公式 (封闭曲线全程走这里)
|
||||
knot.Position = (pPrev + 4f * pCurr + pNext) / 6f;
|
||||
knot.TangentOut = (pNext - pPrev) / 6f;
|
||||
knot.TangentIn = (pPrev - pNext) / 6f;
|
||||
}
|
||||
|
||||
knot.Rotation = Quaternion.Euler(pathNodeList[i].transformSubmodule.currentEulerAngles); // 直接使用节点的欧拉角作为旋转,保持与节点编辑器一致
|
||||
return knot;
|
||||
}
|
||||
|
||||
public void UpdateSplineFromPathNode(int index)
|
||||
{
|
||||
if (container == null || container.Splines.Count == 0) return;
|
||||
UnitySpline spline = new UnitySpline();
|
||||
int count = pathNodeList.Count;
|
||||
|
||||
if (index < 0 || index >= spline.Count)
|
||||
{
|
||||
Debug.LogError($"节点索引 {index} 越界!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (trackSpaceType is Track.TrackSpaceType.Linear or Track.TrackSpaceType.CatmullRom)
|
||||
{
|
||||
BezierKnot knot = spline[index];
|
||||
Vector3 newPosition = pathNodeList[index].transformSubmodule.currentPosition;
|
||||
|
||||
// 1. 提取当前节点 (使用 spline[index] 读取可以保留该节点原本的切线数据)
|
||||
// 这一步对于 Catmull-Rom 非常重要,因为它的切线是由 Unity 自动维护的
|
||||
// 转换到本地坐标系 (如果传入的是世界坐标)
|
||||
knot.Position = container.transform.InverseTransformPoint(newPosition);
|
||||
|
||||
// 2. 更新旋转 (如果需要的话)
|
||||
Quaternion newRotation = Quaternion.Euler(pathNodeList[index].transformSubmodule.currentEulerAngles);
|
||||
knot.Rotation = newRotation; // 直接使用节点的欧拉角作为旋转,保持与节点编辑器一致
|
||||
|
||||
// 3. 将修改后的 Knot 写回 Spline
|
||||
// 此时 Unity 底层会自动触发它自己的 Dirty 标记
|
||||
spline.SetKnot(index, knot);
|
||||
}
|
||||
else if (trackSpaceType == Track.TrackSpaceType.BSpline)
|
||||
{
|
||||
if (isClosed)
|
||||
{
|
||||
// 封闭曲线使用取模处理环绕越界
|
||||
int i0 = (index - 1 + count) % count;
|
||||
int i1 = (index + 1) % count;
|
||||
spline.SetKnot(i0, CalculateBSplineKnot(i0));
|
||||
spline.SetKnot(index, CalculateBSplineKnot(index));
|
||||
spline.SetKnot(i1, CalculateBSplineKnot(i1));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 开放曲线需进行安全边界检查
|
||||
if (index - 1 >= 0) spline.SetKnot(index - 1, CalculateBSplineKnot(index - 1));
|
||||
spline.SetKnot(index, CalculateBSplineKnot(index));
|
||||
if (index + 1 < count) spline.SetKnot(index + 1, CalculateBSplineKnot(index + 1));
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 触发我们自己的表现层脏标记
|
||||
isSplineDirty = true;
|
||||
}
|
||||
|
||||
public void UpdatePoint(Transform pointTransform, float progress)
|
||||
{
|
||||
UnitySpline spline = container.Splines[0];
|
||||
progress = isClosed ? Mathf.Repeat(progress, 1f) : Mathf.Clamp01(progress);
|
||||
float mathT = progress;
|
||||
if (trackSamplingType == Track.TrackSamplingType.DistanceDistributed)
|
||||
{
|
||||
float targetDistance = progress * spline.GetLength();
|
||||
mathT = spline.ConvertIndexUnit(targetDistance, PathIndexUnit.Distance, PathIndexUnit.Normalized);
|
||||
}
|
||||
container.Evaluate(0, mathT, out float3 pos, out float3 tangent, out float3 upVector);
|
||||
pointTransform.position = pos;
|
||||
|
||||
if (math.lengthsq(tangent) > 0)
|
||||
{
|
||||
Vector3 worldTangent = container.transform.TransformDirection(tangent);
|
||||
Vector3 worldUp = container.transform.TransformDirection(upVector);
|
||||
pointTransform.rotation = quaternion.LookRotationSafe(worldTangent, worldUp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Beatmap
|
||||
{
|
||||
public class TrackPathSubmodule_BM : Submodule_BM
|
||||
|
||||
@@ -65,6 +65,8 @@ namespace Ichni.RhythmGame
|
||||
|
||||
protected void SetMesh()
|
||||
{
|
||||
this.meshGenerator.enabled = false;
|
||||
|
||||
if (track.trackTimeSubmodule is TrackTimeSubmoduleMovable trackTimeSubmoduleMovable)
|
||||
{
|
||||
meshGenerator.clipFrom = trackTimeSubmoduleMovable.tailPercent;
|
||||
|
||||
Reference in New Issue
Block a user