Firstborn/Assets/AwesomeTechnologies/VegetationStudioPro/Runtime/VegetationSystemPro/VegetationSystemPro_Billboa...

372 lines
17 KiB
C#
Raw Permalink Normal View History

using System;
using System.Collections.Generic;
using AwesomeTechnologies.Billboards;
using AwesomeTechnologies.BillboardSystem;
using AwesomeTechnologies.Utility.Quadtree;
using Unity.Jobs;
using Unity.Jobs.LowLevel.Unsafe;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
namespace AwesomeTechnologies.VegetationSystem
{
public partial class VegetationSystemPro
{
[NonSerialized]
private readonly List<VegetationCell> _billboardTempVegetationCellList = new List<VegetationCell>();
[NonSerialized] private readonly List<BillboardCell> _loadBillboardCellList = new List<BillboardCell>();
private void DisposeBillboardCells()
{
_prepareVegetationHandle.Complete();
for (var i = 0; i <= BillboardCellList.Count - 1; i++) BillboardCellList[i].Dispose();
BillboardCellList.Clear();
}
public void UpdateBillboardCulling()
{
for (var i = 0; i <= VegetationStudioCameraList.Count - 1; i++)
VegetationStudioCameraList[i].UpdateBillboardCullingGroup();
}
public void RefreshBillboards()
{
}
private void LoadBillboardCells()
{
_loadBillboardCellList.Clear();
Profiler.BeginSample("Load billboard cells");
_billboardTempVegetationCellList.Clear();
VegetationCellSpawner.CellJobHandleList.Clear();
Profiler.BeginSample("Find billboard cells with quadtree");
for (var i = 0; i <= VegetationStudioCameraList.Count - 1; i++)
{
if (!VegetationStudioCameraList[i].Enabled) continue;
for (var j = 0;
j <= VegetationStudioCameraList[i].BillboardJobCullingGroup.VisibleCellIndexList.Length - 1;
j++)
{
var index = VegetationStudioCameraList[i].BillboardJobCullingGroup.VisibleCellIndexList[j];
var billboardCell = BillboardCellList[index];
if (billboardCell.Loaded) continue;
billboardCell.OverlapVegetationCells.Clear();
VegetationCellQuadTree.Query(billboardCell.Rectangle, billboardCell.OverlapVegetationCells);
_billboardTempVegetationCellList.AddRange(billboardCell.OverlapVegetationCells);
if (!_loadBillboardCellList.Contains(billboardCell)) _loadBillboardCellList.Add(billboardCell);
}
}
Profiler.EndSample();
Profiler.BeginSample("Load needed cells");
for (var i = 0; i <= _billboardTempVegetationCellList.Count - 1; i++)
{
var vegetationCell = _billboardTempVegetationCellList[i];
if (vegetationCell.LoadedDistanceBand <= 1) continue;
if (vegetationCell.LoadedBillboards) continue;
if (!Application.isPlaying && !vegetationCell.Prepared)
VegetationCellSpawner.PrepareVegetationCell(vegetationCell);
// ReSharper disable once InlineOutVariableDeclaration
bool hasInstancedIndirect;
var spawnVegetationCellHandle = VegetationCellSpawner.SpawnVegetationCell(vegetationCell, 1, out hasInstancedIndirect, true);
CompactMemoryCellList.Add(vegetationCell);
LoadedVegetationCellList.Add(vegetationCell);
#if UNITY_EDITOR
if (JobsUtility.JobDebuggerEnabled)
{
spawnVegetationCellHandle.Complete();
ReturnVegetationCellTemporaryMemory();
}
#endif
VegetationCellSpawner.CellJobHandleList.Add(spawnVegetationCellHandle);
if (hasInstancedIndirect) ProcessInstancedIndirectCellList.Add(vegetationCell);
}
var loadAllCellsHandle = JobHandle.CombineDependencies(VegetationCellSpawner.CellJobHandleList);
VegetationCellSpawner.CellJobHandleList.Clear();
Profiler.EndSample();
Profiler.BeginSample("Merge cells and create mesh data");
for (var i = 0; i <= _loadBillboardCellList.Count - 1; i++)
{
var billboardCell = _loadBillboardCellList[i];
if (billboardCell.Loaded) continue;
for (var j = 0; j <= billboardCell.VegetationPackageBillboardInstancesList.Count - 1; j++)
for (var k = 0;
k <= billboardCell.VegetationPackageBillboardInstancesList[j].BillboardInstanceList.Count - 1;
k++)
{
var vegetationItemInfoPro = VegetationPackageProList[j].VegetationInfoList[k];
if (vegetationItemInfoPro.VegetationType != VegetationType.Tree) continue;
var billboardInstance = billboardCell.VegetationPackageBillboardInstancesList[j]
.BillboardInstanceList[k];
if (billboardInstance.Loaded) continue;
var billboardPrepareMeshDataJobHandle = loadAllCellsHandle;
for (var l = 0; l <= billboardCell.OverlapVegetationCells.Count - 1; l++)
{
var vegetationCell = billboardCell.OverlapVegetationCells[l];
var cellInstanceList =
vegetationCell.VegetationPackageInstancesList[j].VegetationItemMatrixList[k];
var mergeCellInstancesJob = new MergeCellInstancesJob
{
OutputNativeList = billboardInstance.InstanceList, InputNativeList = cellInstanceList
};
billboardPrepareMeshDataJobHandle =
mergeCellInstancesJob.Schedule(billboardPrepareMeshDataJobHandle);
}
var vegetationItemSize = Mathf.Max(vegetationItemInfoPro.Bounds.extents.x,
vegetationItemInfoPro.Bounds.extents.y,
vegetationItemInfoPro.Bounds.extents.z) * 2f;
var createBillboardMeshJob = new BillboardGenerator.CreateBillboardMeshJob
{
InstanceList = billboardInstance.InstanceList,
VerticeList = billboardInstance.VerticeList,
NormalList = billboardInstance.NormalList,
UvList = billboardInstance.UvList,
Uv2List = billboardInstance.Uv2List,
Uv3List = billboardInstance.Uv3List,
IndexList = billboardInstance.IndexList,
BoundsYExtent = vegetationItemInfoPro.Bounds.extents.y,
VegetationItemSize = vegetationItemSize
};
billboardPrepareMeshDataJobHandle =
createBillboardMeshJob.Schedule(billboardPrepareMeshDataJobHandle);
VegetationCellSpawner.CellJobHandleList.Add(billboardPrepareMeshDataJobHandle);
}
}
var combinedMergeJobHandle = JobHandle.CombineDependencies(VegetationCellSpawner.CellJobHandleList);
VegetationCellSpawner.CellJobHandleList.Clear();
loadAllCellsHandle.Complete();
combinedMergeJobHandle.Complete();
Profiler.EndSample();
Profiler.BeginSample("Create Mesh Objects");
for (var i = 0; i <= _loadBillboardCellList.Count - 1; i++)
{
var billboardCell = _loadBillboardCellList[i];
if (billboardCell.Loaded) continue;
for (var j = 0; j <= billboardCell.VegetationPackageBillboardInstancesList.Count - 1; j++)
for (var k = 0;
k <= billboardCell.VegetationPackageBillboardInstancesList[j].BillboardInstanceList.Count - 1;
k++)
{
var billboardInstance = billboardCell.VegetationPackageBillboardInstancesList[j]
.BillboardInstanceList[k];
if (billboardInstance.Loaded) continue;
billboardInstance.InstanceCount = billboardInstance.InstanceList.Length;
if (billboardInstance.InstanceCount > 0)
billboardInstance.Mesh = BillboardGenerator.CreateMeshFromBillboardInstance(billboardInstance);
billboardInstance.Loaded = true;
}
billboardCell.Loaded = true;
}
_loadBillboardCellList.Clear();
Profiler.EndSample();
Profiler.EndSample();
}
private void ClearBillboardCellsCache()
{
for (var i = 0; i <= BillboardCellList.Count - 1; i++)
{
var billboardCell = BillboardCellList[i];
billboardCell.ClearCache();
}
}
private void ClearBillboardCellsCache(int vegetationPackageIndex, int vegetationItemIndex)
{
for (var i = 0; i <= BillboardCellList.Count - 1; i++)
{
var billboardCell = BillboardCellList[i];
billboardCell.ClearCache(vegetationPackageIndex, vegetationItemIndex);
}
}
private void ClearBillboardCellsCache(Bounds bounds)
{
_prepareVegetationHandle.Complete();
if (BillboardCellQuadTree == null) return;
var clearRect = RectExtension.CreateRectFromBounds(bounds);
var overlapBillboardCellList = new List<BillboardCell>();
BillboardCellQuadTree.Query(clearRect, overlapBillboardCellList);
for (var i = 0; i <= overlapBillboardCellList.Count - 1; i++)
{
var billboardCell = overlapBillboardCellList[i];
billboardCell.ClearCache();
}
}
private void ClearBillboardCellsCache(Bounds bounds,int vegetationPackageIndex, int vegetationItemIndex)
{
var clearRect = RectExtension.CreateRectFromBounds(bounds);
_prepareVegetationHandle.Complete();
var overlapBillboardCellList = new List<BillboardCell>();
BillboardCellQuadTree.Query(clearRect, overlapBillboardCellList);
for (var i = 0; i <= overlapBillboardCellList.Count - 1; i++)
{
var billboardCell = overlapBillboardCellList[i];
billboardCell.ClearCache(vegetationPackageIndex, vegetationItemIndex);
}
}
private void SetupBillboardShaderIDs()
{
_cameraPositionID = Shader.PropertyToID("_CameraPosition");
_cullDistanceID = Shader.PropertyToID("_CullDistance");
_farCullDistanceID = Shader.PropertyToID("_FarCullDistance");
}
public void RenderBillboardCells()
{
Profiler.BeginSample("Draw billboards");
var farCullDistance = Mathf.RoundToInt(VegetationSettings.GetBillboardDistance());
var isPlaying = Application.isPlaying;
var shadowCastingMode = VegetationSettings.GetBillboardShadowCastingMode();
var layer = VegetationSettings.GetBillboardLayer();
var positionMatrix = Matrix4x4.TRS(FloatingOriginOffset, Quaternion.identity, Vector3.one);
for (var i = 0; i <= VegetationStudioCameraList.Count - 1; i++)
{
if (!VegetationStudioCameraList[i].Enabled) continue;
var targetCamera = VegetationStudioCameraList[i].RenderDirectToCamera
? VegetationStudioCameraList[i].SelectedCamera
: null;
if (!isPlaying) targetCamera = null;
for (var j = 0;
j <= VegetationStudioCameraList[i].BillboardJobCullingGroup.VisibleCellIndexList.Length - 1;
j++)
{
var index = VegetationStudioCameraList[i].BillboardJobCullingGroup.VisibleCellIndexList[j];
var billboardCell = BillboardCellList[index];
for (var k = 0; k <= billboardCell.VegetationPackageBillboardInstancesList.Count - 1; k++)
for (var l = 0;
l <= billboardCell.VegetationPackageBillboardInstancesList[k].BillboardInstanceList.Count - 1;
l++)
{
var billboardInstance = billboardCell.VegetationPackageBillboardInstancesList[k]
.BillboardInstanceList[l];
if (billboardInstance.Loaded && billboardInstance.InstanceCount > 0)
{
if (VegetationStudioCameraList[i].SelectedCamera == null) continue;
var vegetationItemModelInfo = VegetationPackageProModelsList[k].VegetationItemModelList[l];
var vegetationItemInfoPro = VegetationPackageProList[k].VegetationInfoList[l];
if (!vegetationItemInfoPro.UseBillboards) continue;
var camPos = VegetationStudioCameraList[i].SelectedCamera.transform.position;
var renderDistanceFactor = vegetationItemInfoPro.RenderDistanceFactor;
if (VegetationSettings.DisableRenderDistanceFactor) renderDistanceFactor = 1;
var cullDistance =
Mathf.RoundToInt(VegetationSettings.GetTreeDistance() * renderDistanceFactor);
if (vegetationItemModelInfo.BillboardLODFadeCrossfade)
cullDistance -= 10;
//vegetationItemModelInfo.BillboardMaterial.SetVector(_cameraPositionID, camPos);
MaterialPropertyBlock materialPropertyBlock =
vegetationItemModelInfo.CameraBillboardMaterialPropertyBlockList[i];
materialPropertyBlock.SetVector(_cameraPositionID, camPos);
materialPropertyBlock.SetInt(_cullDistanceID,
VegetationStudioCameraList[i].RenderBillboardsOnly ? 0 : cullDistance);
materialPropertyBlock.SetInt(_farCullDistanceID, farCullDistance);
materialPropertyBlock.SetFloat(_nearFadeDistanceID, VegetationRenderSettings.CrossFadeDistance);
Graphics.DrawMesh(billboardInstance.Mesh, positionMatrix,
vegetationItemModelInfo.BillboardMaterial, layer, targetCamera, 0, materialPropertyBlock,
shadowCastingMode, true);
}
}
}
}
Profiler.EndSample();
}
private void PrepareAllBillboardCells()
{
for (var i = 0; i <= VegetationStudioCameraList.Count - 1; i++)
for (var j = 0; j <= BillboardCellList.Count - 1; j++)
{
var billboardCell = BillboardCellList[j];
if (!billboardCell.Prepared) billboardCell.PrepareBillboardCell(VegetationPackageProList);
}
}
private void CreateBillboardCells()
{
DisposeBillboardCells();
var expandedBounds = new Bounds(VegetationSystemBounds.center, VegetationSystemBounds.size);
var currentBillboardCellSize = BillboardCellSize;
if (!Application.isPlaying) currentBillboardCellSize = 400;
expandedBounds.Expand(new Vector3(currentBillboardCellSize * 2f, 0, currentBillboardCellSize * 2f));
BillboardCellQuadTree = new QuadTree<BillboardCell>(RectExtension.CreateRectFromBounds(expandedBounds));
var cellXCount = Mathf.CeilToInt(VegetationSystemBounds.size.x / currentBillboardCellSize);
var cellZCount = Mathf.CeilToInt(VegetationSystemBounds.size.z / currentBillboardCellSize);
var corner = new Vector2(VegetationSystemBounds.center.x - VegetationSystemBounds.size.x / 2f,
VegetationSystemBounds.center.z - VegetationSystemBounds.size.z / 2f);
for (var x = 0; x <= cellXCount - 1; x++)
for (var z = 0; z <= cellZCount - 1; z++)
{
var billboardCell = new BillboardCell(
new Rect(
new Vector2(currentBillboardCellSize * x + corner.x, currentBillboardCellSize * z + corner.y),
new Vector2(currentBillboardCellSize, currentBillboardCellSize)),
VegetationSystemBounds.center.y, VegetationSystemBounds.size.y);
BillboardCellList.Add(billboardCell);
billboardCell.Index = BillboardCellList.Count - 1;
BillboardCellQuadTree.Insert(billboardCell);
}
PrepareAllBillboardCells();
}
}
}