public override void OnInspectorGUI() { base.OnInspectorGUI(); if (GUILayout.Button("Create")) { GrassBakeSettings grassBakeSettings = target as GrassBakeSettings; if (grassBakeSettings == null) { return; } string path = EditorUtility.SaveFilePanel("Save Grass Asset", "Assets/", name, "prefab"); if (string.IsNullOrEmpty(path)) { return; } path = FileUtil.GetProjectRelativePath(path); string meshDirectory = GetMeshDirectory(path); Mesh[,,] generatedMeshes = SaveMeshes(grassBakeSettings, meshDirectory); SavePrefabs(generatedMeshes, grassBakeSettings, path); } }
private Mesh[,,] SaveMeshes(GrassBakeSettings grassBakeSettings, string directory) { Mesh[,,] generatedMeshes = new Mesh[(int)grassBakeSettings.numTiles.x, (int)grassBakeSettings.numTiles.y, grassBakeSettings.grassLODLevelSettings.Length]; for (int x = 0; x < generatedMeshes.GetLength(0); ++x) { for (int y = 0; y < generatedMeshes.GetLength(1); ++y) { for (int i = 0; i < generatedMeshes.GetLength(2); ++i) { bool success = GrassBuilder.Run(grassBakeSettings, i, out generatedMeshes[x, y, i]); if (success) { string meshPath = directory + "/" + directory.Substring(directory.LastIndexOf('/') + 1, directory.Length - directory.LastIndexOf('/') - 1) + x + y + i + ".asset"; AssetDatabase.CreateAsset(generatedMeshes[x, y, i], meshPath); } else { Debug.LogError("Fail to create grass"); return(null); } } } } AssetDatabase.Refresh(); return(generatedMeshes); }
private void SavePrefabs(Mesh[,,] generatedMeshes, GrassBakeSettings grassBakeSettings, string path) { GameObject topParentObject = new GameObject(); Vector2 tileSize = grassBakeSettings.extents / grassBakeSettings.numTiles; for (int x = 0; x < generatedMeshes.GetLength(0); ++x) { for (int y = 0; y < generatedMeshes.GetLength(1); ++y) { GameObject tileParentObject = new GameObject(); tileParentObject.transform.parent = topParentObject.transform; tileParentObject.name = "Tile" + x + y; LODGroup lodGroup = tileParentObject.AddComponent <LODGroup>(); LOD[] lods = new LOD[generatedMeshes.GetLength(2)]; for (int i = 0; i < generatedMeshes.GetLength(2); ++i) { GameObject generatedGrass = new GameObject(); generatedGrass.name = "" + x + y + "_LOD" + i; generatedGrass.transform.position = new Vector3( x * tileSize.x - generatedMeshes.GetLength(0) * tileSize.x / 2f, 0f, y * tileSize.y - generatedMeshes.GetLength(1) * tileSize.y / 2f); MeshFilter meshFilter = generatedGrass.AddComponent <MeshFilter>(); meshFilter.sharedMesh = generatedMeshes[x, y, i]; MeshRenderer meshRenderer = generatedGrass.AddComponent <MeshRenderer>(); meshRenderer.sharedMaterial = grassBakeSettings.grassLODLevelSettings[i].grassMaterial; generatedGrass.transform.parent = tileParentObject.transform; Renderer[] renderers = new Renderer[1]; renderers[0] = meshRenderer; lods[i] = new LOD(grassBakeSettings.grassLODLevelSettings[i].lodPercent, renderers); } lodGroup.SetLODs(lods); lodGroup.RecalculateBounds(); } } PrefabUtility.SaveAsPrefabAsset(topParentObject, path); DestroyImmediate(topParentObject); AssetDatabase.SaveAssets(); }
public static bool Run(GrassBakeSettings settings, int lod, out Mesh generatedMesh) { GrassLODLevelSettings currentLOD; try { currentLOD = settings.grassLODLevelSettings[lod]; } catch (Exception e) { Console.WriteLine(e); generatedMesh = null; return(false); } DecomposeMesh(currentLOD.grassBladeMesh, 0, out SourceVertex[] sourceGrassBladeVertices, out int[] sourceGrassBladeIndices); int numBlades = (int)((settings.extents.x / settings.numTiles.x) * (settings.extents.y / settings.numTiles.y) / (currentLOD.density * currentLOD.density)); GeneratedVertex[] generatedVertices = new GeneratedVertex[numBlades * sourceGrassBladeVertices.Length]; int[] generatedIndices = new int[numBlades * sourceGrassBladeIndices.Length]; GraphicsBuffer sourceGrassBladeVertexBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, sourceGrassBladeIndices.Length, SOURCE_VERTEX_STRIDE); GraphicsBuffer sourceGrassBladeIndexBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, sourceGrassBladeIndices.Length, SOURCE_INDEX_STRIDE); GraphicsBuffer generatedVertexBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, generatedVertices.Length, GENERATED_VERTEX_STRIDE); GraphicsBuffer generatedIndexBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, generatedIndices.Length, GENERATED_INDEX_STRIDE); ComputeShader shader = settings.computeShader; int idGrassKernel = shader.FindKernel("CSMain"); shader.SetBuffer(idGrassKernel, "_SourceGrassBladeVertices", sourceGrassBladeVertexBuffer); shader.SetBuffer(idGrassKernel, "_SourceGrassBladeIndices", sourceGrassBladeIndexBuffer); shader.SetBuffer(idGrassKernel, "_GeneratedVertices", generatedVertexBuffer); shader.SetBuffer(idGrassKernel, "_GeneratedIndices", generatedIndexBuffer); shader.SetVector("_MinMaxRandomScale", currentLOD.minMaxScale); shader.SetVector("_TileSize", settings.extents / settings.numTiles); shader.SetFloat("_Density", currentLOD.density); shader.SetFloat("_MaxRandomPositionShift", currentLOD.maxRandomPositionShift); shader.SetInt("_NumGrassBladeVertices", sourceGrassBladeVertices.Length); shader.SetInt("_NumGrassBladeIndices", sourceGrassBladeIndices.Length); sourceGrassBladeVertexBuffer.SetData(sourceGrassBladeVertices); sourceGrassBladeIndexBuffer.SetData(sourceGrassBladeIndices); int numBladesRemaining = numBlades; for (int i = 0; i <= generatedVertices.Length / MAX_VERTS_PER_DISPATCH; ++i) { int maxBlades = MAX_VERTS_PER_DISPATCH / sourceGrassBladeVertices.Length; int numBladesToCalculate = numBladesRemaining > maxBlades ? maxBlades : numBladesRemaining; if (numBladesRemaining == 0) { break; } shader.SetInt("_NumBlades", numBladesToCalculate); shader.SetInt("_StartBladeIndex", i * maxBlades); shader.SetInt("_StartVertexIndex", i * Mathf.FloorToInt((float)MAX_VERTS_PER_DISPATCH / sourceGrassBladeVertices.Length) * sourceGrassBladeVertices.Length); shader.GetKernelThreadGroupSizes(idGrassKernel, out uint threadGroupSize, out _, out _); int dispatchSize = Mathf.CeilToInt((float)numBladesToCalculate / threadGroupSize); shader.Dispatch(idGrassKernel, dispatchSize, 1, 1); generatedVertexBuffer.GetData(generatedVertices, i * maxBlades * sourceGrassBladeVertices.Length, 0, numBladesToCalculate * sourceGrassBladeVertices.Length); generatedIndexBuffer.GetData(generatedIndices, i * maxBlades * sourceGrassBladeIndices.Length, 0, numBladesToCalculate * sourceGrassBladeIndices.Length); numBladesRemaining -= numBladesToCalculate; } generatedMesh = ComposeMesh(generatedVertices, generatedIndices); sourceGrassBladeVertexBuffer.Release(); sourceGrassBladeIndexBuffer.Release(); generatedVertexBuffer.Release(); generatedIndexBuffer.Release(); return(true); }