/// <summary> /// Remove Grass Map Globally /// </summary> /// <param name="id"></param> public static void RemoveGrassMap(FoliagePrototype prototype) { if (instance == null) { return; } var chunks = instance.sector.foliageChunks; FoliageCore_Chunk chunk; FoliageManagerInstance mInstance; for (int i = 0; i < chunks.Count; i++) { chunk = chunks[i]; if (!chunk.isFoliageInstanceAttached) { continue; // if no manager instance attached then there's nothing to remove!. } mInstance = chunk.GetOrCreateFoliageManagerInstance(); mInstance.RemoveGrassMap(prototype); } }
/// <summary> /// Create Foliage mesh instances for a certain index and foliage size. /// </summary> /// <param name="meshInstances"></param> /// <param name="prototypeIndex"></param> public static void GenerateFoliageMeshInstanceForIndex(int prototypeIndex, FoliageResolutions resolution) { Dictionary <int, GPUMesh> meshInstances = prototypeMeshInstances[resolution]; FoliagePrototype prototype = FoliageDB.sortedPrototypes[prototypeIndex]; if (!FoliageCore_MainManager.instance.enabled) { return; } bool prototypeMeshExists = prototypeMeshInstances != null && meshInstances.ContainsKey(prototypeIndex); if (prototypeMeshExists) { meshInstances[prototypeIndex].Destroy(); meshInstances.Remove(prototypeIndex); } Mesh[] meshes = new Mesh[prototype.meshLodsCount]; int[] densities = new int[prototype.meshLodsCount]; List <UNPhysicsTemplate>[] physicsObjects = new List <UNPhysicsTemplate> [prototype.meshLodsCount]; for (int i = 0; i < prototype.meshLodsCount; i++) { meshes[i] = CreateNewMesh(); densities[i] = Mathf.FloorToInt((float)prototype.maxGeneratedDensity / (i + 1)); FoliageMeshInstance.CreateGPUMesh(prototype, meshes[i], densities[i]); } meshInstances.Add(prototypeIndex, new GPUMesh(meshes, densities, prototypeIndex, physicsObjects, resolution)); }
private void DebugPrototypeInformation(int prototypeID) { FoliagePrototype prototype = FoliageDB.sortedPrototypes[prototypeID]; GUILayout.Label(string.Format("{0} (ID: {1})", prototype.name, prototypeID), UNStandaloneUtility.boldLabel); GUILayout.Space(5); UNStandaloneUtility.BeginHorizontalOffset(25); GUILayout.Label("GPU Generated Density: " + prototype.maxGeneratedDensity); GUILayout.Label("Generation Radius: " + prototype.FoliageGenerationRadius.ToString().Replace("_", "")); //show radius and remove the "_" character. GUILayout.Label(string.Format("Width Noise: {0} ~ {1}", System.Math.Round(prototype.minimumWidth, 2), System.Math.Round(prototype.maximumWidth, 2))); GUILayout.Label(string.Format("Height Noise: {0} ~ {1}", System.Math.Round(prototype.minimumHeight, 2), System.Math.Round(prototype.maximumHeight, 2))); GUILayout.Space(5); GUILayout.Label("Wind:"); UNStandaloneUtility.BeginHorizontalOffset(25); GUILayout.Label("Individual Wind: " + prototype.useCustomWind); GUILayout.Label("Wind Bending: " + (prototype.useCustomWind == false ? FoliageDB.instance.globalWindSettings.windBending : prototype.customWindSettings.windBending)); GUILayout.Label("Wind Speed: " + (prototype.useCustomWind == false ? FoliageDB.instance.globalWindSettings.windSpeed : prototype.customWindSettings.windSpeed)); UNStandaloneUtility.EndHorizontalOffset(); UNStandaloneUtility.EndHorizontalOffset(); }
internal void Destroy() { _currentChunk = null; prototype = null; System.GC.SuppressFinalize(this); }
/// <summary> /// Register a new prototype. /// </summary> /// <param name="prototype"></param> internal void RegisterNewPrototype(FoliagePrototype prototype) { _prototypes.Add(prototype); if (!sortedPrototypes.ContainsKey(prototype.id)) { sortedPrototypes.Add(prototype.id, prototype); } }
public static FoliageMeshInstance CreateFoliageMesh(FoliagePrototype prototype, Vector3 position, int maxInstancesPerMesh) { FoliageMeshInstance instance = new FoliageMeshInstance(); instance.prototype = prototype; instance.position = position; instance.maxInstancesPerMesh = maxInstancesPerMesh; return(instance); }
public void RemoveGrassMap(FoliagePrototype prototype) { if (grassMaps.ContainsKey(prototype)) { FoliageGrassMap grassMap = grassMaps[prototype]; grassMaps.Remove(prototype); #if UNITY_EDITOR grassMap.Dispose(); #endif } }
/// <summary> /// Called when the enable state of a prototype is changed /// </summary> /// <param name="changedPrototype"></param> /// <param name="value"></param> private void OnFoliagePrototypeChanged(FoliagePrototype changedPrototype, bool value) { if (value) { foreach (var meshInstances in prototypeMeshInstances) { GenerateFoliageMeshInstanceForIndex(changedPrototype.id, meshInstances.Key); } } else { DestroyMeshInstance(changedPrototype.id); } }
/// <summary> /// Create a prototype. /// </summary> /// <param name="texture"></param> /// <param name="prefab"></param> /// <param name="minSize"></param> /// <param name="maxSize"></param> /// <param name="spread"></param> /// <param name="id"></param> /// <returns></returns> public static FoliagePrototype CreatePrototype(Texture2D texture, GameObject prefab, float minWidth, float minHeight, float maxWidth, float maxHeight, float spread, int layer, int id, Color healthyColor, Color dryColor) { FoliagePrototype prototype = new FoliagePrototype(texture, prefab, minWidth, minHeight, maxWidth, maxHeight, spread, layer, id); FoliageDB.instance.RegisterNewPrototype(prototype); prototype.GenerateInstantiatedMesh(healthyColor, dryColor); prototype.instancedEuler = prototype.FoliageInstancedMeshData.eulerAngles; prototype.maxFoliageCapability = prototype.CalculateMaxFoliageCapability(); prototype.UpdateManagerInformation(); FoliageCore_MainManager.UpdateGrassMap(); return(prototype); }
/// <summary> /// Calculate the amount of permitted mesh instances per mesh. /// </summary> /// <param name="prototype"></param> /// <returns></returns> private static int CalculatePerMeshInstances(FoliagePrototype prototype, int generatableDensity) { int maxInstancesDensed = Mathf.FloorToInt(Mathf.Sqrt((float)prototype.maxFoliageCapability / generatableDensity)); float flooredChunkSize = (int)FoliageCore_MainManager.instance.instancesSectorChunkSize; for (int i = maxInstancesDensed; i > 0; i--) { if (((flooredChunkSize / i) % 1) == 0) { return(i); } } return(maxInstancesDensed); }
/// <summary> /// Remove an existing Foliage prototype. /// </summary> public void RemovePrototype(FoliagePrototype prototype) { _prototypes.Remove(prototype); sortedPrototypes.Remove(prototype.id); FoliageCore_MainManager.DestroyMeshInstance(prototype.id); FoliageCore_MainManager.RemoveGrassMap(prototype); #if UNITY_EDITOR if (!Application.isPlaying) { UnityEditor.EditorUtility.SetDirty(this); } #endif FoliageChunk.OnPrototypeDeleted(prototype.id); System.GC.SuppressFinalize(prototype); }
/// <summary> /// Add a new Foliage prototype. /// </summary> public void AddPrototype(Texture2D texture, GameObject prefab, float minWidth, float minHeight, float maxWidth, float maxHeight, float spread, int layer, Color healthyColor, Color dryColor) { int id = lastID; FoliagePrototype.CreatePrototype(texture, prefab, minWidth, minHeight, maxWidth, maxHeight, spread, layer, id, healthyColor, dryColor); FoliageCore_MainManager.GenerateFoliageMeshInstances(id); FoliageChunk.OnPrototypeCreated(id); #if UNITY_EDITOR if (!Application.isPlaying) { UnityEditor.EditorUtility.SetDirty(this); } #endif lastID++; }
public static FoliageMeshInstancesGroup CreateFoliageInstances(int prototypeIndex, int density, FoliageResolutions resolution) { float resMultiplier = (float)resolution / FoliageCore_MainManager.FOLIAGE_INSTANCE_AREA_SIZE; FoliagePrototype prototype = FoliageDB.sortedPrototypes[prototypeIndex]; int maxGenerationInstancesPerMesh = (int)(CalculatePerMeshInstances(prototype, density) / resMultiplier); int generationAmountPerRadius = GENERATION_AMOUNT_PER_RADIUS(maxGenerationInstancesPerMesh); FoliageMeshInstancesGroup meshGroup = new FoliageMeshInstancesGroup(); Vector3 position; int gAmountX = generationAmountPerRadius - (int)prototype.meshInstancesGenerationOffset.x; if (gAmountX == 0) { gAmountX = 1; // dont clamp, it can be minus } int gAmountZ = generationAmountPerRadius - (int)prototype.meshInstancesGenerationOffset.y; if (gAmountZ == 0) { gAmountZ = 1; // dont clamp, it can be minus } for (int x = 0; x < gAmountX; x++) { for (int z = 0; z < gAmountZ; z++) { position = new Vector3(z * maxGenerationInstancesPerMesh, 0, x * maxGenerationInstancesPerMesh); meshGroup.AddMeshInstance(FoliageMeshInstance.CreateFoliageMesh(prototype, position, maxGenerationInstancesPerMesh)); } } return(meshGroup); }
internal void DrawAndUpdate(Vector3 position, Mesh mesh, Material mat, Camera camera, Vector3 cameraPos, FoliagePrototype prototype, MaterialPropertyBlock matBlock, bool useQualitySettingsShadows, float shadowDistance) { ShadowCastingMode castMode = prototype.castShadows && (camera == null || (useQualitySettingsShadows || Vector3.Distance(position, cameraPos) < shadowDistance)) ? ShadowCastingMode.On : ShadowCastingMode.Off; Graphics.DrawMesh(mesh, GENERATION_OPTIMIZATION_PRE_GENERATED_VECTOR3_ZERO, GENERATION_OPTIMIZATION_PRE_GENERATED_QUATERNION_IDENTITY, mat, prototype.renderingLayer, camera, 0, matBlock, castMode, prototype.receiveShadows, null); }
public static void CreateGPUMesh(FoliagePrototype prototype, Mesh mesh, int density) { int currentValues = 0; List <UNCombineInstance> combineInstances = new List <UNCombineInstance>(); UNCombineInstance instance; int maxPerMeshInstances = CalculatePerMeshInstances(prototype, density); float rndX; float rndZ; Vector3 position; for (int x = 0; x < maxPerMeshInstances; x++) { for (int z = 0; z < maxPerMeshInstances; z++) { currentValues++; position.x = x; position.y = prototype.FoliageInstancedMeshData.offset.y; position.z = z; for (int densityIndex = 1; densityIndex <= density; densityIndex++) { rndX = Random.Range(-1f, 1f); rndZ = Random.Range(-1f, 1f); for (int i = 0; i < prototype.FoliageInstancedMeshData.meshes.Length; i++) { instance = new UNCombineInstance() { mesh = prototype.FoliageInstancedMeshData.meshes[i], transform = Matrix4x4.TRS(position, Quaternion.identity, Vector3.one), densityOfffset = new Vector2(rndX, rndZ), density = densityIndex }; combineInstances.Add(instance); } //physicsObjects.Add(new UNPhysicsTemplate(position, rndX, rndZ, densityIndex, prototype)); } if (currentValues >= prototype.maxFoliageCapability) { break; } } if (currentValues >= prototype.maxFoliageCapability) { break; } } Utility.UNBatchUtility.CombineMeshes(combineInstances, prototype.FoliageInstancedMeshData.mat, mesh, prototype, false, 0, true, null); mesh.name = string.Format("uNature Mesh ({0}) ({1})", density, mesh.vertexCount); mesh.bounds = FoliageCore_MainManager.FOLIAGE_MAIN_AREA_BOUNDS; }
public static int GENERATION_RANGE_OFFSET(FoliagePrototype prototype) { return(Mathf.Abs(1 - Mathf.CeilToInt(((float)prototype.FoliageGenerationRadius / 2)))); // from 3 -> 1 }