Created
August 1, 2019 16:48
-
-
Save keenanwoodall/99470af37d9c926b271a24f42a3d65fb to your computer and use it in GitHub Desktop.
A test for deforming meshes without using a deformable component
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEditor; | |
using Unity.Jobs; | |
using Deform; | |
public class AutomatedDeformationTestWindow : EditorWindow | |
{ | |
private Mesh mesh; | |
[MenuItem("Tools/Automated Deformation Window")] | |
public static void Open() | |
{ | |
GetWindow<AutomatedDeformationTestWindow>("Deformableless Deformation"); | |
} | |
private void OnGUI() | |
{ | |
using (var check = new EditorGUI.ChangeCheckScope()) | |
{ | |
var newMesh = (Mesh)EditorGUILayout.ObjectField("Mesh", mesh, typeof(Mesh), false); | |
if (check.changed) | |
{ | |
Undo.RecordObject(this, "Changed Mesh"); | |
mesh = newMesh; | |
} | |
} | |
if (GUILayout.Button("Deform")) | |
SaveMesh(Deform(mesh)); | |
} | |
private Mesh Deform(Mesh mesh) | |
{ | |
// Make a copy of the mesh | |
var newMesh = Instantiate(mesh); | |
// Generate managed and native data from the mesh | |
var managedData = new ManagedMeshData(newMesh); | |
var nativeData = new NativeMeshData(managedData); | |
var vertexData = nativeData.VertexBuffer.Length; | |
// Schedule a job that will deform the native data's vertex buffer with 3D simplex noise | |
var handle = new SimplexNoiseDeformer._3DNoiseJob | |
{ | |
frequency = 3f, | |
magnitude = 0.1f, | |
// meshToAxis is used to make the relative to another transform, but in this case it doesn't need to be relative to anything | |
// so I'm creating a matrix that won't affect the vertices at all | |
meshToAxis = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one), | |
offset = Vector4.zero, | |
vertices = nativeData.VertexBuffer | |
}.Schedule(vertexData, Deformer.DEFAULT_BATCH_COUNT); | |
/* | |
* To add another deformer, just create and schedule another job with 'handle' as the dependecy. | |
* It will look something like this: | |
* | |
* handle = new SomeDeformer.SomeDeformerJob | |
* { | |
* someFloatParameter = 1f, | |
* someVectorParameter = Vector3.one | |
* }.Schedule(vertexData, Deformer.DEFAULT_BATCH_COUNT, handle); | |
*/ | |
// Schedule normal recalculation after the noise finishes | |
handle = MeshUtils.RecalculateNormals(nativeData, handle); | |
// Schedule bounds recalculation after the normal recalculation finishes | |
handle = MeshUtils.RecalculateBounds(nativeData, handle); | |
// Force the jobs to complete | |
handle.Complete(); | |
// Copy the native data to the managed data | |
DataUtils.CopyNativeDataToManagedData(managedData, nativeData, DataFlags.All); | |
// Dispose of the native data so we don't leak memory | |
nativeData.Dispose(); | |
// Assign all of the new managed data to the new mesh | |
newMesh.vertices = managedData.Vertices; | |
newMesh.normals = managedData.Normals; | |
newMesh.tangents = managedData.Tangents; | |
newMesh.uv = managedData.UVs; | |
newMesh.colors = managedData.Colors; | |
newMesh.triangles = managedData.Triangles; | |
newMesh.bounds = managedData.Bounds; | |
// Return the modified mesh | |
return newMesh; | |
} | |
// I'd recommend you use your own mesh serializer as what I'm doing gere is kinda gross. | |
// If that doesn't bother you, this is a good method for saving a mesh. | |
private void SaveMesh(Mesh mesh) | |
{ | |
// C:/...<ProjectName>/Assets/ | |
var projectPath = Application.dataPath + "/"; | |
// We have to generate the full asset path starting from the Assets folder for GeneratorUniqueAssetPath to work, | |
var assetPath = EditorUtility.SaveFilePanelInProject("Save Obj", $"{mesh.name}.obj", "obj", ""); | |
if (string.IsNullOrEmpty(assetPath)) | |
return; | |
// Now that we have a unique asset path we can remove the "Assets/" and ".obj" to get the unique name. | |
var fileName = assetPath; | |
// It's pretty gross, but it works and this code doesn't need to be performant. | |
fileName = fileName.Remove(0, 7); | |
fileName = fileName.Remove(fileName.Length - 4, 4); | |
ObjExporter.SaveMesh(mesh, null, projectPath, fileName); | |
AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment