From 1287e729ebf76c3f4a376de4fd5ea2c7a4175b6a Mon Sep 17 00:00:00 2001 From: drewcassidy Date: Fri, 29 May 2020 21:02:58 -0700 Subject: [PATCH] Add projection logic --- Source/ConformalDecals/ConformalDecals.csproj | 27 +++--- .../MaterialPropertyCollection.cs | 61 ++++++++----- .../TextureMaterialProperty.cs | 16 ++-- Source/ConformalDecals/ProjectionTarget.cs | 86 +++++++++++++++++++ 4 files changed, 150 insertions(+), 40 deletions(-) create mode 100644 Source/ConformalDecals/ProjectionTarget.cs diff --git a/Source/ConformalDecals/ConformalDecals.csproj b/Source/ConformalDecals/ConformalDecals.csproj index d16ef11..be0f319 100644 --- a/Source/ConformalDecals/ConformalDecals.csproj +++ b/Source/ConformalDecals/ConformalDecals.csproj @@ -1,6 +1,6 @@ - + Debug AnyCPU @@ -10,7 +10,7 @@ v4.6 512 true - 7.3 + 8 ConformalDecals @@ -37,24 +37,25 @@ dlls/Shabby.dll - - + + dlls/UnityEngine.dll - - - - - - - - + + + + + + + + + - + sh -e -c "cp -v '$(TargetPath)' '$(SolutionDir)/Releases/ConformalDecals/Gamedata'" diff --git a/Source/ConformalDecals/MaterialModifiers/MaterialPropertyCollection.cs b/Source/ConformalDecals/MaterialModifiers/MaterialPropertyCollection.cs index 6b455d6..7dabc81 100644 --- a/Source/ConformalDecals/MaterialModifiers/MaterialPropertyCollection.cs +++ b/Source/ConformalDecals/MaterialModifiers/MaterialPropertyCollection.cs @@ -4,32 +4,39 @@ using UnityEngine; namespace ConformalDecals.MaterialModifiers { public class MaterialPropertyCollection { - public Shader ShaderRef { get; } - public TextureMaterialProperty MainTextureMaterial { get; } + public TextureMaterialProperty MainTextureProperty { get; } + + public Material ParsedMaterial { get; } public bool UseBaseNormal { get; } - private List _materialModifiers; - private List _texturePropertyMaterialModifiers; + private readonly List _materialProperties; + private readonly List _textureMaterialProperties; - public MaterialPropertyCollection(ConfigNode node, PartModule module) { - _materialModifiers = new List(); - _texturePropertyMaterialModifiers = new List(); + public String BaseNormalSrc { get; } + public String BaseNormalDest { get; } - var shaderString = node.GetValue("shader"); + private const string _normalTextureName = "_BumpMap"; - if (shaderString == null) - throw new FormatException("Missing shader name in material"); + public MaterialPropertyCollection(ConfigNode node, PartModule module) { - if (shaderString == string.Empty) - throw new FormatException("Empty shader name in material"); + // Initialize fields + _materialProperties = new List(); + _textureMaterialProperties = new List(); + // Get shader + var shaderString = node.GetValue("shader") ?? throw new FormatException("Missing shader name in material"); - //TODO: USE SHABBY PROVIDED METHOD HERE INSTEAD - ShaderRef = Shader.Find(shaderString); + var shaderRef = Shabby.Shabby.FindShader(shaderString); + + // note to self: null coalescing does not work on UnityEngine classes + if (shaderRef == null) { + throw new FormatException($"Shader not found: '{shaderString}'"); + } - if (ShaderRef == null) throw new FormatException($"Shader not found: {shaderString}"); + ParsedMaterial = new Material(shaderRef); + // Get useBaseNormal value var useBaseNormalString = node.GetValue("useBaseNormal"); if (useBaseNormalString != null) { @@ -44,6 +51,11 @@ namespace ConformalDecals.MaterialModifiers { UseBaseNormal = false; } + // Get basenormal source and destination property names + BaseNormalSrc = node.GetValue("baseNormalSource") ?? _normalTextureName; + BaseNormalDest = node.GetValue("baseNormalDestination") ?? _normalTextureName; + + // Parse all materialProperties foreach (ConfigNode propertyNode in node.nodes) { try { MaterialProperty property; @@ -60,26 +72,27 @@ namespace ConformalDecals.MaterialModifiers { property = new TextureMaterialProperty(propertyNode); var textureModifier = (TextureMaterialProperty) property; if (textureModifier.IsMain) { - if (MainTextureMaterial == null) { - MainTextureMaterial = textureModifier; + if (MainTextureProperty == null) { + MainTextureProperty = textureModifier; } else { // multiple textures have been marked as main! // non-fatal issue, ignore this one and keep using current main texture module.LogWarning( $"Material texture property {textureModifier.TextureUrl} is marked as main, but material already has a main texture! \n" + - $"Defaulting to {MainTextureMaterial.TextureUrl}"); + $"Defaulting to {MainTextureProperty.TextureUrl}"); } } - _texturePropertyMaterialModifiers.Add(textureModifier); + _textureMaterialProperties.Add(textureModifier); break; default: throw new FormatException($"Invalid property type '{propertyNode.name}' in material"); } - _materialModifiers.Add(property); + _materialProperties.Add(property); + property.Modify(ParsedMaterial); } catch (Exception e) { @@ -89,5 +102,13 @@ namespace ConformalDecals.MaterialModifiers { } } } + + public void UpdateMaterial(Vector2 scale) { + foreach (var textureProperty in _textureMaterialProperties) { + textureProperty.UpdateScale(ParsedMaterial, scale); + } + } + + } } \ No newline at end of file diff --git a/Source/ConformalDecals/MaterialModifiers/TextureMaterialProperty.cs b/Source/ConformalDecals/MaterialModifiers/TextureMaterialProperty.cs index 71375bc..a13592f 100644 --- a/Source/ConformalDecals/MaterialModifiers/TextureMaterialProperty.cs +++ b/Source/ConformalDecals/MaterialModifiers/TextureMaterialProperty.cs @@ -5,15 +5,17 @@ namespace ConformalDecals.MaterialModifiers { public class TextureMaterialProperty : MaterialProperty { public string TextureUrl { get; } public Texture2D TextureRef { get; } - - private Vector2 _textureOffset; - private Vector2 _textureScale; - + public bool IsNormal { get; } public bool IsMain { get; } public bool AutoScale { get; } public Rect TileRect { get; } + + public float AspectRatio => TileRect.height / TileRect.width; + + private readonly Vector2 _textureOffset; + private readonly Vector2 _textureScale; public TextureMaterialProperty(ConfigNode node) : base(node) { TextureUrl = node.GetValue("textureURL"); @@ -28,9 +30,9 @@ namespace ConformalDecals.MaterialModifiers { if (TextureRef == null) throw new Exception($"Cannot get texture from texture info '{TextureUrl}' isNormalMap = {IsNormal}"); - IsNormal = ParsePropertyBool(node, "isNormalMap", true, false); - IsMain = ParsePropertyBool(node, "isMain", true, false); - AutoScale = ParsePropertyBool(node, "autoScale", true, false); + IsNormal = ParsePropertyBool(node, "isNormalMap", true); + IsMain = ParsePropertyBool(node, "isMain", true); + AutoScale = ParsePropertyBool(node, "autoScale", true); TileRect = ParsePropertyRect(node, "tileRect", true, new Rect(0, 0, TextureRef.width, TextureRef.height)); _textureScale.x = TileRect.width / TextureRef.width; diff --git a/Source/ConformalDecals/ProjectionTarget.cs b/Source/ConformalDecals/ProjectionTarget.cs new file mode 100644 index 0000000..d633bb6 --- /dev/null +++ b/Source/ConformalDecals/ProjectionTarget.cs @@ -0,0 +1,86 @@ +using System; +using ConformalDecals.MaterialModifiers; +using UnityEngine; +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"); + + // Projector object data + public Transform Projector; + + // Target object data + public readonly Transform Target; + + private readonly Renderer _targetRenderer; + private readonly Mesh _targetMesh; + private Boolean _projectionEnabled; + + // property block + public readonly MaterialPropertyBlock DecalMPB; + + public ProjectionTarget(MeshRenderer targetRenderer, Mesh targetMesh, MaterialPropertyCollection properties) { + Target = targetRenderer.transform; + _targetRenderer = targetRenderer; + _targetMesh = targetMesh; + var targetMaterial = targetRenderer.sharedMaterial; + + DecalMPB = new MaterialPropertyBlock(); + + if (properties.UseBaseNormal) { + var normalSrcID = Shader.PropertyToID(properties.BaseNormalSrc); + var normalDestID = Shader.PropertyToID(properties.BaseNormalDest); + var normalDestIDST = Shader.PropertyToID(properties.BaseNormalDest + "_ST"); + + var normal = targetMaterial.GetTexture(normalSrcID); + if (normal != null) { + + DecalMPB.SetTexture(normalDestID, targetMaterial.GetTexture(normalSrcID)); + + var normalScale = targetMaterial.GetTextureScale(normalSrcID); + var normalOffset = targetMaterial.GetTextureOffset(normalSrcID); + + DecalMPB.SetVector(normalDestIDST, new Vector4(normalScale.x, normalScale.y, normalOffset.x, normalOffset.y)); + } + } + } + + public void Project(Matrix4x4 orthoMatrix, OrientedBounds projectorBounds) { + var projectorToTargetMatrix = Target.worldToLocalMatrix * Projector.localToWorldMatrix; + + var projectionMatrix = orthoMatrix * projectorToTargetMatrix.inverse; + 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); + + var targetBounds = new OrientedBounds(Target.localToWorldMatrix, _targetRenderer.bounds); + _projectionEnabled = projectorBounds.Intersects(targetBounds); + } + + public bool Render(Material decalMaterial) { + if (_projectionEnabled) { + if (HighLogic.LoadedSceneIsEditor) { + var camera = EditorLogic.fetch.editorCamera; + Graphics.DrawMesh(_targetMesh, Target.worldToLocalMatrix, decalMaterial, 0, camera, 0, DecalMPB, ShadowCastingMode.Off, true); + return true; + } + + if (HighLogic.LoadedSceneIsFlight) { + foreach (var camera in FlightCamera.fetch.cameras) + { + Graphics.DrawMesh(_targetMesh, Target.worldToLocalMatrix, decalMaterial, 0, camera, 0, DecalMPB, ShadowCastingMode.Off, true); + } + return true; + } + } + + return false; + } + } +} \ No newline at end of file