namespace UnluckSoftware { // Simple Particle Scaler // Copyright Unluck Software // www.chemicalbliss.com // Save prefabs button removed as its functionality is now built into Unity. using UnityEngine; using UnityEditor; [System.Serializable] #pragma warning disable 0618 public class ParticleScaler :EditorWindow { private float scaleMultiplier = 1.0f; private bool autoRename; private string titleTex = "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"; private Texture2D tex; private GUIStyle styleBigButton = null; private GUIStyle styleScaleButton = null; private GUIStyle styleToggle = null; [MenuItem("Tools/Simple Particle Scaler")] private static void ShowWindow() { EditorWindow win = EditorWindow.GetWindow(typeof(ParticleScaler)); win.titleContent = new GUIContent("Simple Particle Scaler"); win.minSize = new Vector2(230.0f, 150.0f); win.maxSize = new Vector2(230.0f, 150.0f); } private void GenerateTitle() { if (tex != null) return; byte[] b64_bytes = System.Convert.FromBase64String(titleTex); tex = new Texture2D(1, 1); tex.LoadImage(b64_bytes); } private void ScaleParticles() { foreach (GameObject gameObj in Selection.gameObjects) { if (autoRename) { string[] s = gameObj.name.Split('¤'); if (s.Length == 1) { gameObj.name += " ¤" + scaleMultiplier; } else { float i = float.Parse(s[s.Length - 1]); gameObj.name = s[0] + "¤" + scaleMultiplier * i; } } ParticleSystem[] pss = null; pss = gameObj.GetComponentsInChildren(); foreach (ParticleSystem ps in pss) { ps.Stop(); ScaleParticles(gameObj, ps); ps.Play(); } } } private void StyleSetup() { if (styleBigButton != null) return; styleBigButton = new GUIStyle(GUI.skin.button); styleBigButton.fixedWidth = 90.0f; styleBigButton.fixedHeight = 30.0f; styleBigButton.fontSize = 12; styleScaleButton = new GUIStyle(GUI.skin.button); styleScaleButton.fixedWidth = 46.0f; styleScaleButton.fixedHeight = 15.0f; styleScaleButton.fontSize = 9; styleToggle = new GUIStyle(GUI.skin.toggle); styleToggle.fontSize = 9; } private void OnGUI() { // Setup styles StyleSetup(); GenerateTitle(); EditorGUILayout.Space(); // Draw header texture (if assigned) if (tex != null) { GUI.DrawTexture(new Rect(position.width * 0.5f - 100, 7, 200, 22), tex, ScaleMode.ScaleToFit, true, 0); } GUILayout.Space(20); EditorGUILayout.Space(); // Scale multiplier slider EditorGUILayout.BeginHorizontal(); EditorGUILayout.Space(); scaleMultiplier = EditorGUILayout.Slider(scaleMultiplier, 0.01f, 4.0f); EditorGUILayout.Space(); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); // Quick-scale preset buttons (0.25, 0.5, 1.5, 2) EditorGUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("0.25", styleScaleButton)) { scaleMultiplier = 0.25f; ScaleParticles(); } if (GUILayout.Button("0.5", styleScaleButton)) { scaleMultiplier = 0.5f; ScaleParticles(); } if (GUILayout.Button("1.5", styleScaleButton)) { scaleMultiplier = 1.5f; ScaleParticles(); } if (GUILayout.Button("2", styleScaleButton)) { scaleMultiplier = 2f; ScaleParticles(); } GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.Space(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Scale", styleBigButton)) { ScaleParticles(); } GUILayout.FlexibleSpace(); EditorGUILayout.Space(); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); // Auto rename toggle EditorGUILayout.BeginHorizontal(); GUILayout.Label("", GUILayout.Width(10.0f)); autoRename = GUILayout.Toggle(autoRename, " Automatic Rename", styleToggle); GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); } private void UpdateParticles() { foreach (GameObject gameObj in Selection.gameObjects) { ParticleSystem[] pss = null; pss = gameObj.GetComponentsInChildren(); foreach (ParticleSystem ps in pss) { ps.Stop(); ps.Play(); } } } private void ParticleCalls(string call) { foreach (GameObject gameObj in Selection.gameObjects) { ParticleSystem[] pss = null; pss = gameObj.GetComponentsInChildren(); foreach (ParticleSystem ps in pss) { if (call == "Pause") ps.Pause(); else if (call == "Play") ps.Play(); else if (call == "Stop") { ps.Stop(); ps.Clear(); } } } } private void ScaleParticles(GameObject __parent_cs1, ParticleSystem __particles_cs1) { Undo.RecordObject(__particles_cs1, "Scale ParticleSystem Properties"); // Transform Position: Scale the local position of the particle system if (__parent_cs1 != __particles_cs1.gameObject) { __particles_cs1.transform.localPosition *= scaleMultiplier; } // SerializedObject: Accessing the particle system's properties for modification SerializedObject serializedParticles = new SerializedObject(__particles_cs1); serializedParticles.Update(); // Shape Module: Scaling properties related to the shape of the particles serializedParticles.FindProperty("ShapeModule.m_Scale").vector3Value *= scaleMultiplier; // Scaling the shape's overall size // NoiseModule: scale only spatial displacements (strength, positionAmount), skip size & rotation amounts serializedParticles.FindProperty("NoiseModule.strength.scalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("NoiseModule.strength.minScalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("NoiseModule.strengthY.scalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("NoiseModule.strengthY.minScalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("NoiseModule.strengthZ.scalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("NoiseModule.strengthZ.minScalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("NoiseModule.positionAmount.scalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("NoiseModule.positionAmount.minScalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("NoiseModule.frequency").floatValue /= scaleMultiplier; serializedParticles.FindProperty("NoiseModule.scrollSpeed.scalar").floatValue /= scaleMultiplier; serializedParticles.FindProperty("NoiseModule.scrollSpeed.minScalar").floatValue /= scaleMultiplier; ScaleCurve(serializedParticles.FindProperty("NoiseModule.scrollSpeed.minCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("NoiseModule.scrollSpeed.maxCurve").animationCurveValue); //ScaleCurve(serializedParticles.FindProperty("NoiseModule.positionAmount.minCurve").animationCurveValue); //ScaleCurve(serializedParticles.FindProperty("NoiseModule.positionAmount.maxCurve").animationCurveValue); // Lights Module: Scaling properties related to particle system lights serializedParticles.FindProperty("LightsModule.rangeCurve.scalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("LightsModule.rangeCurve.minScalar").floatValue *= scaleMultiplier; // Gravity Modifier: Scaling gravity-related properties (added back here) serializedParticles.FindProperty("InitialModule.gravityModifier.scalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("InitialModule.gravityModifier.minScalar").floatValue *= scaleMultiplier; // Initial Module: Scaling properties related to particle size and speed at initialization serializedParticles.FindProperty("InitialModule.startSize.scalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("InitialModule.startSize.minScalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("InitialModule.startSizeY.scalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("InitialModule.startSizeY.minScalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("InitialModule.startSizeZ.scalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("InitialModule.startSizeZ.minScalar").floatValue *= scaleMultiplier; ScaleCurve(serializedParticles.FindProperty("InitialModule.startSize.minCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("InitialModule.startSize.maxCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("InitialModule.startSizeY.minCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("InitialModule.startSizeY.maxCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("InitialModule.startSizeZ.minCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("InitialModule.startSizeZ.maxCurve").animationCurveValue); serializedParticles.FindProperty("InitialModule.startSpeed.scalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("InitialModule.startSpeed.minScalar").floatValue *= scaleMultiplier; // Velocity over Lifetime Module: Scaling velocity applied during particle lifetime serializedParticles.FindProperty("VelocityModule.x.minScalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("VelocityModule.x.scalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("VelocityModule.y.minScalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("VelocityModule.y.scalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("VelocityModule.z.minScalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("VelocityModule.z.scalar").floatValue *= scaleMultiplier; ScaleCurve(serializedParticles.FindProperty("VelocityModule.x.minCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("VelocityModule.x.maxCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("VelocityModule.y.minCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("VelocityModule.y.maxCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("VelocityModule.z.minCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("VelocityModule.z.maxCurve").animationCurveValue); // Trail Module: Scaling the width over trail (if using trails in your particle system) serializedParticles.FindProperty("TrailModule.widthOverTrail.minScalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("TrailModule.widthOverTrail.scalar").floatValue *= scaleMultiplier; ScaleCurve(serializedParticles.FindProperty("TrailModule.widthOverTrail.minCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("TrailModule.widthOverTrail.maxCurve").animationCurveValue); // Clamp Velocity Module: Scaling velocity constraints for the particles serializedParticles.FindProperty("ClampVelocityModule.x.minScalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("ClampVelocityModule.y.minScalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("ClampVelocityModule.z.minScalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("ClampVelocityModule.magnitude.minScalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("ClampVelocityModule.x.scalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("ClampVelocityModule.y.scalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("ClampVelocityModule.z.scalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("ClampVelocityModule.magnitude.scalar").floatValue *= scaleMultiplier; ScaleCurve(serializedParticles.FindProperty("ClampVelocityModule.x.minCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("ClampVelocityModule.x.maxCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("ClampVelocityModule.y.minCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("ClampVelocityModule.y.maxCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("ClampVelocityModule.z.minCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("ClampVelocityModule.z.maxCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("ClampVelocityModule.magnitude.minCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("ClampVelocityModule.magnitude.maxCurve").animationCurveValue); // Force Module: Scaling forces applied to particles (external forces like gravity) serializedParticles.FindProperty("ForceModule.x.minScalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("ForceModule.y.minScalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("ForceModule.z.minScalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("ForceModule.x.scalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("ForceModule.y.scalar").floatValue *= scaleMultiplier; serializedParticles.FindProperty("ForceModule.z.scalar").floatValue *= scaleMultiplier; ScaleCurve(serializedParticles.FindProperty("ForceModule.x.minCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("ForceModule.x.maxCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("ForceModule.y.minCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("ForceModule.y.maxCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("ForceModule.z.minCurve").animationCurveValue); ScaleCurve(serializedParticles.FindProperty("ForceModule.z.maxCurve").animationCurveValue); // Apply all modified properties to the particle system serializedParticles.ApplyModifiedProperties(); } private void ScaleCurve(AnimationCurve curve) { for (int i = 0; i < curve.keys.Length; i++) { var tmp_cs1 = curve.keys[i]; tmp_cs1.value *= scaleMultiplier; curve.keys[i] = tmp_cs1; } } } }