Files
Cielonos/Assets/Scripts/MainGame/Effects/VFX/MeshEffect.cs
SoulliesOfficial 50ee502684 完善
2026-02-13 09:22:11 -05:00

241 lines
8.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using Cielonos.MainGame.Characters;
using Sirenix.OdinInspector;
using SLSUtilities.LeanPoolAssistance;
using UnityEngine;
namespace Cielonos.MainGame
{
[Serializable]
[InlineProperty]
public class MeshEffectRendererInfo
{
public Renderer renderer;
public float referenceScale = 1f;
}
public class MeshEffect : PooledObject
{
[System.Serializable]
[InlineProperty]
public class AdaptiveParameter
{
// Renamed for compactness as requested: C = Constant, R2C = RandomTwoConstants
public enum ParamMode { Constant, RandomRanged }
[HorizontalGroup("Line", Width = 120)]
[HideLabel]
public ParamMode mode = ParamMode.Constant;
[HorizontalGroup("Line", Width = 100)]
[ShowIf("mode", ParamMode.Constant)]
[LabelText("Constant")]
[LabelWidth(60)]
public float constantValue = 1f;
[HorizontalGroup("Line", Width = 100)]
[ShowIf("mode", ParamMode.RandomRanged)]
[LabelText("Min")]
[LabelWidth(30)]
public float constantMin = 1f;
[HorizontalGroup("Line", Width = 100)]
[ShowIf("mode", ParamMode.RandomRanged)]
[LabelText("Max")]
[LabelWidth(30)]
public float constantMax = 2f;
[HideInInspector]
public bool isCurveDetected = false;
[ShowIf("isCurveDetected")]
[InfoBox("Original source used Curves. Converted to Constant (Lossy).", InfoMessageType.Warning)]
private bool ShowCurveWarning => isCurveDetected;
public AdaptiveParameter(float defaultVal)
{
mode = ParamMode.Constant;
constantValue = defaultVal;
}
public ParticleSystem.MinMaxCurve GetScaledCurve(float scale)
{
if (mode == ParamMode.Constant)
{
return new ParticleSystem.MinMaxCurve(constantValue * scale);
}
else
{
return new ParticleSystem.MinMaxCurve(constantMin * scale, constantMax * scale);
}
}
public void PullFrom(ParticleSystem.MinMaxCurve source)
{
isCurveDetected = false;
switch (source.mode)
{
case ParticleSystemCurveMode.Constant:
mode = ParamMode.Constant;
constantValue = source.constant;
break;
case ParticleSystemCurveMode.TwoConstants:
mode = ParamMode.RandomRanged;
constantMin = source.constantMin;
constantMax = source.constantMax;
break;
case ParticleSystemCurveMode.Curve:
case ParticleSystemCurveMode.TwoCurves:
isCurveDetected = true;
mode = ParamMode.Constant;
constantValue = source.curveMultiplier;
break;
}
}
}
[System.Serializable]
public class ParticleSetting
{
[Required]
[OnValueChanged("PullFromParticleSystem")]
public ParticleSystem particleSystem;
[LabelText("Start Size"), LabelWidth(80)]
public AdaptiveParameter baseStartSize = new AdaptiveParameter(0.5f);
[LabelText("Emission"), LabelWidth(80)]
public AdaptiveParameter baseEmissionRate = new AdaptiveParameter(10f);
[HorizontalGroup("Sensitivity")]
[LabelText("Size Sens."), LabelWidth(70)]
[Range(0f, 1f)]
public float sizeScaleSensitivity = 0f;
[HorizontalGroup("Sensitivity")]
[LabelText("Emission Sens."), LabelWidth(90)]
[Range(0f, 1f)]
public float emissionScaleSensitivity = 1f;
/// <summary>
/// Automatically pull values from the assigned ParticleSystem.
/// 自动读取粒子系统参数
/// </summary>
public void PullFromParticleSystem()
{
if (particleSystem != null)
{
baseStartSize.PullFrom(particleSystem.main.startSize);
baseEmissionRate.PullFrom(particleSystem.emission.rateOverTime);
}
}
}
[Title("Mesh Effect Configuration")]
[Button("Add All Child Particles", ButtonSizes.Medium), PropertyOrder(-1)]
[Tooltip("Automatically find all ParticleSystems in children and add them to the list.")]
public void AutoPopulateChildren()
{
var systems = GetComponentsInChildren<ParticleSystem>(true);
foreach (var ps in systems)
{
if (particleSettings.Any(p => p.particleSystem == ps)) continue;
var newSetting = new ParticleSetting();
newSetting.particleSystem = ps;
newSetting.PullFromParticleSystem();
particleSettings.Add(newSetting);
}
}
[ListDrawerSettings(ShowFoldout = true)]
public List<ParticleSetting> particleSettings = new List<ParticleSetting>();
[Title("Global Adjustments")]
[Tooltip("Global scale multiplier for the entire effect. \n全局系数用于整体调整效果强弱")]
public float globalMultiplier = 1f;
[Tooltip("Reference scale for calculating 'One Unit'. Usually set to 1 or the average size of a character. \n参考尺寸用于定义“单位大小”。通常设为1或者标准角色的大小")]
public float referenceScale = 1f;
public Renderer targetRenderer;
private void Reset()
{
isAutoDespawn = false;
}
public void AttachTo(MeshEffectRendererInfo target)
{
if (target == null) return;
targetRenderer = target.renderer;
transform.SetParent(targetRenderer.transform, true);
transform.localPosition = Vector3.zero;
transform.localRotation = Quaternion.identity;
transform.localScale = Vector3.one;
referenceScale = target.referenceScale;
ApplyEffectSettings();
}
public void StopAllParticles()
{
foreach (var setting in particleSettings.Where(setting => setting.particleSystem != null))
{
setting.particleSystem.Stop();
}
}
private void ApplyEffectSettings()
{
if (targetRenderer == null) return;
// Calculate Scale Factor based on Bounds
Vector3 size = targetRenderer.bounds.size;
float averageSize = (size.x + size.y + size.z) / 3f;
float scaleRatio = (averageSize / referenceScale);
if (scaleRatio <= 0.001f) scaleRatio = 1f;
foreach (var setting in particleSettings)
{
if (setting.particleSystem == null) continue;
var main = setting.particleSystem.main;
var emission = setting.particleSystem.emission;
var shape = setting.particleSystem.shape;
// 1. Adaptive Shape Setup
shape.enabled = true;
if (targetRenderer is SkinnedMeshRenderer smr)
{
shape.shapeType = ParticleSystemShapeType.SkinnedMeshRenderer;
shape.skinnedMeshRenderer = smr;
}
else if (targetRenderer is MeshRenderer mr)
{
shape.shapeType = ParticleSystemShapeType.MeshRenderer;
shape.meshRenderer = mr;
}
// 2. Calculate Adaptive Parameters
// Size Logic
float sizeFactor = Mathf.Lerp(1f, scaleRatio, setting.sizeScaleSensitivity);
float finalSizeScale = sizeFactor * globalMultiplier;
main.startSize = setting.baseStartSize.GetScaledCurve(finalSizeScale);
// Emission Logic
float areaRatio = Mathf.Pow(scaleRatio, 2);
float emissionFactor = Mathf.Lerp(1f, areaRatio, setting.emissionScaleSensitivity);
float finalEmissionScale = emissionFactor * globalMultiplier;
emission.rateOverTime = setting.baseEmissionRate.GetScaledCurve(finalEmissionScale);
}
}
}
}