Files
Hasebe/Assets/MK/MKToon/Editor/Base/FeatureComponents/ParticlesComponent.cs
T
2026-10-09 17:25:14 +03:00

354 lines
17 KiB
C#

//////////////////////////////////////////////////////
// MK Toon Editor Particles Component //
// //
// Created by Michael Kremmel //
// www.michaelkremmel.de //
// Copyright © 2020 All rights reserved. //
//////////////////////////////////////////////////////
#if UNITY_EDITOR
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Linq;
using System;
using UnityEditor.Utils;
using UnityEditorInternal;
using EditorHelper = MK.Toon.Editor.EditorHelper;
namespace MK.Toon.Editor
{
internal sealed class ParticlesComponent : ShaderGUI
{
internal bool active { get { return _particlesBehavior != null; } }
/////////////////////////////////////////////////////////////////////////////////////////////
// Properties //
/////////////////////////////////////////////////////////////////////////////////////////////
//Unity source based particle properties
#if UNITY_6000_5_OR_NEWER
[Unity.Scripting.LifecycleManagement.AutoStaticsCleanup]
#endif
private static ReorderableList vertexStreamList;
List<ParticleSystemRenderer> _renderersUsingThisMaterial = new List<ParticleSystemRenderer>();
/////////////////
// Particles //
/////////////////
internal MaterialProperty _flipbook;
internal MaterialProperty _softFade;
internal MaterialProperty _softFadeNearDistance;
internal MaterialProperty _softFadeFarDistance;
internal MaterialProperty _cameraFade;
internal MaterialProperty _cameraFadeNearDistance;
internal MaterialProperty _cameraFadeFarDistance;
internal MaterialProperty _colorBlend;
private MaterialProperty _particlesBehavior;
internal void FindProperties(MaterialProperty[] props)
{
_flipbook = FindProperty(Properties.flipbook.uniform.name, props, false);
_softFade = FindProperty(Properties.softFade.uniform.name, props, false);
_softFadeNearDistance = FindProperty(Properties.softFadeNearDistance.uniform.name, props, false);
_softFadeFarDistance = FindProperty(Properties.softFadeFarDistance.uniform.name, props, false);
_cameraFade = FindProperty(Properties.cameraFade.uniform.name, props, false);
_cameraFadeNearDistance = FindProperty(Properties.cameraFadeNearDistance.uniform.name, props, false);
_cameraFadeFarDistance = FindProperty(Properties.cameraFadeFarDistance.uniform.name, props, false);
_colorBlend = FindProperty(Properties.colorBlend.uniform.name, props, false);
_particlesBehavior = FindProperty(EditorProperties.particlesTab.uniform.name, props, false);
}
/////////////////////////////////////////////////////////////////////////////////////////////
// Setup //
/////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Find similar values from the changed shader
/// </summary>
/// <param name="propertiesSrc"></param>
/// <param name="materialDst"></param>
/// <param name="materialSrc"></param>
internal void ConvertSimilarValues(MaterialProperty[] propertiesSrc, Material materialSrc, Material materialDst)
{
MaterialProperty flipbook = FindProperty("_Flipbook", propertiesSrc, false);
MaterialProperty flipbookBlending = FindProperty("_FlipbookBlending", propertiesSrc, false);
MaterialProperty softParticlesEnabled = FindProperty("_SoftParticlesEnabled", propertiesSrc, false);
MaterialProperty softParticlesNearFadeDistance = FindProperty("_SoftParticlesNearFadeDistance", propertiesSrc, false);
MaterialProperty softParticlesFarFadeDistance = FindProperty("_SoftParticlesFarFadeDistance", propertiesSrc, false);
MaterialProperty cameraFadingEnabled = FindProperty("_CameraFadingEnabled", propertiesSrc, false);
MaterialProperty cameraNearFadeDistance = FindProperty("_CameraNearFadeDistance", propertiesSrc, false);
MaterialProperty cameraFarFadeDistance = FindProperty("_CameraFarFadeDistance", propertiesSrc, false);
MaterialProperty colorBlend = FindProperty("_ColorMode", propertiesSrc, false);
if(flipbook != null)
Properties.flipbook.SetValue(materialDst, flipbook.floatValue > 0 ? true : false);
if(flipbookBlending != null)
Properties.flipbook.SetValue(materialDst, flipbookBlending.floatValue > 0 ? true : false);
if(softParticlesEnabled != null)
Properties.softFade.SetValue(materialDst, softParticlesEnabled.floatValue > 0 ? true : false);
if(softParticlesNearFadeDistance != null)
Properties.softFadeNearDistance.SetValue(materialDst, softParticlesNearFadeDistance.floatValue);
if(softParticlesFarFadeDistance != null)
Properties.softFadeFarDistance.SetValue(materialDst, softParticlesFarFadeDistance.floatValue);
if(cameraFadingEnabled != null)
Properties.cameraFade.SetValue(materialDst, cameraFadingEnabled.floatValue > 0 ? true : false);
if(cameraNearFadeDistance != null)
Properties.cameraFadeNearDistance.SetValue(materialDst, cameraNearFadeDistance.floatValue);
if(cameraFarFadeDistance != null)
Properties.cameraFadeFarDistance.SetValue(materialDst, cameraFarFadeDistance.floatValue);
if(colorBlend != null)
Properties.colorBlend.SetValue(materialDst, (ColorBlend) colorBlend.floatValue);
}
/////////////////////////////////////////////////////////////////////////////////////////////
// Draw //
/////////////////////////////////////////////////////////////////////////////////////////////
internal void Initialize(MaterialEditor materialEditor)
{
CacheRenderersUsingThisMaterial(materialEditor);
}
//Cache function based on unity source
private void CacheRenderersUsingThisMaterial(MaterialEditor materialEditor)
{
_renderersUsingThisMaterial.Clear();
Material material = materialEditor.target as Material;
foreach (var obj in materialEditor.targets)
{
#if UNITY_6000_5_OR_NEWER
ParticleSystemRenderer[] renderers = UnityEngine.Object.FindObjectsByType<ParticleSystemRenderer>();
#elif UNITY_2023_1_OR_NEWER
ParticleSystemRenderer[] renderers = UnityEngine.Object.FindObjectsByType<ParticleSystemRenderer>(FindObjectsSortMode.InstanceID);
#else
ParticleSystemRenderer[] renderers = UnityEngine.Object.FindObjectsOfType(typeof(ParticleSystemRenderer)) as ParticleSystemRenderer[];
#endif
foreach (ParticleSystemRenderer renderer in renderers)
{
if (renderer.sharedMaterial == material)
_renderersUsingThisMaterial.Add(renderer);
}
}
}
internal void DrawParticles(MaterialEditor materialEditor, MaterialProperty[] properties, MaterialProperty surface, ShaderTemplate shaderTemplate)
{
//All refraction properties needs to be available on the material
//the refraction tab is used for check
if(_particlesBehavior != null)
{
if(EditorHelper.HandleBehavior(UI.particlesTab.text, "", _particlesBehavior, null, materialEditor, false))
{
DrawColorBlend(materialEditor);
DrawFlipbookMode(materialEditor);
DrawSoftFadeMode(materialEditor, (Surface) surface.floatValue);
DrawCameraFadeMode(materialEditor, (Surface) surface.floatValue);
DrawVertexDataStream(materialEditor, shaderTemplate);
}
EditorHelper.DrawSplitter();
}
}
/////////////////
// Options //
/////////////////
internal void DrawColorBlend(MaterialEditor materialEditor)
{
materialEditor.ShaderProperty(_colorBlend, UI.colorBlend);
}
/////////////////
// Advanced //
/////////////////
private static void VertexStreamsArea(Material material, List<ParticleSystemRenderer> renderers, ShaderTemplate shaderTemplate)
{
bool useLighting, isPBS;
useLighting = shaderTemplate != ShaderTemplate.Unlit ? true : false;
isPBS = shaderTemplate == ShaderTemplate.PhysicallyBased ? true : false;
EditorGUILayout.Space();
// Display list of streams required to make this shader work
bool useNormalMap = false;
bool useFlipbookBlending = Properties.flipbook.GetValue(material);
if(useLighting)
useNormalMap = Properties.normalMap.GetValue(material) != null;
bool useHeightMap = false;
if(isPBS)
useHeightMap = Properties.heightMap.GetValue(material) != null;
bool useDetailNormalMap = false;
if(isPBS)
useDetailNormalMap = Properties.detailNormalMap.GetValue(material) != null && isPBS;
bool useAnisotropicSpecular = false;
if(useLighting)
useAnisotropicSpecular = Properties.specular.GetValue(material) != Specular.Anisotropic && isPBS;
// Build the list of expected vertex streams
List<ParticleSystemVertexStream> streams = new List<ParticleSystemVertexStream>();
List<string> streamList = new List<string>();
streams.Add(ParticleSystemVertexStream.Position);
streamList.Add(EditorHelper.EditorStyles.streamPositionText);
if (useLighting)
{
streams.Add(ParticleSystemVertexStream.Normal);
streamList.Add(EditorHelper.EditorStyles.streamNormalText);
if (useNormalMap || useDetailNormalMap || useDetailNormalMap || useHeightMap)
{
streams.Add(ParticleSystemVertexStream.Tangent);
streamList.Add(EditorHelper.EditorStyles.streamTangentText);
}
}
streams.Add(ParticleSystemVertexStream.Color);
streamList.Add(EditorHelper.EditorStyles.streamColorText);
streams.Add(ParticleSystemVertexStream.UV);
streamList.Add(EditorHelper.EditorStyles.streamUVText);
if (useFlipbookBlending)
{
streams.Add(ParticleSystemVertexStream.UV2);
streamList.Add(EditorHelper.EditorStyles.streamUV2Text);
streams.Add(ParticleSystemVertexStream.AnimBlend);
streamList.Add(EditorHelper.EditorStyles.streamAnimBlendText);
}
vertexStreamList = new ReorderableList(streamList, typeof(string), false, true, false, false);
vertexStreamList.drawHeaderCallback = (Rect rect) => {
EditorGUI.LabelField(rect, "Vertex Streams");
};
vertexStreamList.DoLayoutList();
// Display a warning if any renderers have incorrect vertex streams
string Warnings = "";
List<ParticleSystemVertexStream> rendererStreams = new List<ParticleSystemVertexStream>();
foreach (ParticleSystemRenderer renderer in renderers)
{
renderer.GetActiveVertexStreams(rendererStreams);
if (!rendererStreams.SequenceEqual(streams))
Warnings += "-" + renderer.name + "\n";
}
if (!string.IsNullOrEmpty(Warnings))
{
EditorGUILayout.HelpBox(
"The following Particle System Renderers are using this material with incorrect Vertex Streams:\n" +
Warnings, MessageType.Error, true);
// Set the streams on all systems using this material
if (GUILayout.Button(EditorHelper.EditorStyles.streamApplyToAllSystemsText, EditorStyles.miniButton, GUILayout.ExpandWidth(true)))
{
Undo.RecordObjects(renderers.Where(r => r != null).ToArray(), EditorHelper.EditorStyles.undoApplyCustomVertexStreams);
foreach (ParticleSystemRenderer renderer in renderers)
{
renderer.SetActiveVertexStreams(streams);
}
}
}
}
internal void DrawFlipbookMode(MaterialEditor materialEditor)
{
materialEditor.ShaderProperty(_flipbook, UI.flipbook);
}
internal void DrawSoftFadeMode(MaterialEditor materialEditor, Surface surface)
{
if(surface == Surface.Transparent)
{
materialEditor.ShaderProperty(_softFade, UI.softFade);
if(_softFade.floatValue > 0)
{
materialEditor.ShaderProperty(_softFadeNearDistance, UI.softFadeNearDistance);
materialEditor.ShaderProperty(_softFadeFarDistance, UI.softFadeFarDistance);
}
}
}
internal void DrawCameraFadeMode(MaterialEditor materialEditor, Surface surface)
{
if(surface == Surface.Transparent)
{
materialEditor.ShaderProperty(_cameraFade, UI.cameraFade);
if(_cameraFade.floatValue > 0)
{
materialEditor.ShaderProperty(_cameraFadeNearDistance, UI.cameraFadeNearDistance);
materialEditor.ShaderProperty(_cameraFadeFarDistance, UI.cameraFadeFarDistance);
}
}
}
internal void DrawVertexDataStream(MaterialEditor materialEditor, ShaderTemplate shaderTemplate)
{
EditorHelper.VerticalSpace();
EditorGUI.BeginChangeCheck();
{
foreach (Material mat in _colorBlend.targets)
{
VertexStreamsArea(mat, _renderersUsingThisMaterial, shaderTemplate);
}
}
EditorGUI.EndChangeCheck();
}
/////////////////////////////////////////////////////////////////////////////////////////////
// Variants Setup //
/////////////////////////////////////////////////////////////////////////////////////////////
internal void ManageKeywordsColorBlend(Material material)
{
if(_particlesBehavior != null)
{
//Color Mode
ColorBlend cm = Properties.colorBlend.GetValue(material);
EditorHelper.SetKeyword(Properties.surface.GetValue(material) == Surface.Transparent && Properties.colorBlend.GetValue(material) == ColorBlend.Additive, Keywords.colorBlend[1], material);
EditorHelper.SetKeyword(Properties.surface.GetValue(material) == Surface.Transparent && Properties.colorBlend.GetValue(material) == ColorBlend.Subtractive, Keywords.colorBlend[2], material);
EditorHelper.SetKeyword(Properties.surface.GetValue(material) == Surface.Transparent && Properties.colorBlend.GetValue(material) == ColorBlend.Overlay, Keywords.colorBlend[3], material);
EditorHelper.SetKeyword(Properties.surface.GetValue(material) == Surface.Transparent && Properties.colorBlend.GetValue(material) == ColorBlend.Color, Keywords.colorBlend[4], material);
EditorHelper.SetKeyword(Properties.surface.GetValue(material) == Surface.Transparent && Properties.colorBlend.GetValue(material) == ColorBlend.Difference, Keywords.colorBlend[5], material);
//No Keyword == Multiply
Properties.colorBlend.SetValue(material, cm);
}
}
internal void ManageKeywordsFlipbook(Material material)
{
if(_particlesBehavior != null)
{
//Flipbook Mode
EditorHelper.SetKeyword(Properties.flipbook.GetValue(material), Keywords.flipbook, material);
}
}
internal void ManageKeywordsSoftFade(Material material)
{
if(_particlesBehavior != null)
{
//Soft Fade Mode
EditorHelper.SetKeyword(Properties.surface.GetValue(material) == Surface.Transparent && Properties.softFade.GetValue(material), Keywords.softFade, material);
}
}
internal void ManageKeywordsCameraFade(Material material)
{
if(_particlesBehavior != null)
{
//Camera Fade Mode
EditorHelper.SetKeyword(Properties.surface.GetValue(material) == Surface.Transparent && Properties.cameraFade.GetValue(material), Keywords.cameraFade, material);
}
}
internal void UpdateKeywords(Material material)
{
ManageKeywordsColorBlend(material);
ManageKeywordsFlipbook(material);
ManageKeywordsSoftFade(material);
ManageKeywordsCameraFade(material);
}
}
}
#endif