Пример #1
0
        private int CalcBorderWidth(Heightmap heightmap, int distance)
        {
            if (m_hlod.SimplifierType == typeof(Simplifier.None))
            {
                return(1);
            }
            dynamic options = m_hlod.SimplifierOptions;

            int   maxPolygonCount = options.SimplifyMaxPolygonCount;
            int   minPolygonCount = options.SimplifyMinPolygonCount;
            float polygonRatio    = options.SimplifyPolygonRatio;
            int   triangleCount   = (heightmap.Width - 1) * (heightmap.Height - 1) * 2;

            float maxQuality = Mathf.Min((float)maxPolygonCount / (float)triangleCount, polygonRatio);
            float minQuality = Mathf.Max((float)minPolygonCount / (float)triangleCount, 0.0f);

            var ratio = maxQuality * Mathf.Pow(polygonRatio, distance);

            ratio = Mathf.Max(ratio, minQuality);

            int expectPolygonCount = (int)(triangleCount * ratio);

            float areaSize         = (heightmap.Size.x * heightmap.Size.z);
            float sourceSizePerTri = areaSize / triangleCount;
            float targetSizePerTri = areaSize / expectPolygonCount;
            float sizeRatio        = targetSizePerTri / sourceSizePerTri;
            float sizeRatioSqrt    = Mathf.Sqrt(sizeRatio);

            //sizeRatioSqrt is little bit big i think.
            //So I adjust the value by divide 2.
            return(Mathf.Max((int)sizeRatioSqrt / 2, 1));
        }
Пример #2
0
        private void ReampUV(WorkingMesh mesh, Heightmap heightmap)
        {
            var vertices = mesh.vertices;
            var uvs      = mesh.uv;

            for (int i = 0; i < mesh.vertexCount; ++i)
            {
                Vector2 uv;
                uv.x   = (vertices[i].x - heightmap.Offset.x) / heightmap.Size.x;
                uv.y   = (vertices[i].z - heightmap.Offset.z) / heightmap.Size.z;
                uvs[i] = uv;
                //vertices[i].
            }

            mesh.uv = uvs;
        }
Пример #3
0
        private WorkingObject CreateBakedTerrain(string name, Bounds bounds, Heightmap heightmap, int distance)
        {
            WorkingObject wo = new WorkingObject(Allocator.Persistent);

            wo.Name = name;


            m_queue.EnqueueJob(() =>
            {
                WorkingMesh mesh = CreateBakedGeometry(name, heightmap, bounds, distance);
                wo.SetMesh(mesh);
            });

            m_queue.EnqueueJob(() =>
            {
                WorkingMaterial material = CreateBakedMaterial(name, bounds);
                wo.Materials.Add(material);
            });


            return(wo);
        }
Пример #4
0
        private WorkingObject CreateBakedTerrain(string name, Bounds bounds, Heightmap heightmap, int distance, bool isLeaf)
        {
            WorkingObject wo = new WorkingObject(Allocator.Persistent);

            wo.Name            = name;
            wo.LightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off;

            m_queue.EnqueueJob(() =>
            {
                WorkingMesh mesh = CreateBakedGeometry(name, heightmap, bounds, distance);
                wo.SetMesh(mesh);
            });

            m_queue.EnqueueJob(() =>
            {
                WorkingMaterial material = CreateBakedMaterial(name, bounds, isLeaf);
                wo.Materials.Add(material);
            });


            return(wo);
        }
Пример #5
0
        public Heightmap GetHeightmap(int beginX, int beginZ, int width, int height)
        {
            Heightmap heightmap = new Heightmap();

            heightmap.m_width  = width;
            heightmap.m_height = height;

            heightmap.m_offset = new Vector3(beginX * m_scale.x, 0.0f, beginZ * m_scale.z);
            heightmap.m_size   = new Vector3(m_scale.x * (width - 1), m_size.y, m_scale.z * (height - 1));
            heightmap.m_scale  = m_scale;

            heightmap.m_heights = new float[height + 2, width + 2];

            for (int x = 0; x < width + 2; ++x)
            {
                for (int z = 0; z < height + 2; ++z)
                {
                    heightmap.m_heights[z, x] = m_heights[z + beginZ, x + beginX];
                }
            }

            return(heightmap);
        }
Пример #6
0
        public IEnumerator CreateImpl()
        {
            try
            {
                using (m_queue = new JobQueue(8))
                {
                    Stopwatch sw = new Stopwatch();

                    AssetDatabase.Refresh();
                    AssetDatabase.SaveAssets();

                    sw.Reset();
                    sw.Start();

                    EditorUtility.DisplayProgressBar("Bake HLOD", "Initialize Bake", 0.0f);


                    TerrainData data = m_hlod.TerrainData;

                    m_size = data.size;

                    m_heightmap = new Heightmap(data.heightmapResolution, data.heightmapResolution, data.size,
                                                data.GetHeights(0, 0, data.heightmapResolution, data.heightmapResolution));

                    string materialPath = AssetDatabase.GUIDToAssetPath(m_hlod.MaterialGUID);
                    m_terrainMaterial = AssetDatabase.LoadAssetAtPath <Material>(materialPath);
                    if (m_terrainMaterial == null)
                    {
                        m_terrainMaterial = new Material(Shader.Find("Standard"));
                    }

                    m_terrainMaterialInstanceId = m_terrainMaterial.GetInstanceID();
                    m_terrainMaterialName       = m_terrainMaterial.name;

                    using (m_alphamaps = new DisposableList <WorkingTexture>())
                        using (m_layers = new DisposableList <Layer>())
                        {
                            for (int i = 0; i < data.alphamapTextures.Length; ++i)
                            {
                                m_alphamaps.Add(new WorkingTexture(Allocator.Persistent, data.alphamapTextures[i]));
                            }

                            for (int i = 0; i < data.terrainLayers.Length; ++i)
                            {
                                m_layers.Add(new Layer(data.terrainLayers[i]));
                            }


                            QuadTreeSpaceSplitter splitter =
                                new QuadTreeSpaceSplitter(0.0f);

                            SpaceNode rootNode = splitter.CreateSpaceTree(m_hlod.GetBounds(), m_hlod.ChunkSize * 2.0f,
                                                                          m_hlod.transform.position, null, progress => { });

                            EditorUtility.DisplayProgressBar("Bake HLOD", "Create mesh", 0.0f);

                            using (DisposableList <HLODBuildInfo> buildInfos = CreateBuildInfo(data, rootNode))
                            {
                                yield return(m_queue.WaitFinish());

                                //Write material & textures

                                for (int i = 0; i < buildInfos.Count; ++i)
                                {
                                    int curIndex = i;
                                    m_queue.EnqueueJob(() =>
                                    {
                                        ISimplifier simplifier = (ISimplifier)Activator.CreateInstance(m_hlod.SimplifierType,
                                                                                                       new object[] { m_hlod.SimplifierOptions });
                                        simplifier.SimplifyImmidiate(buildInfos[curIndex]);
                                    });
                                }

                                EditorUtility.DisplayProgressBar("Bake HLOD", "Simplify meshes", 0.0f);
                                yield return(m_queue.WaitFinish());

                                Debug.Log("[TerrainHLOD] Simplify: " + sw.Elapsed.ToString("g"));
                                sw.Reset();
                                sw.Start();
                                EditorUtility.DisplayProgressBar("Bake HLOD", "Make border", 0.0f);

                                for (int i = 0; i < buildInfos.Count; ++i)
                                {
                                    HLODBuildInfo info = buildInfos[i];
                                    m_queue.EnqueueJob(() =>
                                    {
                                        for (int oi = 0; oi < info.WorkingObjects.Count; ++oi)
                                        {
                                            WorkingObject o       = info.WorkingObjects[oi];
                                            int borderVertexCount = m_hlod.BorderVertexCount * Mathf.RoundToInt(Mathf.Pow(2.0f, (float)info.Distances[oi]));
                                            using (WorkingMesh m = MakeBorder(o.Mesh, info.Heightmap, borderVertexCount))
                                            {
                                                ReampUV(m, info.Heightmap);
                                                o.SetMesh(MakeFillHoleMesh(m));
                                            }
                                        }
                                    });
                                }
                                yield return(m_queue.WaitFinish());

                                Debug.Log("[TerrainHLOD] Make Border: " + sw.Elapsed.ToString("g"));
                                sw.Reset();
                                sw.Start();


                                for (int i = 0; i < buildInfos.Count; ++i)
                                {
                                    SpaceNode     node = buildInfos[i].Target;
                                    HLODBuildInfo info = buildInfos[i];
                                    if (node.HasChild() == false)
                                    {
                                        SpaceNode parent = node.ParentNode;
                                        node.ParentNode = null;

                                        GameObject go = new GameObject(buildInfos[i].Name);

                                        for (int wi = 0; wi < info.WorkingObjects.Count; ++wi)
                                        {
                                            WorkingObject wo       = info.WorkingObjects[wi];
                                            GameObject    targetGO = null;
                                            if (wi == 0)
                                            {
                                                targetGO = go;
                                            }
                                            else
                                            {
                                                targetGO = new GameObject(wi.ToString());
                                                targetGO.transform.SetParent(go.transform, false);
                                            }

                                            List <Material> materials = new List <Material>();
                                            for (int mi = 0; mi < wo.Materials.Count; ++mi)
                                            {
                                                WorkingMaterial wm = wo.Materials[mi];
                                                if (wm.NeedWrite() == false)
                                                {
                                                    materials.Add(wm.ToMaterial());
                                                    continue;
                                                }

                                                Material mat          = new Material(wm.ToMaterial());
                                                string[] textureNames = wm.GetTextureNames();
                                                for (int ti = 0; ti < textureNames.Length; ++ti)
                                                {
                                                    WorkingTexture wt  = wm.GetTexture(textureNames[ti]);
                                                    Texture2D      tex = wt.ToTexture();
                                                    tex.wrapMode = wt.WrapMode;
                                                    mat.name     = targetGO.name + "_Mat";
                                                    mat.SetTexture(textureNames[ti], tex);
                                                }
                                                mat.EnableKeyword("_NORMALMAP");
                                                materials.Add(mat);
                                            }

                                            targetGO.AddComponent <MeshFilter>().sharedMesh        = wo.Mesh.ToMesh();
                                            targetGO.AddComponent <MeshRenderer>().sharedMaterials = materials.ToArray();
                                        }

                                        go.transform.SetParent(m_hlod.transform, false);
                                        m_hlod.AddGeneratedResource(go);

                                        parent.Objects.Add(go);
                                        buildInfos.RemoveAt(i);
                                        i -= 1;
                                    }
                                }

                                //controller
                                IStreamingBuilder builder =
                                    (IStreamingBuilder)Activator.CreateInstance(m_hlod.StreamingType,
                                                                                new object[] { m_hlod, m_hlod.StreamingOptions });

                                builder.Build(rootNode, buildInfos, m_hlod.gameObject, m_hlod.CullDistance, m_hlod.LODDistance, true, false,
                                              progress =>
                                {
                                    EditorUtility.DisplayProgressBar("Bake HLOD", "Storing results.",
                                                                     0.75f + progress * 0.25f);
                                });

                                Debug.Log("[TerrainHLOD] Build: " + sw.Elapsed.ToString("g"));
                            }
                        }

                    EditorUtility.SetDirty(m_hlod.gameObject);
                }
            }
            finally
            {
                EditorUtility.ClearProgressBar();
                GC.Collect();
            }
        }
Пример #7
0
        private WorkingMesh MakeBorder(WorkingMesh source, Heightmap heightmap, int borderCount)
        {
            List <Vector3> vertices    = source.vertices.ToList();
            List <Vector3> normals     = source.normals.ToList();
            List <Vector2> uvs         = source.uv.ToList();
            List <int[]>   subMeshTris = new List <int[]>();

            int maxTris = 0;

            for (int si = 0; si < source.subMeshCount; ++si)
            {
                List <int>          tris         = source.GetTriangles(si).ToList();
                List <Vector2Int>   edges        = GetEdgeList(tris);
                HashSet <int>       vertexIndces = new HashSet <int>();
                List <BorderVertex> edgeVertices = new List <BorderVertex>();

                for (int ei = 0; ei < edges.Count; ++ei)
                {
                    vertexIndces.Add(edges[ei].x);
                    vertexIndces.Add(edges[ei].y);
                }

                List <BorderVertex> borderVertices = GenerateBorderVertices(heightmap, borderCount);

                //calculate closest vertex from border vertices.
                for (int i = 0; i < borderVertices.Count; ++i)
                {
                    float        closestDistance = Single.MaxValue;
                    BorderVertex v = borderVertices[i];
                    foreach (var index in vertexIndces)
                    {
                        Vector3 pos  = vertices[index];
                        float   dist = Vector3.SqrMagnitude(pos - borderVertices[i].Pos);
                        if (dist < closestDistance)
                        {
                            closestDistance = dist;
                            v.ClosestIndex  = index;
                        }
                    }

                    borderVertices[i] = v;
                }

                //generate tris
                int startAddIndex = vertices.Count;
                for (int bi = 0; bi < borderVertices.Count; ++bi)
                {
                    int next = (bi == borderVertices.Count - 1) ? 0 : bi + 1;

                    tris.Add(bi + startAddIndex);
                    tris.Add(borderVertices[bi].ClosestIndex);
                    tris.Add(next + startAddIndex);

                    Vector2 uv;
                    uv.x = (borderVertices[bi].Pos.x - heightmap.Offset.x) / heightmap.Size.x;
                    uv.y = (borderVertices[bi].Pos.z - heightmap.Offset.z) / heightmap.Size.z;
                    vertices.Add(borderVertices[bi].Pos);

                    if (m_hlod.UseNormal)
                    {
                        normals.Add(Vector3.up);
                    }
                    else
                    {
                        normals.Add(heightmap.GetInterpolatedNormal(uv.x, uv.y));
                    }

                    uvs.Add(uv);

                    if (borderVertices[bi].ClosestIndex == borderVertices[next].ClosestIndex)
                    {
                        continue;
                    }

                    tris.Add(borderVertices[bi].ClosestIndex);
                    tris.Add(borderVertices[next].ClosestIndex);
                    tris.Add(next + startAddIndex);
                }

                maxTris += tris.Count;
                subMeshTris.Add(tris.ToArray());
            }

            WorkingMesh mesh = new WorkingMesh(Allocator.Persistent, vertices.Count, maxTris, subMeshTris.Count, 0);

            mesh.name     = source.name;
            mesh.vertices = vertices.ToArray();
            mesh.normals  = normals.ToArray();
            mesh.uv       = uvs.ToArray();

            for (int i = 0; i < subMeshTris.Count; ++i)
            {
                mesh.SetTriangles(subMeshTris[i], i);
            }

            return(mesh);
        }
Пример #8
0
        private List <BorderVertex> GenerateBorderVertices(Heightmap heightmap, int borderCount)
        {
            //generate border vertices
            List <BorderVertex> borderVertices = new List <BorderVertex>((heightmap.Width + heightmap.Height) * 2);

            int xBorderOffset = Mathf.Max((heightmap.Width - 1) / borderCount, 1);     //< avoid 0
            int yBorderOffset = Mathf.Max((heightmap.Height - 1) / borderCount, 1);    //< avoid 0

            //upside
            for (int i = 0; i < heightmap.Width - 1; i += xBorderOffset)
            {
                float h = heightmap[0, i];

                BorderVertex v;
                v.Pos.x = (heightmap.Size.x * i) / (heightmap.Width - 1);
                v.Pos.y = (heightmap.Size.y * h);
                v.Pos.z = 0.0f;
                v.Pos  += heightmap.Offset;

                v.ClosestIndex = -1;

                borderVertices.Add(v);
            }

            //rightside
            for (int i = 0; i < heightmap.Height - 1; i += yBorderOffset)
            {
                float h = heightmap[i, heightmap.Width - 1];

                BorderVertex v;
                v.Pos.x = heightmap.Size.x;
                v.Pos.y = (heightmap.Size.y * h);
                v.Pos.z = (heightmap.Size.z * i) / (heightmap.Height - 1);
                v.Pos  += heightmap.Offset;

                v.ClosestIndex = -1;

                borderVertices.Add(v);
            }

            //downside
            for (int i = heightmap.Width - 1; i > 0; i -= xBorderOffset)
            {
                float h = heightmap[heightmap.Height - 1, i];

                BorderVertex v;
                v.Pos.x = (heightmap.Size.x * i) / (heightmap.Width - 1);
                v.Pos.y = (heightmap.Size.y * h);
                v.Pos.z = heightmap.Size.z;
                v.Pos  += heightmap.Offset;

                v.ClosestIndex = -1;

                borderVertices.Add(v);
            }

            //leftside
            for (int i = heightmap.Height - 1; i > 0; i -= yBorderOffset)
            {
                float h = heightmap[i, 0];

                BorderVertex v;
                v.Pos.x = 0.0f;
                v.Pos.y = (heightmap.Size.y * h);
                v.Pos.z = (heightmap.Size.z * i) / (heightmap.Height - 1);
                v.Pos  += heightmap.Offset;

                v.ClosestIndex = -1;

                borderVertices.Add(v);
            }

            return(borderVertices);
        }
Пример #9
0
        private WorkingMesh CreateBakedGeometry(string name, Heightmap heightmap, Bounds bounds, int distance)
        {
            int borderWidth   = CalcBorderWidth(heightmap, distance);
            int borderWidth2x = borderWidth * 2;

            WorkingMesh mesh =
                new WorkingMesh(Allocator.Persistent, heightmap.Width * heightmap.Height,
                                (heightmap.Width - borderWidth2x - 1) * (heightmap.Height - borderWidth2x - 1) * 6, 1, 0);

            mesh.name = name + "_Mesh";


            Vector3[] vertices  = new Vector3[(heightmap.Width - borderWidth2x) * (heightmap.Height - borderWidth2x)];
            Vector3[] normals   = new Vector3[(heightmap.Width - borderWidth2x) * (heightmap.Height - borderWidth2x)];
            Vector2[] uvs       = new Vector2[(heightmap.Width - borderWidth2x) * (heightmap.Height - borderWidth2x)];
            int[]     triangles = new int[(heightmap.Width - borderWidth2x - 1) * (heightmap.Height - borderWidth2x - 1) * 6];


            int vi = 0;

            //except boder line
            for (int z = borderWidth; z < heightmap.Height - borderWidth; ++z)
            {
                for (int x = borderWidth; x < heightmap.Width - borderWidth; ++x)
                {
                    int index = vi++;

                    vertices[index].x = bounds.size.x * (x) / (heightmap.Width - 1) + bounds.min.x;
                    vertices[index].y = heightmap.Size.y * heightmap[z, x];
                    vertices[index].z = bounds.size.z * (z) / (heightmap.Height - 1) + bounds.min.z;

                    uvs[index].x = (float)x / (heightmap.Width - 1);
                    uvs[index].y = (float)z / (heightmap.Height - 1);

                    if (m_hlod.UseNormal)
                    {
                        normals[index] = Vector3.up;
                    }
                    else
                    {
                        normals[index] = heightmap.GetInterpolatedNormal(uvs[index].x, uvs[index].y);
                    }
                }
            }

            int ii = 0;

            for (int z = 0; z < heightmap.Height - borderWidth2x - 1; ++z)
            {
                for (int x = 0; x < heightmap.Width - borderWidth2x - 1; ++x)
                {
                    int i00 = z * (heightmap.Width - borderWidth2x) + x;
                    int i10 = z * (heightmap.Width - borderWidth2x) + x + 1;
                    int i01 = (z + 1) * (heightmap.Width - borderWidth2x) + x;
                    int i11 = (z + 1) * (heightmap.Width - borderWidth2x) + x + 1;

                    triangles[ii + 0] = i00;
                    triangles[ii + 1] = i11;
                    triangles[ii + 2] = i10;
                    triangles[ii + 3] = i11;
                    triangles[ii + 4] = i00;
                    triangles[ii + 5] = i01;
                    ii += 6;
                }
            }

            mesh.vertices = vertices;
            mesh.normals  = normals;
            mesh.uv       = uvs;
            mesh.SetTriangles(triangles, 0);

            return(mesh);
        }