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();
        }
Exemple #4
0
        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);
        }