193 lines
5.5 KiB
C#
193 lines
5.5 KiB
C#
using UnityEngine;
|
|
|
|
namespace NBShader
|
|
{
|
|
[ExecuteAlways]
|
|
[DisallowMultipleComponent]
|
|
[RequireComponent(typeof(ParticleSystem))]
|
|
public sealed class NBParticleLocalTransformHelper : MonoBehaviour
|
|
{
|
|
private const string NBShaderName = "Effects/NBShader";
|
|
private const string LegacyShaderName = "Effects/NBShader(Legacy)";
|
|
private const string CustomLocalTransformKeyword = "_CUSTOM_LOCAL_TRANSFORM";
|
|
|
|
private static readonly int CustomLocalTransformLocalToWorldId =
|
|
Shader.PropertyToID("_CustomLocalTransformLocalToWorld");
|
|
|
|
private static readonly int CustomLocalTransformWorldToLocalId =
|
|
Shader.PropertyToID("_CustomLocalTransformWorldToLocal");
|
|
|
|
private ParticleSystemRenderer _particleRenderer;
|
|
private Material _runtimeMaterial;
|
|
private Material _lastAppliedMaterial;
|
|
private string _lastWarning;
|
|
|
|
private void OnEnable()
|
|
{
|
|
CacheRenderer();
|
|
ApplyCustomTransform();
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
ApplyCustomTransform();
|
|
}
|
|
|
|
private void OnValidate()
|
|
{
|
|
CacheRenderer();
|
|
ApplyCustomTransform();
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
SetCustomTransformKeyword(false);
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
SetCustomTransformKeyword(false);
|
|
}
|
|
|
|
private void CacheRenderer()
|
|
{
|
|
if (_particleRenderer == null)
|
|
{
|
|
TryGetComponent(out _particleRenderer);
|
|
}
|
|
}
|
|
|
|
private void ApplyCustomTransform()
|
|
{
|
|
if (!TryGetWritableMaterial(out Material material))
|
|
{
|
|
DisableLastAppliedKeyword();
|
|
return;
|
|
}
|
|
|
|
if (_lastAppliedMaterial != null && _lastAppliedMaterial != material)
|
|
{
|
|
_lastAppliedMaterial.DisableKeyword(CustomLocalTransformKeyword);
|
|
}
|
|
|
|
Matrix4x4 localToWorld = transform.localToWorldMatrix;
|
|
Matrix4x4 worldToLocal = transform.worldToLocalMatrix;
|
|
|
|
material.SetMatrix(CustomLocalTransformLocalToWorldId, localToWorld);
|
|
material.SetMatrix(CustomLocalTransformWorldToLocalId, worldToLocal);
|
|
material.EnableKeyword(CustomLocalTransformKeyword);
|
|
|
|
_lastAppliedMaterial = material;
|
|
_lastWarning = null;
|
|
}
|
|
|
|
private void SetCustomTransformKeyword(bool enabled)
|
|
{
|
|
Material material = GetExistingMaterial();
|
|
if (material == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (enabled)
|
|
{
|
|
material.EnableKeyword(CustomLocalTransformKeyword);
|
|
}
|
|
else
|
|
{
|
|
material.DisableKeyword(CustomLocalTransformKeyword);
|
|
if (material == _lastAppliedMaterial)
|
|
{
|
|
_lastAppliedMaterial = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
private Material GetExistingMaterial()
|
|
{
|
|
if (_lastAppliedMaterial != null)
|
|
{
|
|
return _lastAppliedMaterial;
|
|
}
|
|
|
|
CacheRenderer();
|
|
if (_particleRenderer == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (Application.isPlaying)
|
|
{
|
|
return _runtimeMaterial;
|
|
}
|
|
|
|
return _particleRenderer.sharedMaterial;
|
|
}
|
|
|
|
private bool TryGetWritableMaterial(out Material material)
|
|
{
|
|
CacheRenderer();
|
|
if (_particleRenderer == null)
|
|
{
|
|
material = null;
|
|
LogWarningOnce("NBParticleLocalTransformHelper requires a ParticleSystemRenderer on the same GameObject.");
|
|
return false;
|
|
}
|
|
|
|
material = Application.isPlaying ? GetRuntimeMaterial() : _particleRenderer.sharedMaterial;
|
|
if (material == null)
|
|
{
|
|
LogWarningOnce("NBParticleLocalTransformHelper could not find a material on the ParticleSystemRenderer.");
|
|
return false;
|
|
}
|
|
|
|
if (material.shader == null || !IsSupportedShader(material.shader))
|
|
{
|
|
material = null;
|
|
LogWarningOnce("NBParticleLocalTransformHelper only supports NBShader materials using shader '" +
|
|
NBShaderName + "' or '" + LegacyShaderName + "'.");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static bool IsSupportedShader(Shader shader)
|
|
{
|
|
return shader.name == NBShaderName || shader.name == LegacyShaderName;
|
|
}
|
|
|
|
private Material GetRuntimeMaterial()
|
|
{
|
|
if (_runtimeMaterial == null && _particleRenderer != null)
|
|
{
|
|
_runtimeMaterial = _particleRenderer.material;
|
|
}
|
|
|
|
return _runtimeMaterial;
|
|
}
|
|
|
|
private void DisableLastAppliedKeyword()
|
|
{
|
|
if (_lastAppliedMaterial == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_lastAppliedMaterial.DisableKeyword(CustomLocalTransformKeyword);
|
|
_lastAppliedMaterial = null;
|
|
}
|
|
|
|
private void LogWarningOnce(string message)
|
|
{
|
|
if (_lastWarning == message)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_lastWarning = message;
|
|
Debug.LogWarning(message, this);
|
|
}
|
|
}
|
|
}
|