959e80cf72
assets upload description.
558 lines
17 KiB
C#
558 lines
17 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using AwesomeTechnologies.Common;
|
|
using AwesomeTechnologies.VegetationSystem;
|
|
using Unity.Burst;
|
|
using Unity.Collections;
|
|
using Unity.Jobs;
|
|
using Unity.Mathematics;
|
|
using UnityEngine;
|
|
// ReSharper disable DelegateSubtraction
|
|
|
|
namespace AwesomeTechnologies.Utility
|
|
{
|
|
public struct ItemSelectorInstanceInfo
|
|
{
|
|
public int VegetationCellIndex;
|
|
public int VegetationCellItemIndex;
|
|
public Vector3 Position;
|
|
public Quaternion Rotation;
|
|
public Vector3 Scale;
|
|
public int Visible;
|
|
public int LastVisible;
|
|
public int Remove;
|
|
}
|
|
|
|
public class VegetationItemSelector
|
|
{
|
|
private readonly VisibleVegetationCellSelector _visibleVegetationCellSelector;
|
|
[NonSerialized]
|
|
public readonly List<VegetationCell> ReadyToLoadVegetationCellList = new List<VegetationCell>();
|
|
[NonSerialized]
|
|
public readonly List<VegetationCell> ReadyToUnloadVegetationCellList = new List<VegetationCell>();
|
|
[NonSerialized]
|
|
public readonly List<VegetationCell> LoadedVegetationCellList = new List<VegetationCell>();
|
|
public NativeList<ItemSelectorInstanceInfo> InstanceList;
|
|
|
|
public delegate void MultiOnVegetationItemVisibilityChangeDelegate(ItemSelectorInstanceInfo itemSelectorInstanceInfo,VegetationItemIndexes vegetationItemIndexes,string vegetationItemID);
|
|
public MultiOnVegetationItemVisibilityChangeDelegate OnVegetationItemVisibleDelegate;
|
|
public MultiOnVegetationItemVisibilityChangeDelegate OnVegetationItemInvisibleDelegate;
|
|
|
|
public delegate void MultiOnVegetationCellVisibilityChangeDelegate(int vegetationCellIndex);
|
|
public MultiOnVegetationCellVisibilityChangeDelegate OnVegetationCellInvisibleDelegate;
|
|
|
|
private NativeList<int> _removeVegetationCellIndexList;
|
|
private NativeList<int> _visibilityChangedIndexList;
|
|
private readonly VegetationSystemPro _vegetationSystemPro;
|
|
public readonly string VegetationItemID;
|
|
private readonly VegetationItemIndexes _vegetationItemIndexes;
|
|
public float CullingDistance = 50f;
|
|
|
|
private readonly bool _useSpawnChance;
|
|
private readonly float _spawnChance;
|
|
private readonly int _spawnSeed;
|
|
|
|
public VegetationItemSelector(VisibleVegetationCellSelector visibleVegetationCellSelector, VegetationSystemPro vegetationSystemPro, VegetationItemInfoPro vegetationItemInfoPro, bool useSpawnChance, float spawnChance, int spawnSeed)
|
|
{
|
|
_useSpawnChance = useSpawnChance;
|
|
_spawnChance = spawnChance;
|
|
_spawnSeed = spawnSeed;
|
|
|
|
_visibleVegetationCellSelector = visibleVegetationCellSelector;
|
|
_vegetationSystemPro = vegetationSystemPro;
|
|
|
|
VegetationItemID = vegetationItemInfoPro.VegetationItemID;
|
|
_vegetationItemIndexes = _vegetationSystemPro.GetVegetationItemIndexes(VegetationItemID);
|
|
|
|
_visibleVegetationCellSelector.OnVegetationCellVisibleDelegate += OnVegetationCellVisible;
|
|
_visibleVegetationCellSelector.OnVegetationCellInvisibleDelegate += OnVegetationCellInvisible;
|
|
|
|
_vegetationSystemPro.OnVegetationCellLoaded += OnVegetationCellLoaded;
|
|
|
|
InstanceList = new NativeList<ItemSelectorInstanceInfo>(512,Allocator.Persistent);
|
|
_removeVegetationCellIndexList = new NativeList<int>(64,Allocator.Persistent);
|
|
_visibilityChangedIndexList = new NativeList<int>(512,Allocator.Persistent);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_visibleVegetationCellSelector.OnVegetationCellVisibleDelegate -= OnVegetationCellVisible;
|
|
_visibleVegetationCellSelector.OnVegetationCellInvisibleDelegate -= OnVegetationCellInvisible;
|
|
_vegetationSystemPro.OnVegetationCellLoaded -= OnVegetationCellLoaded;
|
|
|
|
if (InstanceList.IsCreated) InstanceList.Dispose();
|
|
if (_removeVegetationCellIndexList.IsCreated) _removeVegetationCellIndexList.Dispose();
|
|
if (_visibilityChangedIndexList.IsCreated) _visibilityChangedIndexList.Dispose();
|
|
}
|
|
|
|
public void OnVegetationCellLoaded(VegetationCell vegetationCell)
|
|
{
|
|
if (LoadedVegetationCellList.Contains(vegetationCell))
|
|
{
|
|
if (!ReadyToUnloadVegetationCellList.Contains(vegetationCell))
|
|
{
|
|
ReadyToUnloadVegetationCellList.Add(vegetationCell);
|
|
}
|
|
|
|
if (!ReadyToLoadVegetationCellList.Contains(vegetationCell))
|
|
{
|
|
ReadyToLoadVegetationCellList.Add(vegetationCell);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void OnVegetationCellVisible(VegetationCell vegetationCell)
|
|
{
|
|
ReadyToLoadVegetationCellList.Add(vegetationCell);
|
|
}
|
|
|
|
public void OnVegetationCellInvisible(VegetationCell vegetationCell)
|
|
{
|
|
ReadyToUnloadVegetationCellList.Add(vegetationCell);
|
|
}
|
|
|
|
public void RefreshVegetationCell(VegetationCell vegetationCell)
|
|
{
|
|
if (!LoadedVegetationCellList.Contains(vegetationCell)) return;
|
|
|
|
if (!ReadyToUnloadVegetationCellList.Contains(vegetationCell))
|
|
{
|
|
ReadyToUnloadVegetationCellList.Add(vegetationCell);
|
|
}
|
|
|
|
if (!ReadyToLoadVegetationCellList.Contains(vegetationCell))
|
|
{
|
|
ReadyToLoadVegetationCellList.Add(vegetationCell);
|
|
}
|
|
}
|
|
|
|
public void RefreshAllVegetationCells()
|
|
{
|
|
for (int i = 0; i <= LoadedVegetationCellList.Count - 1; i++)
|
|
{
|
|
VegetationCell vegetationCell = LoadedVegetationCellList[i];
|
|
|
|
if (!ReadyToUnloadVegetationCellList.Contains(vegetationCell))
|
|
{
|
|
ReadyToUnloadVegetationCellList.Add(vegetationCell);
|
|
}
|
|
|
|
if (!ReadyToLoadVegetationCellList.Contains(vegetationCell))
|
|
{
|
|
ReadyToLoadVegetationCellList.Add(vegetationCell);
|
|
}
|
|
}
|
|
}
|
|
|
|
public JobHandle ProcessVisibleCells(JobHandle processCullingHandle)
|
|
{
|
|
processCullingHandle = LoadVisibleCells(processCullingHandle);
|
|
return processCullingHandle;
|
|
}
|
|
|
|
public JobHandle ProcessInvisibleCells(JobHandle processCullingHandle)
|
|
{
|
|
processCullingHandle = RemoveInvisibleCells(processCullingHandle);
|
|
return processCullingHandle;
|
|
}
|
|
|
|
public JobHandle ProcessCulling(JobHandle processCullingHandle)
|
|
{
|
|
ResetVisibilityJob resetVisibilityJob = new ResetVisibilityJob
|
|
{
|
|
InstanceList = InstanceList
|
|
};
|
|
processCullingHandle = resetVisibilityJob.Schedule(processCullingHandle);
|
|
|
|
for (int i = 0; i <= _vegetationSystemPro.VegetationStudioCameraList.Count - 1; i++)
|
|
{
|
|
VegetationStudioCamera vegetationStudioCamera = _vegetationSystemPro.VegetationStudioCameraList[i];
|
|
|
|
|
|
if (!vegetationStudioCamera.Enabled) continue;
|
|
if (vegetationStudioCamera.SelectedCamera == null) continue;
|
|
|
|
DistanceCullingJob distanceCullingJob = new DistanceCullingJob
|
|
{
|
|
InstanceList = InstanceList,
|
|
CameraPosition = vegetationStudioCamera.SelectedCamera.transform.position - _vegetationSystemPro.FloatingOriginOffset,
|
|
CullingDistance = CullingDistance,
|
|
};
|
|
processCullingHandle = distanceCullingJob.Schedule(processCullingHandle);
|
|
}
|
|
|
|
_visibilityChangedIndexList.Clear();
|
|
|
|
VisibilityChangedFilterManualJob visibilityChangedFilterManualJob =
|
|
new VisibilityChangedFilterManualJob
|
|
{
|
|
InstanceList = InstanceList, VisibilityChangedIndexList = _visibilityChangedIndexList
|
|
};
|
|
processCullingHandle = visibilityChangedFilterManualJob.Schedule(processCullingHandle);
|
|
return processCullingHandle;
|
|
}
|
|
|
|
public void ProcessEvents()
|
|
{
|
|
for (int i = 0; i <= _visibilityChangedIndexList.Length - 1; i++)
|
|
{
|
|
ItemSelectorInstanceInfo itemSelectorInstanceInfo = InstanceList[_visibilityChangedIndexList[i]];
|
|
if (itemSelectorInstanceInfo.Visible == 1)
|
|
{
|
|
OnVegetationItemVisibleDelegate?.Invoke(itemSelectorInstanceInfo,_vegetationItemIndexes,VegetationItemID);
|
|
}
|
|
else
|
|
{
|
|
OnVegetationItemInvisibleDelegate?.Invoke(itemSelectorInstanceInfo,_vegetationItemIndexes,VegetationItemID);
|
|
}
|
|
}
|
|
}
|
|
|
|
JobHandle LoadVisibleCells(JobHandle processCullingHandle)
|
|
{
|
|
for (int i = 0; i <= ReadyToLoadVegetationCellList.Count - 1; i++)
|
|
{
|
|
VegetationCell vegetationCell = ReadyToLoadVegetationCellList[i];
|
|
if (!vegetationCell.Prepared)
|
|
{
|
|
Debug.Log("Unprepared cell" + vegetationCell.Index);
|
|
continue;
|
|
}
|
|
//NativeList<MatrixInstance> matrixInstanceArray = vegetationCell.GetVegetationPackageInstancesList(_vegetationItemIndexes.VegetationPackageIndex,_vegetationItemIndexes.VegetationItemIndex);
|
|
NativeList<MatrixInstance> matrixInstanceArray = vegetationCell
|
|
.VegetationPackageInstancesList[_vegetationItemIndexes.VegetationPackageIndex]
|
|
.VegetationItemMatrixList[_vegetationItemIndexes.VegetationItemIndex];
|
|
|
|
// if (!matrixInstanceArray.IsCreated)
|
|
// {
|
|
// Debug.Log("not created");
|
|
// continue;
|
|
// }
|
|
|
|
if (_useSpawnChance)
|
|
{
|
|
AddInstancesSpawnChanceJob addInstancesSpawnChanceJob = new AddInstancesSpawnChanceJob
|
|
{
|
|
InstanceList = InstanceList,
|
|
RandomNumbers = _vegetationSystemPro.VegetationCellSpawner.RandomNumbers,
|
|
SpawnChance = _spawnChance,
|
|
MatrixInstanceList = matrixInstanceArray,
|
|
RandomNumberIndex = vegetationCell.Index + _spawnSeed,
|
|
VegetationCellIndex = vegetationCell.Index
|
|
};
|
|
processCullingHandle = addInstancesSpawnChanceJob.Schedule(processCullingHandle);
|
|
}
|
|
else
|
|
{
|
|
AddInstancesJob addInstancesJob = new AddInstancesJob
|
|
{
|
|
InstanceList = InstanceList,
|
|
MatrixInstanceList = matrixInstanceArray,
|
|
VegetationCellIndex = vegetationCell.Index
|
|
};
|
|
|
|
processCullingHandle = addInstancesJob.Schedule(processCullingHandle);
|
|
}
|
|
LoadedVegetationCellList.Add(vegetationCell);
|
|
}
|
|
|
|
ReadyToLoadVegetationCellList.Clear();
|
|
|
|
return processCullingHandle;
|
|
}
|
|
|
|
JobHandle RemoveInvisibleCells(JobHandle processCullingHandle)
|
|
{
|
|
_removeVegetationCellIndexList.Clear();
|
|
bool needsRemoval = false;
|
|
|
|
for (int i = 0; i <= ReadyToUnloadVegetationCellList.Count - 1; i++)
|
|
{
|
|
_removeVegetationCellIndexList.Add(ReadyToUnloadVegetationCellList[i].Index);
|
|
|
|
VegetationCell vegetationCell = ReadyToUnloadVegetationCellList[i];
|
|
|
|
// ReSharper disable once InlineOutVariableDeclaration
|
|
int index = LoadedVegetationCellList.IndexOf(ReadyToUnloadVegetationCellList[i]);
|
|
if (index > -1)
|
|
{
|
|
LoadedVegetationCellList.RemoveAtSwapBack(index);
|
|
}
|
|
|
|
OnVegetationCellInvisibleDelegate?.Invoke(vegetationCell.Index);
|
|
needsRemoval = true;
|
|
}
|
|
ReadyToUnloadVegetationCellList.Clear();
|
|
|
|
if (needsRemoval)
|
|
{
|
|
FlagInstancesForRemovalJob flagInstancesForRemovalJob =
|
|
new FlagInstancesForRemovalJob
|
|
{
|
|
InstanceList = InstanceList,
|
|
RemoveCellIndexList = _removeVegetationCellIndexList
|
|
};
|
|
|
|
processCullingHandle = flagInstancesForRemovalJob.Schedule(processCullingHandle);
|
|
|
|
RemoveInstancesJob removeInstancesJob = new RemoveInstancesJob
|
|
{
|
|
InstanceList = InstanceList
|
|
};
|
|
|
|
processCullingHandle = removeInstancesJob.Schedule(processCullingHandle);
|
|
}
|
|
return processCullingHandle;
|
|
}
|
|
}
|
|
|
|
[BurstCompile]
|
|
public struct DistanceCullingJob : IJob
|
|
{
|
|
public NativeList<ItemSelectorInstanceInfo> InstanceList;
|
|
public float3 CameraPosition;
|
|
public float CullingDistance;
|
|
|
|
public void Execute()
|
|
{
|
|
for (int i = 0; i <= InstanceList.Length - 1; i++)
|
|
{
|
|
ItemSelectorInstanceInfo itemSelectorInstanceInfo = InstanceList[i];
|
|
float distance = math.distance(itemSelectorInstanceInfo.Position, CameraPosition);
|
|
|
|
if (distance <= CullingDistance)
|
|
{
|
|
itemSelectorInstanceInfo.Visible = 1;
|
|
}
|
|
else
|
|
{
|
|
itemSelectorInstanceInfo.Visible = -1;
|
|
}
|
|
|
|
InstanceList[i] = itemSelectorInstanceInfo;
|
|
}
|
|
}
|
|
}
|
|
|
|
[BurstCompile]
|
|
public struct ResetVisibilityJob : IJob
|
|
{
|
|
public NativeList<ItemSelectorInstanceInfo> InstanceList;
|
|
public void Execute()
|
|
{
|
|
for (int i = 0; i <= InstanceList.Length - 1; i++)
|
|
{
|
|
ItemSelectorInstanceInfo itemSelectorInstanceInfo = InstanceList[i];
|
|
itemSelectorInstanceInfo.LastVisible = itemSelectorInstanceInfo.Visible;
|
|
itemSelectorInstanceInfo.Visible = 0;
|
|
InstanceList[i] = itemSelectorInstanceInfo;
|
|
}
|
|
}
|
|
}
|
|
|
|
[BurstCompile]
|
|
public struct VisibilityChangedFilterManualJob : IJob
|
|
{
|
|
[ReadOnly]
|
|
public NativeList<ItemSelectorInstanceInfo> InstanceList;
|
|
public NativeList<int> VisibilityChangedIndexList;
|
|
public void Execute()
|
|
{
|
|
for (int i = 0; i <= InstanceList.Length - 1; i++)
|
|
{
|
|
ItemSelectorInstanceInfo itemSelectorInstanceInfo = InstanceList[i];
|
|
if (itemSelectorInstanceInfo.Visible != itemSelectorInstanceInfo.LastVisible)
|
|
{
|
|
VisibilityChangedIndexList.Add(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[BurstCompile]
|
|
public struct RemoveInstancesJob : IJob
|
|
{
|
|
public NativeList<ItemSelectorInstanceInfo> InstanceList;
|
|
|
|
public void Execute()
|
|
{
|
|
for (int i = InstanceList.Length - 1; i >= 0; i--)
|
|
{
|
|
if (InstanceList[i].Remove == 1)
|
|
{
|
|
InstanceList.RemoveAtSwapBack(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[BurstCompile]
|
|
public struct AddInstancesSpawnChanceJob : IJob
|
|
{
|
|
public NativeList<ItemSelectorInstanceInfo> InstanceList;
|
|
public NativeList<MatrixInstance> MatrixInstanceList;
|
|
[ReadOnly]
|
|
public NativeArray<float> RandomNumbers;
|
|
|
|
public int RandomNumberIndex;
|
|
public float SpawnChance;
|
|
public int VegetationCellIndex;
|
|
public void Execute()
|
|
{
|
|
for (int i = MatrixInstanceList.Length - 1; i >= 0; i--)
|
|
{
|
|
MatrixInstance matrixInstance = MatrixInstanceList[i];
|
|
|
|
if (!RandomCutoff(SpawnChance, RandomNumberIndex))
|
|
{
|
|
ItemSelectorInstanceInfo itemSelectorInstanceInfo = new ItemSelectorInstanceInfo
|
|
{
|
|
VegetationCellIndex = VegetationCellIndex,
|
|
VegetationCellItemIndex = i,
|
|
Position = ExtractTranslationFromMatrix(matrixInstance.Matrix),
|
|
Scale = ExtractScaleFromMatrix(matrixInstance.Matrix),
|
|
Rotation = ExtractRotationFromMatrix(matrixInstance.Matrix),
|
|
LastVisible = -1,
|
|
Visible = -1
|
|
|
|
};
|
|
|
|
InstanceList.Add(itemSelectorInstanceInfo);
|
|
}
|
|
RandomNumberIndex++;
|
|
}
|
|
}
|
|
|
|
private bool RandomCutoff(float value, int randomNumberIndex)
|
|
{
|
|
float randomNumber = RandomRange(randomNumberIndex, 0, 1);
|
|
return !(value > randomNumber);
|
|
}
|
|
|
|
public float RandomRange(int randomNumberIndex, float min, float max)
|
|
{
|
|
while (randomNumberIndex > 9999)
|
|
randomNumberIndex = randomNumberIndex - 10000;
|
|
|
|
return Mathf.Lerp(min, max, RandomNumbers[randomNumberIndex]);
|
|
}
|
|
|
|
private static float3 ExtractTranslationFromMatrix(Matrix4x4 matrix)
|
|
{
|
|
float3 translate;
|
|
translate.x = matrix.m03;
|
|
translate.y = matrix.m13;
|
|
translate.z = matrix.m23;
|
|
return translate;
|
|
}
|
|
|
|
private static Quaternion ExtractRotationFromMatrix(Matrix4x4 matrix)
|
|
{
|
|
Vector3 forward;
|
|
forward.x = matrix.m02;
|
|
forward.y = matrix.m12;
|
|
forward.z = matrix.m22;
|
|
|
|
if (forward == Vector3.zero) return Quaternion.identity;
|
|
|
|
Vector3 upwards;
|
|
upwards.x = matrix.m01;
|
|
upwards.y = matrix.m11;
|
|
upwards.z = matrix.m21;
|
|
|
|
return Quaternion.LookRotation(forward, upwards);
|
|
}
|
|
|
|
private static float3 ExtractScaleFromMatrix(Matrix4x4 matrix)
|
|
{
|
|
return new float3(matrix.GetColumn(0).magnitude, matrix.GetColumn(1).magnitude, matrix.GetColumn(2).magnitude);
|
|
}
|
|
}
|
|
|
|
[BurstCompile]
|
|
public struct AddInstancesJob : IJob
|
|
{
|
|
public NativeList<ItemSelectorInstanceInfo> InstanceList;
|
|
public NativeList<MatrixInstance> MatrixInstanceList;
|
|
public int VegetationCellIndex;
|
|
public void Execute()
|
|
{
|
|
for (int i = MatrixInstanceList.Length - 1; i >= 0; i--)
|
|
{
|
|
MatrixInstance matrixInstance = MatrixInstanceList[i];
|
|
|
|
ItemSelectorInstanceInfo itemSelectorInstanceInfo = new ItemSelectorInstanceInfo
|
|
{
|
|
VegetationCellIndex = VegetationCellIndex,
|
|
VegetationCellItemIndex = i,
|
|
Position = ExtractTranslationFromMatrix(matrixInstance.Matrix),
|
|
Scale = ExtractScaleFromMatrix(matrixInstance.Matrix),
|
|
Rotation = ExtractRotationFromMatrix(matrixInstance.Matrix),
|
|
LastVisible = -1,
|
|
Visible = -1
|
|
|
|
};
|
|
|
|
InstanceList.Add(itemSelectorInstanceInfo);
|
|
}
|
|
}
|
|
|
|
private static float3 ExtractTranslationFromMatrix(Matrix4x4 matrix)
|
|
{
|
|
float3 translate;
|
|
translate.x = matrix.m03;
|
|
translate.y = matrix.m13;
|
|
translate.z = matrix.m23;
|
|
return translate;
|
|
}
|
|
|
|
private static Quaternion ExtractRotationFromMatrix(Matrix4x4 matrix)
|
|
{
|
|
Vector3 forward;
|
|
forward.x = matrix.m02;
|
|
forward.y = matrix.m12;
|
|
forward.z = matrix.m22;
|
|
|
|
if (forward == Vector3.zero) return Quaternion.identity;
|
|
|
|
Vector3 upwards;
|
|
upwards.x = matrix.m01;
|
|
upwards.y = matrix.m11;
|
|
upwards.z = matrix.m21;
|
|
|
|
return Quaternion.LookRotation(forward, upwards);
|
|
}
|
|
|
|
private static float3 ExtractScaleFromMatrix(Matrix4x4 matrix)
|
|
{
|
|
return new float3(matrix.GetColumn(0).magnitude, matrix.GetColumn(1).magnitude, matrix.GetColumn(2).magnitude);
|
|
}
|
|
}
|
|
|
|
[BurstCompile]
|
|
public struct FlagInstancesForRemovalJob : IJob
|
|
{
|
|
public NativeList<ItemSelectorInstanceInfo> InstanceList;
|
|
[ReadOnly]
|
|
public NativeList<int> RemoveCellIndexList;
|
|
|
|
public void Execute()
|
|
{
|
|
for (int j = 0; j <= InstanceList.Length - 1; j++)
|
|
{
|
|
ItemSelectorInstanceInfo instanceInfo = InstanceList[j];
|
|
for (int i = 0; i <= RemoveCellIndexList.Length - 1; i++)
|
|
{
|
|
if (instanceInfo.VegetationCellIndex == RemoveCellIndexList[i])
|
|
{
|
|
instanceInfo.Remove = 1;
|
|
InstanceList[j] = instanceInfo;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|