Namespace: MDPackage.Modifiers
Base modifier class for all the modifier instances. Implement this base class to any script that should behave like a 'mesh-modifier'.
Please read the APi below carefully as the setup for classes that inherit from this base class is slightly different.
Public Methods
public static T CreateModifier<T>(GameObject entry, MeshReferenceType meshReferenceType)
protected virtual void MDModifier_InitializeBase(MeshReferenceType meshReferenceType = MeshReferenceType.GetFromPreferences, bool forceInitialization = false, bool affectUpdateEveryFrameField = true)
protected virtual void MDModifier_InitializeMeshData(bool initialMeshData = true, bool backupMeshData = true, bool workingMeshData = true)
public abstract void MDModifier_ProcessModifier();
public void MDModifier_RestoreMesh()
public void MDModifier_SubdivideMesh(int level = 2)
public void MDModifier_SmoothMesh(float intensity = 0.5f)
public void MDModifier_BakeMesh(bool forceInitialMeshData = false, bool forceBackupMeshData = false, bool forceWorkingMeshData = false)
public void MDModifier_CreateNewMeshReference(string meshName = "")
public virtual void MDModifierThreading_StartThread(string threadName = "DefaultMDThread")
public virtual void MDModifierThreading_StopThread()
Public Fields and Properties
public bool MbIsInitialized { get; }
public bool MbMultithreadedModifier { get; }
public Thread ThreadInstance { get; }
public ManualResetEvent ThreadEvent { get; protected set; }
public bool MbUseModifierMeshFeatures = true;
public MbMeshData MbInitialMeshData { get; }
public MbMeshData MbBackupMeshData { get; }
public MbMeshData MbWorkingMeshData { get; }
public Action OnModifierInitialized;
public event Action OnMeshRestored;
public event Action OnMeshBaked;
public event Action OnMeshSubdivided;
public event Action OnMeshSmoothed;
public event Action OnNewMeshReferenceCreated;
Examples & Setup
All the modifiers that inherit from this base class must be initialized in a certain way.
You can either simply call gameObject.AddComponent() or call a static method MD_ModifierBase.CreateModifier(Advanced data...).
using UnityEngine;
using MDPackage.Modifiers;
public class SampleScript : MonoBehaviour
{
private MDM_Bend modifier;
private void Start()
{
modifier = MD_ModifierBase.CreateModifier<MDM_Bend>(gameObject, MD_ModifierBase.MeshReferenceType.GetFromPreferences);
}
}
The ModifierBase contains an interface called IMDThreadingSupport that allows you to add multithreading features.
See the following example script with custom modifier written from scratch.
using System.Threading;
using UnityEngine;
using MDPackage.Modifiers;
#if UNITY_EDITOR
using UnityEditor;
using MDPackage;
using MDPackage_Editor;
#endif
public class SampleScript : MD_ModifierBase, MD_ModifierBase.IMDThreadingSupport
{
public bool ThreadUseMultithreading { get => _threadUseMultithreading; set => _threadUseMultithreading = value; }
[SerializeField] private bool _threadUseMultithreading;
public bool ThreadEditorThreadSupported { get => _threadEditorThreadSupported; private set => _threadEditorThreadSupported = value; }
[SerializeField] private bool _threadEditorThreadSupported;
public bool ThreadIsDone { get; private set; }
public int ThreadSleep { get => _threadSleep; set => _threadSleep = value; }
[SerializeField, Range(5, 60)] private int _threadSleep = 20;
public float vertexFloatingMultiplier = 1;
private float unityTime;
protected override void MDModifier_InitializeBase(MeshReferenceType meshReferenceType = MeshReferenceType.GetFromPreferences, bool forceInitialization = false, bool affectUpdateEveryFrameField = true)
{
base.MDModifier_InitializeBase(meshReferenceType, forceInitialization, affectUpdateEveryFrameField);
MDModifier_InitializeMeshData();
ThreadEditorThreadSupported = true;
MbUseModifierMeshFeatures = true;
useNormalSmoothingAngle = true;
}
private void Awake()
{
if (ThreadUseMultithreading)
MDModifierThreading_StartThread();
}
protected override void Update()
{
if (!MbIsInitialized)
return;
base.Update();
unityTime = Time.time;
if (!ThreadUseMultithreading)
{
ProcessModifierThreadSafeAPi();
MDMeshBase_UpdateMesh();
MDMeshBase_RecalculateMesh();
}
}
public override void MDModifier_ProcessModifier()
{
if (!MbIsInitialized)
return;
if (ThreadUseMultithreading)
{
if (ThreadIsDone)
{
MDMeshBase_UpdateMesh();
MDMeshBase_RecalculateMesh();
}
else ThreadEvent?.Set();
return;
}
MDMeshBase_UpdateMesh();
MDMeshBase_RecalculateMesh();
}
private void ProcessModifierThreadSafeAPi()
{
for (int i = 0; i < MbWorkingMeshData.vertices.Length; i++)
{
MbWorkingMeshData.vertices[i] =
MbBackupMeshData.vertices[i] + Vector3.up *
(Mathf.Sin(unityTime * MbBackupMeshData.vertices[i].x * 3.5f)
* vertexFloatingMultiplier + Mathf.Abs(MbBackupMeshData.vertices[i].y));
}
}
public void MDThreading_ProcessThreadWorker()
{
while (true)
{
ThreadIsDone = false;
ThreadEvent?.WaitOne();
ProcessModifierThreadSafeAPi();
ThreadIsDone = true;
Thread.Sleep(ThreadSleep);
ThreadEvent?.Reset();
}
}
}
#if UNITY_EDITOR
[CanEditMultipleObjects]
[CustomEditor(typeof(SampleScript))]
public sealed class SampleScriptEditor : MD_ModifierBase_Editor
{
public override void OnEnable()
{
base.OnEnable();
mMeshBase = (MD_MeshBase)target;
mModifierBase = (MD_ModifierBase)target;
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
MDE_DrawProperty("vertexFloatingMultiplier", "vertexFloatingMultiplier");
}
}
#endif