Article

Published 8 months ago
322
0

# 访问代码

https://github.com/itsKristin/Jobified-Meshdeformation

# DeformableMesh.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Collections;
using Unity.Jobs;

[RequireComponent(typeof(MeshFilter),(typeof(MeshRenderer)))]
public class DeformableMesh : MonoBehaviour
{
[SerializeField] float verticalSize;
[SerializeField] float horizontalSize;

[SerializeField] Material meshMaterial;

[SerializeField] float force;

Mesh mesh;
MeshFilter meshFilter;
MeshRenderer meshRenderer;
MeshCollider meshCollider;

//网格信息
Vector3[] vertices;
Vector3[] modifiedVertices;
int[] triangles;

Vector2 verticeAmount;

void Awake()
{
meshRenderer = GetComponent<MeshRenderer>();
meshFilter = GetComponent<MeshFilter>();
meshFilter.mesh = new Mesh();
mesh = meshFilter.mesh;
GeneratePlane();
}

/*网格是由顶点和三角形构建的，基本上由其中的三个顶点构建。我们首先处理顶点的位置。

void GeneratePlane()
{
vertices = new Vector3[((int)horizontalSize + 1) *
((int)verticalSize + 1)];
Vector2[] uv = new Vector2[vertices.Length];

/*现在使用嵌套的for循环相应地定位顶点*/
for(int z = 0, y = 0; y <= (int)verticalSize; y++)
{
for(int x = 0; x <= (int)horizontalSize; x++, z++)
{
vertices[z] = new Vector3(x,0,y);
uv[z] = new Vector2(x/(int)horizontalSize,
y/(int)verticalSize);
}
}

/*我们已经生成并定位了顶点，应该开始生成合适的网格。

mesh.vertices = vertices;

/*我们还需要确保我们的顶点和修改的顶点在一开始就相互匹配*/
modifiedVertices = new Vector3[vertices.Length];
for(int i = 0; i < vertices.Length; i++)
{
modifiedVertices[i] = vertices[i];
}
mesh.uv = uv;

/*网格此时还不会出现，因为它没有任何三角形。我们会通过循环构成三角形的点来生成三角形，这些三角形的标签会进入int类型的triangles数组中*/
triangles = new int[(int)horizontalSize *
(int)verticalSize * 6];

for(int t = 0, v = 0, y = 0; y < (int)verticalSize; y++, v++)
{
for(int x = 0; x <(int)horizontalSize; x++, t+= 6, v++)
{
triangles[t] = v;
triangles[t + 3] = triangles[t + 2] = v + 1;
triangles[t + 4] = triangles[t + 1] = v + (int)horizontalSize + 1;
triangles[t + 5] = v + (int)horizontalSize + 2;
}
}

/*最后，我们需要将三角形指定为网格三角形，然后重新计算法线，确保得到正确的光照效果*/
mesh.triangles = triangles;
mesh.RecalculateNormals();
mesh.RecalculateBounds();
mesh.RecalculateTangents();

/*我们还需要碰撞体，从而能够使用物理系统检测交互*/
meshCollider.sharedMesh = mesh;

//我们需要设置网格材质，以避免出现难看的红色平面
meshRenderer.material = meshMaterial;
}

void OnCollisionEnter(Collision other) {
if(other.contacts.Length > 0)
{
Vector3[] contactPoints = new Vector3[other.contacts.Length];
for(int i = 0; i < other.contacts.Length; i++)
{
Vector3 currentContactpoint = other.contacts[i].point;
currentContactpoint = transform.InverseTransformPoint(currentContactpoint);
contactPoints[i] = currentContactpoint;
}
IndentSnow(force,contactPoints);
}
}

{
StartCoroutine(MarkHitpointDebug(inputPoint));
}

IEnumerator MarkHitpointDebug(Vector3 point)
{
GameObject marker = GameObject.CreatePrimitive(PrimitiveType.Sphere);
marker.transform.position = point;
yield return new WaitForSeconds(0.5f);
Destroy(marker);
}

public void IndentSnow(float force, Vector3[] worldPositions)
{
NativeArray<Vector3> contactpoints = new NativeArray<Vector3>
(worldPositions, Allocator.TempJob);
NativeArray<Vector3> initialVerts = new NativeArray<Vector3>
(vertices, Allocator.TempJob);
NativeArray<Vector3> modifiedVerts = new NativeArray<Vector3>
(modifiedVertices, Allocator.TempJob);
IndentationJob meshIndentationJob = new IndentationJob
{
contactPoints = contactpoints,
initialVertices = initialVerts,
modifiedVertices = modifiedVerts,
force = force,
};

JobHandle indentationJobhandle = meshIndentationJob.Schedule(initialVerts.Length,initialVerts.Length);
indentationJobhandle.Complete();
contactpoints.Dispose();
initialVerts.Dispose();
modifiedVerts.CopyTo(modifiedVertices);
modifiedVerts.Dispose();

mesh.vertices = modifiedVertices;
vertices = mesh.vertices;
mesh.RecalculateNormals();
}

void IndentSnow(float force, Vector3[] worldPositions,ref HandledResult newHandledResult)
{

newHandledResult.contactpoints = new NativeArray<Vector3>
(worldPositions, Allocator.TempJob);
newHandledResult.initialVerts = new NativeArray<Vector3>
(vertices, Allocator.TempJob);
newHandledResult.modifiedVerts = new NativeArray<Vector3>
(modifiedVertices, Allocator.TempJob);
IndentationJob meshIndentationJob = new IndentationJob
{
contactPoints = newHandledResult.contactpoints,
initialVertices = newHandledResult.initialVerts,
modifiedVertices = newHandledResult.modifiedVerts,
force = force,
};

JobHandle indentationJobhandle = meshIndentationJob.Schedule(newHandledResult.initialVerts.Length,newHandledResult.initialVerts.Length);
newHandledResult.jobHandle = indentationJobhandle;

}

void CompleteJob(HandledResult handle)
{
scheduledJobs.Remove(handle);

handle.jobHandle.Complete();
handle.contactpoints.Dispose();
handle.initialVerts.Dispose();
handle.modifiedVerts.CopyTo(modifiedVertices);
handle.modifiedVerts.Dispose();

mesh.vertices = modifiedVertices;
vertices = mesh.vertices;
mesh.RecalculateNormals();
}
}

struct HandledResult
{
public JobHandle jobHandle;
public NativeArray<Vector3> contactpoints;
public NativeArray<Vector3> initialVerts;
public NativeArray<Vector3> modifiedVerts;
}

# IndentationJob.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Collections;
using Unity.Jobs;

public struct IndentationJob : IJobParallelFor {

public NativeArray<Vector3> contactPoints;
public NativeArray<Vector3> initialVertices;
public NativeArray<Vector3> modifiedVertices;

public float force;

public void Execute(int i)
{
for(int c = 0; c < contactPoints.Length; c++)
{
Vector3 pointToVert = (modifiedVertices[i] - contactPoints[c]);
float distance = pointToVert.sqrMagnitude;

{
Vector3 newVertice = initialVertices[i] + Vector3.down * (force);
modifiedVertices[i] = newVertice;
}
}
}
}

Unity China
576