diff --git a/Distribution/GameData/ConformalDecals/Parts/decal-blank.cfg b/Distribution/GameData/ConformalDecals/Parts/decal-blank.cfg index eb33229..feea208 100644 --- a/Distribution/GameData/ConformalDecals/Parts/decal-blank.cfg +++ b/Distribution/GameData/ConformalDecals/Parts/decal-blank.cfg @@ -47,6 +47,7 @@ PART decalFront = Decal-Front decalBack = Decal-Back + decalModel = Decal-Model useBaseNormal = false diff --git a/Distribution/GameData/ConformalDecals/Parts/decal-flag.cfg b/Distribution/GameData/ConformalDecals/Parts/decal-flag.cfg index d71de30..49fb31e 100644 --- a/Distribution/GameData/ConformalDecals/Parts/decal-flag.cfg +++ b/Distribution/GameData/ConformalDecals/Parts/decal-flag.cfg @@ -48,6 +48,7 @@ PART decalFront = Decal-Front decalBack = Decal-Back + decalModel = Decal-Model useBaseNormal = true } diff --git a/Distribution/GameData/ConformalDecals/Plugins/ConformalDecals.dll b/Distribution/GameData/ConformalDecals/Plugins/ConformalDecals.dll index c8b9335..8514de4 100644 --- a/Distribution/GameData/ConformalDecals/Plugins/ConformalDecals.dll +++ b/Distribution/GameData/ConformalDecals/Plugins/ConformalDecals.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:42f45fb15fed4898f02296262f32f1a1aaad38a8bee3ae538002b488a1420064 -size 34304 +oid sha256:c8c2ebf552538f84512d4bc7018c8b294750317bc2afbc7cd556448bc6067c34 +size 35328 diff --git a/Source/ConformalDecals/ConformalDecals.csproj b/Source/ConformalDecals/ConformalDecals.csproj index 43b0a27..c70863f 100644 --- a/Source/ConformalDecals/ConformalDecals.csproj +++ b/Source/ConformalDecals/ConformalDecals.csproj @@ -49,8 +49,9 @@ - - + + + diff --git a/Source/ConformalDecals/ConformalDecalConfig.cs b/Source/ConformalDecals/DecalConfig.cs similarity index 95% rename from Source/ConformalDecals/ConformalDecalConfig.cs rename to Source/ConformalDecals/DecalConfig.cs index d1e990c..be98770 100644 --- a/Source/ConformalDecals/ConformalDecalConfig.cs +++ b/Source/ConformalDecals/DecalConfig.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using UnityEngine; namespace ConformalDecals { - public static class ConformalDecalConfig { + public static class DecalConfig { private static List _shaderBlacklist; public static bool IsBlacklisted(Shader shader) { diff --git a/Source/ConformalDecals/ConformalDecalIconFixer.cs b/Source/ConformalDecals/DecalIconFixer.cs similarity index 75% rename from Source/ConformalDecals/ConformalDecalIconFixer.cs rename to Source/ConformalDecals/DecalIconFixer.cs index 22f99e4..9255f85 100644 --- a/Source/ConformalDecals/ConformalDecalIconFixer.cs +++ b/Source/ConformalDecals/DecalIconFixer.cs @@ -3,7 +3,7 @@ using UnityEngine; namespace ConformalDecals { [KSPAddon(KSPAddon.Startup.EditorAny, true)] - public class ConformalDecalIconFixer : MonoBehaviour { + public class DecalIconFixer : MonoBehaviour { private static readonly List PartNames = new List(); public static void QueuePart(string name) { @@ -11,12 +11,12 @@ namespace ConformalDecals { } public void Start() { - foreach (var name in PartNames) { - Debug.Log($"Unf*&king decal preview on {name}"); - var partInfo = PartLoader.getPartInfoByName(name); + foreach (var partName in PartNames) { + Debug.Log($"Unf*&king decal preview on {partName}"); + var partInfo = PartLoader.getPartInfoByName(partName); if (partInfo == null) { - Debug.Log($"Part {name} not found!"); + Debug.Log($"Part {partName} not found!"); continue; } @@ -24,21 +24,16 @@ namespace ConformalDecals { var decalModule = partInfo.partPrefab.FindModuleImplementing(); - if (partInfo == null) { - Debug.Log($"Part {name} has no decal module!"); - continue; - } - var frontTransform = Part.FindHeirarchyTransform(icon.transform, decalModule.decalFront); var backTransform = Part.FindHeirarchyTransform(icon.transform, decalModule.decalBack); if (frontTransform == null) { - Debug.Log($"Part {name} has no frontTransform"); + Debug.Log($"Part {partName} has no frontTransform"); continue; } if (backTransform == null) { - Debug.Log($"Part {name} has no backTransform"); + Debug.Log($"Part {partName} has no backTransform"); continue; } @@ -52,7 +47,8 @@ namespace ConformalDecals { } backTransform.GetComponent().material = decalModule.backMaterial; - + frontTransform.GetComponent().material = decalModule.materialProperties.PreviewMaterial; + if (decalModule.updateBackScale) { backTransform.GetComponent().material.SetTextureScale(PropertyIDs._MainTex, backScale); } diff --git a/Source/ConformalDecals/DecalPropertyIDs.cs b/Source/ConformalDecals/DecalPropertyIDs.cs new file mode 100644 index 0000000..0be88d1 --- /dev/null +++ b/Source/ConformalDecals/DecalPropertyIDs.cs @@ -0,0 +1,15 @@ +using UnityEngine; +// ReSharper disable InconsistentNaming + +namespace ConformalDecals { + public static class DecalPropertyIDs { + public static readonly int _BumpMap = Shader.PropertyToID("_BumpMap"); + public static readonly int _BumpMap_ST = Shader.PropertyToID("_BumpMap_ST"); + public static readonly int _Cull = Shader.PropertyToID("_Cull"); + public static readonly int _Cutoff = Shader.PropertyToID("_Cutoff"); + public static readonly int _DecalNormal = Shader.PropertyToID("_DecalNormal"); + public static readonly int _DecalOpacity = Shader.PropertyToID("_DecalOpacity"); + public static readonly int _DecalTangent = Shader.PropertyToID("_DecalTangent"); + public static readonly int _ProjectionMatrix = Shader.PropertyToID("_ProjectionMatrix"); + } +} \ No newline at end of file diff --git a/Source/ConformalDecals/MaterialModifiers/MaterialPropertyCollection.cs b/Source/ConformalDecals/MaterialModifiers/MaterialPropertyCollection.cs index 4c56065..f7c2fe9 100644 --- a/Source/ConformalDecals/MaterialModifiers/MaterialPropertyCollection.cs +++ b/Source/ConformalDecals/MaterialModifiers/MaterialPropertyCollection.cs @@ -3,11 +3,19 @@ using System.Collections.Generic; using System.Runtime.Serialization; using UniLinq; using UnityEngine; +using UnityEngine.Rendering; namespace ConformalDecals.MaterialModifiers { public class MaterialPropertyCollection : ScriptableObject, ISerializationCallbackReceiver { - private static readonly int OpacityId = Shader.PropertyToID("_DecalOpacity"); - private static readonly int CutoffId = Shader.PropertyToID("_Cutoff"); + [SerializeField] private Shader _shader; + [SerializeField] private MaterialTextureProperty _mainTexture; + [SerializeField] private string[] _serializedNames; + [SerializeField] private MaterialProperty[] _serializedProperties; + + private Dictionary _materialProperties; + + private Material _decalMaterial; + private Material _previewMaterial; public Shader DecalShader => _shader; @@ -16,6 +24,8 @@ namespace ConformalDecals.MaterialModifiers { if (_decalMaterial == null) { _decalMaterial = new Material(_shader); UpdateMaterial(_decalMaterial); + + _previewMaterial.SetInt(DecalPropertyIDs._Cull, (int) CullMode.Off); } return _decalMaterial; @@ -27,7 +37,9 @@ namespace ConformalDecals.MaterialModifiers { if (_previewMaterial == null) { _previewMaterial = new Material(_shader); UpdateMaterial(_previewMaterial); + _previewMaterial.EnableKeyword("DECAL_PREVIEW"); + _previewMaterial.SetInt(DecalPropertyIDs._Cull, (int) CullMode.Back); } return _previewMaterial; @@ -50,41 +62,31 @@ namespace ConformalDecals.MaterialModifiers { Debug.Log("No main texture specified! returning 1 for aspect ratio"); return 1; } + return MainTexture.AspectRatio; } } - [SerializeField] private string[] _serializedIDs; - [SerializeField] private MaterialProperty[] _serializedProperties; - - [SerializeField] private Shader _shader; - [SerializeField] private MaterialTextureProperty _mainTexture; - - private Dictionary _materialProperties; - - private Material _decalMaterial; - private Material _previewMaterial; - public void OnBeforeSerialize() { Debug.Log($"Serializing MaterialPropertyCollection {this.GetInstanceID()}"); - if (_materialProperties == null) throw new SerializationException("Tried to serialize an unininitalized MaterialPropertyCollection"); + if (_materialProperties == null) throw new SerializationException("Tried to serialize an uninitialized MaterialPropertyCollection"); - _serializedIDs = _materialProperties.Keys.ToArray(); + _serializedNames = _materialProperties.Keys.ToArray(); _serializedProperties = _materialProperties.Values.ToArray(); } public void OnAfterDeserialize() { Debug.Log($"Deserializing MaterialPropertyCollection {this.GetInstanceID()}"); - if (_serializedIDs == null) throw new SerializationException("ID array is null"); + if (_serializedNames == null) throw new SerializationException("ID array is null"); if (_serializedProperties == null) throw new SerializationException("Property array is null"); - if (_serializedProperties.Length != _serializedIDs.Length) throw new SerializationException("Material property arrays are different lengths."); + if (_serializedProperties.Length != _serializedNames.Length) throw new SerializationException("Material property arrays are different lengths."); _materialProperties ??= new Dictionary(); - for (var i = 0; i < _serializedIDs.Length; i++) { + for (var i = 0; i < _serializedNames.Length; i++) { var property = MaterialProperty.Instantiate(_serializedProperties[i]); Debug.Log($"insantiating {property.GetType().Name} {property.GetInstanceID()}"); - _materialProperties.Add(_serializedIDs[i], property); + _materialProperties.Add(_serializedNames[i], property); if (property is MaterialTextureProperty textureProperty) { _mainTexture = textureProperty; @@ -98,7 +100,7 @@ namespace ConformalDecals.MaterialModifiers { } public void AddProperty(MaterialProperty property) { - if (property == null) throw new ArgumentNullException("Tried to add a null property"); + if (property == null) throw new ArgumentNullException(nameof(property)); _materialProperties.Add(property.name, property); @@ -107,16 +109,61 @@ namespace ConformalDecals.MaterialModifiers { } } - public void ParseProperty(ConfigNode node) where T : MaterialProperty { - var name = node.GetValue("name"); - if (string.IsNullOrEmpty(name)) throw new ArgumentException("node has no name"); + public T AddProperty(string propertyName) where T : MaterialProperty { + if (_materialProperties.ContainsKey(propertyName)) throw new ArgumentException("property with that name already exists!"); + var newProperty = MaterialProperty.CreateInstance(); + newProperty.PropertyName = propertyName; + _materialProperties.Add(propertyName, newProperty); + return newProperty; + } - Debug.Log($"Parsing material property {name}"); + public T GetProperty(string propertyName) where T : MaterialProperty { + if (_materialProperties.ContainsKey(propertyName) && _materialProperties[propertyName] is T property) { + return property; + } + else { + return null; + } + } + + public T AddOrGetProperty(string propertyName) where T : MaterialProperty { + if (_materialProperties.ContainsKey(propertyName) && _materialProperties[propertyName] is T property) { + return property; + } + else { + return AddProperty(propertyName); + } + } + + public MaterialTextureProperty AddTextureProperty(string propertyName, bool isMain = false) { + var newProperty = AddProperty(propertyName); + if (isMain) MainTexture = newProperty; + return newProperty; + } + + public MaterialTextureProperty GetTextureProperty(string propertyName) { + return GetProperty(propertyName); + } + + public MaterialTextureProperty AddOrGetTextureProperty(string propertyName, bool isMain = false) { + if (_materialProperties.ContainsKey(propertyName) && _materialProperties[propertyName] is MaterialTextureProperty property) { + return property; + } + else { + return AddTextureProperty(propertyName, isMain); + } + } + + public void ParseProperty(ConfigNode node) where T : MaterialProperty { + var propertyName = node.GetValue("name"); + if (string.IsNullOrEmpty(propertyName)) throw new ArgumentException("node has no name"); + + Debug.Log($"Parsing material property {propertyName}"); T newProperty; - if (_materialProperties.ContainsKey(name)) { - if (_materialProperties[name] is T property) { + if (_materialProperties.ContainsKey(propertyName)) { + if (_materialProperties[propertyName] is T property) { newProperty = property; property.ParseNode(node); } @@ -128,7 +175,7 @@ namespace ConformalDecals.MaterialModifiers { newProperty = MaterialProperty.CreateInstance(); Debug.Log($"Adding new material property of type {newProperty.GetType().Name} {newProperty.GetInstanceID()}"); newProperty.ParseNode(node); - _materialProperties.Add(name, newProperty); + _materialProperties.Add(propertyName, newProperty); } if (newProperty is MaterialTextureProperty textureProperty && textureProperty.isMain) { @@ -170,11 +217,13 @@ namespace ConformalDecals.MaterialModifiers { } public void SetOpacity(float opacity) { - DecalMaterial.SetFloat(OpacityId, opacity); + DecalMaterial.SetFloat(DecalPropertyIDs._DecalOpacity, opacity); + PreviewMaterial.SetFloat(DecalPropertyIDs._DecalOpacity, opacity); } public void SetCutoff(float cutoff) { - DecalMaterial.SetFloat(CutoffId, cutoff); + DecalMaterial.SetFloat(DecalPropertyIDs._Cutoff, cutoff); + PreviewMaterial.SetFloat(DecalPropertyIDs._Cutoff, cutoff); } public void UpdateMaterials() { @@ -195,8 +244,11 @@ namespace ConformalDecals.MaterialModifiers { public void UpdateMaterial(Material material) { if (material == null) throw new ArgumentNullException(nameof(material)); + foreach (var entry in _materialProperties) { + Debug.Log($"Applying material property {entry.Key} {entry.Value.PropertyName} {entry.Value.GetInstanceID()}"); + entry.Value.Modify(material); } } diff --git a/Source/ConformalDecals/ModuleConformalDecalBase.cs b/Source/ConformalDecals/ModuleConformalDecalBase.cs index 296781e..373ef4b 100644 --- a/Source/ConformalDecals/ModuleConformalDecalBase.cs +++ b/Source/ConformalDecals/ModuleConformalDecalBase.cs @@ -99,7 +99,7 @@ namespace ConformalDecals { // find model transform if (string.IsNullOrEmpty(decalModel)) { - decalModelTransform = part.transform.Find("model"); + decalModelTransform = decalFrontTransform; } else { decalModelTransform = part.FindModelTransform(decalModel); @@ -135,7 +135,7 @@ namespace ConformalDecals { } } - ConformalDecalIconFixer.QueuePart(part.name); + DecalIconFixer.QueuePart(part.name); // set shader materialProperties.SetShader(shader); @@ -149,6 +149,9 @@ namespace ConformalDecals { UpdateScale(); UpdateProjection(); } + else { + UpdateScale(); + } } public override void OnAwake() { @@ -176,7 +179,6 @@ namespace ConformalDecals { materialProperties.SetRenderQueue(DecalQueue); UpdateMaterials(); - UpdateScale(); if (HighLogic.LoadedSceneIsGame) { // set initial attachment state @@ -308,6 +310,9 @@ namespace ConformalDecals { protected void UpdateMaterials() { materialProperties.UpdateMaterials(); + materialProperties.SetOpacity(opacity); + materialProperties.SetCutoff(cutoff); + _decalMaterial = materialProperties.DecalMaterial; _previewMaterial = materialProperties.PreviewMaterial; @@ -345,7 +350,7 @@ namespace ConformalDecals { if (renderer.gameObject.activeInHierarchy == false) continue; // skip blacklisted shaders - if (ConformalDecalConfig.IsBlacklisted(renderer.material.shader)) continue; + if (DecalConfig.IsBlacklisted(renderer.material.shader)) continue; var meshFilter = renderer.GetComponent(); if (meshFilter == null) continue; // object has a meshRenderer with no filter, invalid diff --git a/Source/ConformalDecals/ModuleConformalDecalFlag.cs b/Source/ConformalDecals/ModuleConformalDecalFlag.cs index 1ad425d..8aa5bea 100644 --- a/Source/ConformalDecals/ModuleConformalDecalFlag.cs +++ b/Source/ConformalDecals/ModuleConformalDecalFlag.cs @@ -1,22 +1,13 @@ -using ConformalDecals.MaterialModifiers; using ConformalDecals.Util; -using UnityEngine; namespace ConformalDecals { public class ModuleConformalDecalFlag : ModuleConformalDecalBase { - [KSPField] public MaterialTextureProperty flagTextureProperty; - - private const string defaultFlag = "Squad/Flags/default"; + private const string DefaultFlag = "Squad/Flags/default"; public override void OnLoad(ConfigNode node) { base.OnLoad(node); - if (HighLogic.LoadedSceneIsGame) { - UpdateFlag(EditorLogic.FlagURL != string.Empty ? EditorLogic.FlagURL : HighLogic.CurrentGame.flagURL); - } - else { - UpdateFlag(defaultFlag); - } + UpdateFlag(GetDefaultFlag()); } public override void OnStart(StartState state) { @@ -25,6 +16,8 @@ namespace ConformalDecals { if (HighLogic.LoadedSceneIsGame) { GameEvents.onMissionFlagSelect.Add(UpdateFlag); } + + UpdateFlag(GetDefaultFlag()); } public override void OnIconCreate() { @@ -37,6 +30,15 @@ namespace ConformalDecals { base.OnDestroy(); } + private string GetDefaultFlag() { + if (HighLogic.LoadedSceneIsGame) { + return EditorLogic.FlagURL != string.Empty ? EditorLogic.FlagURL : HighLogic.CurrentGame.flagURL; + } + else { + return DefaultFlag; + } + } + private void UpdateFlag(string flagUrl) { this.Log($"Loading flag texture '{flagUrl}'."); var flagTexture = GameDatabase.Instance.GetTexture(flagUrl, false); @@ -45,18 +47,7 @@ namespace ConformalDecals { return; } - if (flagTextureProperty == null) { - this.Log("Initializing flag property"); - flagTextureProperty = ScriptableObject.CreateInstance(); - flagTextureProperty.PropertyName = "_Decal"; - flagTextureProperty.isMain = true; - materialProperties.AddProperty(flagTextureProperty); - materialProperties.MainTexture = flagTextureProperty; - } - else { } - - flagTextureProperty.texture = flagTexture; - + materialProperties.AddOrGetTextureProperty("_Decal", true).texture = flagTexture; UpdateMaterials(); } diff --git a/Source/ConformalDecals/ProjectionTarget.cs b/Source/ConformalDecals/ProjectionTarget.cs index 9d559b6..53c0b42 100644 --- a/Source/ConformalDecals/ProjectionTarget.cs +++ b/Source/ConformalDecals/ProjectionTarget.cs @@ -4,28 +4,28 @@ using UnityEngine.Rendering; namespace ConformalDecals { public class ProjectionTarget { - private static readonly int _projectionMatrixID = Shader.PropertyToID("_ProjectionMatrix"); - private static readonly int _decalNormalID = Shader.PropertyToID("_DecalNormal"); - private static readonly int _decalTangentID = Shader.PropertyToID("_DecalTangent"); - // Target object data public readonly Transform target; private readonly Renderer _targetRenderer; private readonly Mesh _targetMesh; private bool _projectionEnabled; + private readonly int _cullMode; // property block private readonly MaterialPropertyBlock _decalMPB; - private static readonly int normalID = Shader.PropertyToID("_BumpMap"); - private static readonly int normalIDST = Shader.PropertyToID("_BumpMap_ST"); - public ProjectionTarget(MeshRenderer targetRenderer, Mesh targetMesh, bool useBaseNormal) { target = targetRenderer.transform; _targetRenderer = targetRenderer; _targetMesh = targetMesh; _decalMPB = new MaterialPropertyBlock(); + + var targetScale = target.lossyScale; + Debug.Log($"{target.name} scale = {targetScale}"); + var targetDeterminant = (targetScale.x * targetScale.y * targetScale.z); + _cullMode = targetDeterminant < 0 ? (int) CullMode.Front : (int) CullMode.Back; + _decalMPB.SetInt(DecalPropertyIDs._Cull, 0); } public void Project(Matrix4x4 orthoMatrix, OrientedBounds projectorBounds, Transform projector, bool useBaseNormal) { @@ -40,21 +40,21 @@ namespace ConformalDecals { var decalNormal = projectorToTargetMatrix.MultiplyVector(Vector3.back).normalized; var decalTangent = projectorToTargetMatrix.MultiplyVector(Vector3.right).normalized; - _decalMPB.SetMatrix(_projectionMatrixID, projectionMatrix); - _decalMPB.SetVector(_decalNormalID, decalNormal); - _decalMPB.SetVector(_decalTangentID, decalTangent); + _decalMPB.SetMatrix(DecalPropertyIDs._ProjectionMatrix, projectionMatrix); + _decalMPB.SetVector(DecalPropertyIDs._DecalNormal, decalNormal); + _decalMPB.SetVector(DecalPropertyIDs._DecalTangent, decalTangent); Debug.Log($"Projection enabled for {target.gameObject}"); - - if (useBaseNormal && targetMaterial.HasProperty(normalID)) { - var normal = targetMaterial.GetTexture(normalID); + + if (useBaseNormal && targetMaterial.HasProperty(DecalPropertyIDs._BumpMap)) { + var normal = targetMaterial.GetTexture(DecalPropertyIDs._BumpMap); if (normal != null) { - _decalMPB.SetTexture(normalID, targetMaterial.GetTexture(normalID)); + _decalMPB.SetTexture(DecalPropertyIDs._BumpMap, targetMaterial.GetTexture(DecalPropertyIDs._BumpMap)); - var normalScale = targetMaterial.GetTextureScale(normalID); - var normalOffset = targetMaterial.GetTextureOffset(normalID); + var normalScale = targetMaterial.GetTextureScale(DecalPropertyIDs._BumpMap); + var normalOffset = targetMaterial.GetTextureOffset(DecalPropertyIDs._BumpMap); - _decalMPB.SetVector(normalIDST, new Vector4(normalScale.x, normalScale.y, normalOffset.x, normalOffset.y)); + _decalMPB.SetVector(DecalPropertyIDs._BumpMap_ST, new Vector4(normalScale.x, normalScale.y, normalOffset.x, normalOffset.y)); } } }