Skip to content

Creating a Custom Deformer

Keenan Woodall edited this page May 7, 2019 · 3 revisions

Creating a Custom Deformer

Video

Text

To show how to make your own deformer I'm going to walk you through how to create a simple "Offset" deformer, which will simply add an offset to a Deformable's vertices. Before creating your own deformers you should be slightly familiar with the Job System and Mathematics library.

Step 1 Create a new C# script named "OffsetDeformer".

Step 2 Open the script and delete everything.

Step 3 Make a class called OffsetDeformer that inherits from Deformer and put it in the Deform namespace.

namespace Deform
{
	public class OffsetDeformer : Deformer
	{
	}
}

Step 4 Implement the abstract members.

public override DataFlags DataFlags => throw new System.NotImplementedException ();

public override JobHandle Process (MeshData data, JobHandle dependency = default)
{
	throw new System.NotImplementedException ();
}

Step 5 The Deformer.DataFlags property is used to determine what data the deformer is going to change. This lets deformables figure out what data needs to be copied to the mesh.

Because we only want to change vertices, make DataFlags return DataFlags.Vertices.

public override DataFlags DataFlags => DataFlags.Vertices;

However, if you are going to modify multiple types of data you can use the OR operator like so:

public override DataFlags DataFlags => DataFlags.Vertices | DataFlags.Normals;

Step 6 The Process method is where you will schedule your deformer's work. Deformable's call Process on each of their deformers and send their own MeshData as the argument for the data parameter. You can access native arrays that contain different elements of a mesh. Once a deformable's deformers are done processing, the deformable will copy any modified native mesh data to it's mesh.

In this case, we want to change the vertices, so we can create and schedule a job that changes the native vertices array. The deformable will know to apply changes we make to the array since we override the DataFlags enum value with DataFlags.Vertices.

Make sure to add using statements.

public override JobHandle Process (MeshData data, JobHandle dependency = default)
{
	return new OffsetJob
	{
		vertices = data.DynamicNative.VertexBuffer
	}.Schedule (data.Length, 64, dependency);
}

...

private struct OffsetJob : IJobParallelFor
{
	public NativeArray<float3> vertices;

	public void Execute (int index)
	{
	}
}

Now you've technically got a deformer. It doesn't do anything, but if you add it to a Deformable and open the "Debug Info" foldout you'll see it thinks there are modified vertices. Let's do what it thinks we're doing and actually modify some vertices!

Step 7 Create a public Vector3 field called offset in the OffsetDeformer class.

public Vector3 offset;

Then create a public float3 field called offset in the OffsetJob struct;

public float3 offset;

Step 8 When creating the new job, set it's offset to the deformer's offset.

return new OffsetJob
{
	offset = offset,
	vertices = data.DynamicNative.VertexBuffer
}.Schedule (data.Length, BatchCount, dependency);

Step 9 Add the offset to the current index in the offset job.

public void Execute (int index)
{
	vertices[index] += offset;
}

Now it should work. If you add an Offset Deformer to a deformable and change the offset field it should offset the mesh.

Example Deformer

Step 10 For a finishing touch, make sure to add the [BurstCompile] attribute to the OffsetJob. This will make your code be compiled by Burst (it'll run waaay faster).

If you want your deformer to be added to the Creator window, add a [Deformer] attribute to the class.

Here's the final script:

using UnityEngine;
using Unity.Jobs;
using Unity.Burst;
using Unity.Collections;
using Unity.Mathematics;

namespace Deform
{
	[Deformer (Name = "Offset", Type = typeof (OffsetDeformer))]
	public class OffsetDeformer : Deformer
	{
		public Vector3 offset;

		public override DataFlags DataFlags => DataFlags.Vertices;

		public override JobHandle Process (MeshData data, JobHandle dependency = default)
		{
			return new OffsetJob
			{
				offset = offset,
				vertices = data.DynamicNative.VertexBuffer
			}.Schedule (data.Length, 64, dependency);
		}

		[BurstCompile]
		private struct OffsetJob : IJobParallelFor
		{
			public float3 offset;
			public NativeArray<float3> vertices;

			public void Execute (int index)
			{
				vertices[index] += offset;
			}
		}
	}
}
Clone this wiki locally