Beispiel #1
0
        public void CollectMeshInfo(int maxLodLevel)
        {
            lodMeshInfos = new LodMeshInfo[maxLodLevel + 1];
            for (int lod = 0; lod <= maxLodLevel; lod++)
            {
                lodMeshInfos[lod] = new LodMeshInfo();
                if (layerType == LayerType.SingleMesh_Max4Layer)
                {
                    lodMeshInfos[lod].layerIndices    = new int[1];
                    lodMeshInfos[lod].layerIndices[0] = 0;
                }
                else
                {
                    lodMeshInfos[lod].layerIndices = new int[trees[0].validNums.Length];
                    int maxIndex = trees[0].GetMaxValidNumIndex();
                    for (int i = 0; i < lodMeshInfos[lod].layerIndices.Length; i++)
                    {
                        lodMeshInfos[lod].layerIndices[i == maxIndex ? 0 : (i < maxIndex ? i + 1 : i)] = i;
                    }
                }

                lodMeshInfos[lod].intVertices = TerrainToMeshTool.GetIntVertices(trees[lod]);
                lodMeshInfos[lod].vecNormals  = TerrainToMeshTool.GetNormals(lodMeshInfos[lod].intVertices, terrainData);
                lodMeshInfos[lod].indices     = TerrainToMeshTool.GetIndices(trees[lod], lodMeshInfos[lod].layerIndices);
            }
        }
        public void CreateGridObjects()
        {
            TerrainData terrainData = terrain.terrainData;

            float[,] heights = terrain.terrainData.GetHeights(0, 0, terrain.terrainData.heightmapWidth, terrain.terrainData.heightmapHeight);
            Material matBase = new Material(Shader.Find("Diffuse"));

            matBase.mainTexture = TerrainToMeshTool.BakeBaseTexture(terrainData);
            List <Material> matAdd   = new List <Material>();
            List <Material> matFirst = new List <Material>();

            for (int l = 0; l < terrainData.alphamapLayers; l++)
            {
                matAdd.Add(TerrainToMeshTool.GetMaterial(terrainData, l, false));
                matFirst.Add(TerrainToMeshTool.GetMaterial(terrainData, l, true));
            }

            int w        = terrainData.heightmapWidth - 1;
            int gridNumX = w / gridSize;

            tiles = new TerrainToMeshTile[gridNumX * gridNumX];

            for (int x = 0; x < gridNumX; x++)
            {
                for (int y = 0; y < gridNumX; y++)
                {
                    GameObject objGrid = new GameObject("mesh_" + x + "_" + y);
                    objGrid.transform.SetParent(this.transform, false);
                    TerrainToMeshTile tile = objGrid.AddComponent <TerrainToMeshTile>();
                    tiles[y * gridNumX + x] = tile;
                    tile.matBase            = matBase;
                    tile.matAdd             = matAdd;
                    tile.matFirst           = matFirst;
                    tile.roots       = roots;
                    tile.trees       = new Node[roots.Length];
                    tile.lodLevel    = -1;
                    tile.terrainData = terrainData;
                    tile.heights     = heights;
                    for (int i = 0; i < roots.Length; i++)
                    {
                        tile.trees[i] = roots[i].FindSizeNode(x * gridSize, y * gridSize, gridSize);
                    }
                }
            }
            for (int x = 0; x < gridNumX; x++)
            {
                for (int y = 0; y < gridNumX; y++)
                {
                    //  2
                    //1   3
                    //  0
                    tiles[y * gridNumX + x].adjacencies[0] = y > 0 ? tiles[(y - 1) * gridNumX + x] : null;
                    tiles[y * gridNumX + x].adjacencies[2] = y < gridNumX - 1 ? tiles[(y + 1) * gridNumX + x] : null;
                    tiles[y * gridNumX + x].adjacencies[1] = x > 0 ? tiles[y * gridNumX + x - 1] : null;
                    tiles[y * gridNumX + x].adjacencies[3] = x < gridNumX - 1 ? tiles[y * gridNumX + x + 1] : null;
                }
            }
            Update();
        }
        public void UpdateChildren()
        {
            lodLevel = newLodLevel;
            while (transform.childCount > 0)
            {
                DestroyImmediate(transform.GetChild(0).gameObject);
            }

            SetNodeSkirts(trees[lodLevel]);
            if (lodLevel <= 1)
            {
                int[] layerIndices = new int[trees[0].validNums.Length];
                int   maxIndex     = trees[0].GetMaxValidNumIndex();
                for (int i = 0; i < trees[0].validNums.Length; i++)
                {
                    layerIndices[i == maxIndex ? 0 : (i < maxIndex ? i + 1 : i)] = i;
                }
                Mesh mesh = TerrainToMeshTool.CreateMesh(trees[lodLevel], terrainData, heights, layerIndices);

                GameObject   obj      = new GameObject("layer_lod_" + lodLevel);
                MeshRenderer renderer = obj.AddComponent <MeshRenderer>();
                MeshFilter   filter   = obj.AddComponent <MeshFilter>();
                obj.transform.SetParent(transform, false);
                filter.sharedMesh = mesh;
                Material[] sharedMaterials = new Material[mesh.subMeshCount];
                for (int i = 0; i < mesh.subMeshCount; i++)
                {
                    sharedMaterials[i] = (i == 0) ? matFirst[layerIndices[i]] : matAdd [layerIndices[i]];
                }
                renderer.sharedMaterials = sharedMaterials;
            }
            else
            {
                Mesh mesh = TerrainToMeshTool.CreateMesh(trees[lodLevel], terrainData, heights, new int[] { 0 });

                GameObject   obj      = new GameObject("base_lod_" + lodLevel);
                MeshRenderer renderer = obj.AddComponent <MeshRenderer>();
                MeshFilter   filter   = obj.AddComponent <MeshFilter>();
                renderer.sharedMaterial = matBase;
                filter.sharedMesh       = mesh;
                obj.transform.SetParent(transform, false);
            }
        }
Beispiel #4
0
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();
            if (converter.terrain)
            {
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("测试"))
                {
                    converter.bakedControlTexture = TerrainToMeshTool.BakeTextureIndex(converter.terrain.terrainData);
                }
                if (GUILayout.Button("生成分层网格"))
                {
                    converter.trees = new LodNodeTree[converter.maxLodLevel + 1];
                    for (int i = 0; i <= converter.maxLodLevel; i++)
                    {
                        converter.trees[i] = new LodNodeTree();
                        float       error    = converter.minError * Mathf.Pow(Mathf.Pow(converter.maxError / converter.minError, 1.0f / (converter.maxLodLevel)), i);
                        Node        tempNode = CreateNode(error, converter.gridSize);
                        List <byte> bytes    = new List <byte>();
                        tempNode.ToBytes(bytes);
                        converter.trees[i].tree        = bytes.ToArray();
                        converter.trees[i].alphaLayers = tempNode.GetAlphaBytes();
                    }

                    converter.LoadNodes();

                    converter.ClearChildren();
                    converter.CollectInfos();
                    if (converter.staticLodMesh)
                    {
                        converter.CreateStaticMeshes();
                        converter.ClearCollectedInfo();
                    }
                    else
                    {
                        converter.Update();
                    }
                }
                GUILayout.EndHorizontal();
            }
            EditorGUILayout.LabelField("内存", converter.GetMemorySize().ToString());
        }
Beispiel #5
0
        Node CreateNode(float maxError, int maxSize)
        {
            int w = converter.terrain.terrainData.heightmapWidth;
            int h = converter.terrain.terrainData.heightmapHeight;

            float[,] heights = converter.terrain.terrainData.GetHeights(0, 0, w, h);
            int aw = converter.terrain.terrainData.alphamapWidth;
            int ah = converter.terrain.terrainData.alphamapHeight;

            float[,,] alphamaps = converter.terrain.terrainData.GetAlphamaps(0, 0, aw, ah);

            Node root = new Node(0, 0, w - 1);

            AddNode(root);

            //统计不透明的格子数量
            root.PostorderTraversal((Node node) => {
                node.validNums = new int[converter.terrain.terrainData.alphamapLayers];
                for (int alphaLayer = 0; alphaLayer < node.validNums.Length; alphaLayer++)
                {
                    if (node.size == 1)
                    {
                        node.validNums[alphaLayer] = TestAlphaMap(alphamaps, node.x * aw / (w - 1), node.y * ah / (h - 1), aw / (w - 1), alphaLayer) ? 1 : 0;
                    }
                    else
                    {
                        node.validNums[alphaLayer] = node.childs[0].validNums[alphaLayer] + node.childs[1].validNums[alphaLayer] + node.childs[2].validNums[alphaLayer] + node.childs[3].validNums[alphaLayer];
                    }
                }
            });

            //合并格子
            for (int m = 1; 1 << m < w; m++)
            {
                int step = 1 << m;
                if (step < maxSize)
                {
                    root.TraversalSize(step, (Node node) => {
                        bool allChildrenIsMerged = node.childs != null && node.childs[0].childs == null && node.childs[1].childs == null && node.childs[2].childs == null && node.childs[3].childs == null;
                        if (allChildrenIsMerged)
                        {
                            float childErrorSum = node.childs[0].error + node.childs[1].error + node.childs[2].error + node.childs[3].error;
                            float error         = childErrorSum * 0.3f + GetHeightError(heights, node.x, node.y, node.size, out node.swapEdge) * converter.terrain.terrainData.size.y;
                            if (error < maxError && CheckSourrond(root, node.x, node.y, node.size))
                            {
                                node.error  = error;
                                node.childs = null;
                            }
                        }
                    });
                }
            }

            //为了消除T接缝,如果相邻格子比自己大,则靠近大格子的两个三角形要合并为一个
            root.PreorderTraversal((Node node) => {
                if (node.childs != null)
                {
                    //x - 1
                    if (node.childs[0].childs == null && node.childs[2].childs == null && TerrainToMeshTool.IsSizeLeaf(root, node.x - 1, node.y, node.size))
                    {
                        node.mergeTriangle |= 1 << 1;
                    }
                    //y - 1
                    if (node.childs[0].childs == null && node.childs[1].childs == null && TerrainToMeshTool.IsSizeLeaf(root, node.x, node.y - 1, node.size))
                    {
                        node.mergeTriangle |= 1 << 0;
                    }

                    //x + 1
                    if (node.childs[1].childs == null && node.childs[3].childs == null && TerrainToMeshTool.IsSizeLeaf(root, node.x + node.size + 1, node.y, node.size))
                    {
                        node.mergeTriangle |= 1 << 3;
                    }
                    //y + 1
                    if (node.childs[2].childs == null && node.childs[3].childs == null && TerrainToMeshTool.IsSizeLeaf(root, node.x, node.y + node.size + 1, node.size))
                    {
                        node.mergeTriangle |= 1 << 2;
                    }
                }
            });

            return(root);
        }
Beispiel #6
0
        //创建某个级别的LOD的网格
        public List <Renderer> CreateRenderersForOneLodLevel(int lod)
        {
            List <Renderer> lodRenderers = new List <Renderer>(10);

            if (lod >= 0 && lod < lodMeshInfos.Length)
            {
                lodRenderers.Clear();
                if (lod < 2)
                {
                    bool[] layerValid = new bool[lodMeshInfos[lod].layerIndices.Length];

                    if (layerType == LayerType.SubMesh)
                    {
                        for (int i = 0; i < lodMeshInfos[lod].layerIndices.Length; i++)
                        {
                            if (lodMeshInfos[lod].indices[lodMeshInfos[lod].layerIndices[i]].Length > 0)
                            {
                                layerValid[i] = true;
                            }
                        }
                        Mesh         mesh     = TerrainToMeshTool.CreateMesh(terrainData, heights, lodMeshInfos[lod].intVertices, lodMeshInfos[lod].vecNormals, lodMeshInfos[lod].indices, -1);
                        MeshRenderer renderer = CreateMeshRenderer_SubMesh(mesh, layerValid, lodMeshInfos[lod].layerIndices, lod);
                        if (renderer)
                        {
                            lodRenderers.Add(renderer);
                        }
                    }
                    else if (layerType == LayerType.SingleMesh_Max4Layer)
                    {
                        Mesh         mesh     = TerrainToMeshTool.CreateMesh(terrainData, heights, lodMeshInfos[lod].intVertices, lodMeshInfos[lod].vecNormals, lodMeshInfos[lod].indices, 0);
                        MeshRenderer renderer = CreateMeshRenderer_SingleMesh(mesh, lod);
                        if (renderer)
                        {
                            lodRenderers.Add(renderer);
                        }
                    }
                    else if (layerType == LayerType.SingleMesh_LayerIndexTexture)
                    {
                        Mesh         mesh     = TerrainToMeshTool.CreateMesh(terrainData, heights, lodMeshInfos[lod].intVertices, lodMeshInfos[lod].vecNormals, lodMeshInfos[lod].indices, 0);
                        MeshRenderer renderer = CreateMeshRenderer_SingleMesh_TextureIndex(mesh, lod);
                        if (renderer)
                        {
                            lodRenderers.Add(renderer);
                        }
                    }
                    else
                    {
                        for (int i = 0; i < lodMeshInfos[lod].layerIndices.Length; i++)
                        {
                            Mesh         mesh     = TerrainToMeshTool.CreateMesh(terrainData, heights, lodMeshInfos[lod].intVertices, lodMeshInfos[lod].vecNormals, lodMeshInfos[lod].indices, i);
                            MeshRenderer renderer = CreateMeshRenderer_OneOfMultiMesh(mesh, lodMeshInfos[lod].layerIndices[i], i == 0, lod);
                            if (renderer)
                            {
                                lodRenderers.Add(renderer);
                            }
                        }
                    }
                }
                else
                {
                    List <TerrainToMeshTool.VecInt3>   intVertices = TerrainToMeshTool.GetIntVertices(trees[lod]);
                    List <TerrainToMeshTool.VecNormal> vecNormals  = TerrainToMeshTool.GetNormals(intVertices, terrainData);
                    List <int[]> indices = TerrainToMeshTool.GetIndices(trees[lod], new int[] { 0 });

                    Mesh mesh = TerrainToMeshTool.CreateMesh(terrainData, heights, intVertices, vecNormals, indices, 0);

                    GameObject   obj      = new GameObject("base_lod_" + lod);
                    MeshRenderer renderer = obj.AddComponent <MeshRenderer>();
                    MeshFilter   filter   = obj.AddComponent <MeshFilter>();
                    renderer.sharedMaterial = matBase;
                    filter.sharedMesh       = mesh;
                    obj.transform.SetParent(transform, false);
                    lodRenderers.Add(renderer);
                }
            }
            return(lodRenderers);
        }
Beispiel #7
0
        public void CollectInfos()
        {
            TerrainData     terrainData = terrain.terrainData;
            Texture2D       baseTexture = TerrainToMeshTool.BakeBaseTexture(terrain.terrainData);
            List <Material> matAdd      = new List <Material>();
            List <Material> matFirst    = new List <Material>();
            Material        matBase     = new Material(shaderBase);

            matBase.SetTexture("_MainTex", baseTexture);
            float[,] heights = terrain.terrainData.GetHeights(0, 0, terrain.terrainData.heightmapWidth, terrain.terrainData.heightmapHeight);
            Texture2DArray texArray        = null;
            Material       terrainMaterial = new Material(Shader.Find("Nature/Terrain/Diffuse"));

            if (layerType == LayerType.SingleMesh_LayerIndexTexture)
            {
                bakedControlTexture = TerrainToMeshTool.BakeTextureIndex(terrain.terrainData);
                {
                    Texture firstTexture = terrainData.splatPrototypes[0].texture;
                    texArray = new Texture2DArray(firstTexture.width, firstTexture.height, terrainData.splatPrototypes.Length, TextureFormat.ARGB32, true, true);
                    for (int i = 0; i < terrainData.splatPrototypes.Length; i++)
                    {
                        texArray.SetPixels32(terrainData.splatPrototypes[i].texture.GetPixels32(), i);
                    }
                    texArray.Apply();
                }
                if (terrainTextureIndexMaterial == null)
                {
                    terrainTextureIndexMaterial = new Material(Shader.Find("Mobile/TerrainTextureIndex"));
                }
                else
                {
                    terrainTextureIndexMaterial.shader = Shader.Find("Mobile/TerrainTextureIndex");
                }
                terrainTextureIndexMaterial.SetTexture("_IndexControl", bakedControlTexture);
                terrainTextureIndexMaterial.SetTexture("_TexArray", texArray);
                terrainTextureIndexMaterial.SetFloat("_TexArrayNum", terrainData.splatPrototypes.Length);

                terrainTextureIndexMaterial.SetVectorArray("_ScaleOffset", GetScaleOffsets(terrainData));
            }
            else if (layerType == LayerType.SingleMesh_Max4Layer)
            {
                bakedControlTexture = TerrainToMeshTool.BakeControlTexture(terrain.terrainData, roots[0], gridSize, 4);
            }
            else
            {
                for (int l = 0; l < terrainData.alphamapLayers; l++)
                {
                    LayerProperty lp = l < layerProperties.Length ? layerProperties[l] : null;
                    matAdd.Add(TerrainToMeshTool.GetMaterial(terrain, l, shaderAdd, lp));
                    matFirst.Add(TerrainToMeshTool.GetMaterial(terrain, l, shaderFirst, lp));
                }
            }

            int w        = terrainData.heightmapWidth - 1;
            int gridNumX = w / gridSize;

            tiles = new TerrainToMeshTile[gridNumX * gridNumX];

            for (int x = 0; x < gridNumX; x++)
            {
                for (int y = 0; y < gridNumX; y++)
                {
                    GameObject objGrid = new GameObject("mesh_" + x + "_" + y);
                    objGrid.transform.SetParent(GetRootTransform(), false);
                    TerrainToMeshTile tile = objGrid.AddComponent <TerrainToMeshTile>();
                    tiles[y * gridNumX + x] = tile;
                    tile.matBase            = matBase;
                    tile.matAdd             = matAdd;
                    tile.matFirst           = matFirst;
                    tile.lodLevel           = -1;
                    tile.terrainData        = terrainData;
                    tile.heights            = heights;
                    tile.roots                       = roots;
                    tile.trees                       = new Node[roots.Length];
                    tile.layerType                   = layerType;
                    tile.lodPower                    = lodPower;
                    tile.terrainMaterial             = terrainMaterial;
                    tile.bakedControlTexture         = bakedControlTexture;
                    tile.terrainTextureIndexMaterial = terrainTextureIndexMaterial;
                    tile.texArray                    = texArray;
                    for (int lod = 0; lod < roots.Length; lod++)
                    {
                        tile.trees[lod] = roots[lod].FindSizeNode(x * gridSize, y * gridSize, gridSize);
                        TerrainToMeshTool.SetNodeSkirts(tile.trees[lod], tile.trees[lod]);
                    }
                }
            }

            for (int x = 0; x < gridNumX; x++)
            {
                for (int y = 0; y < gridNumX; y++)
                {
                    tiles[y * gridNumX + x].CollectMeshInfo(maxLodLevel);
                }
            }
        }