mirror of
https://github.com/drewcassidy/KSP-Conformal-Decals.git
synced 2024-09-01 18:23:54 +00:00
Refactor material parsing and loading
This should hopefully pave the way for usable module switching using B9PS
This commit is contained in:
parent
114fc745f0
commit
7e520f97ca
@ -47,10 +47,9 @@ PART
|
||||
|
||||
decalFront = Decal-Front
|
||||
decalBack = Decal-Back
|
||||
decalShader = ConformalDecals/Feature/Bumped
|
||||
|
||||
MATERIAL
|
||||
{
|
||||
shader = ConformalDecals/Feature/Bumped
|
||||
useBaseNormal = false
|
||||
|
||||
TEXTURE
|
||||
{
|
||||
@ -66,5 +65,4 @@ PART
|
||||
isNormalMap = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
@ -49,11 +49,11 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="MaterialModifiers\ColorMaterialProperty.cs" />
|
||||
<Compile Include="MaterialModifiers\FloatMaterialProperty.cs" />
|
||||
<Compile Include="MaterialModifiers\MaterialColorProperty.cs" />
|
||||
<Compile Include="MaterialModifiers\MaterialFloatProperty.cs" />
|
||||
<Compile Include="MaterialModifiers\MaterialProperty.cs" />
|
||||
<Compile Include="MaterialModifiers\MaterialPropertyCollection.cs" />
|
||||
<Compile Include="MaterialModifiers\TextureMaterialProperty.cs" />
|
||||
<Compile Include="MaterialModifiers\MaterialTextureProperty.cs" />
|
||||
<Compile Include="ProjectionTarget.cs" />
|
||||
<Compile Include="ModuleConformalDecal.cs" />
|
||||
<Compile Include="Logging.cs" />
|
||||
|
@ -2,10 +2,10 @@ using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ConformalDecals.MaterialModifiers {
|
||||
public class ColorMaterialProperty : MaterialProperty {
|
||||
public class MaterialColorProperty : MaterialProperty {
|
||||
private readonly Color _color;
|
||||
|
||||
public ColorMaterialProperty(ConfigNode node) : base(node) {
|
||||
public MaterialColorProperty(ConfigNode node) : base(node) {
|
||||
_color = ParsePropertyColor(node, "color", false);
|
||||
}
|
||||
|
@ -2,10 +2,10 @@ using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ConformalDecals.MaterialModifiers {
|
||||
public class FloatMaterialProperty : MaterialProperty {
|
||||
public class MaterialFloatProperty : MaterialProperty {
|
||||
private readonly float _value;
|
||||
|
||||
public FloatMaterialProperty(ConfigNode node) : base(node) {
|
||||
public MaterialFloatProperty(ConfigNode node) : base(node) {
|
||||
_value = ParsePropertyFloat(node, "value", false);
|
||||
}
|
||||
|
@ -1,22 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Smooth.Delegates;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ConformalDecals.MaterialModifiers {
|
||||
public class MaterialPropertyCollection : ScriptableObject {
|
||||
private static int _opacityID = Shader.PropertyToID("_Opacity");
|
||||
private static int _cutoffID = Shader.PropertyToID("_Cutoff");
|
||||
private static readonly int OpacityId = Shader.PropertyToID("_Opacity");
|
||||
private static readonly int CutoffId = Shader.PropertyToID("_Cutoff");
|
||||
|
||||
public TextureMaterialProperty MainTextureProperty { get; set; }
|
||||
|
||||
public bool UseBaseNormal { get; private set; }
|
||||
public MaterialTextureProperty MainMaterialTextureProperty { get; set; }
|
||||
|
||||
private List<MaterialProperty> _materialProperties;
|
||||
private List<TextureMaterialProperty> _textureMaterialProperties;
|
||||
|
||||
public String BaseNormalSrc { get; private set; }
|
||||
public String BaseNormalDest { get; private set; }
|
||||
private List<MaterialTextureProperty> _textureMaterialProperties;
|
||||
|
||||
public Material DecalMaterial {
|
||||
get {
|
||||
@ -31,90 +25,43 @@ namespace ConformalDecals.MaterialModifiers {
|
||||
private Shader _decalShader;
|
||||
private Material _protoDecalMaterial;
|
||||
|
||||
private const string _normalTextureName = "_BumpMap";
|
||||
|
||||
public void Initialize(ConfigNode node, PartModule module) {
|
||||
|
||||
// Initialize fields
|
||||
public void Initialize() {
|
||||
_materialProperties = new List<MaterialProperty>();
|
||||
_textureMaterialProperties = new List<TextureMaterialProperty>();
|
||||
|
||||
// Get shader
|
||||
var shaderString = node.GetValue("shader") ?? throw new FormatException("Missing shader name in material");
|
||||
|
||||
_decalShader = Shabby.Shabby.FindShader(shaderString);
|
||||
|
||||
// note to self: null coalescing does not work on UnityEngine classes
|
||||
if (_decalShader == null) {
|
||||
throw new FormatException($"Shader not found: '{shaderString}'");
|
||||
_textureMaterialProperties = new List<MaterialTextureProperty>();
|
||||
}
|
||||
|
||||
// Get useBaseNormal value
|
||||
var useBaseNormalString = node.GetValue("useBaseNormal");
|
||||
|
||||
if (useBaseNormalString != null) {
|
||||
if (bool.TryParse(useBaseNormalString, out var useBaseNormalRef)) {
|
||||
UseBaseNormal = useBaseNormalRef;
|
||||
public void AddProperty(MaterialProperty property) {
|
||||
foreach (var p in _materialProperties) {
|
||||
if (p.PropertyName == property.PropertyName) {
|
||||
_materialProperties.Remove(property);
|
||||
}
|
||||
else {
|
||||
throw new FormatException($"Improperly formatted bool value for 'useBaseNormal' : {useBaseNormalString}");
|
||||
}
|
||||
}
|
||||
else {
|
||||
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;
|
||||
switch (propertyNode.name) {
|
||||
case "FLOAT":
|
||||
property = new FloatMaterialProperty(propertyNode);
|
||||
break;
|
||||
|
||||
case "COLOR":
|
||||
property = new ColorMaterialProperty(propertyNode);
|
||||
break;
|
||||
|
||||
case "TEXTURE":
|
||||
property = new TextureMaterialProperty(propertyNode);
|
||||
var textureModifier = (TextureMaterialProperty) property;
|
||||
if (textureModifier.IsMain) {
|
||||
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 {MainTextureProperty.TextureUrl}");
|
||||
}
|
||||
}
|
||||
|
||||
_textureMaterialProperties.Add(textureModifier);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new FormatException($"Invalid property type '{propertyNode.name}' in material");
|
||||
}
|
||||
|
||||
_materialProperties.Add(property);
|
||||
}
|
||||
|
||||
catch (Exception e) {
|
||||
// Catch exception from parsing current material property
|
||||
// And print it to the log as an Error
|
||||
module.LogException("Exception while parsing material node", e);
|
||||
if (property is MaterialTextureProperty textureProperty) {
|
||||
foreach (var p in _textureMaterialProperties) {
|
||||
if (p.PropertyName == textureProperty.PropertyName) {
|
||||
_textureMaterialProperties.Remove(textureProperty);
|
||||
}
|
||||
}
|
||||
|
||||
module.Log($"Parsed {_materialProperties.Count} properties");
|
||||
_textureMaterialProperties.Add(textureProperty);
|
||||
|
||||
if (textureProperty.IsMain) MainMaterialTextureProperty ??= textureProperty;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetShader(string shaderName) {
|
||||
if (_decalShader == null && string.IsNullOrEmpty(shaderName)) {
|
||||
throw new FormatException("Shader name not provided");
|
||||
}
|
||||
|
||||
var shader = Shabby.Shabby.FindShader(shaderName);
|
||||
|
||||
if (shader == null) throw new FormatException($"Unable to find specified shader '{shaderName}'");
|
||||
|
||||
_decalShader = shader;
|
||||
}
|
||||
|
||||
public void SetScale(Material material, Vector2 scale) {
|
||||
@ -124,11 +71,11 @@ namespace ConformalDecals.MaterialModifiers {
|
||||
}
|
||||
|
||||
public void SetOpacity(Material material, float opacity) {
|
||||
material.SetFloat(_opacityID, opacity);
|
||||
material.SetFloat(OpacityId, opacity);
|
||||
}
|
||||
|
||||
public void SetCutoff(Material material, float cutoff) {
|
||||
material.SetFloat(_cutoffID, cutoff);
|
||||
material.SetFloat(CutoffId, cutoff);
|
||||
}
|
||||
|
||||
private Material MakeMaterial(Shader shader) {
|
||||
|
@ -2,7 +2,7 @@ using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ConformalDecals.MaterialModifiers {
|
||||
public class TextureMaterialProperty : MaterialProperty {
|
||||
public class MaterialTextureProperty : MaterialProperty {
|
||||
public string TextureUrl { get; }
|
||||
public Texture2D TextureRef { get; }
|
||||
|
||||
@ -17,7 +17,7 @@ namespace ConformalDecals.MaterialModifiers {
|
||||
private readonly Vector2 _textureOffset;
|
||||
private readonly Vector2 _textureScale;
|
||||
|
||||
public TextureMaterialProperty(ConfigNode node) : base(node) {
|
||||
public MaterialTextureProperty(ConfigNode node) : base(node) {
|
||||
TextureUrl = node.GetValue("textureURL");
|
||||
|
||||
var textureInfo = GameDatabase.Instance.GetTextureInfo(TextureUrl);
|
@ -28,6 +28,7 @@ namespace ConformalDecals {
|
||||
[KSPField] public string decalBack = string.Empty;
|
||||
[KSPField] public string decalModel = string.Empty;
|
||||
[KSPField] public string decalProjector = string.Empty;
|
||||
[KSPField] public string decalShader = string.Empty;
|
||||
|
||||
[KSPField] public Transform decalFrontTransform;
|
||||
[KSPField] public Transform decalBackTransform;
|
||||
@ -46,9 +47,12 @@ namespace ConformalDecals {
|
||||
[KSPField] public Vector2 decalQueueRange = new Vector2(2100, 2400);
|
||||
|
||||
[KSPField] public bool updateBackScale = true;
|
||||
[KSPField] public bool useBaseNormal = true;
|
||||
|
||||
[KSPField] public MaterialPropertyCollection materialProperties;
|
||||
|
||||
[KSPField] public Material decalMaterial;
|
||||
[KSPField] public Material backMaterial;
|
||||
|
||||
private static int _decalQueueCounter = -1;
|
||||
|
||||
@ -59,7 +63,11 @@ namespace ConformalDecals {
|
||||
private Bounds _decalBounds;
|
||||
private Vector2 _backTextureBaseScale;
|
||||
|
||||
private Material _backMaterial;
|
||||
public ModuleConformalDecal() {
|
||||
decalBackTransform = null;
|
||||
decalModelTransform = null;
|
||||
decalProjectorTransform = null;
|
||||
}
|
||||
|
||||
private int DecalQueue {
|
||||
get {
|
||||
@ -76,16 +84,40 @@ namespace ConformalDecals {
|
||||
public override void OnLoad(ConfigNode node) {
|
||||
this.Log("Loading module");
|
||||
try {
|
||||
// parse MATERIAL node
|
||||
var materialNode = node.GetNode("MATERIAL") ?? throw new FormatException("Missing MATERIAL node in module");
|
||||
|
||||
if (materialProperties == null) {
|
||||
// materialProperties is null, so make a new one
|
||||
materialProperties = ScriptableObject.CreateInstance<MaterialPropertyCollection>();
|
||||
materialProperties.Initialize(materialNode, this);
|
||||
materialProperties.Initialize();
|
||||
}
|
||||
else {
|
||||
// materialProperties already exists, so make a copy
|
||||
materialProperties = ScriptableObject.Instantiate(materialProperties);
|
||||
}
|
||||
|
||||
// add texture nodes
|
||||
foreach (var textureNode in node.GetNodes("TEXTURE")) {
|
||||
materialProperties.AddProperty(new MaterialTextureProperty(textureNode));
|
||||
}
|
||||
|
||||
// add float nodes
|
||||
foreach (var floatNode in node.GetNodes("FLOAT")) {
|
||||
materialProperties.AddProperty(new MaterialFloatProperty(floatNode));
|
||||
}
|
||||
|
||||
// add color nodes
|
||||
foreach (var colorNode in node.GetNodes("COLOR")) {
|
||||
materialProperties.AddProperty(new MaterialColorProperty(colorNode));
|
||||
}
|
||||
|
||||
// set shader
|
||||
materialProperties.SetShader(decalShader);
|
||||
|
||||
// get decal material
|
||||
decalMaterial = materialProperties.DecalMaterial;
|
||||
|
||||
// get aspect ratio from main texture, if it exists
|
||||
var mainTexture = materialProperties.MainTextureProperty;
|
||||
var mainTexture = materialProperties.MainMaterialTextureProperty;
|
||||
if (mainTexture != null) {
|
||||
aspectRatio = mainTexture.AspectRatio;
|
||||
}
|
||||
@ -127,6 +159,12 @@ namespace ConformalDecals {
|
||||
decalProjectorTransform = part.FindModelTransform(decalProjector);
|
||||
if (decalProjectorTransform == null) throw new FormatException($"Could not find decalProjector transform: '{decalProjector}'.");
|
||||
}
|
||||
|
||||
// update EVERYTHING if currently attached
|
||||
if (_isAttached) {
|
||||
OnDetach();
|
||||
OnAttach();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
this.LogException("Exception parsing partmodule", e);
|
||||
@ -207,12 +245,12 @@ namespace ConformalDecals {
|
||||
this.LogError($"Specified decalBack transform {decalBack} has no renderer attached! Setting updateBackScale to false.");
|
||||
updateBackScale = false;
|
||||
}
|
||||
else if ((_backMaterial = backRenderer.material) == null) {
|
||||
else if ((backMaterial = backRenderer.material) == null) {
|
||||
this.LogError($"Specified decalBack transform {decalBack} has a renderer but no material! Setting updateBackScale to false.");
|
||||
updateBackScale = false;
|
||||
}
|
||||
else {
|
||||
_backTextureBaseScale = _backMaterial.GetTextureScale(PropertyIDs._MainTex);
|
||||
_backTextureBaseScale = backMaterial.GetTextureScale(PropertyIDs._MainTex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -300,7 +338,7 @@ namespace ConformalDecals {
|
||||
|
||||
this.Log($"Adding target for object {meshFilter.gameObject.name} with the mesh {mesh.name}");
|
||||
// create new ProjectionTarget to represent the renderer
|
||||
var target = new ProjectionTarget(renderer, mesh, materialProperties);
|
||||
var target = new ProjectionTarget(renderer, mesh, useBaseNormal);
|
||||
|
||||
this.Log("done.");
|
||||
|
||||
@ -349,7 +387,7 @@ namespace ConformalDecals {
|
||||
|
||||
// update back material scale
|
||||
if (updateBackScale) {
|
||||
_backMaterial.SetTextureScale(PropertyIDs._MainTex, new Vector2(size.x * _backTextureBaseScale.x, size.y * _backTextureBaseScale.y));
|
||||
backMaterial.SetTextureScale(PropertyIDs._MainTex, new Vector2(size.x * _backTextureBaseScale.x, size.y * _backTextureBaseScale.y));
|
||||
}
|
||||
|
||||
// update material scale
|
||||
|
@ -17,30 +17,29 @@ namespace ConformalDecals {
|
||||
private bool _projectionEnabled;
|
||||
|
||||
// property block
|
||||
public readonly MaterialPropertyBlock decalMPB;
|
||||
private readonly MaterialPropertyBlock _decalMPB;
|
||||
|
||||
public ProjectionTarget(MeshRenderer targetRenderer, Mesh targetMesh, MaterialPropertyCollection properties) {
|
||||
public ProjectionTarget(MeshRenderer targetRenderer, Mesh targetMesh, bool useBaseNormal) {
|
||||
target = targetRenderer.transform;
|
||||
_targetRenderer = targetRenderer;
|
||||
_targetMesh = targetMesh;
|
||||
var targetMaterial = targetRenderer.sharedMaterial;
|
||||
|
||||
decalMPB = new MaterialPropertyBlock();
|
||||
_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");
|
||||
if (useBaseNormal) {
|
||||
var normalID = Shader.PropertyToID("_BumpMap");
|
||||
var normalIDST = Shader.PropertyToID("_BumpMap_ST");
|
||||
|
||||
var normal = targetMaterial.GetTexture(normalSrcID);
|
||||
var normal = targetMaterial.GetTexture(normalID);
|
||||
if (normal != null) {
|
||||
|
||||
decalMPB.SetTexture(normalDestID, targetMaterial.GetTexture(normalSrcID));
|
||||
_decalMPB.SetTexture(normalID, targetMaterial.GetTexture(normalID));
|
||||
|
||||
var normalScale = targetMaterial.GetTextureScale(normalSrcID);
|
||||
var normalOffset = targetMaterial.GetTextureOffset(normalSrcID);
|
||||
var normalScale = targetMaterial.GetTextureScale(normalID);
|
||||
var normalOffset = targetMaterial.GetTextureOffset(normalID);
|
||||
|
||||
decalMPB.SetVector(normalDestIDST, new Vector4(normalScale.x, normalScale.y, normalOffset.x, normalOffset.y));
|
||||
_decalMPB.SetVector(normalIDST, new Vector4(normalScale.x, normalScale.y, normalOffset.x, normalOffset.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -55,9 +54,9 @@ 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(_projectionMatrixID, projectionMatrix);
|
||||
_decalMPB.SetVector(_decalNormalID, decalNormal);
|
||||
_decalMPB.SetVector(_decalTangentID, decalTangent);
|
||||
Debug.Log($"Projection enabled for {target.gameObject}");
|
||||
}
|
||||
else {
|
||||
@ -68,10 +67,10 @@ namespace ConformalDecals {
|
||||
|
||||
public bool Render(Material decalMaterial, MaterialPropertyBlock partMPB, Camera camera) {
|
||||
if (_projectionEnabled) {
|
||||
decalMPB.SetFloat(PropertyIDs._RimFalloff, partMPB.GetFloat(PropertyIDs._RimFalloff));
|
||||
decalMPB.SetColor(PropertyIDs._RimColor, partMPB.GetColor(PropertyIDs._RimColor));
|
||||
_decalMPB.SetFloat(PropertyIDs._RimFalloff, partMPB.GetFloat(PropertyIDs._RimFalloff));
|
||||
_decalMPB.SetColor(PropertyIDs._RimColor, partMPB.GetColor(PropertyIDs._RimColor));
|
||||
|
||||
Graphics.DrawMesh(_targetMesh, target.localToWorldMatrix, decalMaterial, 0, camera, 0, decalMPB, ShadowCastingMode.Off, true);
|
||||
Graphics.DrawMesh(_targetMesh, target.localToWorldMatrix, decalMaterial, 0, camera, 0, _decalMPB, ShadowCastingMode.Off, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user