This commit is contained in:
CortexCore
2024-03-18 18:20:23 +08:00
parent a87aa47882
commit 8acd61ea57
412 changed files with 1799371 additions and 31676 deletions

View File

@@ -0,0 +1,472 @@
// Magica Cloth 2.
// Copyright (c) 2023 MagicaSoft.
// https://magicasoft.jp
using System.Runtime.CompilerServices;
using System.Threading;
using Unity.Burst;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using Unity.Mathematics;
namespace MagicaCloth2
{
/// <summary>
/// Nativeバッファへのインターロック書き込み制御関連
/// </summary>
public static class InterlockUtility
{
/// <summary>
/// 固定小数点への変換倍率
/// </summary>
const int ToFixed = 100000;
/// <summary>
/// 少数への復元倍率
/// </summary>
const float ToFloat = 0.00001f;
//=========================================================================================
/// <summary>
/// 集計バッファの指定インデックスにfloat3を固定小数点として加算しカウンタをインクリメントする
/// </summary>
/// <param name="index"></param>
/// <param name="add"></param>
/// <param name="cntPt"></param>
/// <param name="sumPt"></param>
unsafe internal static void AddFloat3(int index, float3 add, int* cntPt, int* sumPt)
{
Interlocked.Increment(ref cntPt[index]);
int3 iadd = (int3)(add * ToFixed);
//Debug.Log($"InterlockAdd [{index}]:{iadd}");
index *= 3;
for (int i = 0; i < 3; i++, index++)
{
if (iadd[i] != 0)
Interlocked.Add(ref sumPt[index], iadd[i]);
}
}
/// <summary>
/// 集計バッファの指定インデックスにfloat3を固定小数点として加算するカウントは操作しない
/// </summary>
/// <param name="index"></param>
/// <param name="add"></param>
/// <param name="sumPt"></param>
unsafe internal static void AddFloat3(int index, float3 add, int* sumPt)
{
int3 iadd = (int3)(add * ToFixed);
index *= 3;
for (int i = 0; i < 3; i++, index++)
{
if (iadd[i] != 0)
Interlocked.Add(ref sumPt[index], iadd[i]);
}
}
/// <summary>
/// 集計バッファのカウンタのみインクリメントする
/// </summary>
/// <param name="index"></param>
/// <param name="cntPt"></param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
unsafe internal static void Increment(int index, int* cntPt)
{
Interlocked.Increment(ref cntPt[index]);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
unsafe internal static void Max(int index, float value, int* pt)
{
int ival = (int)value * ToFixed;
int now = pt[index];
int oldNow = now + 1;
while (ival > now && now != oldNow)
{
oldNow = now;
now = Interlocked.CompareExchange(ref pt[index], ival, now);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static float3 ReadAverageFloat3(int index, in NativeArray<int> countArray, in NativeArray<int> sumArray)
{
int count = countArray[index];
if (count == 0)
return 0;
int dataIndex = index * 3;
// 集計
float3 add = new float3(sumArray[dataIndex], sumArray[dataIndex + 1], sumArray[dataIndex + 2]);
add /= count;
// データは固定小数点なので戻す
add *= ToFloat;
return add;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static float3 ReadFloat3(int index, in NativeArray<int> bufferArray)
{
int dataIndex = index * 3;
float3 v = new float3(bufferArray[dataIndex], bufferArray[dataIndex + 1], bufferArray[dataIndex + 2]);
// データは固定小数点なので戻す
v *= ToFloat;
return v;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static float ReadFloat(int index, in NativeArray<int> bufferArray)
{
return bufferArray[index] * ToFloat;
}
#if false
/// <summary>
/// 指定アドレスにfloat値を加算する
/// </summary>
/// <param name="pt"></param>
/// <param name="index"></param>
/// <param name="value"></param>
unsafe public static void AddFloat(int* pt, int index, float value)
{
float current = UnsafeUtility.ReadArrayElement<float>(pt, index);
int currenti = math.asint(current);
while (true)
{
float next = current + value;
int nexti = math.asint(next);
int prev = Interlocked.CompareExchange(ref pt[index], nexti, currenti);
if (prev == currenti)
return;
else
{
currenti = prev;
current = math.asfloat(prev);
}
}
}
#endif
//=========================================================================================
/// <summary>
/// 加算集計バッファを平均化してnextPosに加算する
/// </summary>
/// <param name="particleList"></param>
/// <param name="jobHandle"></param>
/// <returns></returns>
internal static JobHandle SolveAggregateBufferAndClear(in NativeList<int> particleList, float velocityAttenuation, JobHandle jobHandle)
{
var sm = MagicaManager.Simulation;
if (velocityAttenuation > 1e-06f)
{
// 速度影響あり
var job = new AggregateWithVelocityJob()
{
jobParticleIndexList = particleList,
nextPosArray = sm.nextPosArray.GetNativeArray(),
velocityPosArray = sm.velocityPosArray.GetNativeArray(),
velocityAttenuation = velocityAttenuation,
countArray = sm.countArray,
sumArray = sm.sumArray,
};
jobHandle = job.Schedule(particleList, 16, jobHandle);
}
else
{
// 速度影響なし
var job = new AggregateJob()
{
//velocityLimit = velocityLimit,
jobParticleIndexList = particleList,
nextPosArray = sm.nextPosArray.GetNativeArray(),
countArray = sm.countArray,
sumArray = sm.sumArray,
};
jobHandle = job.Schedule(particleList, 16, jobHandle);
}
return jobHandle;
}
[BurstCompile]
struct AggregateJob : IJobParallelForDefer
{
// 速度制限
//public float velocityLimit;
[Unity.Collections.ReadOnly]
public NativeList<int> jobParticleIndexList;
// particle
[NativeDisableParallelForRestriction]
public NativeArray<float3> nextPosArray;
// aggregate
[NativeDisableParallelForRestriction]
public NativeArray<int> countArray;
[NativeDisableParallelForRestriction]
public NativeArray<int> sumArray;
// 集計パーティクルごと
public void Execute(int index)
{
int pindex = jobParticleIndexList[index];
int count = countArray[pindex];
if (count == 0)
return;
int dataIndex = pindex * 3;
// 集計
float3 add = new float3(sumArray[dataIndex], sumArray[dataIndex + 1], sumArray[dataIndex + 2]);
add /= count;
// データは固定小数点なので戻す
add *= ToFloat;
// 速度制限
//add = MathUtility.ClampVector(add, velocityLimit);
// 書き出し
nextPosArray[pindex] = nextPosArray[pindex] + add;
// 集計バッファクリア
countArray[pindex] = 0;
sumArray[dataIndex] = 0;
sumArray[dataIndex + 1] = 0;
sumArray[dataIndex + 2] = 0;
}
}
/// <summary>
/// 速度影響あり
/// </summary>
[BurstCompile]
struct AggregateWithVelocityJob : IJobParallelForDefer
{
[Unity.Collections.ReadOnly]
public NativeList<int> jobParticleIndexList;
// particle
[NativeDisableParallelForRestriction]
public NativeArray<float3> nextPosArray;
[NativeDisableParallelForRestriction]
public NativeArray<float3> velocityPosArray;
// aggregate
public float velocityAttenuation;
[NativeDisableParallelForRestriction]
public NativeArray<int> countArray;
[NativeDisableParallelForRestriction]
public NativeArray<int> sumArray;
// 集計パーティクルごと
public void Execute(int index)
{
int pindex = jobParticleIndexList[index];
int count = countArray[pindex];
if (count == 0)
return;
int dataIndex = pindex * 3;
// 集計
float3 add = new float3(sumArray[dataIndex], sumArray[dataIndex + 1], sumArray[dataIndex + 2]);
add /= count;
// データは固定小数点なので戻す
add *= ToFloat;
// 書き出し
nextPosArray[pindex] = nextPosArray[pindex] + add;
// 速度影響
velocityPosArray[pindex] = velocityPosArray[pindex] + add * velocityAttenuation;
// 集計バッファクリア
countArray[pindex] = 0;
sumArray[dataIndex] = 0;
sumArray[dataIndex + 1] = 0;
sumArray[dataIndex + 2] = 0;
}
}
internal static JobHandle SolveAggregateBufferAndClear(in ExProcessingList<int> processingList, float velocityAttenuation, JobHandle jobHandle)
{
return SolveAggregateBufferAndClear(processingList.Buffer, processingList.Counter, velocityAttenuation, jobHandle);
}
unsafe internal static JobHandle SolveAggregateBufferAndClear(in NativeArray<int> particleArray, in NativeReference<int> counter, float velocityAttenuation, JobHandle jobHandle)
{
var sm = MagicaManager.Simulation;
if (velocityAttenuation > 1e-06f)
{
// 速度影響あり
var job = new AggregateWithVelocityJob2()
{
particleIndexArray = particleArray,
nextPosArray = sm.nextPosArray.GetNativeArray(),
velocityPosArray = sm.velocityPosArray.GetNativeArray(),
velocityAttenuation = velocityAttenuation,
countArray = sm.countArray,
sumArray = sm.sumArray,
};
jobHandle = job.Schedule((int*)counter.GetUnsafePtrWithoutChecks(), 16, jobHandle);
}
else
{
// 速度影響なし
var job = new AggregateJob2()
{
//velocityLimit = velocityLimit,
particleIndexArray = particleArray,
nextPosArray = sm.nextPosArray.GetNativeArray(),
countArray = sm.countArray,
sumArray = sm.sumArray,
};
jobHandle = job.Schedule((int*)counter.GetUnsafePtrWithoutChecks(), 16, jobHandle);
}
return jobHandle;
}
[BurstCompile]
struct AggregateJob2 : IJobParallelForDefer
{
// 速度制限
//public float velocityLimit;
[Unity.Collections.ReadOnly]
public NativeArray<int> particleIndexArray;
// particle
[NativeDisableParallelForRestriction]
public NativeArray<float3> nextPosArray;
// aggregate
[NativeDisableParallelForRestriction]
public NativeArray<int> countArray;
[NativeDisableParallelForRestriction]
public NativeArray<int> sumArray;
// 集計パーティクルごと
public void Execute(int index)
{
int pindex = particleIndexArray[index];
int count = countArray[pindex];
if (count == 0)
return;
int dataIndex = pindex * 3;
// 集計
float3 add = new float3(sumArray[dataIndex], sumArray[dataIndex + 1], sumArray[dataIndex + 2]);
add /= count;
// データは固定小数点なので戻す
add *= ToFloat;
// 速度制限
//add = MathUtility.ClampVector(add, velocityLimit);
// 書き出し
nextPosArray[pindex] = nextPosArray[pindex] + add;
// 集計バッファクリア
countArray[pindex] = 0;
sumArray[dataIndex] = 0;
sumArray[dataIndex + 1] = 0;
sumArray[dataIndex + 2] = 0;
}
}
/// <summary>
/// 速度影響あり
/// </summary>
[BurstCompile]
struct AggregateWithVelocityJob2 : IJobParallelForDefer
{
[Unity.Collections.ReadOnly]
public NativeArray<int> particleIndexArray;
// particle
[NativeDisableParallelForRestriction]
public NativeArray<float3> nextPosArray;
[NativeDisableParallelForRestriction]
public NativeArray<float3> velocityPosArray;
// aggregate
public float velocityAttenuation;
[NativeDisableParallelForRestriction]
public NativeArray<int> countArray;
[NativeDisableParallelForRestriction]
public NativeArray<int> sumArray;
// 集計パーティクルごと
public void Execute(int index)
{
int pindex = particleIndexArray[index];
int count = countArray[pindex];
if (count == 0)
return;
int dataIndex = pindex * 3;
// 集計
float3 add = new float3(sumArray[dataIndex], sumArray[dataIndex + 1], sumArray[dataIndex + 2]);
add /= count;
// データは固定小数点なので戻す
add *= ToFloat;
// 書き出し
nextPosArray[pindex] = nextPosArray[pindex] + add;
// 速度影響
velocityPosArray[pindex] = velocityPosArray[pindex] + add * velocityAttenuation;
// 集計バッファクリア
countArray[pindex] = 0;
sumArray[dataIndex] = 0;
sumArray[dataIndex + 1] = 0;
sumArray[dataIndex + 2] = 0;
}
}
/// <summary>
/// 集計バッファのカウンタのみゼロクリアする
/// </summary>
/// <param name="jobHandle"></param>
/// <returns></returns>
internal static JobHandle ClearCountArray(JobHandle jobHandle)
{
var sm = MagicaManager.Simulation;
return JobUtility.Fill(sm.countArray, sm.countArray.Length, 0, jobHandle);
}
}
}

View File

@@ -0,0 +1,717 @@
// Magica Cloth 2.
// Copyright (c) 2023 MagicaSoft.
// https://magicasoft.jp
using System;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;
namespace MagicaCloth2
{
public static class JobUtility
{
//=========================================================================================
/// <summary>
/// 配列をValueで埋めるジョブを発行します
/// ジェネリック型ジョブは明示的に型を<T>で指定する必要があるため型ごとに関数が発生します
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="array"></param>
/// <param name="length"></param>
/// <param name="value"></param>
/// <param name="dependsOn"></param>
/// <returns></returns>
public static JobHandle Fill(NativeArray<int> array, int length, int value, JobHandle dependsOn = new JobHandle())
{
var job = new FillJob<int>() { value = value, array = array, };
return job.Schedule(length, 32, dependsOn);
}
public static JobHandle Fill(NativeArray<Vector4> array, int length, Vector4 value, JobHandle dependsOn = new JobHandle())
{
var job = new FillJob<Vector4>() { value = value, array = array, };
return job.Schedule(length, 32, dependsOn);
}
public static JobHandle Fill(NativeArray<VirtualMeshBoneWeight> array, int length, VirtualMeshBoneWeight value, JobHandle dependsOn = new JobHandle())
{
var job = new FillJob<VirtualMeshBoneWeight>() { value = value, array = array, };
return job.Schedule(length, 32, dependsOn);
}
public static JobHandle Fill(NativeArray<byte> array, int length, byte value, JobHandle dependsOn = new JobHandle())
{
var job = new FillJob<byte>() { value = value, array = array, };
return job.Schedule(length, 32, dependsOn);
}
public static void FillRun(NativeArray<int> array, int length, int value)
{
var job = new FillJob<int>() { value = value, array = array, };
job.Run(length);
}
public static void FillRun(NativeArray<Vector4> array, int length, Vector4 value)
{
var job = new FillJob<Vector4>() { value = value, array = array, };
job.Run(length);
}
public static void FillRun(NativeArray<quaternion> array, int length, quaternion value)
{
var job = new FillJob<quaternion>() { value = value, array = array, };
job.Run(length);
}
public static void FillRun(NativeArray<VirtualMeshBoneWeight> array, int length, VirtualMeshBoneWeight value)
{
var job = new FillJob<VirtualMeshBoneWeight>() { value = value, array = array, };
job.Run(length);
}
[BurstCompile]
struct FillJob<T> : IJobParallelFor where T : unmanaged
{
public T value;
[Unity.Collections.WriteOnly]
public NativeArray<T> array;
public void Execute(int index)
{
array[index] = value;
}
}
/// <summary>
/// 配列をValueで埋めるジョブを発行します(startIndexあり)
/// ジェネリック型ジョブは明示的に型を<T>で指定する必要があるため型ごとに関数が発生します
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="array"></param>
/// <param name="startIndex"></param>
/// <param name="length"></param>
/// <param name="value"></param>
/// <param name="dependsOn"></param>
/// <returns></returns>
public static JobHandle Fill(NativeArray<int> array, int startIndex, int length, int value, JobHandle dependsOn = new JobHandle())
{
var job = new FillJob2<int>() { value = value, startIndex = startIndex, array = array, };
return job.Schedule(length, 32, dependsOn);
}
[BurstCompile]
struct FillJob2<T> : IJobParallelFor where T : unmanaged
{
public T value;
public int startIndex;
[NativeDisableParallelForRestriction]
[Unity.Collections.WriteOnly]
public NativeArray<T> array;
public void Execute(int index)
{
array[startIndex + index] = value;
}
}
public static JobHandle Fill(NativeReference<int> reference, int value, JobHandle dependsOn = new JobHandle())
{
var job = new FillRefJob<int>() { value = value, reference = reference, };
return job.Schedule(dependsOn);
}
[BurstCompile]
struct FillRefJob<T> : IJob where T : unmanaged
{
public T value;
[Unity.Collections.WriteOnly]
public NativeReference<T> reference;
public void Execute()
{
reference.Value = value;
}
}
//=========================================================================================
/// <summary>
/// 配列に連番を格納するジョブを発行します
/// </summary>
/// <param name="array"></param>
/// <param name="length"></param>
/// <param name="dependsOn"></param>
/// <returns></returns>
public static JobHandle SerialNumber(NativeArray<int> array, int length, JobHandle dependsOn = new JobHandle())
{
var job = new SerialNumberJob()
{
array = array,
};
return job.Schedule(length, 32, dependsOn);
}
public static void SerialNumberRun(NativeArray<int> array, int length)
{
var job = new SerialNumberJob()
{
array = array,
};
job.Run(length);
}
[BurstCompile]
struct SerialNumberJob : IJobParallelFor
{
[Unity.Collections.WriteOnly]
public NativeArray<int> array;
public void Execute(int index)
{
array[index] = index;
}
}
//=========================================================================================
/// <summary>
/// NativeHashSetのキーをNativeListに変換するジョブを発行します
/// ジェネリック型ジョブは明示的に型を<T>で指定する必要があるため型ごとに関数が発生します
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="hashSet"></param>
/// <param name="list"></param>
/// <param name="dependsOn"></param>
/// <returns></returns>
public static JobHandle ConvertHashSetToNativeList(NativeParallelHashSet<int> hashSet, NativeList<int> list, JobHandle dependsOn = new JobHandle())
{
var job = new ConvertHashSetToListJob<int>() { hashSet = hashSet, list = list, };
return job.Schedule(dependsOn);
}
[BurstCompile]
struct ConvertHashSetToListJob<T> : IJob where T : unmanaged, IEquatable<T>
{
[Unity.Collections.ReadOnly]
public NativeParallelHashSet<T> hashSet;
[Unity.Collections.WriteOnly]
public NativeList<T> list;
public void Execute()
{
foreach (var key in hashSet)
{
list.AddNoResize(key);
}
}
}
//=========================================================================================
#if false
/// <summary>
/// NativeMultiHashMapのキーをNativeListに変換するジョブを発行する
/// ジェネリック型ジョブは明示的に型を<T>で指定する必要があるため型ごとに関数が発生します
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="U"></typeparam>
/// <param name="hashMap"></param>
/// <param name="keyList"></param>
/// <param name="dependsOn"></param>
/// <returns></returns>
public static JobHandle ConvertMultiHashMapKeyToNativeList(
NativeParallelMultiHashMap<int2, int> hashMap,
NativeList<int2> keyList,
JobHandle dependsOn = new JobHandle())
{
// todo:この処理は重い
var job = new ConvertMultiHashMapKeyToListJob<int2, int>()
{
hashMap = hashMap,
list = keyList,
};
return job.Schedule(dependsOn);
}
[BurstCompile]
struct ConvertMultiHashMapKeyToListJob<T, U> : IJob where T : unmanaged, IEquatable<T> where U : unmanaged
{
[Unity.Collections.ReadOnly]
public NativeParallelMultiHashMap<T, U> hashMap;
[Unity.Collections.WriteOnly]
public NativeList<T> list;
public void Execute()
{
var keySet = new NativeParallelHashSet<T>(hashMap.Count(), Allocator.Temp); // ここが問題となる可能性がある(unity2023.1.5事件)
var keyArray = hashMap.GetKeyArray(Allocator.Temp); // ここが問題となる可能性がある(unity2023.1.5事件)
// GetKeyArray()の結果はキーが重複しまた順不同なので注意!
for (int i = 0; i < keyArray.Length; i++)
keySet.Add(keyArray[i]);
foreach (var key in keySet)
list.Add(key);
}
}
#endif
//=========================================================================================
/// <summary>
/// NativeHashSetの内容をNativeListに変換するジョブを発行する
/// ジェネリック型ジョブは明示的に型を<T>で指定する必要があるため型ごとに関数が発生します
/// </summary>
/// <param name="hashSet"></param>
/// <param name="keyList"></param>
/// <param name="dependsOn"></param>
/// <returns></returns>
public static JobHandle ConvertHashSetKeyToNativeList(
NativeParallelHashSet<int2> hashSet,
NativeList<int2> keyList,
JobHandle dependsOn = new JobHandle())
{
var job = new ConvertHashSetKeyToListJob<int2>() { hashSet = hashSet, list = keyList, };
return job.Schedule(dependsOn);
}
public static JobHandle ConvertHashSetKeyToNativeList(
NativeParallelHashSet<int4> hashSet,
NativeList<int4> keyList,
JobHandle dependsOn = new JobHandle())
{
var job = new ConvertHashSetKeyToListJob<int4>() { hashSet = hashSet, list = keyList, };
return job.Schedule(dependsOn);
}
[BurstCompile]
struct ConvertHashSetKeyToListJob<T> : IJob where T : unmanaged, IEquatable<T>
{
[Unity.Collections.ReadOnly]
public NativeParallelHashSet<T> hashSet;
[Unity.Collections.WriteOnly]
public NativeList<T> list;
public void Execute()
{
// 順不同なので注意!
foreach (var key in hashSet)
list.Add(key);
}
}
//=========================================================================================
/// <summary>
/// AABBを計算して返すジョブを発行する(NativeArray)
/// </summary>
/// <param name="positions"></param>
/// <param name="length"></param>
/// <param name="outAABB"></param>
/// <param name="dependsOn"></param>
/// <returns></returns>
public static JobHandle CalcAABB(NativeArray<float3> positions, int length, NativeReference<AABB> outAABB, JobHandle dependsOn = new JobHandle())
{
var job = new CalcAABBJob()
{
length = length,
positions = positions,
outAABB = outAABB,
};
return job.Schedule(dependsOn);
}
public static void CalcAABBRun(NativeArray<float3> positions, int length, NativeReference<AABB> outAABB)
{
var job = new CalcAABBJob()
{
length = length,
positions = positions,
outAABB = outAABB,
};
job.Run();
}
/// <summary>
/// AABBを計算して返すジョブを発行する(NativeList)
/// </summary>
/// <param name="positions"></param>
/// <param name="outAABB"></param>
/// <param name="dependsOn"></param>
/// <returns></returns>
public static JobHandle CalcAABB(NativeList<float3> positions, NativeReference<AABB> outAABB, JobHandle dependsOn = new JobHandle())
{
var job = new CalcAABBDeferJob()
{
positions = positions,
outAABB = outAABB,
};
return job.Schedule(dependsOn);
}
public static void CalcAABBRun(NativeList<float3> positions, NativeReference<AABB> outAABB)
{
var job = new CalcAABBDeferJob()
{
positions = positions,
outAABB = outAABB,
};
job.Run();
}
[BurstCompile]
struct CalcAABBJob : IJob
{
public int length;
[Unity.Collections.ReadOnly]
public NativeArray<float3> positions;
public NativeReference<AABB> outAABB;
public void Execute()
{
outAABB.Value = CalcAABBInternal(positions, length);
}
}
[BurstCompile]
struct CalcAABBDeferJob : IJob
{
[Unity.Collections.ReadOnly]
public NativeList<float3> positions;
public NativeReference<AABB> outAABB;
public void Execute()
{
outAABB.Value = CalcAABBInternal(positions.AsArray(), positions.Length);
}
}
static AABB CalcAABBInternal(in NativeArray<float3> positions, int length)
{
if (positions.Length == 0)
{
return new AABB();
}
//float3 min = 0;
//float3 max = 0;
float3 min = float.MaxValue;
float3 max = float.MinValue;
for (int i = 0; i < length; i++)
{
float3 pos = positions[i];
min = math.min(min, pos);
max = math.max(max, pos);
}
var aabb = new AABB(min, max);
return aabb;
}
//=========================================================================================
/// <summary>
/// スフィアマッピングを行いUVを算出するジョブを発行する
/// このUVは接線計算用でありテクスチャ用ではないので注意
/// </summary>
/// <param name="positions"></param>
/// <param name="length"></param>
/// <param name="aabb"></param>
/// <param name="outUVs"></param>
/// <param name="dependsOn"></param>
/// <returns></returns>
public static JobHandle CalcUVWithSphereMapping(NativeArray<float3> positions, int length, NativeReference<AABB> aabb, NativeArray<float2> outUVs, JobHandle dependsOn = new JobHandle())
{
var job = new CalcUVJob()
{
positions = positions,
aabb = aabb,
uvs = outUVs,
};
return job.Schedule(length, 32, dependsOn);
}
public static void CalcUVWithSphereMappingRun(NativeArray<float3> positions, int length, NativeReference<AABB> aabb, NativeArray<float2> outUVs)
{
var job = new CalcUVJob()
{
positions = positions,
aabb = aabb,
uvs = outUVs,
};
job.Run(length);
}
[BurstCompile]
struct CalcUVJob : IJobParallelFor
{
[Unity.Collections.ReadOnly]
public NativeArray<float3> positions;
[Unity.Collections.ReadOnly]
public NativeReference<AABB> aabb;
[Unity.Collections.WriteOnly]
public NativeArray<float2> uvs;
public void Execute(int index)
{
// 中心位置からのスフィアマッピング
float3 lv = positions[index] - aabb.Value.Center;
lv = math.normalize(lv);
float u = math.atan2(lv.x, lv.z);
u = math.clamp(math.unlerp(-math.PI, math.PI, u), 0.0f, 1.0f);
float v = math.dot(math.up(), lv);
v = math.clamp(math.unlerp(1.0f, -1.0f, v), 0.0f, 1.0f);
//float2 uv = new float2(u, v); // こちらは横方向ベースになる
float2 uv = new float2(v, u); // こちらは縦方向ベースになる
#if false
float len = math.length(lv);
float add = index * 0.001234f; // UVを微妙にずらすための加算値
uv += len * 0.01f + add;
#endif
#if false
//float len = math.length(lv);
float add = index * 0.0001234f; // UVを微妙にずらすための加算値
//uv += len * 0.1f + add;
uv += add;
#endif
#if true
// 方向ベクトル上に同じUVが生成されてしまうのを避けるためUVに距離を加算してずらす
float add = index * 0.0001234f; // UVを微妙にずらすための加算値
// 頂点間のUVの間隔を広めに取り、同じUVが発生しないようにインデックスを使い微妙に値をずらす
uv = uv * 10.0f + add;
#endif
//Debug.Log($"[{index}] {uv}");
uvs[index] = uv;
}
}
//=========================================================================================
/// <summary>
/// intデータを加算して新しい領域にコピーする
/// </summary>
[BurstCompile]
public struct AddIntDataCopyJob : IJobParallelFor
{
public int dstOffset;
public int addData;
// src
[Unity.Collections.ReadOnly]
public NativeArray<int> srcData;
// dst
[NativeDisableParallelForRestriction]
[Unity.Collections.WriteOnly]
public NativeArray<int> dstData;
public void Execute(int index)
{
int dindex = dstOffset + index;
var data = srcData[index];
data += addData;
dstData[dindex] = data;
}
}
/// <summary>
/// int2データを加算して新しい領域にコピーする
/// </summary>
[BurstCompile]
public struct AddInt2DataCopyJob : IJobParallelFor
{
public int dstOffset;
public int2 addData;
// src
[Unity.Collections.ReadOnly]
public NativeArray<int2> srcData;
// dst
[NativeDisableParallelForRestriction]
[Unity.Collections.WriteOnly]
public NativeArray<int2> dstData;
public void Execute(int index)
{
int dindex = dstOffset + index;
var data = srcData[index];
data += addData;
dstData[dindex] = data;
}
}
/// <summary>
/// int3データを加算して新しい領域にコピーする
/// </summary>
[BurstCompile]
public struct AddInt3DataCopyJob : IJobParallelFor
{
public int dstOffset;
public int3 addData;
// src
[Unity.Collections.ReadOnly]
public NativeArray<int3> srcData;
// dst
[NativeDisableParallelForRestriction]
[Unity.Collections.WriteOnly]
public NativeArray<int3> dstData;
public void Execute(int index)
{
int dindex = dstOffset + index;
var data = srcData[index];
data += addData;
dstData[dindex] = data;
}
}
//=========================================================================================
/// <summary>
/// 座標を変換するジョブを発行します
/// </summary>
/// <param name="positions"></param>
/// <param name="length"></param>
/// <param name="toM"></param>
/// <param name="dependsOn"></param>
/// <returns></returns>
public static JobHandle TransformPosition(NativeArray<float3> positions, int length, in float4x4 toM, JobHandle dependsOn = new JobHandle())
{
var job = new TransformPositionJob() { toM = toM, positions = positions, };
return job.Schedule(length, 32, dependsOn);
}
public static void TransformPositionRun(NativeArray<float3> positions, int length, in float4x4 toM)
{
var job = new TransformPositionJob() { toM = toM, positions = positions, };
job.Run(length);
}
public static JobHandle TransformPosition(NativeArray<float3> srcPositions, NativeArray<float3> dstPositions, int length, in float4x4 toM, JobHandle dependsOn = new JobHandle())
{
var job = new TransformPositionJob2() { toM = toM, srcPositions = srcPositions, dstPositions = dstPositions };
return job.Schedule(length, 32, dependsOn);
}
public static void TransformPositionRun(NativeArray<float3> srcPositions, NativeArray<float3> dstPositions, int length, in float4x4 toM)
{
var job = new TransformPositionJob2() { toM = toM, srcPositions = srcPositions, dstPositions = dstPositions };
job.Run(length);
}
[BurstCompile]
public struct TransformPositionJob : IJobParallelFor
{
public float4x4 toM;
public NativeArray<float3> positions;
public void Execute(int vindex)
{
positions[vindex] = MathUtility.TransformPoint(positions[vindex], toM);
}
}
[BurstCompile]
public struct TransformPositionJob2 : IJobParallelFor
{
public float4x4 toM;
[Unity.Collections.ReadOnly]
public NativeArray<float3> srcPositions;
[Unity.Collections.WriteOnly]
public NativeArray<float3> dstPositions;
public void Execute(int vindex)
{
dstPositions[vindex] = MathUtility.TransformPoint(srcPositions[vindex], toM);
}
}
//=========================================================================================
/// <summary>
/// スタートインデックスデータ数とデータのつの配列からHashMapを構築して返す
/// </summary>
/// <param name="indexArray"></param>
/// <param name="dataArray"></param>
/// <returns></returns>
public static NativeParallelMultiHashMap<int, ushort> ToNativeMultiHashMap(in NativeArray<uint> indexArray, in NativeArray<ushort> dataArray)
{
var map = new NativeParallelMultiHashMap<int, ushort>(dataArray.Length, Allocator.Persistent);
var job = new ConvertArrayToMapJob<ushort>()
{
indexArray = indexArray,
dataArray = dataArray,
map = map,
};
job.Run();
return map;
}
[BurstCompile]
struct ConvertArrayToMapJob<TData> : IJob where TData : unmanaged
{
[Unity.Collections.ReadOnly]
public NativeArray<uint> indexArray;
[Unity.Collections.ReadOnly]
public NativeArray<TData> dataArray;
[Unity.Collections.WriteOnly]
public NativeParallelMultiHashMap<int, TData> map;
public void Execute()
{
int cnt = indexArray.Length;
for (int i = 0; i < cnt; i++)
{
DataUtility.Unpack12_20(indexArray[i], out var dcnt, out var dstart);
for (int j = 0; j < dcnt; j++)
{
var data = dataArray[dstart + j];
map.Add(i, data);
}
}
}
}
//=========================================================================================
/// <summary>
/// NativeReferenceをクリアするジョブを発行する
/// </summary>
/// <param name="reference"></param>
/// <param name="jobHandle"></param>
/// <returns></returns>
public static JobHandle ClearReference(NativeReference<int> reference, JobHandle jobHandle)
{
var job = new ClearReferenceJob()
{
reference = reference,
};
return job.Schedule(jobHandle);
}
[BurstCompile]
struct ClearReferenceJob : IJob
{
public NativeReference<int> reference;
public void Execute()
{
reference.Value = 0;
}
}
}
}