Merge pull request #477 from PorktoberRevolution/unifyMaterialModifiers

Make material modifiers more useful
This commit is contained in:
Joseph Wong 2019-03-01 00:12:17 -08:00 committed by GitHub
commit eac19e8c1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 262 additions and 48 deletions

View File

@ -0,0 +1,22 @@
using System;
using UnityEngine;
namespace Restock.MaterialModifiers
{
public class ColorPropertyMaterialModifier : IMaterialModifier
{
private readonly string propertyName;
private readonly Color color;
public ColorPropertyMaterialModifier(string propertyName, Color color)
{
this.propertyName = propertyName ?? throw new ArgumentNullException(nameof(propertyName));
this.color = color;
}
public void Modify(Material material)
{
material.SetColor(propertyName, color);
}
}
}

View File

@ -0,0 +1,22 @@
using System;
using UnityEngine;
namespace Restock.MaterialModifiers
{
public class FloatPropertyMaterialModifier : IMaterialModifier
{
private readonly string propertyName;
private readonly float value;
public FloatPropertyMaterialModifier(string propertyName, float value)
{
this.propertyName = propertyName ?? throw new ArgumentNullException(nameof(propertyName));
this.value = value;
}
public void Modify(Material material)
{
material.SetFloat(propertyName, value);
}
}
}

View File

@ -0,0 +1,10 @@
using System;
using UnityEngine;
namespace Restock.MaterialModifiers
{
public interface IMaterialModifier
{
void Modify(Material material);
}
}

View File

@ -0,0 +1,62 @@
using System;
using UnityEngine;
namespace Restock.MaterialModifiers
{
public class MaterialModifierParser
{
private readonly string logContext;
public MaterialModifierParser(string logContext = nameof(MaterialModifierParser))
{
this.logContext = logContext ?? throw new ArgumentNullException(nameof(logContext));
}
public IMaterialModifier Parse(ConfigNode node)
{
string propertyName = node.GetValue("name");
if (propertyName == null)
throw new FormatException("name not found, cannot create material modifier");
else if (propertyName == string.Empty)
throw new FormatException("name is empty, cannot create material modifier");
if (node.name == "FLOAT_PROPERTY")
{
float value = float.Parse(node.GetValue("value"));
return new FloatPropertyMaterialModifier(propertyName, value);
}
else if (node.name == "COLOR_PROPERTY")
{
Color color = ConfigNode.ParseColor(node.GetValue("color"));
return new ColorPropertyMaterialModifier(propertyName, color);
}
else if (node.name == "TEXTURE_PROPERTY")
{
string textureUrl = node.GetValue("textureUrl");
bool normalMapToggle = false;
if (node.GetValue("isNormalMap") is string normalMapToggleString)
normalMapToggle = bool.Parse(normalMapToggleString);
GameDatabase.TextureInfo textureInfo = GameDatabase.Instance.GetTextureInfo(textureUrl);
if (textureInfo == null)
throw new Exception($"Cannot find texture: '{textureUrl}'");
Texture2D texture = normalMapToggle ? textureInfo.normalMap : textureInfo.texture;
if (texture == null)
throw new Exception($"Cannot get texture from texture info '{textureUrl}' isNormalMap = {normalMapToggle}");
return new TexturePropertyMaterialModifier(propertyName, texture);
}
else
{
throw new FormatException($"Can't create material modifier from node: '{node.name}'");
}
}
}
}

View File

@ -0,0 +1,22 @@
using System;
using UnityEngine;
namespace Restock.MaterialModifiers
{
public class TexturePropertyMaterialModifier : IMaterialModifier
{
private readonly string propertyName;
private readonly Texture2D texture;
public TexturePropertyMaterialModifier(string propertyName, Texture2D texture)
{
this.propertyName = propertyName ?? throw new ArgumentNullException(nameof(propertyName));
this.texture = texture ?? throw new ArgumentNullException(nameof(texture));
}
public void Modify(Material material)
{
material.SetTexture(propertyName, texture);
}
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections;
using UnityEngine;
using Restock.MaterialModifiers;
namespace Restock
{
@ -30,7 +31,7 @@ namespace Restock
if (string.IsNullOrEmpty(serializedNode))
{
Debug.LogError("Serialized node is null or empty!");
this.LogError("Serialized node is null or empty!");
yield break;
}
@ -40,39 +41,34 @@ namespace Restock
if (fairingModule == null)
{
Debug.LogError("No fairing module found on part!");
this.LogError("No fairing module found on part!");
yield break;
}
UpdateMaterial(fairingModule.FairingMaterial, node);
UpdateMaterial(fairingModule.FairingConeMaterial, node);
UpdateMaterial(fairingModule.FairingFlightMaterial, node);
UpdateMaterial(fairingModule.FairingFlightConeMaterial, node);
MaterialModifierParser parser = new MaterialModifierParser();
foreach (ProceduralFairings.FairingPanel fairingPanel in fairingModule.Panels)
{
MeshRenderer renderer = fairingPanel.go.GetComponent<MeshRenderer>();
UpdateMaterial(renderer.material, node);
}
}
private void UpdateMaterial(Material material, ConfigNode node)
{
foreach (ConfigNode node2 in node.nodes)
{
if (node2.name == "COLOR_PROPERTY")
IMaterialModifier modifier;
try
{
string name = node2.GetValue("name");
Color color = ConfigNode.ParseColor(node2.GetValue("color"));
material.SetColor(name, color);
modifier = parser.Parse(node2);
}
else if (node2.name == "FLOAT_PROPERTY")
catch (Exception ex)
{
string name = node2.GetValue("name");
float value = float.Parse(node2.GetValue("value"));
this.LogException($"cannot parse node as material modifier: \n{node2.ToString()}\n", ex);
continue;
}
material.SetFloat(name, value);
modifier.Modify(fairingModule.FairingMaterial);
modifier.Modify(fairingModule.FairingConeMaterial);
modifier.Modify(fairingModule.FairingFlightMaterial);
modifier.Modify(fairingModule.FairingFlightConeMaterial);
foreach (ProceduralFairings.FairingPanel fairingPanel in fairingModule.Panels)
{
MeshRenderer renderer = fairingPanel.go.GetComponent<MeshRenderer>();
modifier.Modify(renderer.material);
}
}
}

View File

@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Restock.MaterialModifiers;
namespace Restock
{
@ -11,18 +14,10 @@ namespace Restock
if (HighLogic.LoadedSceneIsEditor || HighLogic.LoadedSceneIsFlight) return;
Transform modelTransform = part.partTransform.Find("model");
Renderer[] renderers = modelTransform.GetComponentsInChildren<Renderer>();
if (modelTransform == null)
{
Debug.LogError("Couldn't find model transform");
return;
}
foreach (ConfigNode node2 in node.GetNodes("MATERIAL"))
{
IEnumerable<Renderer> renderers = GetRenderers(node2);
if (node2.GetValue("shader") is string newShaderName)
{
if (Shader.Find(newShaderName) is Shader newShader)
@ -34,34 +29,30 @@ namespace Restock
}
else
{
Debug.LogError($"Can't find shader {newShaderName}");
this.LogError($"Can't find shader {newShaderName}");
continue;
}
}
foreach (ConfigNode node3 in node2.GetNodes("TEXTURE_PROPERTY"))
MaterialModifierParser parser = new MaterialModifierParser();
foreach (ConfigNode node3 in node2.nodes)
{
string name = node3.GetValue("name");
string textureUrl = node3.GetValue("textureUrl");
bool normalMapToggle = false;
if (node3.GetValue("isNormalMap") is string normalMapToggleString)
IMaterialModifier modifier;
try
{
normalMapToggle = bool.Parse(normalMapToggleString);
modifier = parser.Parse(node3);
}
GameDatabase.TextureInfo textureInfo = GameDatabase.Instance.GetTextureInfo(textureUrl);
if (textureInfo == null)
catch (Exception ex)
{
Debug.LogError($"Cannot find texture: {textureUrl}");
this.LogException($"cannot parse node as material modifier: \n{node3.ToString()}\n", ex);
continue;
}
foreach (Renderer renderer in renderers)
{
renderer.material.SetTexture(name, normalMapToggle ? textureInfo.normalMap : textureInfo.texture);
modifier.Modify(renderer.material);
}
}
}
@ -69,5 +60,73 @@ namespace Restock
isEnabled = false;
moduleIsEnabled = false;
}
private IEnumerable<Renderer> GetRenderers(ConfigNode node)
{
IEnumerable<Renderer> renderers = Enumerable.Empty<Renderer>();
bool useAllRenderers = true;
foreach (ConfigNode.Value value in node.values)
{
if (value.name == "transform")
{
Transform[] modelTransforms = part.FindModelTransforms(value.name);
if (modelTransforms.Length == 0)
{
this.LogError($"Couldn't find transform named '{value.name}' on part");
continue;
}
List<Renderer> transformRenderers = new List<Renderer>(modelTransforms.Length);
foreach (Transform transform in modelTransforms)
{
Renderer renderer = transform.GetComponent<Renderer>();
if (renderer == null)
this.LogError($"No renderer found on transform '{transform.name}'");
else
transformRenderers.Add(renderer);
}
renderers.Concat(transformRenderers);
useAllRenderers = false;
}
else if (value.name == "baseTransform")
{
Transform[] modelTransforms = part.FindModelTransforms(value.name);
if (modelTransforms.Length == 0)
{
this.LogError($"Couldn't find transform named '{value.name}' on part");
continue;
}
foreach (Transform transform in modelTransforms)
{
Renderer[] transformRenderers = transform.GetComponentsInChildren<Renderer>();
if (transformRenderers.Length == 0)
this.LogError($"No renderers found on transform '{transform.name}' or its children");
else
renderers.Concat(transform.GetComponentsInChildren<Renderer>());
}
useAllRenderers = false;
}
}
if (useAllRenderers)
{
Transform modelTransform = part.partTransform.Find("model");
if (modelTransform == null)
this.LogError("Couldn't find model transform");
else
renderers = modelTransform.GetComponentsInChildren<Renderer>();
}
return renderers;
}
}
}

View File

@ -0,0 +1,16 @@
using System;
using UnityEngine;
namespace Restock
{
public static class PartModuleExtensions
{
public static void Log(this PartModule module, string message) => Debug.Log(FormatMessage(module, message));
public static void LogWarning(this PartModule module, string message) => Debug.LogWarning(FormatMessage(module, message));
public static void LogError(this PartModule module, string message) => Debug.LogError(FormatMessage(module, message));
public static void LogException(this PartModule module, string message, Exception exception) => Debug.LogException(new Exception(FormatMessage(module, message), exception));
private static string FormatMessage(PartModule module, string message) => $"[{GetPartName(module.part)} {module.GetType()}] {message}";
private static string GetPartName(Part part) => part.partInfo?.name ?? part.name;
}
}

View File

@ -41,6 +41,11 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="MaterialModifiers\ColorPropertyMaterialModifier.cs" />
<Compile Include="MaterialModifiers\FloatPropertyMaterialModifier.cs" />
<Compile Include="MaterialModifiers\IMaterialModifier.cs" />
<Compile Include="MaterialModifiers\MaterialModifierParser.cs" />
<Compile Include="MaterialModifiers\TexturePropertyMaterialModifier.cs" />
<Compile Include="ModuleRestockModifyFairingMaterials.cs" />
<Compile Include="ModuleRestockModifyMaterials.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />