Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/adcimon/mesh-deformer
Mesh deformation using the Unity Job System.
https://github.com/adcimon/mesh-deformer
unity
Last synced: 2 months ago
JSON representation
Mesh deformation using the Unity Job System.
- Host: GitHub
- URL: https://github.com/adcimon/mesh-deformer
- Owner: adcimon
- License: mit
- Created: 2018-08-04T16:03:09.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2024-06-02T14:09:01.000Z (8 months ago)
- Last Synced: 2024-08-03T05:18:09.425Z (6 months ago)
- Topics: unity
- Language: C#
- Homepage:
- Size: 702 KB
- Stars: 70
- Watchers: 4
- Forks: 10
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Mesh Deformer
Mesh deformation using the Unity Job System.
This project is a proof of concept application that deforms a mesh using the new Unity Job System. The Unity Job System is a way to write multithreaded code in the CPU providing high performance boost to the games using it. It is integrated with the Unity’s native job system which creates a thread per CPU core and manages small units of work named jobs. This design avoids the thread context switches that cause a waste of CPU resources.
To create a new job you need to implement one interface corresponding to the type of job you want to execute. There are several types of jobs, `IJob`, `IJobParallelFor` and `IJobParallelForTransform` are the most common. The basic one, `IJob`, allows you to execute the code in the secondary threads. It is also very common to want to execute the same operations on large collections of data, for this task you have the job `IJobParallelFor` (which is the one used in this example). The last one, `IJobParallelForTransform`, is another parallel job that is designed for operations using `Transform` components.
Another important thing to consider when writing high performance code is the memory layout of your data. Memory allocations are slow and to gain meaningful speed ups you have to control the lifecycle of your data, avoiding the garbage collector. A new set of native collections of blittable types are exposed to the managed side of Unity to achieve this.
The namespaces that are necessary to use the Job System and the native collections are the following ones:
```
using UnityEngine.Jobs;
using Unity.Collections;
using Unity.Jobs;
```The job that performs the vertex displacement is an `IJobParallelFor` job and receives the following inputs:
-
deltaTime. Time in seconds it took to complete the last frame. -
center. Center of the sphere. -
radius. Radius of the sphere. -
force. Force that is going to be applied to offset the vertices. -
normals. The normal for each vertex to obtain the displacement direction (read only). -
vertices. The vertex positions that are going to be updated.
It is also important to highlight that the delta time must be copied because the jobs are asynchronous and don't have the concept of frame.
The operation that is executed is a vertex inside sphere check and a displacement across the normal with the given force.
```
public struct MeshDeformerJob : IJobParallelFor
{
[ReadOnly] public float deltaTime;
[ReadOnly] public Vector3 center;
[ReadOnly] public float radius;
[ReadOnly] public float force;
[ReadOnly] public NativeArray normals;
public NativeArray vertices;
public void Execute(int index)
{
Vector3 vertex = vertices[index];
float a = Mathf.Pow(vertex.x - center.x, 2);
float b = Mathf.Pow(vertex.y - center.y, 2);
float c = Mathf.Pow(vertex.z - center.z, 2);
if (a + b + c < Mathf.Pow(radius, 2))
{
vertex += normals[index] * force * deltaTime;
vertices[index] = vertex;
}
}
}
```
The execution of this job is performed in the `MeshDeformer.cs` script after the helper class `Pointer.cs` calls it when the mouse button is pressed. The class declares 2 native arrays for the normals and vertices and a `Mesh` that will be shared by the `MeshFilter` and the `MeshCollider`.
```
public class MeshDeformer : MonoBehaviour
{
private Mesh mesh;
private MeshCollider meshCollider;
private NativeArray vertices;
private NativeArray normals;
private bool scheduled = false;
private MeshDeformerJob job;
private JobHandle handle;
private void Start()
{
mesh = gameObject.GetComponent().mesh;
mesh.MarkDynamic();
meshCollider = gameObject.GetComponent();
meshCollider.sharedMesh = null;
meshCollider.sharedMesh = mesh;
vertices = new NativeArray(mesh.vertices, Allocator.Persistent);
normals = new NativeArray(mesh.normals, Allocator.Persistent);
}
...
}
```
Each time the method `public void Deform(Vector3 point, float radius, float force)` is called, the job is scheduled for execution.
```
public void Deform(Vector3 point, float radius, float force)
{
job = new MeshDeformerJob();
job.deltaTime = Time.deltaTime;
job.center = transform.InverseTransformPoint(point);
job.radius = radius;
job.force = force;
job.vertices = vertices;
job.normals = normals;
handle = job.Schedule(vertices.Length, 64);
}
```
The job is completed in the `LateUpdate`, the vertices are copied from the job's native array to the mesh and the bounds are recalculated.
```
private void LateUpdate()
{
handle.Complete();
job.vertices.CopyTo(vertices);
mesh.vertices = vertices.ToArray();
mesh.RecalculateBounds();
}
```
Lastly, don't forget to free resources when the process is done, remember that the native collections are not managed.
```
private void OnDestroy()
{
vertices.Dispose();
normals.Dispose();
}
```
References.
> Unity Manual: C# Job System
> Unite Europe 2017 - C# job system & compiler
> Unite Austin 2017 - Writing High Performance C# Scripts