Files
HauntedBloodlines/Assets/PuppetFace/Scripts/Editor/MeshModifierEditor.cs
2025-05-29 22:31:40 +03:00

1336 lines
40 KiB
C#

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace PuppetFace
{
[CanEditMultipleObjects]
[CustomEditor(typeof(MeshModifier))]
public class MeshModifierEditor : Editor
{
MeshModifier[] _meshModifiers;
public struct Driver
{
public Vector3 point;
public float radius;
}
public Driver[] driverInfo = new Driver[2];
public ComputeBuffer vertexBuffer;
public ComputeBuffer driverBuffer;
public Mesh mesh;
public int[] tris;
public int[] trisDistinct;
public int[] verts;
public bool Hit = false;
public Vector2 mousePosition;
public Vector3 screenPos;
public Vector3 newPos;
public float PrevRadius;
public bool Drawing = true;
public bool DrawingStarted = false;
public bool RadiusChange = false;
private bool _useComputeShader = false;
Tool lastTool = Tool.None;
private float _internalScale = 1f;
public bool InitializeTopology = false;
public bool CheckClosest = true;
private float _internalConnectedVertThreshold = 0f;
private static string _puppetFacePath;
void OnDisable()
{
Tools.current = lastTool;
}
// Use this for initialization
void OnEnable()
{
_puppetFacePath = "Assets" + RecursivelyFindFolderPath().Substring(Application.dataPath.Length);
Initialize();
}
void TopologyInitializer()
{
foreach (MeshModifier m in _meshModifiers)
{
int vertCount = mesh.vertexCount;
for (int i = 0; i < vertCount; i++)
{
if (InitializeTopology)
{
float[] connectedLengths;
int[] connectedVerts = GetConnectedVertices(i, out connectedLengths, m, CheckClosest);
m._vertexDataFull[i].connectedIndexes = connectedVerts;
m._vertexDataFull[i].connectedLengths = connectedLengths;
}
}
}
}
void TopologyInitializer(MeshModifier m)
{
int vertCount = mesh.vertexCount;
if (InitializeTopology)
{
for (int i = 0; i < vertCount; i++)
{
if (i % 200 == 0)
{
if (EditorUtility.DisplayCancelableProgressBar("Creating Topology", "Making Connections (To speed up high-res meshes, select less submeshes)", (float)i / (float)vertCount))
{
EditorUtility.ClearProgressBar();
_internalConnectedVertThreshold = m.ConnectedVertexThreshold;
//InitializeTopology = false;
break;
}
}
float[] connectedLengths;
int[] connectedVerts = GetConnectedVertices(i, out connectedLengths, m, CheckClosest);
m._vertexDataFull[i].connectedIndexes = connectedVerts;
m._vertexDataFull[i].connectedLengths = connectedLengths;
}
EditorUtility.ClearProgressBar();
}
}
void Initialize()
{
Object[] monoObjects = targets;
_meshModifiers = new MeshModifier[monoObjects.Length];
for (int i = 0; i < monoObjects.Length; i++)
{
_meshModifiers[i] = monoObjects[i] as MeshModifier;
}
foreach (MeshModifier m in _meshModifiers)
{
lastTool = Tools.current;
Tools.current = Tool.None;
m._smr = m.GetComponent<SkinnedMeshRenderer>();
if (m._smr == null)
{
m._mf = m.GetComponent<MeshFilter>();
mesh = m._mf.sharedMesh;
}
else
{
mesh = m._smr.sharedMesh;
}
_internalScale = m.GetComponent<Renderer>().bounds.size.y;
m.Radius = _internalScale / 15f;
List<int> trisList = new List<int>();
for (int i=0;i<mesh.subMeshCount;i++)
{
int[] trisToAdd = mesh.GetTriangles(i);
trisList.AddRange(trisToAdd);
}
tris = trisList.ToArray();
trisDistinct = tris.Distinct().ToArray();
Debug.Log("tri count " + tris.Length/3f);
InitializeTopology = true;
if (tris.Length / 3f > 120000)
{
Debug.LogWarning("Mesh exceeds 120K tris, unable to index mesh. Try choosing a submesh.");
InitializeTopology = false;
}
else if (tris.Length / 3f > 60000)
{
//InitializeTopology = false;
Debug.LogWarning("Mesh exceeds 60K tris, overlapping vertices ignored");
CheckClosest = false;
}
else
{
}
m._meshCol = m.GetComponent<MeshCollider>();
if (m._meshCol == null)
{
m._meshCol = m.gameObject.AddComponent<MeshCollider>();
m._meshCol.sharedMesh = mesh;
}
if (_useComputeShader)
{
string shaderName = "MeshModify";
ComputeShader[] compShaders = (ComputeShader[])Resources.FindObjectsOfTypeAll(typeof(ComputeShader));
for (int i = 0; i < compShaders.Length; i++)
{
if (compShaders[i].name == shaderName)
{
m._shader = compShaders[i];
break;
}
}
}
if (m._newMesh == null || m._vertexDataFull == null)
{
m._vertexData = new MeshModifier.VertexInfo[mesh.vertexCount];
m._vertexDataOutput = new MeshModifier.VertexInfo[mesh.vertexCount];
m._vertexDataFull = new MeshModifier.VertexInfoFull[mesh.vertexCount];
m._verts = mesh.vertices;
m._normals = mesh.normals;
Vector3[] originalVerts = new Vector3[0];
if (m.BlendShapeType == 2)
{
if (m.TargetSkin != null)
{
Mesh bakedMesh = new Mesh();
m.TargetSkin.BakeMesh(bakedMesh);
originalVerts = bakedMesh.vertices;
}
}
else if (m.TargetSkin != null)
originalVerts = m.TargetSkin.sharedMesh.vertices;
int vertCount = mesh.vertexCount;
Vector3[] vertArray = mesh.vertices;
for (int i = 0; i < vertCount; i++)
{
m._vertexData[i].point = (vertArray[i]);
m._vertexData[i].prevPoint = (vertArray[i]);
if (m.TargetSkin != null)
m._vertexDataOutput[i].point = originalVerts[i];
else
m._vertexDataOutput[i].point = (vertArray[i]);
m._vertexDataFull[i].connectedIndexes = new int[0];
m._vertexDataFull[i].connectedLengths = new float[0];
if (InitializeTopology)
{
if (i % 200 == 0)
{
if (EditorUtility.DisplayCancelableProgressBar("Creating Topology", "Generating connections (For high-res meshes, select less submeshes)", (float)i / (float)vertCount))
{
EditorUtility.ClearProgressBar();
m._vertexDataFull[i].connectedIndexes = null;
m._vertexDataFull[i].connectedLengths = new float[0];
InitializeTopology = false;
}
}
float[] connectedLengths;
int[] connectedVerts = GetConnectedVertices(i, out connectedLengths, m, CheckClosest);
m._vertexDataFull[i].connectedIndexes = connectedVerts;
m._vertexDataFull[i].connectedLengths = connectedLengths;
}
m._vertexDataFull[i].point = (vertArray[i]);
m._vertexDataFull[i].id = i;
m._vertexDataFull[i].workingLength = 0f;
}
EditorUtility.ClearProgressBar();
if(InitializeTopology)
m.selectionType = MeshModifier.SelectionType.Topology;
m._newMesh = new Mesh();
m._newMesh.vertices = mesh.vertices;
m._newMesh.subMeshCount = mesh.subMeshCount;
for (int index = 0; index < mesh.subMeshCount; index++)
{
m._newMesh.SetTriangles(mesh.GetTriangles(index), index);
}
m._newMesh.normals = mesh.normals;
m._newMesh.tangents = mesh.tangents;
m._newMesh.uv = mesh.uv;
m._newMesh.name = m.name + "_BS";
m._newMesh.colors = mesh.colors;
m._newMesh.bindposes = mesh.bindposes;
m._newMesh.boneWeights = mesh.boneWeights;
CopyAllBlendShapes(ref mesh,ref m._newMesh);
/*GoToBindPose(m._smr);
m.transform.position = Vector3.zero;
m.transform.rotation = Quaternion.identity;
m.transform.localScale = Vector3.one;*/
}
//SaveMesh(m.newMesh);
//verts = new Vector3[mesh.vertexCount];
m._meshCol = m.GetComponent<MeshCollider>();
if (_useComputeShader)
{
vertexBuffer = new ComputeBuffer(m._vertexData.Length, 64);
vertexBuffer.SetData(m._vertexData);
driverBuffer = new ComputeBuffer(driverInfo.Length, 16);
}
EditorUtility.SetDirty(m._newMesh);
AssetDatabase.SaveAssets();
}
}
public static void GoToBindPose(SkinnedMeshRenderer smr)
{
Matrix4x4[] bindPoses = smr.sharedMesh.bindposes;
for (int j = 0; j < bindPoses.Length; j++)
{
for (int i = 0; i < bindPoses.Length; i++)
{
Matrix4x4 localMatrix = bindPoses[i];
if (smr.bones[i].parent != null)
{
localMatrix = (localMatrix * smr.bones[i].parent.worldToLocalMatrix.inverse).inverse;
}
else
localMatrix = localMatrix.inverse;
smr.bones[i].localPosition = localMatrix.MultiplyPoint(Vector3.zero);
smr.bones[i].localRotation = Quaternion.LookRotation(localMatrix.GetColumn(2), localMatrix.GetColumn(1));
smr.bones[i].localScale = new Vector3(localMatrix.GetColumn(0).magnitude, localMatrix.GetColumn(1).magnitude, localMatrix.GetColumn(2).magnitude);
}
}
}
public static void CopyAllBlendShapes(ref Mesh sourceMesh, ref Mesh destMesh)
{
Vector3[] dVertices = new Vector3[sourceMesh.vertexCount];
Vector3[] dNormals = new Vector3[sourceMesh.vertexCount];
Vector3[] dTangents = new Vector3[sourceMesh.vertexCount];
for (int shape = 0; shape < sourceMesh.blendShapeCount; shape++)
{
for (int frame = 0; frame < sourceMesh.GetBlendShapeFrameCount(shape); frame++)
{
string shapeName = sourceMesh.GetBlendShapeName(shape);
float frameWeight = sourceMesh.GetBlendShapeFrameWeight(shape, frame);
sourceMesh.GetBlendShapeFrameVertices(shape, frame, dVertices, dNormals, dTangents);
destMesh.AddBlendShapeFrame(shapeName, frameWeight, dVertices, dNormals, dTangents);
}
}
}
public float DistanceOptimised(Vector3 firstPosition, Vector3 secondPosition)
{
Vector3 heading;
heading.x = firstPosition.x - secondPosition.x;
heading.y = firstPosition.y - secondPosition.y;
heading.z = firstPosition.z - secondPosition.z;
float distanceSquared = heading.x * heading.x + heading.y * heading.y + heading.z * heading.z;
return Mathf.Sqrt(distanceSquared);
}
int[] GetConnectedVertices(int index, out float[] connectedLengths, MeshModifier m, bool checkClosest = true )
{
List<int> connectedVerts = new List<int>();
for (int t = 0; t < tris.Length; t += 3)
{
//int c1 = tris[t];
//int c2 = tris[t + 1];
//int c3 = tris[t + 2];
if (tris[t] == index)
{
connectedVerts.Add(tris[t + 1]);
connectedVerts.Add(tris[t + 2]);
}
else if (tris[t + 1] == index)
{
connectedVerts.Add(tris[t]);
connectedVerts.Add(tris[t + 2]);
}
else if(tris[t + 2] == index)
{
connectedVerts.Add(tris[t]);
connectedVerts.Add(tris[t + 1]);
}
}
int count = trisDistinct.Length;
if (checkClosest)
{
for (int i = 0; i < count; i++)
{
if(m._verts[trisDistinct[i]].Equals(m._verts[index]))
connectedVerts.Add(i);
//if (DistanceOptimised(m._verts[trisDistinct[i]], m._verts[index]) <= m.ConnectedVertexThreshold)
// connectedVerts.Add(i);
}
}
connectedVerts = connectedVerts.Distinct().ToList();
connectedLengths = new float[connectedVerts.Count];
count = connectedVerts.Count;
for (int i = 0; i < count; i++)
{
connectedLengths[i] = DistanceOptimised(m._verts[connectedVerts[i]], m._verts[index]);
}
return connectedVerts.ToArray();
}
public void OnDestroy()
{
if (_useComputeShader)
{
vertexBuffer.Release();
driverBuffer.Release();
}
}
public override void OnInspectorGUI()
{
foreach (MeshModifier m in _meshModifiers)
{
string GUI_push = (_puppetFacePath +"/Textures/GUI/GUI_Push.png");
Texture GUI_pushTexture = AssetDatabase.LoadAssetAtPath(GUI_push, typeof(Texture)) as Texture;
string GUI_pushDown = (_puppetFacePath +"/Textures/GUI/GUI_PushDown.png");
Texture GUI_pushDownTexture = AssetDatabase.LoadAssetAtPath(GUI_pushDown, typeof(Texture)) as Texture;
string GUI_pull = (_puppetFacePath +"/Textures/GUI/GUI_pull.png");
Texture GUI_pullTexture = AssetDatabase.LoadAssetAtPath(GUI_pull, typeof(Texture)) as Texture;
string GUI_pullDown = (_puppetFacePath +"/Textures/GUI/GUI_pullDown.png");
Texture GUI_pullDownTexture = AssetDatabase.LoadAssetAtPath(GUI_pullDown, typeof(Texture)) as Texture;
string GUI_smooth = (_puppetFacePath +"/Textures/GUI/GUI_Smooth.png");
Texture GUI_smoothTexture = AssetDatabase.LoadAssetAtPath(GUI_smooth, typeof(Texture)) as Texture;
string GUI_smoothDown = (_puppetFacePath +"/Textures/GUI/GUI_SmoothDown.png");
Texture GUI_smoothDownTexture = AssetDatabase.LoadAssetAtPath(GUI_smoothDown, typeof(Texture)) as Texture;
string GUI_move = (_puppetFacePath +"/Textures/GUI/GUI_Move.png");
Texture GUI_moveTexture = AssetDatabase.LoadAssetAtPath(GUI_move, typeof(Texture)) as Texture;
string GUI_moveDown = (_puppetFacePath +"/Textures/GUI/GUI_MoveDown.png");
Texture GUI_moveDownTexture = AssetDatabase.LoadAssetAtPath(GUI_moveDown, typeof(Texture)) as Texture;
string GUI_erase = (_puppetFacePath +"/Textures/GUI/GUI_Erase.png");
Texture GUI_eraseTexture = AssetDatabase.LoadAssetAtPath(GUI_erase, typeof(Texture)) as Texture;
string GUI_eraseDown = (_puppetFacePath +"/Textures/GUI/GUI_EraseDown.png");
Texture GUI_eraseDownTexture = AssetDatabase.LoadAssetAtPath(GUI_eraseDown, typeof(Texture)) as Texture;
GUIStyle guistyle = new GUIStyle();
guistyle.fixedHeight = 0;
guistyle.fixedWidth = 0;
guistyle.stretchWidth = true;
GUILayout.Space(20);
GUILayout.BeginHorizontal();
GUILayout.Space(10);
if (m.paintType == MeshModifier.PaintType.Move)
{
if (GUILayout.Button(new GUIContent(GUI_moveDownTexture, "Move Tool (W).\n\nThis tool moves the vertices. Click and drag to move the vertices around.\n\nHold Control To Erase.\nHold Shift to Smooth\n"), guistyle))
{
m.paintType = MeshModifier.PaintType.Move;
}
}
else
{
if (GUILayout.Button(new GUIContent(GUI_moveTexture, "Move Tool (W).\n\nThis tool moves the vertices. Click and drag to move the vertices around.\n\nHold Control To Erase.\nHold Shift to Smooth\n"), guistyle))
{
m.paintType = MeshModifier.PaintType.Move;
}
}
if (m.paintType == MeshModifier.PaintType.Pull)
{
if (GUILayout.Button(new GUIContent(GUI_pullDownTexture, "Push Tool (E).\n\nThis tool pushes the vertices out by their normals,\n\nHold Control To Pull.\nHold Shift to Smooth\n"), guistyle))
{
m.paintType = MeshModifier.PaintType.Pull;
}
}
else
{
if (GUILayout.Button(new GUIContent(GUI_pullTexture, "Push Tool (E).\n\nThis tool pushes the vertices out by their normals,\n\nHold Control To Pull.\nHold Shift to Smooth\n"), guistyle))
{
m.paintType = MeshModifier.PaintType.Pull;
}
}
if (m.paintType == MeshModifier.PaintType.Push)
{
if (GUILayout.Button(new GUIContent(GUI_pushDownTexture, "Pull Tool (R).\n\nThis tool pulls the vertices out by their normals,\n\nHold Control To Push.\nHold Shift to Smooth\n"), guistyle))
{
m.paintType = MeshModifier.PaintType.Push;
}
}
else
{
if (GUILayout.Button(new GUIContent(GUI_pushTexture, "Pull Tool (R).\n\nThis tool pulls the vertices out by their normals,\n\nHold Control To Push.\nHold Shift to Smooth\n"), guistyle))
{
m.paintType = MeshModifier.PaintType.Push;
}
}
if (m.paintType == MeshModifier.PaintType.Smooth)
{
if (GUILayout.Button(new GUIContent(GUI_smoothDownTexture, "Smooth Tool (T).\n\nThis tool smooths the vertices out\n\nHold Control To Erase.\n"), guistyle))
{
m.paintType = MeshModifier.PaintType.Smooth;
}
}
else
{
if (GUILayout.Button(new GUIContent(GUI_smoothTexture, "Smooth Tool (T).\n\nThis tool smooths the vertices out\n\nHold Control To Erase.\n"), guistyle))
{
m.paintType = MeshModifier.PaintType.Smooth;
}
}
if (m.paintType == MeshModifier.PaintType.Erase)
{
if (GUILayout.Button(new GUIContent(GUI_eraseDownTexture, "Erase Tool (Y).\n\nThis tool transforms the vertices back to their original position,\n"), guistyle))
{
m.paintType = MeshModifier.PaintType.Erase;
}
}
else
{
if (GUILayout.Button(new GUIContent(GUI_eraseTexture, "Erase Tool (Y).\n\nThis tool transforms the vertices back to their original position,\n"), guistyle))
{
m.paintType = MeshModifier.PaintType.Erase;
}
}
GUILayout.EndHorizontal();
GUILayout.Space(10);
DrawDefaultInspector();
if (GUILayout.Button("Set Blend Shape"))
{
if (m.TargetSkin == m._smr)
{
Debug.LogWarning("The Target SkinnnedMeshRenderer needs to be different to this gameObject");
}
else if (m.TargetSkin != null)
{
PuppetFace.BlendShapeManager BlendShapeManager = m.TargetSkin.GetComponent<PuppetFace.BlendShapeManager>();
if (BlendShapeManager != null)
{
if (m.Index < BlendShapeManager.BlendShapeTextures.Length && m.Index >= 0)
BlendShapeManager.BlendShapeTextures[m.Index] = TakeScreenShot();
else
{
List<Texture2D> texs = new List<Texture2D>(BlendShapeManager.BlendShapeTextures);
texs.Add(TakeScreenShot());
BlendShapeManager.BlendShapeTextures = texs.ToArray();
}
}
SetBlendShape(m);
m.TargetSkin.enabled = true;
Selection.activeGameObject = m.TargetSkin.gameObject;
if (m._smr != m.TargetSkin)
DestroyImmediate(m.gameObject);
}
else
{
Debug.LogWarning("Needs a Target SkinnedMeshRenderer");
}
}
if (GUILayout.Button("Reset"))
{
if (_internalConnectedVertThreshold != m.ConnectedVertexThreshold)
{
TopologyInitializer(m);
_internalConnectedVertThreshold = m.ConnectedVertexThreshold;
}
for (int i = 0; i < m._verts.Length; i++)
{
m._verts[i] = m._vertexData[i].point;
m._newMesh.vertices = m._verts;
}
}
if (GUILayout.Button("Discard"))
{
if (m.TargetSkin == m._smr)
{
Debug.LogWarning("The Target SkinnnedMeshRenderer needs to be different to this gameObject");
}
else if (m.TargetSkin != null)
{
m.TargetSkin.enabled = true;
Selection.activeGameObject = m.TargetSkin.gameObject;
DestroyImmediate(m.gameObject);
}
else
{
Debug.LogWarning("Needs a Target SkinnedMeshRenderer");
}
}
}
}
public void SetBlendShape(MeshModifier m)
{
string BlendShapeName = m.name;
Mesh mesh = m._newMesh;
Mesh meshCurrent = new Mesh();
if (m.BlendShapeType == 2)
m.TargetSkin.BakeMesh(meshCurrent);
else
meshCurrent = m.TargetSkin.sharedMesh;
Vector3[] deltas = new Vector3[mesh.vertexCount];
Vector3[] deltaNormals = new Vector3[mesh.vertexCount];
Vector3[] deltaTangents = new Vector3[mesh.vertexCount];
if (mesh.vertexCount != meshCurrent.vertexCount)
{
Debug.LogWarning("Vert Count mismatch " + mesh.vertexCount + " " + meshCurrent.vertexCount);
}
int vertCount = mesh.vertexCount;
Vector3[] verts = mesh.vertices;
Vector3[] vertsCurrent = meshCurrent.vertices;
Vector3[] normals = mesh.normals;
Vector4[] tangents = mesh.tangents;
Vector3[] normalsCurrent = m.TargetSkin.sharedMesh.normals;
Vector4[] tangentsCurrent = m.TargetSkin.sharedMesh.tangents;
if (tangents.Length > 0)
{
for (int i = 0; i < vertCount; i++)
{
deltas[i] = verts[i] - vertsCurrent[i];
deltaNormals[i] = normals[i] - normalsCurrent[i];
deltaTangents[i] = tangents[i] - tangentsCurrent[i];
}
}
else
{
for (int i = 0; i < vertCount; i++)
{
deltas[i] = verts[i] - vertsCurrent[i];
deltaNormals[i] = normals[i] - normalsCurrent[i];
}
}
ReplaceBlendShape(BlendShapeName, deltas, deltaNormals, deltaTangents, m);
}
public void ReplaceBlendShape(string blendShapeName, Vector3[] deltasNew, Vector3[] deltaNormalsNew, Vector3[] deltaTangentsNew, MeshModifier m)
{
string BlendShapeName = m.name;
Mesh tmpMesh = new Mesh();
tmpMesh.vertices = m.TargetSkin.sharedMesh.vertices;
Vector3[] dVertices = new Vector3[m.TargetSkin.sharedMesh.vertexCount];
Vector3[] dNormals = new Vector3[m.TargetSkin.sharedMesh.vertexCount];
Vector3[] dTangents = new Vector3[m.TargetSkin.sharedMesh.vertexCount];
bool added = false;
for (int shape = 0; shape < m.TargetSkin.sharedMesh.blendShapeCount; shape++)
{
for (int frame = 0; frame < m.TargetSkin.sharedMesh.GetBlendShapeFrameCount(shape); frame++)
{
string shapeName = m.TargetSkin.sharedMesh.GetBlendShapeName(shape);
float frameWeight = m.TargetSkin.sharedMesh.GetBlendShapeFrameWeight(shape, frame);
m.TargetSkin.sharedMesh.GetBlendShapeFrameVertices(shape, frame, dVertices, dNormals, dTangents);
if (shapeName == blendShapeName)
{
dVertices = deltasNew;
dNormals = deltaNormalsNew;
dTangents = deltaTangentsNew;
added = true;
}
tmpMesh.AddBlendShapeFrame(shapeName, frameWeight, dVertices, dNormals, dTangents);
}
}
Mesh myMesh = SaveMesh(m.TargetSkin.sharedMesh);
m.TargetSkin.sharedMesh = myMesh;
m.TargetSkin.sharedMesh.ClearBlendShapes();
for (int shape = 0; shape < tmpMesh.blendShapeCount; shape++)
{
for (int frame = 0; frame < tmpMesh.GetBlendShapeFrameCount(shape); frame++)
{
string shapeName = tmpMesh.GetBlendShapeName(shape);
float frameWeight = tmpMesh.GetBlendShapeFrameWeight(shape, frame);
tmpMesh.GetBlendShapeFrameVertices(shape, frame, dVertices, dNormals, dTangents);
myMesh.AddBlendShapeFrame(shapeName, frameWeight, dVertices, dNormals, dTangents);
}
}
if (!added)
{
m.TargetSkin.sharedMesh.AddBlendShapeFrame(BlendShapeName, 100f, deltasNew, deltaNormalsNew, deltaTangentsNew);
}
EditorUtility.SetDirty(m.TargetSkin.sharedMesh);
AssetDatabase.SaveAssets();
}
public Mesh SaveMesh(Mesh mesh, bool Duplicate = false)
{
string path = AssetDatabase.GetAssetPath(mesh);
string extension = Path.GetExtension(path);
if (extension == ".asset" && !Duplicate)
{
return mesh;
}
else
{
string[] pathSplit = path.Split('/');
string meshPath = "";
for (int i = 0; i < pathSplit.Length - 1; i++)
{
meshPath += pathSplit[i] + "/";
}
if (meshPath == "" || (meshPath.Contains("Library")))
meshPath = "Assets/";
string outMeshPath = meshPath + mesh.name + "P3D.asset";
outMeshPath = AssetDatabase.GenerateUniqueAssetPath(outMeshPath);
Mesh newMesh = new Mesh();
newMesh.vertices = mesh.vertices;
newMesh.colors = mesh.colors;
newMesh.normals = mesh.normals;
newMesh.uv = mesh.uv;
newMesh.bindposes = mesh.bindposes;
newMesh.boneWeights = mesh.boneWeights;
newMesh.tangents = mesh.tangents;
newMesh.subMeshCount = mesh.subMeshCount;
for (int index = 0; index < mesh.subMeshCount; index++)
{
newMesh.SetTriangles(mesh.GetTriangles(index), index);
}
AssetDatabase.CreateAsset(newMesh, outMeshPath);
Debug.Log("Saving mesh into " + outMeshPath);
return AssetDatabase.LoadAssetAtPath(outMeshPath, typeof(Mesh)) as Mesh;
}
}
void RunShader(MeshModifier m)
{
ComputeBuffer driverBuffer = new ComputeBuffer(driverInfo.Length, 16);
driverBuffer.SetData(driverInfo);
int kernelMove = m._shader.FindKernel("MoveVertex");
m._shader.SetBuffer(kernelMove, "vertexBuffer", vertexBuffer);
m._shader.SetBuffer(kernelMove, "driverBuffer", driverBuffer);
m._shader.Dispatch(kernelMove, m._vertexData.Length / 16, 1, 1);
vertexBuffer.GetData(m._vertexDataOutput);
for (int i = 0; i < m._vertexDataOutput.Length; i++)
{
m._verts[i] = m._vertexDataOutput[i].point;
}
m._newMesh.vertices = m._verts;
if (m._smr != null)
m._smr.sharedMesh = m._newMesh;
else
m._mf.sharedMesh = m._newMesh;
driverBuffer.Release();
}
public RaycastHit hit;
void OnSceneGUI()
{
foreach (MeshModifier m in _meshModifiers)
{
Tools.current = Tool.None;
Camera cam = SceneView.GetAllSceneCameras()[0];
m.Radius = Mathf.Max(0.000001f, m.Radius);
driverInfo[0].radius = 1f / m.Radius;
Event e = Event.current;
if (!m.ShiftDown && e.shift)
m._previousTool = m.paintType;
if (e.shift)
{
m.ShiftDown = true;
}
if (!m.ControlDown && e.control)
m._previousTool = m.paintType;
if (e.control)
{
m.ControlDown = true;
}
switch (e.type)
{
case EventType.KeyDown:
if (e.keyCode == KeyCode.B)
{
mousePosition = Event.current.mousePosition;
PrevRadius = m.Radius;
if(!DrawingStarted)
Drawing = false;
RadiusChange = true;
}
if (e.keyCode == KeyCode.LeftAlt)
{
if (!DrawingStarted)
Drawing = false;
}
if (e.keyCode == KeyCode.W)
{
m.paintType = MeshModifier.PaintType.Move;
}
if (e.keyCode == KeyCode.E)
{
m.paintType = MeshModifier.PaintType.Pull;
}
if (e.keyCode == KeyCode.R)
{
m.paintType = MeshModifier.PaintType.Push;
}
if (e.keyCode == KeyCode.T)
{
m.paintType = MeshModifier.PaintType.Smooth;
}
if (e.keyCode == KeyCode.Y)
{
m.paintType = MeshModifier.PaintType.Erase;
}
break;
case EventType.KeyUp:
if (e.keyCode == KeyCode.B)
{
RadiusChange = false;
Drawing = true;
}
if (e.keyCode == KeyCode.LeftAlt)
{
Drawing = true;
}
break;
case EventType.MouseDown:
if (Drawing && Event.current.button == 0)
{
DrawingStarted = true;
Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
if (Physics.Raycast(ray, out hit, 100.0f))
{
driverInfo[0].point = m.transform.InverseTransformPoint(hit.point);
Hit = true;
}
driverInfo[1].point = driverInfo[0].point;
screenPos = cam.WorldToScreenPoint(hit.point);
}
break;
case EventType.MouseDrag:
if (Drawing && Hit)
{
DrawingStarted = true;
driverInfo[1].point = m.transform.InverseTransformPoint(newPos);
}
break;
case EventType.MouseUp:
if (Drawing)
{
DrawingStarted = false;
Hit = false;
m._meshCol.sharedMesh = null;
m._meshCol.sharedMesh = m._newMesh;
driverInfo[1].point = driverInfo[0].point;
if (_useComputeShader)
{
for (int i = 0; i < m._vertexDataOutput.Length; i++)
{
m._vertexData[i].prevPoint = m._vertexDataOutput[i].point;
m._vertexData[i].point = m._vertexDataOutput[i].point;
}
vertexBuffer.Release();
vertexBuffer = new ComputeBuffer(m._vertexData.Length, 64);
vertexBuffer.SetData(m._vertexData);
}
}
break;
}
if (m.ShiftDown)
m.paintType = MeshModifier.PaintType.Smooth;
if (m.ControlDown)
{
if (m.paintType == MeshModifier.PaintType.Move || m.paintType == MeshModifier.PaintType.Smooth)
m.paintType = MeshModifier.PaintType.Erase;
if (m._previousTool == MeshModifier.PaintType.Push)
{
m.paintType = MeshModifier.PaintType.Pull;
}
else if (m._previousTool == MeshModifier.PaintType.Pull)
{
m.paintType = MeshModifier.PaintType.Push;
}
}
if (m.ShiftDown && !e.shift)
{
m.paintType = m._previousTool;
m.ShiftDown = false;
}
if (m.ControlDown && !e.control)
{
m.paintType = m._previousTool;
m.ControlDown = false;
}
if (Drawing)
{
Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
newPos = cam.WorldToScreenPoint(ray.origin);
newPos.z = screenPos.z;
newPos = cam.ScreenToWorldPoint(newPos);
if (Physics.Raycast(ray, out hit, 100000.0f))
{
Handles.DrawWireDisc(hit.point, (cam.transform.position - hit.point).normalized, m.Radius);
if (m.Mirror)
{
Vector3 reflPos = Vector3.Reflect(hit.point - m.transform.position, Vector3.left) + m.transform.position;
Handles.DrawWireDisc(reflPos, (cam.transform.position - hit.point).normalized, m.Radius);
}
}
else
{
Handles.DrawWireDisc(newPos, (cam.transform.position - newPos).normalized, m.Radius);
if (m.Mirror)
{
Vector3 reflPos = Vector3.Reflect(newPos - m.transform.position, Vector3.left) + m.transform.position;
Handles.DrawWireDisc(reflPos, (cam.transform.position - hit.point).normalized, m.Radius);
}
}
}
else
{
Handles.DrawWireDisc(newPos, (cam.transform.position - hit.point).normalized, m.Radius);
if (m.Mirror)
{
Vector3 reflPos = Vector3.Reflect(newPos - m.transform.position, Vector3.left) + m.transform.position;
Handles.DrawWireDisc(reflPos, (cam.transform.position - hit.point).normalized, m.Radius);
}
if (RadiusChange)
m.Radius = Mathf.Abs(PrevRadius + (Event.current.mousePosition.x - mousePosition.x) * (0.001f * _internalScale));
}
GUIUtility.GetControlID(FocusType.Passive);
HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));
if (_useComputeShader)
RunShader(m);
Vector3 dir = driverInfo[1].point - driverInfo[0].point;
int id = GetClosestVert(dir, driverInfo[0].point, driverInfo[1].point, m);
Vector3 reflectedStart = m.transform.InverseTransformPoint(Vector3.Reflect(m.transform.TransformPoint(driverInfo[0].point) - m.transform.position, Vector3.left) + m.transform.position);
Vector3 reflectedEnd = m.transform.InverseTransformPoint(Vector3.Reflect(m.transform.TransformPoint(driverInfo[1].point) - m.transform.position, Vector3.left) + m.transform.position);
Vector3 dirReflected = reflectedEnd - reflectedStart;
int id2 = 0;
if (m.Mirror)
{
id2 = GetClosestVert(dirReflected, reflectedStart, reflectedEnd, m);
}
Undo.RecordObject(m, "record mesh");
if (m.selectionType == MeshModifier.SelectionType.Topology)
{
SurfaceSearchAndMove(dir, id, driverInfo[0].point.x, m);
if (m.Mirror)
{
//movedVerts
SurfaceSearchAndMove(dirReflected, id2, reflectedStart.x, m, -1);
}
}
m._newMesh.vertices = m._verts;
if (m.RecalculateNormals)
{
m._newMesh.RecalculateNormals();
m._newMesh.RecalculateTangents();
}
m._newMesh.RecalculateBounds();
if (m._smr != null)
m._smr.sharedMesh = m._newMesh;
else
m._mf.sharedMesh = m._newMesh;
Handles.color = new Color(14f / 255f, 229f / 255f, 198f / 255f, 1f);
Vector3[] p1 = new Vector3[2];
p1[0] = cam.ScreenToWorldPoint(new Vector3(0, 0, cam.nearClipPlane + 1));
p1[1] = cam.ScreenToWorldPoint(new Vector3(0, cam.pixelHeight, cam.nearClipPlane + 1));
Vector3[] p2 = new Vector3[2];
p2[0] = cam.ScreenToWorldPoint(new Vector3(cam.pixelWidth, 0, cam.nearClipPlane + 1));
p2[1] = cam.ScreenToWorldPoint(new Vector3(cam.pixelWidth, cam.pixelHeight, cam.nearClipPlane + 1));
Vector3[] p3 = new Vector3[2];
p3[0] = cam.ScreenToWorldPoint(new Vector3(0, 0, cam.nearClipPlane + 1));
p3[1] = cam.ScreenToWorldPoint(new Vector3(cam.pixelWidth, 0, cam.nearClipPlane + 1));
Vector3[] p4 = new Vector3[2];
p4[0] = cam.ScreenToWorldPoint(new Vector3(0, cam.pixelHeight, cam.nearClipPlane + 1));
p4[1] = cam.ScreenToWorldPoint(new Vector3(cam.pixelWidth, cam.pixelHeight, cam.nearClipPlane + 1));
Handles.DrawAAPolyLine(15f, p1);
Handles.DrawAAPolyLine(15f, p2);
Handles.DrawAAPolyLine(15f, p3);
Handles.DrawAAPolyLine(15f, p4);
SceneView.RepaintAll();
}
}
private void SurfaceSearchAndMove(Vector3 dir, int id, float startX, MeshModifier m, int mirror = 1)
{
float strength = 1f;
List<int> movedVerts = new List<int>();
Queue<MeshModifier.VertexInfoFull> vertQueue = new Queue<MeshModifier.VertexInfoFull>();
m._vertexDataFull[id].moved = true;
vertQueue.Enqueue(m._vertexDataFull[id]);
movedVerts.Add(id);
while (vertQueue.Count > 0)
{
MeshModifier.VertexInfoFull v = vertQueue.Dequeue();
strength = 1f - v.workingLength / m.Radius;
if (m.DispayVerts)
{
Handles.color = new Color(1, 1, 1.2f, 1);
Handles.DrawSolidDisc(m.transform.TransformPoint(m._verts[v.id]), Vector3.forward, strength * .0025f);
}
Vector3 direction = dir;
if (m.Mirror)
{
if (Mathf.Abs(m._vertexDataFull[v.id].point.x) < 0.001f * _internalScale)
{
direction.x = 0;
}
if (startX <= 0 && m._vertexDataFull[v.id].point.x <= 0f)
{
if (m.paintType == MeshModifier.PaintType.Move)
Move(direction, m, v.id, strength);
else if (m.paintType == MeshModifier.PaintType.Erase)
Erase(direction, v.id, 0, m);
else if (m.paintType == MeshModifier.PaintType.Smooth)
Smooth(direction, m, v.id, 0);
movedVerts.Add(v.id);
}
if (startX > 0 && m._vertexDataFull[v.id].point.x > 0f)
{
if (m.paintType == MeshModifier.PaintType.Move)
Move(direction, m, v.id, strength);
else if (m.paintType == MeshModifier.PaintType.Erase)
Erase(direction, v.id, 0, m);
else if (m.paintType == MeshModifier.PaintType.Smooth)
Smooth(direction, m, v.id, 0);
movedVerts.Add(v.id);
}
}
else
{
if (m.paintType == MeshModifier.PaintType.Move)
Move(direction, m, v.id, strength);
else if (m.paintType == MeshModifier.PaintType.Erase)
Erase(direction, v.id, 0, m);
else if (m.paintType == MeshModifier.PaintType.Smooth)
Smooth(direction, m, v.id, 0);
movedVerts.Add(v.id);
}
for (int index = 0; index < v.connectedIndexes.Length; index++)
{
float newLength = v.connectedLengths[index] + v.workingLength;
if (!m._vertexDataFull[v.connectedIndexes[index]].moved && newLength < m.Radius)
{
m._vertexDataFull[v.connectedIndexes[index]].moved = true;
m._vertexDataFull[v.connectedIndexes[index]].workingLength = newLength;
movedVerts.Add(v.connectedIndexes[index]);
vertQueue.Enqueue(m._vertexDataFull[v.connectedIndexes[index]]);
}
}
}
for (int i = 0; i < movedVerts.Count; i++)
{
m._vertexDataFull[movedVerts[i]].moved = false;
m._vertexDataFull[movedVerts[i]].workingLength = 0f;
}
}
public int GetClosestVert(Vector3 dir, Vector3 startPos, Vector3 endPos, MeshModifier m)
{
int id = 0;
float dist = 9999999;
for (int i = 0; i < m._vertexDataFull.Length; i++)
{
m._vertexDataFull[i].moved = false;
m._vertexDataFull[i].workingLength = 0f;
if (dir.magnitude == 0f)
m._vertexDataFull[i].point = m._verts[i];
float testDist = Vector3.Distance(m._vertexDataFull[i].point, startPos);
if (dist > testDist)
{
id = i;
dist = testDist;
}
if (m.paintType == MeshModifier.PaintType.Move && m.selectionType == MeshModifier.SelectionType.World)
{
float strength = 1f - Mathf.Clamp01(testDist / m.Radius);
if (strength > 0)
{
Vector3 direction = dir;
if (m.Mirror)
{
if (Mathf.Abs(m._vertexDataFull[i].point.x) < 0.001f*_internalScale)
{
direction.x = 0;
}
if (startPos.x >= 0 && m._vertexDataFull[i].point.x >= 0)
m._verts[i] = m._vertexDataFull[i].point + direction * strength;
if (startPos.x < 0 && m._vertexDataFull[i].point.x < 0)
m._verts[i] = m._vertexDataFull[i].point + direction * strength;
}
else
m._verts[i] = m._vertexDataFull[i].point + direction * strength;
}
if (m.DispayVerts)
{
Handles.color = new Color(1, 1, 1, 1);
Handles.DrawSolidDisc(m.transform.TransformPoint(m._verts[i]), Vector3.forward, strength * .0025f);
}
}
else if (m.selectionType == MeshModifier.SelectionType.World)
{
if (m.paintType == MeshModifier.PaintType.Erase)
{
Erase(dir, i, testDist, m);
}
else if (m.paintType == MeshModifier.PaintType.Smooth)
{
Smooth(dir, m, i, testDist);
}
}
}
if (m.paintType == MeshModifier.PaintType.Push || m.paintType == MeshModifier.PaintType.Pull)
{
for (int i = 0; i < m._vertexDataFull.Length; i++)
{
float testDist = Vector3.Distance(m._vertexDataFull[i].point, endPos);
float strength = 1f - Mathf.Clamp01(testDist / m.Radius);
if (strength > 0 && dir.magnitude > 0f)
{
Vector3 pushDirection = m._newMesh.normals[i].normalized;
if (m.selectionType == MeshModifier.SelectionType.World)
{
pushDirection = m._newMesh.normals[id].normalized;
}
if (m.paintType == MeshModifier.PaintType.Push)
m._verts[i] -= pushDirection * strength * .0005f * m.Strength * _internalScale;
else
m._verts[i] += pushDirection * strength * .0005f * m.Strength * _internalScale;
if (m.selectionType == MeshModifier.SelectionType.Topology)
{
for (int index = 0; index < m._vertexDataFull[i].connectedIndexes.Length; index++)
{
if (m._vertexDataFull[i].connectedLengths[index] == 0)
m._verts[m._vertexDataFull[i].connectedIndexes[index]] = m._verts[i];
}
}
}
}
}
return id;
}
private static void Move(Vector3 dir, MeshModifier m, int i, float strength)
{
m._verts[i] = m._vertexDataFull[i].point + dir * strength;
for (int index = 0; index < m._vertexDataFull[i].connectedIndexes.Length; index++)
{
if (m._vertexDataFull[i].connectedLengths[index] == 0)
m._verts[m._vertexDataFull[i].connectedIndexes[index]] = m._verts[i];
}
}
private static void Smooth(Vector3 dir, MeshModifier m, int i, float testDist)
{
float strength = 1f - Mathf.Clamp01(testDist / m.Radius);
if (strength > 0 && dir.magnitude > 0)
{
Vector3 average = m._verts[i];
for (int index = 0; index < m._vertexDataFull[i].connectedIndexes.Length; index++)
{
average += m._verts[m._vertexDataFull[i].connectedIndexes[index]];
}
average /= m._vertexDataFull[i].connectedIndexes.Length + 1;
m._verts[i] = Vector3.Lerp(m._verts[i], average, m.Strength * strength * .1f);
for (int index = 0; index < m._vertexDataFull[i].connectedIndexes.Length; index++)
{
if (m._vertexDataFull[i].connectedLengths[index] == 0)
m._verts[m._vertexDataFull[i].connectedIndexes[index]] = m._verts[i];
}
}
}
private void Erase(Vector3 dir, int i, float testDist, MeshModifier m)
{
float strength = 1f - Mathf.Clamp01((testDist / m.Radius));
if (strength > 0 && dir.magnitude > 0f)
{
m._verts[i] = Vector3.Lerp(m._verts[i], m._vertexDataOutput[i].point, strength * .025f * m.Strength);
}
}
public Texture2D TakeScreenShot()
{
Camera viewCam = SceneView.lastActiveSceneView.camera;
return Screenshot(viewCam);
}
Texture2D Screenshot(Camera cam)
{
if (cam == null)
{
Debug.LogWarning("Need a preview camera on the selected BlendShape");
return null;
}
int resWidth = 80; //cam.pixelWidth;
int resHeight = 80;// cam.pixelHeight;
resWidth = (int)(float)(resWidth);
resHeight = (int)(float)(resHeight);
RenderTexture rt = new RenderTexture(resWidth, resHeight, 32);
cam.targetTexture = rt;
Texture2D screenShot = new Texture2D(resWidth, resHeight, TextureFormat.ARGB32, false);
cam.Render();
RenderTexture.active = rt;
screenShot.ReadPixels(new Rect(0, 0, resWidth, resHeight), 0, 0);
screenShot.Apply();
cam.targetTexture = null;
RenderTexture.active = null; // JC: added to avoid errors
DestroyImmediate(rt);
return screenShot;
}
public Texture2D SaveScreenshotToFile(string fileName, Camera cam)
{
Texture2D screenShot = Screenshot(cam);
byte[] bytes = screenShot.EncodeToPNG();
Debug.Log("Saving " + fileName);
System.IO.File.WriteAllBytes(fileName, bytes);
return screenShot;
}
private static string RecursivelyFindFolderPath()
{
DirectoryInfo directoryInfo = new DirectoryInfo(Application.dataPath);
DirectoryInfo[] dirInfos = directoryInfo.GetDirectories("*", SearchOption.AllDirectories);
foreach (DirectoryInfo d in dirInfos)
{
if (d.Name == "PuppetFace" && d.Parent.Name != "Gizmos")
return d.FullName;
}
return "";
}
}
}