Add Editor scripts
This commit is contained in:
parent
39df2be2e7
commit
0d429b8b2b
219
Editor/MeshPostProcessor.cs
Normal file
219
Editor/MeshPostProcessor.cs
Normal file
@ -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
Normal file
137
Editor/TexturePostProcessor.cs
Normal file
@ -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…
Reference in New Issue
Block a user