private void PoolMeshInstances() { if (FoliageCore_MainManager.instance == null) { return; } _meshInstances = FoliageCore_MainManager.GetPrototypeMeshInstances(foliageAreaResolution); }
protected override void OnEnable() { base.OnEnable(); _instance = this; if (sector == null) { } // call this to force the sector to be created if not available. FoliagePrototype.OnFoliageEnabledStateChangedEvent += OnFoliagePrototypeChanged; }
/// <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> /// 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++; }
protected virtual void ApplyScaleChange() { if (FoliageCore_MainManager.instance == null) { return; } FoliageCore_MainManager mInstance = FoliageCore_MainManager.instance; float scaleX = worldScale.x * transform.localScale.x; float scaleZ = worldScale.z * transform.localScale.z; mInstance.UpdateHeights(Mathf.FloorToInt(transform.position.x), Mathf.FloorToInt(transform.position.z), Mathf.CeilToInt(scaleX), Mathf.CeilToInt(scaleZ)); scaleX = worldScale.x * lastReadScale.x; scaleZ = worldScale.z * lastReadScale.z; //revert old scale mInstance.UpdateHeights(Mathf.FloorToInt(transform.position.x), Mathf.FloorToInt(transform.position.z), Mathf.CeilToInt(scaleX), Mathf.CeilToInt(scaleZ)); lastReadScale = transform.localScale; FoliageCore_MainManager.SaveDelayedMaps(); }
/// <summary> /// Set detail layer in world cords /// </summary> /// <param name="baseX">WORLD CORDS!!</param> /// <param name="baseZ">WORLD CORDS!!</param> /// <param name="sizeX">WORLD CORDS!!</param> /// <param name="sizeZ">WORLD CORDS!!</param> /// <param name="prototypeIndex">prototype.id</param> /// <param name="densities">the density in bytes from 0 -> 15</param> public void SetDetailLayer(int baseX, int baseZ, int sizeX, int sizeZ, int prototypeIndex, byte[,] densities) { if (sector == null) { return; } if (densities.GetLength(0) != sizeX || densities.GetLength(1) != sizeZ) { Debug.LogError("uNature: Densities out of range!!"); return; } Vector3 pos = transform.position; int startX = baseX; int startZ = baseZ; int endX = startX + sizeX; int endZ = startZ + sizeZ; int interpolatedX; int interpolatedZ; int mChunkID; FoliageCore_Chunk mChunk; FoliageManagerInstance mInstance; FoliagePrototype prototype; FoliageGrassMap grassMap; for (int x = startX; x < endX; x++) { for (int z = startZ; z < endZ; z++) { mChunkID = GetChunkID(x - pos.x, z - pos.z); if (!CheckChunkInBounds(mChunkID)) { continue; // if position is out of bounds continue to the next position [very rare] } mChunk = _sector.foliageChunks[mChunkID]; if (!mChunk.isFoliageInstanceAttached) { continue; // if this chunk doesnt have an manager instance attached then there's no need to modify it. } mInstance = mChunk.GetOrCreateFoliageManagerInstance(); interpolatedX = mInstance.TransformCord(x, mInstance.transform.position.x); interpolatedZ = mInstance.TransformCord(z, mInstance.transform.position.z); prototype = FoliageDB.sortedPrototypes[prototypeIndex]; grassMap = mInstance.grassMaps[prototype]; grassMap.mapPixels[interpolatedX + interpolatedZ * grassMap.mapWidth].b = densities[x - startX, z - startZ]; grassMap.SetPixels32Delayed(); grassMap.dirty = true; } } FoliageCore_MainManager.SaveDelayedMaps(); }
public void OnGUI() { if (FoliageCore_MainManager.instance == null) { GUILayout.BeginVertical(); GUILayout.Label("Foliage Manager Not Found!!"); if (GUILayout.Button("Create Foliage Manager")) { FoliageCore_MainManager.InitializeAndCreateIfNotFound(); } GUILayout.EndVertical(); return; } globalScrollPos = EditorGUILayout.BeginScrollView(globalScrollPos); ctrlPressed = Event.current == null ? false : Event.current.control; if (Event.current != null && Event.current.keyCode == KeyCode.Escape) // try to disable brush on GUI window { chosenBrushes.Clear(); EditorUtility.SetDirty(FoliageDB.instance); EditorUtility.SetDirty(FoliageCore_MainManager.instance); } if (invisibleButtonStyle == null) { invisibleButtonStyle = new GUIStyle("Box"); invisibleButtonStyle.normal.background = null; invisibleButtonStyle.focused.background = null; invisibleButtonStyle.hover.background = null; invisibleButtonStyle.active.background = null; } FoliageCore_MainManager.instance.enabled = UNEditorUtility.DrawHelpBox(string.Format("Foliage Manager: (GUID : {0})", FoliageCore_MainManager.instance.guid), "Here you can manage and paint \nFoliage all over your scene!", true, FoliageCore_MainManager.instance.enabled); // add variable to edit. GUI.enabled = FoliageCore_MainManager.instance.enabled; DrawPaintWindow(); GUILayout.Space(5); DrawPrototypesWindow(); prototypesEditDataPos = EditorGUILayout.BeginScrollView(prototypesEditDataPos); GUILayout.Space(2); DrawPrototypesEditUI(); GUILayout.Space(5); DrawGlobalSettingsUI(); GUILayout.Space(5); DrawFoliageInstancesEditingUI(); EditorGUILayout.EndScrollView(); if (GUI.changed) { EditorUtility.SetDirty(FoliageDB.instance); EditorUtility.SetDirty(FoliageCore_MainManager.instance); } EditorGUILayout.EndScrollView(); GUI.enabled = true; }
void PaintBrush(bool isErase, Vector2 position, PaintBrush brush) { FoliageCore_MainManager mManager = FoliageCore_MainManager.instance; int chunkID; FoliageManagerInstance mInstance; brush.TryToResize(paintBrushSize); Texture2D texture = brush.instancedTexture; int textureWidth = texture.width; int textureHeight = texture.height; Color32 pixel; Color32[] grassMapPixels; int mapWidth; int posX; int posZ; int transformedCordX; int transformedCordZ; FoliagePrototype prototype; FoliageGrassMap grassMap; int radius = textureWidth / 2; byte density; for (int prototypeIndex = 0; prototypeIndex < chosenPrototypes.Count; prototypeIndex++) { prototype = chosenPrototypes[prototypeIndex]; for (int x = 0; x < textureWidth; x++) { for (int y = 0; y < textureHeight; y++) { pixel = brush.pixels[x, y]; if (pixel.r == 255 && pixel.g == 255 && pixel.b == 255) { posX = x - radius + (int)position.x - (int)mManager.transform.position.x; posZ = y - radius + (int)position.y - (int)mManager.transform.position.z; chunkID = mManager.GetChunkID(posX, posZ); mInstance = mManager.sector.foliageChunks[chunkID].GetOrCreateFoliageManagerInstance(); transformedCordX = mInstance.TransformCord(posX, mInstance.attachedTo.transform.localPosition.x); transformedCordZ = mInstance.TransformCord(posZ, mInstance.attachedTo.transform.localPosition.z); grassMap = mInstance.grassMaps[prototype]; grassMapPixels = grassMap.mapPixels; mapWidth = grassMap.mapWidth; density = grassMapPixels[transformedCordX + transformedCordZ * mapWidth].b; if (paintDensity > density || (isErase && (instaRemove || paintDensity < density))) { grassMap.mapPixels[transformedCordX + transformedCordZ * mapWidth].b = isErase && instaRemove ? (byte)0 : paintDensity; grassMap.dirty = true; grassMap.SetPixels32Delayed(); } } } } FoliageCore_MainManager.SaveDelayedMaps(); FoliageCore_MainManager.CallInstancesChunksUpdate(); } }
void DrawPrototypesWindow() { GUILayout.BeginVertical("Box", GUILayout.Width(450)); GUILayout.BeginHorizontal(); GUILayout.Label("Prototypes Management:", EditorStyles.boldLabel); GUILayout.FlexibleSpace(); if (chosenPrototypes.Count > 0) { if (GUILayout.Button("-", GUILayout.Width(15), GUILayout.Width(15))) { if (EditorUtility.DisplayDialog("uNature", "Are you sure you want to delete this prototype ? \nThis cannot be undone!", "Yes", "No")) { for (int i = 0; i < chosenPrototypes.Count; i++) { FoliageDB.instance.RemovePrototype(chosenPrototypes[i]); } chosenPrototypes.Clear(); return; } } if (GUILayout.Button(new GUIContent("R", "Remove the prototype density from this foliage manager."))) { if (EditorUtility.DisplayDialog("uNature", "Are you sure you want to remove this prototype's density ? \nThis cannot be undone!", "Yes", "No")) { for (int i = 0; i < chosenPrototypes.Count; i++) { FoliageCore_MainManager.ResetGrassMap(chosenPrototypes); } } } if (GUILayout.Button(new GUIContent("L", "Locate the material instance of this prototype"))) { UnityEngine.Object[] selectionTargets = new UnityEngine.Object[chosenPrototypes.Count]; for (int i = 0; i < selectionTargets.Length; i++) { selectionTargets[i] = chosenPrototypes[i].FoliageInstancedMeshData.mat; } Selection.objects = selectionTargets; } } GUILayout.EndHorizontal(); chosenPrototypes = UNEditorUtility.DrawPrototypesSelector(FoliageDB.unSortedPrototypes, chosenPrototypes, ctrlPressed, 440, ref prototypesScrollPos); #region Drag and drop DragAndDrop.visualMode = DragAndDropVisualMode.Generic; if (Event.current.type == EventType.DragExited) { GameObject targetFoliagePrefab; Texture2D targetFoliageTexture; UnityEngine.Object targetGeneric; bool exists = false; for (int i = 0; i < DragAndDrop.objectReferences.Length; i++) { targetFoliagePrefab = DragAndDrop.objectReferences[i] as GameObject; targetFoliageTexture = DragAndDrop.objectReferences[i] as Texture2D; targetGeneric = targetFoliagePrefab == null ? (UnityEngine.Object)targetFoliageTexture : targetFoliagePrefab; if (targetGeneric != null) { for (int b = 0; b < FoliageDB.unSortedPrototypes.Count; b++) { if ((targetFoliagePrefab != null && targetFoliagePrefab == FoliageDB.unSortedPrototypes[b].FoliageMesh) || (targetFoliageTexture != null && targetFoliageTexture == FoliageDB.unSortedPrototypes[b].FoliageTexture)) { Debug.LogWarning("Foliage : " + targetGeneric.name + " Already exists! Ignored!"); exists = true; break; } } } if (exists) { continue; } if (targetFoliagePrefab != null) { FoliageDB.instance.AddPrototype(targetFoliagePrefab); } else if (targetFoliageTexture != null) { FoliageDB.instance.AddPrototype(targetFoliageTexture); } } } #endregion GUILayout.EndVertical(); }
public void OnDrawCamera(Camera camera) { if (!FoliageCore_MainManager.instance.enabled || prototypeMeshInstances == null) { return; } bool runCameraCheck = true; FoliageReceiver receiver = null; #if UNITY_EDITOR runCameraCheck = !UnityEditor.SceneView.GetAllSceneCameras().Contains(camera); #endif if (runCameraCheck) { if (FoliageReceiver.FReceivers.Count == 0) { return; } for (int i = 0; i < FoliageReceiver.FReceivers.Count; i++) { if (camera == FoliageReceiver.FReceivers[i].playerCamera) { receiver = FoliageReceiver.FReceivers[i]; break; } if (i == FoliageReceiver.FReceivers.Count - 1) { return; } } } if (receiver != null && !receiver.isGrassReceiver) { return; } int areaSizeIntegral = FoliageCore_MainManager.FOLIAGE_INSTANCE_AREA_SIZE; FoliageCore_Chunk[] targetedChunks = null; FoliageCore_Chunk currentMChunk; if (receiver == null) { targetedChunks = UNStandaloneUtility.GetFoliageChunksNeighbors(camera.transform.position - transform.position, targetedChunks); latestManagerChunk = targetedChunks[4]; } else { targetedChunks = receiver.neighbors; latestManagerChunk = receiver.middleFoliageChunkFromNeighbors; } Vector3 normalizedCameraPosition; FoliageManagerInstance mInstance; FoliageSector sector; FoliageChunk chunk; float density = FoliageCore_MainManager.instance.density; int instancesResolution = FoliageCore_MainManager.instance.instancesSectorResolution; #region PER_INSTANCE GPUMesh gpuInstance = null; FoliageChunk currentInstanceChunk; Vector3 pos; Material mat; int chunkIndex; FoliageMeshInstancesGroup meshGroup; FoliagePrototype prototype; int maxDensity; FoliageMeshInstance meshInstance; Vector3 chunkPos; int gpuMeshIndex = -1; Camera renderCamera = Application.isPlaying ? camera : null; List <FoliageChunk> chunks; Mesh targetMesh; Dictionary <int, GPUMesh> prototypeInstances; bool useQualitySettingsShadows = FoliageCore_MainManager.instance.useQualitySettingsShadowDistance; float shadowsDistance = FoliageCore_MainManager.instance.foliageShadowDistance; #endregion propertyBlock.SetVector("_StreamingAdjuster", UNStandaloneUtility.GetStreamingAdjuster()); if (receiver != null) { propertyBlock.SetFloat("_InteractionResolution", receiver.interactionMapResolutionIntegral); } for (int i = 0; i < targetedChunks.Length; i++) { currentMChunk = targetedChunks[i]; if (currentMChunk == null) { continue; } normalizedCameraPosition = camera.transform.position; if (!currentMChunk.InBounds(normalizedCameraPosition, 100) || !currentMChunk.isFoliageInstanceAttached) { continue; } mInstance = currentMChunk.GetOrCreateFoliageManagerInstance(); normalizedCameraPosition -= mInstance.transform.position; normalizedCameraPosition.x = Mathf.Clamp(normalizedCameraPosition.x, 0, areaSizeIntegral - 1); normalizedCameraPosition.z = Mathf.Clamp(normalizedCameraPosition.z, 0, areaSizeIntegral - 1); sector = mInstance.sector; chunks = sector.FoliageChunks; prototypeInstances = mInstance.meshInstances; chunk = sector.getChunk(normalizedCameraPosition) as FoliageChunk; if (chunk == null) { continue; } if (receiver != null) { propertyBlock.SetVector(PROPERTY_ID_FOLIAGE_INTERACTION_POSITION, chunk.position3D); } DEBUG_ResetValues(); mInstance.UpdateMaterialBlock(propertyBlock); for (int prototypeIndex = 0; prototypeIndex < FoliageDB.unSortedPrototypes.Count; prototypeIndex++) { prototype = FoliageDB.unSortedPrototypes[prototypeIndex]; if (!prototype.enabled) { continue; } int chunkOffset = FoliageMeshInstance.GENERATION_RANGE_OFFSET(prototype); int prototypeRadius = (int)prototype.FoliageGenerationRadius; propertyBlock.SetTexture(PROPERTY_ID_GRASSMAP, mInstance.grassMaps[prototype].map); //DEBUG _lastRenderedPrototypes++; try { gpuInstance = prototypeInstances[prototype.id]; } catch (System.Exception ex) { Debug.LogError(ex.ToString()); return; } try { mat = prototype.FoliageInstancedMeshData.mat; } catch { // if Foliage db was deleted/ a detail was removed... FoliageCore_MainManager.DestroyMeshInstance(prototype.id); OnDrawCamera(camera); return; } int xIndex; int zIndex; for (int x = 0; x < prototypeRadius; x++) { for (int z = 0; z < prototypeRadius; z++) { xIndex = chunk.x + (x - chunkOffset); zIndex = chunk.z + (z - chunkOffset); if (xIndex < 0 || zIndex < 0) { continue; } chunkIndex = xIndex + (zIndex * instancesResolution); if (chunkIndex >= chunks.Count) { continue; } currentInstanceChunk = chunks[chunkIndex]; if (currentInstanceChunk != null) { chunkPos = currentInstanceChunk.position3D; maxDensity = (int)(currentInstanceChunk.GetMaxDensityOnArea(prototype.id) * density); gpuMeshIndex = gpuInstance.GetMesh(maxDensity); if (gpuMeshIndex != -1) { //meshGroup = gpuInstance.LODMeshInstances[x, z, gpuMeshIndex]; meshGroup = gpuInstance.LODMeshInstances[gpuMeshIndex]; targetMesh = gpuInstance.meshes[gpuMeshIndex].mesh; for (int j = 0; j < meshGroup.Count; j++) { meshInstance = meshGroup[j]; pos = meshInstance.GetPosition(chunkPos); if (pos.x < 0 || pos.z < 0 || pos.x >= areaSizeIntegral || pos.z >= areaSizeIntegral) { continue; } propertyBlock.SetVector(PROPERTY_ID_WORLDPOSITION, pos); //DEBUG _lastRenderedVertices += targetMesh.vertexCount; //DEBUG _lastRenderedDrawCalls++; meshInstance.DrawAndUpdate(pos, targetMesh, mat, renderCamera, normalizedCameraPosition, prototype, propertyBlock, useQualitySettingsShadows, shadowsDistance); } } } } } } } }