Skip to content

Instantly share code, notes, and snippets.

@shanecelis
Created April 3, 2022 06:49
Show Gist options
  • Save shanecelis/e40050f7f08d70bb8fa1aeffcb44f61e to your computer and use it in GitHub Desktop.
Save shanecelis/e40050f7f08d70bb8fa1aeffcb44f61e to your computer and use it in GitHub Desktop.
Not intended for real distribution. Just enabling a twitter discussion.
using System;
using System.Collections.Generic;
using Nito.Disposables;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Rendering;
using static Unity.Mathematics.math;
namespace SeawispHunter.Buoyancy.DOTS {
#if ! DISABLE_BURST
[BurstCompile]
#endif
// https://gist.github.com/aras-p/4af04b9c9c1fe1180a0a645d499ad430
public struct SurfaceMeshProcessor : IJobParallelFor, IDisposable {
[ReadOnly] public float3 planePosition;
[ReadOnly] public float3 planeNormal;
[ReadOnly] public NativeArray<Mesh.MeshData> meshDatas;
[ReadOnly] public NativeArray<int> vertexCount;
[ReadOnly] public NativeArray<uint> triCount;
[ReadOnly] public NativeArray<float4x4> xforms;
[NativeDisableParallelForRestriction] public NativeArrayOfArrays<float3> outputCentroids;
[NativeDisableParallelForRestriction] public NativeArrayOfArrays<float> outputAreas;
[NativeDisableParallelForRestriction] public NativeArrayOfArrays<float3> outputNormals;
public enum Calculate {
TriangleStatistics,
}
public Calculate calculate;
public SurfaceMeshProcessor(IList<MeshFilter> meshFilters, out IDisposable cleanUp, Allocator allocator) {
planeNormal = float3(0, 1, 0);
planePosition = 0;
int count = meshFilters.Count;
calculate = Calculate.TriangleStatistics;
var options = NativeArrayOptions.UninitializedMemory;
meshDatas = new NativeArray<Mesh.MeshData>(count, allocator, options);
vertexCount = new NativeArray<int>(count, allocator, options);
triCount = new NativeArray<uint>(count, allocator, options);
xforms = new NativeArray<float4x4>(count, allocator, options);
var meshArrays = new List<IDisposable>(count);
var counts = new List<int>();
for (int i = 0; i < count; i++) {
var mesh = meshFilters[i].sharedMesh;
// using (var meshDataArray = Mesh.AcquireReadOnlyMeshData(mesh))
var meshDataArray = Mesh.AcquireReadOnlyMeshData(mesh);
// We must dispose of the array but we can't keep a handle to it here.
meshArrays.Add(meshDataArray);
meshDatas[i] = meshDataArray[0];
xforms[i] = meshFilters[i].transform.localToWorldMatrix;
vertexCount[i] = mesh.vertexCount;
triCount[i] = mesh.GetIndexCount(0);
counts.Add((int) triCount[i]);
}
outputCentroids = new NativeArrayOfArrays<float3>(counts, allocator, options);
outputAreas = new NativeArrayOfArrays<float>(counts, allocator, options);
outputNormals = new NativeArrayOfArrays<float3>(counts, allocator, options);
// Little problem here. We can't keep the meshDataArray directly.
// cleanUp = new Disposable(() => {foreach (var d in meshArrays) d.Dispose(); });
cleanUp = new CollectionDisposable(meshArrays);
}
public void Execute(int index) {
var vCount = vertexCount[index];
if (vCount == 0)
return;
var mat = xforms[index];
var vdata = meshDatas[index];
var verts = new NativeArray<float3>(vCount,
Allocator.Temp,
NativeArrayOptions.UninitializedMemory);
vdata.GetVertices(verts.Reinterpret<Vector3>());
var normals = new NativeArray<float3>(vCount,
Allocator.Temp,
NativeArrayOptions.UninitializedMemory);
vdata.GetNormals(normals.Reinterpret<Vector3>());
var tCount = triCount[index];
float3 centroid = 0f;
float volume = 0f;
var _outputCentroids = outputCentroids[index];
var _outputAreas = outputAreas[index];
var _outputNormals = outputNormals[index];
if (vdata.indexFormat == IndexFormat.UInt16) {
var tris = vdata.GetIndexData<ushort>();
for (var i = 0; i < tCount; i += 3) {
float3 a = math.mul(mat, float4(verts[tris[i + 0]], 1)).xyz;
float3 b = math.mul(mat, float4(verts[tris[i + 1]], 1)).xyz;
float3 c = math.mul(mat, float4(verts[tris[i + 2]], 1)).xyz;
_outputCentroids[i] = (a + b + c) / 3f;
_outputAreas[i] = length(cross(b - a, c - a)) / 2f;
float3 n0 = math.mul(mat, float4(normals[tris[i + 0]], 0)).xyz;
float3 n1 = math.mul(mat, float4(normals[tris[i + 1]], 0)).xyz;
float3 n2 = math.mul(mat, float4(normals[tris[i + 2]], 0)).xyz;
float3 n = (n0 + n1 + n2) / 3f;
_outputNormals[i] = n;
}
} else {
var tris = vdata.GetIndexData<int>();
for (var i = 0; i < tCount; i += 3) {
float3 a = math.mul(mat, float4(verts[tris[i + 0]], 1)).xyz;
float3 b = math.mul(mat, float4(verts[tris[i + 1]], 1)).xyz;
float3 c = math.mul(mat, float4(verts[tris[i + 2]], 1)).xyz;
_outputCentroids[i] = (a + b + c) / 3f;
_outputAreas[i] = length(cross(b - a, c - a)) / 2f;
float3 n0 = math.mul(mat, float4(normals[tris[i + 0]], 0)).xyz;
float3 n1 = math.mul(mat, float4(normals[tris[i + 1]], 0)).xyz;
float3 n2 = math.mul(mat, float4(normals[tris[i + 2]], 0)).xyz;
float3 n = (n0 + n1 + n2) / 3f;
_outputNormals[i] = n;
}
}
verts.Dispose();
}
public void Dispose() {
if (meshDatas.IsCreated)
meshDatas.Dispose();
if (vertexCount.IsCreated)
vertexCount.Dispose();
if (xforms.IsCreated)
xforms.Dispose();
if (triCount.IsCreated)
triCount.Dispose();
if (outputCentroids.IsCreated)
outputCentroids.Dispose();
if (outputAreas.IsCreated)
outputAreas.Dispose();
if (outputNormals.IsCreated)
outputNormals.Dispose();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment