Browse Source

Add Editor scripts

main
Andrew Cassidy 1 year ago
parent
commit
0d429b8b2b
  1. 219
      Editor/MeshPostProcessor.cs
  2. 137
      Editor/TexturePostProcessor.cs

219
Editor/MeshPostProcessor.cs

@ -0,0 +1,219 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;
namespace KSPTools
{
public class MeshPostProcessor : AssetPostprocessor
{
private static string[] components = new string[] {"x", "y", "z", "w"};
private void OnPostprocessModel(GameObject g)
{
var deleteList = new List<GameObject>();
Process(g.transform, deleteList);
foreach (var d in deleteList)
{
Debug.Log("Deleting object " + d.name);
Object.DestroyImmediate(d);
}
}
private static void Process(Transform t, List<GameObject> deleteList)
{
var regex = new Regex(@"\.[0-9][0-9][0-9]");
var name = t.name;
t.name = regex.Replace(name, "");
if (t.name.Contains("_DEL"))
{
deleteList.Add(t.gameObject);
return;
}
if (t.name.Contains("_MERGE"))
{
// get all mesh filters
var filters = t.GetComponentsInChildren<MeshFilter>();
// get all meshes and transforms
var meshes = filters.Select(i => i.sharedMesh).ToArray();
var transforms = filters.Select(i => i.transform).ToArray();
if (meshes.Length != transforms.Length)
Debug.LogError("Mesh and transformation count mismatch when attempting to process " + t.name);
// generate CombineInstance array
var combines = new CombineInstance[meshes.Length];
var mergedMesh = meshes[0];
var newMesh = new Mesh();
var baseMatrix = t.worldToLocalMatrix;
var material = filters[0].GetComponent<MeshRenderer>().sharedMaterial;
for (var i = 0; i < combines.Length; i++)
combines[i] = new CombineInstance
{
mesh = meshes[i],
transform = baseMatrix * transforms[i].localToWorldMatrix
};
// combine meshes into newMesh and copy data to mergedMesh
// we cant use newMesh because it will disappear once importing is done,
// also CombineMeshes doesnt include the base mesh in 2017.1
newMesh.CombineMeshes(combines, true, true, false);
mergedMesh.vertices = newMesh.vertices;
mergedMesh.normals = newMesh.normals;
mergedMesh.triangles = newMesh.triangles;
mergedMesh.colors = newMesh.colors;
mergedMesh.boneWeights = newMesh.boneWeights;
mergedMesh.uv = newMesh.uv;
mergedMesh.RecalculateBounds();
mergedMesh.RecalculateTangents();
mergedMesh.name = t.name;
// clear any existing MeshFilter or MeshRenderer and delete other meshes
Object.DestroyImmediate(t.GetComponent<MeshFilter>());
Object.DestroyImmediate(t.GetComponent<MeshRenderer>());
for (var i = 1; i < combines.Length; i++) Object.DestroyImmediate(meshes[i]);
// assign mesh and material to this gameobject
var filter = t.gameObject.AddComponent<MeshFilter>();
var renderer = t.gameObject.AddComponent<MeshRenderer>();
filter.sharedMesh = mergedMesh;
renderer.sharedMaterial = material;
// add children to list for deletion at end of processing step
deleteList.AddRange(transforms.Select(i => i.gameObject));
return;
}
if (t.name.Contains("_COLLIDER"))
{
var filter = t.GetComponent<MeshFilter>();
var renderer = t.GetComponent<MeshRenderer>();
if (filter == null) Debug.LogWarning("Error processing " + t.name + ": no mesh filter available");
var collider = t.gameObject.AddComponent<MeshCollider>();
collider.sharedMesh = filter.sharedMesh;
collider.convex = true;
Object.DestroyImmediate(renderer);
Object.DestroyImmediate(filter);
}
if (t.name.Contains("_SPHERECOLLIDER"))
{
var filter = t.GetComponent<MeshFilter>();
var renderer = t.GetComponent<MeshRenderer>();
if (filter == null) Debug.LogWarning("Error processing " + t.name + ": no mesh filter available");
var aabb = filter.sharedMesh.bounds;
var collider = t.gameObject.AddComponent<SphereCollider>();
collider.center = aabb.center;
collider.radius = (aabb.size.x + aabb.size.y + aabb.size.z) / 6;
Object.DestroyImmediate(renderer);
Object.DestroyImmediate(filter);
}
if (t.name.Contains("_CAPSULECOLLIDER"))
{
var filter = t.GetComponent<MeshFilter>();
var renderer = t.GetComponent<MeshRenderer>();
if (filter == null) Debug.LogWarning("Error processing " + t.name + ": no mesh filter available");
var aabb = filter.sharedMesh.bounds;
var size = aabb.size;
var collider = t.gameObject.AddComponent<CapsuleCollider>();
collider.center = aabb.center;
if (size.x > size.y && size.x > size.z)
{
collider.radius = (size.y + size.z) / 4;
collider.height = size.x;
collider.direction = 0;
}
else if (size.y > size.z && size.y > size.x)
{
collider.radius = (size.x + size.z) / 4;
collider.height = size.y;
collider.direction = 1;
}
else
{
collider.radius = (size.x + size.y) / 4;
collider.height = size.z;
collider.direction = 2;
}
Object.DestroyImmediate(renderer);
Object.DestroyImmediate(filter);
}
if (t.name.Contains("_BOXCOLLIDER"))
{
var filter = t.GetComponent<MeshFilter>();
var renderer = t.GetComponent<MeshRenderer>();
if (filter == null) Debug.LogWarning("Error processing " + t.name + ": no mesh filter available");
var aabb = filter.sharedMesh.bounds;
var collider = t.gameObject.AddComponent<BoxCollider>();
collider.center = aabb.center;
collider.size = aabb.size;
Object.DestroyImmediate(renderer);
Object.DestroyImmediate(filter);
}
foreach (Transform child in t) Process(child, deleteList);
var anim = t.GetComponent<Animation>();
if (anim != null)
{
foreach (var state in anim)
{
var clip = ((AnimationState) state).clip;
Debug.Log("Trimming animation " + clip.name);
TrimAnimation(clip, t, deleteList);
}
}
}
private static void TrimAnimation(AnimationClip clip, Transform t, List<GameObject> deleteList)
{
var bindings = AnimationUtility.GetCurveBindings(clip);
foreach (EditorCurveBinding b in bindings)
{
var curve = AnimationUtility.GetEditorCurve(clip, b);
var target = (Transform) AnimationUtility.GetAnimatedObject(t.gameObject, b);
if (curve.length > 2) continue;
if (curve.length == 2 && !deleteList.Contains(target.gameObject))
{
continue;
//if (!Mathf.Approximately(curve[0].value, curve[1].value)) continue;
//if (!Mathf.Approximately(curve[0].value, 0.0f) && !Mathf.Approximately(curve[0].value, 1.0f)) continue;
}
AnimationUtility.SetEditorCurve(clip, b, null);
}
}
}
}

137
Editor/TexturePostProcessor.cs

@ -0,0 +1,137 @@
using System;
using UnityEditor;
using UnityEngine;
using System.IO;
namespace KSPTools
{
public class TexturePostProcessor : AssetPostprocessor
{
// what file type to allow
private const string EXTENSION = ".png";
/* SPECULAR */
// enable specular map copying
private const bool SPEC_ENABLE = true;
// what the file name should end with for specular maps
private const string SPEC_TAG = "-spec";
/* NORMALS */
// enable normal map processing
private const bool NORMAL_ENABLE = true;
// what the file name should end with for normal maps
private const string NORMAL_TAG = "-n";
// enable normal map generation from heightmaps
private const bool NORMAL_GENERATE = true;
private Texture2D _otherTexture = null;
private bool _isSpecular = false;
private bool _hasSpecular = false;
void OnPreprocessTexture()
{
var importer = (TextureImporter) assetImporter;
importer.textureCompression = TextureImporterCompression.Uncompressed;
importer.isReadable = true;
var extension = Path.GetExtension(assetPath);
if (extension != EXTENSION) return;
var basename = Path.GetFileNameWithoutExtension(assetPath);
var directory = Path.GetDirectoryName(assetPath);
if (NORMAL_ENABLE)
{
if (basename.EndsWith(NORMAL_TAG))
{
importer.textureType = TextureImporterType.NormalMap;
if (NORMAL_GENERATE) importer.convertToNormalmap = true;
}
}
if (SPEC_ENABLE) {
if (basename.EndsWith(SPEC_TAG))
{
var othername = basename.Replace(SPEC_TAG, "");
var otherpath = directory + "/" + othername + extension;
_otherTexture = (Texture2D) AssetDatabase.LoadAssetAtPath<Texture2D>(otherpath);
if (_otherTexture == null)
{
LogError("Diffuse file " + otherpath + " not found. Aborting");
return;
}
_isSpecular = true;
_hasSpecular = false;
}
else
{
var othername = basename + SPEC_TAG;
var otherpath = directory + "/" + othername + extension;
_otherTexture = (Texture2D) AssetDatabase.LoadAssetAtPath<Texture2D>(otherpath);
if (_otherTexture == null)
{
return;
}
_hasSpecular = true;
importer.alphaSource = TextureImporterAlphaSource.FromGrayScale;
}
}
}
void OnPostprocessTexture(Texture2D texture)
{
if (_isSpecular)
{
CopyAlphaChannel(texture, _otherTexture);
return;
}
if (_hasSpecular)
{
CopyAlphaChannel(_otherTexture, texture);
return;
}
AssetDatabase.SaveAssets();
}
private void CopyAlphaChannel(Texture2D source, Texture2D target)
{
var width = source.width;
var height = source.height;
var depth = source.mipmapCount;
if (width != target.width || height != target.height)
{
LogError("Specular and Diffuse texture sizes to not match in texture " + assetPath);
return;
}
for (int level = 0; level < depth; level++)
{
var sourcePixels = source.GetPixels32(level);
var targetPixels = target.GetPixels32(level);
var length = sourcePixels.Length;
for (var i = 0; i < length; i++)
{
targetPixels[i].a = sourcePixels[i].r;
}
target.SetPixels32(targetPixels, level);
}
target.Apply();
}
}
}
Loading…
Cancel
Save