GPU优化

This commit is contained in:
SoulliesOfficial
2026-02-27 08:21:00 -05:00
parent 0109878661
commit a635ec4221
872 changed files with 197615 additions and 2054 deletions

View File

@@ -212,6 +212,7 @@ namespace Ichni.RhythmGame
{
var mainModule = particle.main;
mainModule.prewarm = prewarm;
mainModule.maxParticles = 500;
}
public void SetSimulationSpace(ParticleSystemSimulationSpace simulationSpace)

View File

@@ -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()
{

View File

@@ -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) + " " +

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -65,6 +65,8 @@ namespace Ichni.RhythmGame
protected void SetMesh()
{
this.meshGenerator.enabled = false;
if (track.trackTimeSubmodule is TrackTimeSubmoduleMovable trackTimeSubmoduleMovable)
{
meshGenerator.clipFrom = trackTimeSubmoduleMovable.tailPercent;