using System; using AwesomeTechnologies.Shaders; using System.Collections.Generic; using AwesomeTechnologies.Utility; using Unity.Collections; using UnityEngine; using UnityEngine.AI; using UnityEngine.Rendering; using Object = UnityEngine.Object; namespace AwesomeTechnologies.VegetationSystem { public class CameraComputeBuffers { public ComputeBuffer MergeBuffer; public ComputeBuffer VisibleBufferLOD0; public ComputeBuffer VisibleBufferLOD1; public ComputeBuffer VisibleBufferLOD2; public ComputeBuffer VisibleBufferLOD3; public ComputeBuffer ShadowBufferLOD0; public ComputeBuffer ShadowBufferLOD1; public ComputeBuffer ShadowBufferLOD2; public ComputeBuffer ShadowBufferLOD3; private readonly uint[] _args = {0, 0, 0, 0, 0}; public readonly List ArgsBufferMergedLOD0List = new List(); public readonly List ArgsBufferMergedLOD1List = new List(); public readonly List ArgsBufferMergedLOD2List = new List(); public readonly List ArgsBufferMergedLOD3List = new List(); public readonly List ShadowArgsBufferMergedLOD0List = new List(); public readonly List ShadowArgsBufferMergedLOD1List = new List(); public readonly List ShadowArgsBufferMergedLOD2List = new List(); public readonly List ShadowArgsBufferMergedLOD3List = new List(); public CameraComputeBuffers(Mesh vegetationMeshLod0, Mesh vegetationMeshLod1, Mesh vegetationMeshLod2, Mesh vegetationMeshLod3) { MergeBuffer = new ComputeBuffer(5000, (16 * 4 * 2) + 16, ComputeBufferType.Append); MergeBuffer.SetCounterValue(0); VisibleBufferLOD0 = new ComputeBuffer(5000, (16 * 4 * 2) + 16, ComputeBufferType.Append); VisibleBufferLOD0.SetCounterValue(0); VisibleBufferLOD1 = new ComputeBuffer(5000, (16 * 4 * 2) + 16, ComputeBufferType.Append); VisibleBufferLOD1.SetCounterValue(0); VisibleBufferLOD2 = new ComputeBuffer(5000, (16 * 4 * 2) + 16, ComputeBufferType.Append); VisibleBufferLOD2.SetCounterValue(0); VisibleBufferLOD3 = new ComputeBuffer(5000, (16 * 4 * 2) + 16, ComputeBufferType.Append); VisibleBufferLOD3.SetCounterValue(0); ShadowBufferLOD0 = new ComputeBuffer(5000, (16 * 4 * 2) + 16, ComputeBufferType.Append); ShadowBufferLOD0.SetCounterValue(0); ShadowBufferLOD1 = new ComputeBuffer(5000, (16 * 4 * 2) + 16, ComputeBufferType.Append); ShadowBufferLOD1.SetCounterValue(0); ShadowBufferLOD2 = new ComputeBuffer(5000, (16 * 4 * 2) + 16, ComputeBufferType.Append); ShadowBufferLOD2.SetCounterValue(0); ShadowBufferLOD3 = new ComputeBuffer(5000, (16 * 4 * 2) + 16, ComputeBufferType.Append); ShadowBufferLOD3.SetCounterValue(0); for (int i = 0; i <= vegetationMeshLod0.subMeshCount - 1; i++) { _args[0] = vegetationMeshLod0.GetIndexCount(i); _args[2] = vegetationMeshLod0.GetIndexStart(i); ComputeBuffer argsBufferMergedLod0 = new ComputeBuffer(1, _args.Length * sizeof(uint), ComputeBufferType.IndirectArguments); argsBufferMergedLod0.SetData(_args); ArgsBufferMergedLOD0List.Add(argsBufferMergedLod0); ComputeBuffer shadowArgsBufferMergedLod0 = new ComputeBuffer(1, _args.Length * sizeof(uint), ComputeBufferType.IndirectArguments); shadowArgsBufferMergedLod0.SetData(_args); ShadowArgsBufferMergedLOD0List.Add(shadowArgsBufferMergedLod0); } for (int i = 0; i <= vegetationMeshLod1.subMeshCount - 1; i++) { _args[0] = vegetationMeshLod1.GetIndexCount(i); _args[2] = vegetationMeshLod1.GetIndexStart(i); ComputeBuffer argsBufferMergedLod1 = new ComputeBuffer(1, _args.Length * sizeof(uint), ComputeBufferType.IndirectArguments); argsBufferMergedLod1.SetData(_args); ArgsBufferMergedLOD1List.Add(argsBufferMergedLod1); ComputeBuffer shadowArgsBufferMergedLod1 = new ComputeBuffer(1, _args.Length * sizeof(uint), ComputeBufferType.IndirectArguments); shadowArgsBufferMergedLod1.SetData(_args); ShadowArgsBufferMergedLOD1List.Add(shadowArgsBufferMergedLod1); } for (int i = 0; i <= vegetationMeshLod2.subMeshCount - 1; i++) { _args[0] = vegetationMeshLod2.GetIndexCount(i); _args[2] = vegetationMeshLod2.GetIndexStart(i); ComputeBuffer argsBufferMergedLod2 = new ComputeBuffer(1, _args.Length * sizeof(uint), ComputeBufferType.IndirectArguments); argsBufferMergedLod2.SetData(_args); ArgsBufferMergedLOD2List.Add(argsBufferMergedLod2); ComputeBuffer shadowArgsBufferMergedLod2 = new ComputeBuffer(1, _args.Length * sizeof(uint), ComputeBufferType.IndirectArguments); shadowArgsBufferMergedLod2.SetData(_args); ShadowArgsBufferMergedLOD2List.Add(shadowArgsBufferMergedLod2); } for (int i = 0; i <= vegetationMeshLod3.subMeshCount - 1; i++) { _args[0] = vegetationMeshLod3.GetIndexCount(i); _args[2] = vegetationMeshLod3.GetIndexStart(i); ComputeBuffer argsBufferMergedLod3 = new ComputeBuffer(1, _args.Length * sizeof(uint), ComputeBufferType.IndirectArguments); argsBufferMergedLod3.SetData(_args); ArgsBufferMergedLOD3List.Add(argsBufferMergedLod3); ComputeBuffer shadowArgsBufferMergedLod3 = new ComputeBuffer(1, _args.Length * sizeof(uint), ComputeBufferType.IndirectArguments); shadowArgsBufferMergedLod3.SetData(_args); ShadowArgsBufferMergedLOD3List.Add(shadowArgsBufferMergedLod3); } } public void UpdateComputeBufferSize(int newInstanceCount) { MergeBuffer?.Release(); MergeBuffer = null; VisibleBufferLOD0?.Release(); VisibleBufferLOD0 = null; VisibleBufferLOD1?.Release(); VisibleBufferLOD1 = null; VisibleBufferLOD2?.Release(); VisibleBufferLOD2 = null; VisibleBufferLOD3?.Release(); VisibleBufferLOD3 = null; ShadowBufferLOD0?.Release(); ShadowBufferLOD0 = null; ShadowBufferLOD1?.Release(); ShadowBufferLOD1 = null; ShadowBufferLOD2?.Release(); ShadowBufferLOD2 = null; ShadowBufferLOD3?.Release(); ShadowBufferLOD3 = null; MergeBuffer = new ComputeBuffer(newInstanceCount, (16 * 4 * 2) + 16, ComputeBufferType.Append); MergeBuffer.SetCounterValue(0); VisibleBufferLOD0 = new ComputeBuffer(newInstanceCount, (16 * 4 * 2) + 16, ComputeBufferType.Append); VisibleBufferLOD0.SetCounterValue(0); VisibleBufferLOD1 = new ComputeBuffer(newInstanceCount, (16 * 4 * 2) + 16, ComputeBufferType.Append); VisibleBufferLOD1.SetCounterValue(0); VisibleBufferLOD2 = new ComputeBuffer(newInstanceCount, (16 * 4 * 2) + 16, ComputeBufferType.Append); VisibleBufferLOD2.SetCounterValue(0); VisibleBufferLOD3 = new ComputeBuffer(newInstanceCount, (16 * 4 * 2) + 16, ComputeBufferType.Append); VisibleBufferLOD3.SetCounterValue(0); ShadowBufferLOD0 = new ComputeBuffer(newInstanceCount, (16 * 4 * 2) + 16, ComputeBufferType.Append); ShadowBufferLOD0.SetCounterValue(0); ShadowBufferLOD1 = new ComputeBuffer(newInstanceCount, (16 * 4 * 2) + 16, ComputeBufferType.Append); ShadowBufferLOD1.SetCounterValue(0); ShadowBufferLOD2 = new ComputeBuffer(newInstanceCount, (16 * 4 * 2) + 16, ComputeBufferType.Append); ShadowBufferLOD2.SetCounterValue(0); ShadowBufferLOD3 = new ComputeBuffer(newInstanceCount, (16 * 4 * 2) + 16, ComputeBufferType.Append); ShadowBufferLOD3.SetCounterValue(0); } public void DestroyComputeBuffers() { MergeBuffer?.Release(); MergeBuffer = null; VisibleBufferLOD0?.Release(); VisibleBufferLOD0 = null; VisibleBufferLOD1?.Release(); VisibleBufferLOD1 = null; VisibleBufferLOD2?.Release(); VisibleBufferLOD2 = null; VisibleBufferLOD3?.Release(); VisibleBufferLOD3 = null; ShadowBufferLOD0?.Release(); ShadowBufferLOD0 = null; ShadowBufferLOD1?.Release(); ShadowBufferLOD1 = null; ShadowBufferLOD2?.Release(); ShadowBufferLOD2 = null; ShadowBufferLOD3?.Release(); ShadowBufferLOD3 = null; ReleaseArgsBuffers(); } void ReleaseArgsBuffers() { for (var i = 0; i <= ArgsBufferMergedLOD0List.Count - 1; i++) { if (ArgsBufferMergedLOD0List[i] != null) ArgsBufferMergedLOD0List[i].Release(); } for (var i = 0; i <= ArgsBufferMergedLOD1List.Count - 1; i++) { if (ArgsBufferMergedLOD1List[i] != null) ArgsBufferMergedLOD1List[i].Release(); } for (var i = 0; i <= ArgsBufferMergedLOD2List.Count - 1; i++) { if (ArgsBufferMergedLOD2List[i] != null) ArgsBufferMergedLOD2List[i].Release(); } for (var i = 0; i <= ArgsBufferMergedLOD3List.Count - 1; i++) { if (ArgsBufferMergedLOD3List[i] != null) ArgsBufferMergedLOD3List[i].Release(); } for (var i = 0; i <= ShadowArgsBufferMergedLOD0List.Count - 1; i++) { if (ShadowArgsBufferMergedLOD0List[i] != null) ShadowArgsBufferMergedLOD0List[i].Release(); } for (var i = 0; i <= ShadowArgsBufferMergedLOD1List.Count - 1; i++) { if (ShadowArgsBufferMergedLOD1List[i] != null) ShadowArgsBufferMergedLOD1List[i].Release(); } for (var i = 0; i <= ShadowArgsBufferMergedLOD2List.Count - 1; i++) { if (ShadowArgsBufferMergedLOD2List[i] != null) ShadowArgsBufferMergedLOD2List[i].Release(); } for (var i = 0; i <= ShadowArgsBufferMergedLOD3List.Count - 1; i++) { if (ShadowArgsBufferMergedLOD3List[i] != null) ShadowArgsBufferMergedLOD3List[i].Release(); } ArgsBufferMergedLOD0List.Clear(); ArgsBufferMergedLOD1List.Clear(); ArgsBufferMergedLOD2List.Clear(); ArgsBufferMergedLOD3List.Clear(); ShadowArgsBufferMergedLOD0List.Clear(); ShadowArgsBufferMergedLOD1List.Clear(); ShadowArgsBufferMergedLOD2List.Clear(); ShadowArgsBufferMergedLOD3List.Clear(); } } public class VegetationItemModelInfo { public GameObject VegetationModel; public Mesh VegetationMeshLod0; public Mesh VegetationMeshLod1; public Mesh VegetationMeshLod2; public Mesh VegetationMeshLod3; public float LOD1Distance; public float LOD2Distance; public float LOD3Distance; public int LODCount; public bool LODFadePercentage; public bool LODFadeCrossfade; public int DistanceBand; public Material[] VegetationMaterialsLOD0; public Material[] VegetationMaterialsLOD1; public Material[] VegetationMaterialsLOD2; public Material[] VegetationMaterialsLOD3; public MeshRenderer VegetationRendererLOD0; public MeshRenderer VegetationRendererLOD1; public MeshRenderer VegetationRendererLOD2; public MeshRenderer VegetationRendererLOD3; public MaterialPropertyBlock VegetationMaterialPropertyBlockLOD0; public MaterialPropertyBlock VegetationMaterialPropertyBlockLOD1; public MaterialPropertyBlock VegetationMaterialPropertyBlockLOD2; public MaterialPropertyBlock VegetationMaterialPropertyBlockLOD3; public MaterialPropertyBlock VegetationMaterialPropertyBlockShadowsLOD0; public MaterialPropertyBlock VegetationMaterialPropertyBlockShadowsLOD1; public MaterialPropertyBlock VegetationMaterialPropertyBlockShadowsLOD2; public MaterialPropertyBlock VegetationMaterialPropertyBlockShadowsLOD3; public VegetationItemInfoPro VegetationItemInfo; public EnvironmentSettings EnvironmentSettings; public VegetationRenderSettings VegetationRenderSettings; public float BoundingSphereRadius; public GameObject SelectedVegetationModelLOD0; public GameObject SelectedVegetationModelLOD1; public GameObject SelectedVegetationModelLOD2; public GameObject SelectedVegetationModelLOD3; public Material BillboardMaterial; //TODO update these automatic when new cameras is added or removed public List WindSamplerMeshRendererList = new List(); public readonly List CameraComputeBufferList = new List(); public readonly List CameraBillboardMaterialPropertyBlockList = new List(); //public NativeArray DistanceFalloffCurveArray; public NativeArray HeightRuleCurveArray; public NativeArray SteepnessRuleCurveArray; private float _maxVegetationSize; [NonSerialized] public IShaderController ShaderControler; public VegetationItemModelInfo(VegetationItemInfoPro vegetationItemInfo, EnvironmentSettings environmentSettings, List windSamplerList, int cameraCount, VegetationRenderSettings vegetationRenderSettings) { EnvironmentSettings = environmentSettings; VegetationRenderSettings = vegetationRenderSettings; VegetationItemInfo = vegetationItemInfo; VegetationModel = vegetationItemInfo.VegetationPrefab; if (vegetationItemInfo.PrefabType == VegetationPrefabType.Texture) { VegetationModel = Resources.Load("DefaultGrassPatch"); } if (VegetationModel == null) { VegetationModel = Resources.Load("MissingVegetationItemCube") as GameObject; Debug.LogError("The vegetation prefab of item: " + vegetationItemInfo.Name + " is missing. Please replace or delete VegetationItem."); } DistanceBand = vegetationItemInfo.GetDistanceBand(); #if UNITY_EDITOR MaterialUtility.EnableMaterialInstancing(VegetationModel); #endif SelectedVegetationModelLOD0 = MeshUtils.SelectMeshObject(VegetationModel, LODLevel.LOD0); SelectedVegetationModelLOD1 = MeshUtils.SelectMeshObject(VegetationModel, LODLevel.LOD1); SelectedVegetationModelLOD2 = MeshUtils.SelectMeshObject(VegetationModel, LODLevel.LOD2); SelectedVegetationModelLOD3 = MeshUtils.SelectMeshObject(VegetationModel, LODLevel.LOD3); ShaderControler = ShaderSelector.GetShaderControler(vegetationItemInfo.ShaderName); if (ShaderControler != null) ShaderControler.Settings = vegetationItemInfo.ShaderControllerSettings; LODCount = MeshUtils.GetLODCount(VegetationModel, ShaderControler); CreateCameraWindSamplerItems(windSamplerList); if (ShaderControler != null) { LODFadePercentage = ShaderControler.Settings.LODFadePercentage; LODFadeCrossfade = ShaderControler.Settings.LODFadeCrossfade; } VegetationMeshLod0 = GetVegetationMesh(VegetationModel, LODLevel.LOD0); VegetationMeshLod1 = GetVegetationMesh(VegetationModel, LODLevel.LOD1); VegetationMeshLod2 = GetVegetationMesh(VegetationModel, LODLevel.LOD2); VegetationMeshLod3 = GetVegetationMesh(VegetationModel, LODLevel.LOD3); VegetationRendererLOD0 = SelectedVegetationModelLOD0.GetComponentInChildren(); VegetationMaterialsLOD0 = CreateMaterials(VegetationRendererLOD0.sharedMaterials, 0); VegetationRendererLOD1 = SelectedVegetationModelLOD1.GetComponentInChildren(); VegetationMaterialsLOD1 = CreateMaterials(VegetationRendererLOD1.sharedMaterials, 1); VegetationRendererLOD2 = SelectedVegetationModelLOD2.GetComponentInChildren(); VegetationMaterialsLOD2 = CreateMaterials(VegetationRendererLOD2.sharedMaterials, 2); VegetationRendererLOD3 = SelectedVegetationModelLOD3.GetComponentInChildren(); VegetationMaterialsLOD3 = CreateMaterials(VegetationRendererLOD3.sharedMaterials, 3); if (vegetationItemInfo.PrefabType == VegetationPrefabType.Texture) { #if UNITY_2019_3_OR_NEWER Shader grassShader = Shader.Find("AwesomeTechnologies/Release/Grass/Grass"); MaterialUtility.ChangeShader(VegetationMaterialsLOD0, grassShader); MaterialUtility.ChangeShader(VegetationMaterialsLOD1, grassShader); MaterialUtility.ChangeShader(VegetationMaterialsLOD2, grassShader); MaterialUtility.ChangeShader(VegetationMaterialsLOD3, grassShader); #endif SetGrassTexture(VegetationMaterialsLOD0, vegetationItemInfo.VegetationTexture); SetGrassTexture(VegetationMaterialsLOD1, vegetationItemInfo.VegetationTexture); SetGrassTexture(VegetationMaterialsLOD2, vegetationItemInfo.VegetationTexture); SetGrassTexture(VegetationMaterialsLOD3, vegetationItemInfo.VegetationTexture); } VegetationMaterialPropertyBlockLOD0 = new MaterialPropertyBlock(); VegetationRendererLOD0.GetPropertyBlock(VegetationMaterialPropertyBlockLOD0); if (VegetationMaterialPropertyBlockLOD0 == null) VegetationMaterialPropertyBlockLOD0 = new MaterialPropertyBlock(); VegetationMaterialPropertyBlockLOD1 = new MaterialPropertyBlock(); VegetationRendererLOD1.GetPropertyBlock(VegetationMaterialPropertyBlockLOD1); if (VegetationMaterialPropertyBlockLOD1 == null) VegetationMaterialPropertyBlockLOD1 = new MaterialPropertyBlock(); VegetationMaterialPropertyBlockLOD2 = new MaterialPropertyBlock(); VegetationRendererLOD2.GetPropertyBlock(VegetationMaterialPropertyBlockLOD2); if (VegetationMaterialPropertyBlockLOD2 == null) VegetationMaterialPropertyBlockLOD2 = new MaterialPropertyBlock(); VegetationMaterialPropertyBlockLOD3 = new MaterialPropertyBlock(); VegetationRendererLOD3.GetPropertyBlock(VegetationMaterialPropertyBlockLOD3); if (VegetationMaterialPropertyBlockLOD3 == null) VegetationMaterialPropertyBlockLOD3 = new MaterialPropertyBlock(); VegetationMaterialPropertyBlockShadowsLOD0 = new MaterialPropertyBlock(); VegetationRendererLOD0.GetPropertyBlock(VegetationMaterialPropertyBlockShadowsLOD0); if (VegetationMaterialPropertyBlockShadowsLOD0 == null) VegetationMaterialPropertyBlockShadowsLOD0 = new MaterialPropertyBlock(); VegetationMaterialPropertyBlockShadowsLOD1 = new MaterialPropertyBlock(); VegetationRendererLOD1.GetPropertyBlock(VegetationMaterialPropertyBlockShadowsLOD1); if (VegetationMaterialPropertyBlockShadowsLOD1 == null) VegetationMaterialPropertyBlockShadowsLOD1 = new MaterialPropertyBlock(); VegetationMaterialPropertyBlockShadowsLOD2 = new MaterialPropertyBlock(); VegetationRendererLOD2.GetPropertyBlock(VegetationMaterialPropertyBlockShadowsLOD2); if (VegetationMaterialPropertyBlockShadowsLOD2 == null) VegetationMaterialPropertyBlockShadowsLOD2 = new MaterialPropertyBlock(); VegetationMaterialPropertyBlockShadowsLOD3 = new MaterialPropertyBlock(); VegetationRendererLOD3.GetPropertyBlock(VegetationMaterialPropertyBlockShadowsLOD3); if (VegetationMaterialPropertyBlockShadowsLOD3 == null) VegetationMaterialPropertyBlockShadowsLOD3 = new MaterialPropertyBlock(); LOD1Distance = GetLODDistance(VegetationModel, 0); LOD2Distance = GetLODDistance(VegetationModel, 1); LOD3Distance = GetLODDistance(VegetationModel, 2); vegetationItemInfo.Bounds = MeshUtils.CalculateBoundsInstantiate(VegetationModel); float maxScaleMultiplier = Mathf.Max(new float[] { vegetationItemInfo.ScaleMultiplier.x, vegetationItemInfo.ScaleMultiplier.y, vegetationItemInfo.ScaleMultiplier.z }); BoundingSphereRadius = (vegetationItemInfo.Bounds.extents.magnitude * VegetationItemInfo.MaxScale * VegetationItemInfo.YScale * maxScaleMultiplier) + 5; CreateCameraBuffers(cameraCount); HeightRuleCurveArray = new NativeArray(4096, Allocator.Persistent); UpdateHeightRuleCurve(); SteepnessRuleCurveArray = new NativeArray(4096, Allocator.Persistent); UpdateSteepnessRuleCurve(); //DistanceFalloffCurveArray = new NativeArray(256, Allocator.Persistent); //UpdateDistanceFalloutCurve(); if (vegetationItemInfo.VegetationType == VegetationType.Tree) { CreateBillboardMaterial(); } } public void CreateCameraWindSamplerItems(List windSamplerList) { if (ShaderControler != null && ShaderControler.Settings.SampleWind) { for (int i = 0; i <= windSamplerList.Count - 1; i++) { GameObject windSampleItem = Object.Instantiate(SelectedVegetationModelLOD0); windSampleItem.hideFlags = HideFlags.HideAndDontSave; windSampleItem.name = "VegetationSystemRenderer"; windSampleItem.transform.SetParent(windSamplerList[i].transform); windSampleItem.transform.localPosition = new Vector3(0, 0, 3); windSampleItem.transform.localRotation = Quaternion.identity; CleanVegetationObject(windSampleItem); MeshRenderer meshRenderer = windSampleItem.GetComponentInChildren(); WindSamplerMeshRendererList.Add(meshRenderer); } } } public void CreateCameraBuffers(int cameraCount) { DisposeCameraBuffers(); CameraBillboardMaterialPropertyBlockList.Clear(); for (int i = 0; i <= cameraCount - 1; i++) { CameraComputeBuffers cameraComputeBuffers = new CameraComputeBuffers(VegetationMeshLod0, VegetationMeshLod1, VegetationMeshLod2, VegetationMeshLod3); CameraComputeBufferList.Add(cameraComputeBuffers); CameraBillboardMaterialPropertyBlockList.Add(new MaterialPropertyBlock()); } } public bool BillboardLODFadeCrossfade; void SetGrassTexture(Material[] materials, Texture2D texture) { for (int i = 0; i <= materials.Length - 1; i++) { materials[i].SetTexture("_MainTex", texture); } } void UpdateBillboardMaterial() { if (!BillboardMaterial) return; BillboardMaterial.SetFloat("_Cutoff", VegetationItemInfo.BillboardCutoff); if (ShaderControler != null) { BillboardLODFadeCrossfade = ShaderControler.Settings.LODFadeCrossfade; } if (ShaderControler != null && ShaderControler.Settings.DynamicHUE) { Color hueColor = ShaderControler.Settings.GetColorPropertyValue("FoliageHue"); BillboardMaterial.SetColor("_HueVariation", hueColor); BillboardMaterial.EnableKeyword("AT_HUE_VARIATION_ON"); } else { BillboardMaterial.SetColor("_HueVariation", new Color(1f, 0.5f, 0f, 25f / 256f)); BillboardMaterial.DisableKeyword("AT_HUE_VARIATION_ON"); } BillboardMaterial.EnableKeyword("LOD_FADE_CROSSFADE"); BillboardMaterial.SetColor("_Color", VegetationItemInfo.BillboardTintColor); BillboardMaterial.SetFloat("_Brightness", VegetationItemInfo.BillboardBrightness); BillboardMaterial.SetFloat("_SnowAmount", Mathf.Clamp01(EnvironmentSettings.SnowAmount)); BillboardMaterial.SetColor("_SnowColor", EnvironmentSettings.BillboardSnowColor); BillboardMaterial.SetFloat("_SnowBlendFactor", EnvironmentSettings.SnowBlendFactor); BillboardMaterial.SetFloat("_SnowBrightness", EnvironmentSettings.SnowBrightness); BillboardMaterial.SetFloat("_BillboardWindSpeed", VegetationItemInfo.BillboardWindSpeed); BillboardMaterial.SetFloat("_Smoothness", VegetationItemInfo.BillboardSmoothness); BillboardMaterial.SetFloat("_NormalStrength", VegetationItemInfo.BillboardNormalStrength); BillboardMaterial.SetFloat("_ShadowOffset", VegetationItemInfo.BillboardShadowOffset); var boundsSize = Mathf.Max(VegetationItemInfo.Bounds.extents.x, VegetationItemInfo.Bounds.extents.y, VegetationItemInfo.Bounds.extents.z); BillboardMaterial.SetFloat("_DepthBoundsSize", boundsSize * 2); BillboardMaterial.SetFloat("_FadeDistance", VegetationItemInfo.BillboardFadeDistance); if (VegetationItemInfo.UseBillboardFade) { BillboardMaterial.SetInt("_UseFade", 1); } else { BillboardMaterial.SetInt("_UseFade", 0); } if (VegetationItemInfo.BillboardRenderMode == BillboardRenderMode.Standard) { BillboardMaterial.SetFloat("_Metallic", VegetationItemInfo.BillboardMetallic); } else { BillboardMaterial.SetFloat("_Specular", VegetationItemInfo.BillboardSpecular); } BillboardMaterial.SetFloat("_Occlusion", VegetationItemInfo.BillboardOcclusion); if (VegetationRenderSettings.ShowLODDebug) { BillboardMaterial.SetColor("_LODDebugColor", GetLODColor(4)); } else { BillboardMaterial.SetColor("_LODDebugColor", Color.white); } } void CreateBillboardMaterial() { #if UNITY_2019_3_OR_NEWER if (VegetationItemInfo.BillboardRenderMode == BillboardRenderMode.Standard) { BillboardMaterial = new Material(Shader.Find("AwesomeTechnologies/Release/Billboards/BillboardsMetallic")) { enableInstancing = true, hideFlags = HideFlags.DontSave }; } else { BillboardMaterial = new Material(Shader.Find("AwesomeTechnologies/Release/Billboards/BetterShaders_GroupBillboards")) { enableInstancing = true, hideFlags = HideFlags.DontSave }; } #else if (VegetationItemInfo.BillboardRenderMode == BillboardRenderMode.Standard) { BillboardMaterial = new Material(Shader.Find("AwesomeTechnologies/Billboards/GroupBillboards")) { enableInstancing = true, hideFlags = HideFlags.DontSave }; } else { BillboardMaterial = new Material(Shader.Find("AwesomeTechnologies/Billboards/GroupBillboardsSpecular")) { enableInstancing = true, hideFlags = HideFlags.DontSave }; } #endif BillboardMaterial.SetTexture("_MainTex", VegetationItemInfo.BillboardTexture); //BillboardMaterial.SetTexture("_AOTex", VegetationItemInfo.BillboardAoTexture); BillboardMaterial.SetTexture("_Bump", VegetationItemInfo.BillboardNormalTexture); BillboardMaterial.SetInt("_InRow", BillboardAtlasRenderer.GetBillboardQualityColumnCount(VegetationItemInfo .BillboardQuality)); BillboardMaterial.SetInt("_InCol", BillboardAtlasRenderer.GetBillboardQualityRowCount(VegetationItemInfo .BillboardQuality)); BillboardMaterial.SetInt("_CullDistance", 340); BillboardMaterial.SetInt("_FarCullDistance", 5000); // if (Application.isPlaying) // { // BillboardMaterial.EnableKeyword("AT_CAMERA_SHADER"); // BillboardMaterial.DisableKeyword("AT_CAMERA_MATERIAL"); // } // else // { // BillboardMaterial.DisableKeyword("AT_CAMERA_SHADER"); // BillboardMaterial.EnableKeyword("AT_CAMERA_MATERIAL"); // } if (ShaderControler != null && ShaderControler.Settings.DynamicHUE) { BillboardMaterial.EnableKeyword("AT_HUE_VARIATION_ON"); BillboardMaterial.DisableKeyword("AT_HUE_VARIATION_OFF"); } else { BillboardMaterial.DisableKeyword("AT_HUE_VARIATION_ON"); BillboardMaterial.EnableKeyword("AT_HUE_VARIATION_OFF"); } if (ShaderControler != null) { if (ShaderControler.Settings.BillboardSnow) { BillboardMaterial.EnableKeyword("USE_SNOW"); } else { BillboardMaterial.DisableKeyword("USE_SNOW"); } if (ShaderControler.Settings.BillboardHDWind) { BillboardMaterial.EnableKeyword("USE_HDWIND"); } else { BillboardMaterial.DisableKeyword("USE_HDWIND"); } } if (VegetationItemInfo.OverrideShaderController) { if (VegetationItemInfo.UseBillboardSnow) { BillboardMaterial.EnableKeyword("USE_SNOW"); } else { BillboardMaterial.DisableKeyword("USE_SNOW"); } } if (VegetationItemInfo.OverrideShaderController) { if (VegetationItemInfo.UseBillboardWind) { BillboardMaterial.EnableKeyword("USE_HDWIND"); } else { BillboardMaterial.DisableKeyword("USE_HDWIND"); } } UpdateBillboardMaterial(); } void DisposeCameraBuffers() { for (int i = 0; i <= CameraComputeBufferList.Count - 1; i++) { CameraComputeBufferList[i].DestroyComputeBuffers(); } CameraComputeBufferList.Clear(); } public void Dispose() { DestroyMaterials(VegetationMaterialsLOD0); DestroyMaterials(VegetationMaterialsLOD1); DestroyMaterials(VegetationMaterialsLOD2); DestroyMaterials(VegetationMaterialsLOD3); DisposeCameraBuffers(); //if (DistanceFalloffCurveArray.IsCreated) DistanceFalloffCurveArray.Dispose(); if (HeightRuleCurveArray.IsCreated) HeightRuleCurveArray.Dispose(); if (SteepnessRuleCurveArray.IsCreated) SteepnessRuleCurveArray.Dispose(); } //public void UpdateDistanceFalloutCurve() //{ // float[] curveArray = VegetationItemInfo.DistanceFallofffAnimationCurve.GenerateCurveArray(); // DistanceFalloffCurveArray.CopyFrom(curveArray); //} public void UpdateHeightRuleCurve() { float[] curveArray = VegetationItemInfo.HeightRuleCurve.GenerateCurveArray(4096); HeightRuleCurveArray.CopyFrom(curveArray); } public void UpdateSteepnessRuleCurve() { float[] curveArray = VegetationItemInfo.SteepnessRuleCurve.GenerateCurveArray(4096); SteepnessRuleCurveArray.CopyFrom(curveArray); } private static void DestroyMaterials(Material[] materials) { for (int i = 0; i <= materials.Length - 1; i++) { if (Application.isPlaying) { Object.Destroy(materials[i]); } else { Object.DestroyImmediate(materials[i]); } } } private static Mesh GetVegetationMesh(GameObject rootVegetationModel, LODLevel lodLevel) { GameObject selectedVegetationModel = MeshUtils.SelectMeshObject(rootVegetationModel, lodLevel); MeshFilter vegetationMeshFilter = selectedVegetationModel.GetComponentInChildren(); if (vegetationMeshFilter.sharedMesh) { return vegetationMeshFilter.sharedMesh; } else { return new Mesh(); } } private static float GetLODDistance(GameObject rootVegetationModel, int lodIndex) { LODGroup lodGroup = rootVegetationModel.GetComponentInChildren(); if (lodGroup) { LOD[] lods = lodGroup.GetLODs(); if (lodIndex >= 0 && lodIndex < lods.Length) { return (lodGroup.size / lods[lodIndex].screenRelativeTransitionHeight); } } return -1; } private Material[] CreateMaterials(Material[] sharedMaterials, int lodIndex) { Material[] materials = new Material[sharedMaterials.Length]; for (int i = 0; i <= sharedMaterials.Length - 1; i++) { if (sharedMaterials[i]) { materials[i] = new Material(sharedMaterials[i]); if (materials[i].shader.name == "Hidden/Nature/Tree Creator Leaves Optimized") { materials[i].shader = Shader.Find("Nature/Tree Creator Leaves"); } } else { materials[i] = new Material(Shader.Find("Standard")) {enableInstancing = true}; } RefreshMaterial(materials[i], lodIndex); } return materials; } private void RefreshMaterial(Material material, int lodIndex) { if (material.HasProperty("_CullFarStart")) { material.SetFloat("_CullFarStart", 100000f); } material.enableInstancing = true; // if (LODFadePercentage) // { // if (lodIndex < LODCount - 1) // { // material.DisableKeyword("LOD_FADE_CROSSFADE"); // material.EnableKeyword("LOD_FADE_PERCENTAGE"); // } // } // if (LODFadeCrossfade) // { // //if (lodIndex == LODCount - 1) // { // material.EnableKeyword("LOD_FADE_CROSSFADE"); // material.DisableKeyword("LOD_FADE_PERCENTAGE"); // } // } // // if (!LODFadePercentage && !LODFadeCrossfade) // { // material.DisableKeyword("LOD_FADE_CROSSFADE"); // material.DisableKeyword("LOD_FADE_PERCENTAGE"); // } if (VegetationItemInfo.VegetationRenderMode == VegetationRenderMode.Normal) { material.DisableKeyword("LOD_FADE_CROSSFADE"); material.DisableKeyword("LOD_FADE_PERCENTAGE"); } if (VegetationItemInfo.EnableCrossFade) { #if USING_HDR if (VegetationItemInfo.VegetationRenderMode == VegetationRenderMode.InstancedIndirect) { material.EnableKeyword("LOD_FADE_CROSSFADE"); } else { material.DisableKeyword("LOD_FADE_CROSSFADE"); } #else material.EnableKeyword("LOD_FADE_CROSSFADE"); #endif } else { material.DisableKeyword("LOD_FADE_CROSSFADE"); } if (material.HasProperty("_LODDebugColor")) { if (VegetationRenderSettings.ShowLODDebug) { material.SetColor("_LODDebugColor", GetLODColor(lodIndex)); } else { material.SetColor("_LODDebugColor", Color.white); } } ShaderControler?.UpdateMaterial(material, EnvironmentSettings); } Color GetLODColor(int lodIndex) { switch (lodIndex) { case 0: return Color.green; case 1: return Color.red; case 2: return Color.blue; case 3: return Color.cyan; case 4: return Color.yellow; } return Color.white; } public void RefreshMaterials() { for (int i = 0; i <= VegetationMaterialsLOD0.Length - 1; i++) { RefreshMaterial(VegetationMaterialsLOD0[i], 0); } for (int i = 0; i <= VegetationMaterialsLOD1.Length - 1; i++) { RefreshMaterial(VegetationMaterialsLOD1[i], 1); } for (int i = 0; i <= VegetationMaterialsLOD2.Length - 1; i++) { RefreshMaterial(VegetationMaterialsLOD2[i], 2); } for (int i = 0; i <= VegetationMaterialsLOD3.Length - 1; i++) { RefreshMaterial(VegetationMaterialsLOD3[i], 3); } UpdateBillboardMaterial(); } //public ComputeBuffer MergeBuffer; //public ComputeBuffer VisibleBufferLOD0; //public ComputeBuffer VisibleBufferLOD1; //public ComputeBuffer VisibleBufferLOD2; //public ComputeBuffer VisibleBufferLOD3; //private readonly uint[] _args = { 0, 0, 0, 0, 0 }; //public List ArgsBufferMergedLOD0List = new List(); //public List ArgsBufferMergedLOD1List = new List(); //public List ArgsBufferMergedLOD2List = new List(); //public List ArgsBufferMergedLOD3List = new List(); public Mesh GetLODMesh(int lodIndex) { switch (lodIndex) { case 0: return VegetationMeshLod0; case 1: return VegetationMeshLod1; case 2: return VegetationMeshLod2; case 3: return VegetationMeshLod3; } return null; } public Material[] GetLODMaterials(int lodIndex) { switch (lodIndex) { case 0: return VegetationMaterialsLOD0; case 1: return VegetationMaterialsLOD1; case 2: return VegetationMaterialsLOD2; case 3: return VegetationMaterialsLOD3; } return null; } public MaterialPropertyBlock GetLODMaterialPropertyBlock(int lodIndex) { switch (lodIndex) { case 0: return VegetationMaterialPropertyBlockLOD0; case 1: return VegetationMaterialPropertyBlockLOD1; case 2: return VegetationMaterialPropertyBlockLOD2; case 3: return VegetationMaterialPropertyBlockLOD3; } return null; } public ComputeBuffer GetLODVisibleBuffer(int lodIndex, int cameraIndex, bool shadows) { if (shadows) { switch (lodIndex) { case 0: return CameraComputeBufferList[cameraIndex].ShadowBufferLOD0; case 1: return CameraComputeBufferList[cameraIndex].ShadowBufferLOD1; case 2: return CameraComputeBufferList[cameraIndex].ShadowBufferLOD2; case 3: return CameraComputeBufferList[cameraIndex].ShadowBufferLOD3; } return null; } else { switch (lodIndex) { case 0: return CameraComputeBufferList[cameraIndex].VisibleBufferLOD0; case 1: return CameraComputeBufferList[cameraIndex].VisibleBufferLOD1; case 2: return CameraComputeBufferList[cameraIndex].VisibleBufferLOD2; case 3: return CameraComputeBufferList[cameraIndex].VisibleBufferLOD3; } return null; } } public List GetLODArgsBufferList(int lodIndex, int cameraIndex, bool shadows) { if (shadows) { switch (lodIndex) { case 0: return CameraComputeBufferList[cameraIndex].ShadowArgsBufferMergedLOD0List; case 1: return CameraComputeBufferList[cameraIndex].ShadowArgsBufferMergedLOD1List; case 2: return CameraComputeBufferList[cameraIndex].ShadowArgsBufferMergedLOD2List; case 3: return CameraComputeBufferList[cameraIndex].ShadowArgsBufferMergedLOD3List; } return null; } else { switch (lodIndex) { case 0: return CameraComputeBufferList[cameraIndex].ArgsBufferMergedLOD0List; case 1: return CameraComputeBufferList[cameraIndex].ArgsBufferMergedLOD1List; case 2: return CameraComputeBufferList[cameraIndex].ArgsBufferMergedLOD2List; case 3: return CameraComputeBufferList[cameraIndex].ArgsBufferMergedLOD3List; } return null; } } void CleanVegetationObject(GameObject go) { Mesh emptyMesh = new Mesh {bounds = new Bounds(new Vector3(0, 0, 0), new Vector3(2, 2, 2))}; MeshFilter[] meshFilters = go.GetComponentsInChildren(); for (int i = 0; i <= meshFilters.Length - 1; i++) { meshFilters[i].sharedMesh = emptyMesh; } Rigidbody[] rigidbodies = go.GetComponentsInChildren(); for (int i = 0; i <= rigidbodies.Length - 1; i++) { if (Application.isPlaying) { Object.Destroy(rigidbodies[i]); } else { Object.DestroyImmediate(rigidbodies[i]); } } Collider[] colliders = go.GetComponentsInChildren(); for (int i = 0; i <= colliders.Length - 1; i++) { if (Application.isPlaying) { Object.Destroy(colliders[i]); } else { Object.DestroyImmediate(colliders[i]); } } BillboardRenderer[] billboardAtlasRenderers = go.GetComponentsInChildren(); for (int i = 0; i <= billboardAtlasRenderers.Length - 1; i++) { if (Application.isPlaying) { Object.Destroy(billboardAtlasRenderers[i]); } else { Object.DestroyImmediate(billboardAtlasRenderers[i]); } } NavMeshObstacle[] navMeshObstacles = go.GetComponentsInChildren(); for (int i = 0; i <= navMeshObstacles.Length - 1; i++) { if (Application.isPlaying) { Object.Destroy(navMeshObstacles[i]); } else { Object.DestroyImmediate(navMeshObstacles[i]); } } Transform[] transforms = go.GetComponentsInChildren(); for (int i = 0; i <= transforms.Length - 1; i++) { if (transforms[i].name.Contains("Billboard")) { if (Application.isPlaying) { Object.Destroy(transforms[i].gameObject); } else { Object.DestroyImmediate(transforms[i].gameObject); } } } transforms = go.GetComponentsInChildren(); for (int i = 0; i <= transforms.Length - 1; i++) { if (transforms[i].name.Contains("CollisionObject")) { if (Application.isPlaying) { Object.Destroy(transforms[i].gameObject); } else { Object.DestroyImmediate(transforms[i].gameObject); } } } LODGroup[] lodgroups = go.GetComponentsInChildren(); for (int i = 0; i <= lodgroups.Length - 1; i++) { if (Application.isPlaying) { Object.Destroy(lodgroups[i]); } else { Object.DestroyImmediate(lodgroups[i]); } } MeshRenderer[] meshRenderers = go.GetComponentsInChildren(); for (int i = 0; i <= meshRenderers.Length - 1; i++) { meshRenderers[i].shadowCastingMode = ShadowCastingMode.Off; meshRenderers[i].receiveShadows = false; meshRenderers[i].lightProbeUsage = LightProbeUsage.Off; if (meshRenderers[i].sharedMaterials.Length > 1) { Material[] materials = new Material[1]; materials[0] = Resources.Load("WindSampler", typeof(Material)) as Material; //_windSamplerMaterial;//meshRenderers[i].sharedMaterials[0]; //_windSamplerMaterial;// meshRenderers[i].sharedMaterials = materials; } } } } }