public void EditorTessEnd()
    {
        if (mTessellationJob == null || LOD == null)
        {
            return;
        }
        //save data
        MTQuadTreeHeader header = new MTQuadTreeHeader(DataName);

        header.QuadTreeDepth = QuadTreeDepth;
        header.BoundMin      = VolumnBound.min;
        header.BoundMax      = VolumnBound.max;
        header.LOD           = LOD.Length;
        foreach (var m in mTessellationJob.mesh)
        {
            MTMeshHeader mh = new MTMeshHeader(m.meshId, m.center);
            header.Meshes.Add(m.meshId, mh);
            MTFileUtils.SaveMesh(DataName, m);
        }
        MTLog.Log("mesh saved!");
        MTFileUtils.SaveQuadTreeHeader(DataName, header, Terrain.activeTerrain.terrainData.alphamapTextureCount);
        MTLog.Log("header saved!");
        string matPath = "Assets/MightyTerrainMesh/Resources";

        MTMatUtils.SaveMaterials(matPath, DataName, Terrain.activeTerrain);
        MTLog.Log("material saved!");
    }
Beispiel #2
0
    public MTRuntimeMesh(int meshid, int lod, string dataName)
    {
        MeshID     = meshid;
        m_LODMeshs = new Mesh[lod];

        //加载所有LOD mesh 存在数组里
        MTFileUtils.LoadMesh(m_LODMeshs, dataName, meshid);
    }
Beispiel #3
0
 public void EditorCreatePreview()
 {
     if (DataName == "")
     {
         Debug.LogError("data should have a name");
         return;
     }
     try
     {
         Transform[] lodParent = new Transform[LOD.Length];
         for (int i = 0; i < LOD.Length; ++i)
         {
             GameObject lodGo = new GameObject("LOD" + i);
             lodGo.transform.parent = transform;
             lodParent[i]           = lodGo.transform;
         }
         MTQuadTreeHeader header = MTFileUtils.LoadQuadTreeHeader(DataName);
         Debug.LogError("RuntimeMats:" + header.RuntimeMats.Length);
         for (int i = 0; i < header.RuntimeMats.Length; i++)
         {
             Debug.LogError("name:" + header.RuntimeMats[i].name);
         }
         foreach (var m in header.Meshes.Values)
         {
             Mesh[] lods = new Mesh[LOD.Length];
             MTFileUtils.LoadMesh(lods, DataName, m.MeshID);
             for (int i = 0; i < LOD.Length; ++i)
             {
                 MeshFilter   meshF;
                 MeshRenderer meshR;
                 GameObject   meshGo = new GameObject("meshObj" + i);
                 meshGo.transform.parent = lodParent[i];
                 meshF            = meshGo.AddComponent <MeshFilter>();
                 meshR            = meshGo.AddComponent <MeshRenderer>();
                 meshR.materials  = header.RuntimeMats;
                 meshF.sharedMesh = lods[i];
             }
         }
     }
     catch
     {
         Debug.LogError("failed to load datas");
     }
 }
Beispiel #4
0
    private void Awake()
    {
        if (DataName == "")
        {
            return;
        }
        m_Go = new GameObject("Chunk");
        m_Go.Reset();

        try
        {
            m_Header = MTFileUtils.LoadQuadTreeHeader(DataName);

            m_Root = new MTQuadTreeNode(m_Header.QuadTreeDepth, m_Header.BoundMin, m_Header.BoundMax, Vector3.zero);
            foreach (var mh in m_Header.Meshes.Values)
            {
                m_Root.AddMesh(mh);
            }
            int gridMax = 1 << m_Header.QuadTreeDepth;               //1<< X 相当于 2的X次方
            mVisiblePatches = new MTArray <uint>(gridMax * gridMax); //(int)Mathf.Pow(2, 2 * m_Header.QuadTreeDepth)

            if (lodPolicy.Length < m_Header.LOD)
            {
                float[] policy = new float[m_Header.LOD];
                for (int i = 0; i < lodPolicy.Length; ++i)
                {
                    policy[i] = lodPolicy[i];
                }
                lodPolicy = policy;
            }
            lodPolicy[0] = Mathf.Clamp(lodPolicy[0], 0.5f * m_Root.Bound.size.x / gridMax, lodPolicy[0]);
            lodPolicy[lodPolicy.Length - 1] = float.MaxValue;
        }
        catch
        {
            m_Header = null;
            m_Root   = null;
            Debug.LogError("MTLoader load quadtree header failed");
        }

        m_Camera = GetComponent <Camera>();
    }
    private ushort SpawnOnePixel(DetailPrototype detailLayer, int layer, float start_x, float start_z, float pixelSize, int subGridSize, int maxDen, float maxH, MemoryStream ms)
    {
        ushort     spawnedCount = 0;
        float      stride       = pixelSize / subGridSize;
        int        layerMask    = 1 << layer;
        RaycastHit hit          = new RaycastHit();

        for (int sub_u = 0; sub_u < subGridSize; ++sub_u)
        {
            for (int sub_v = 0; sub_v < subGridSize; ++sub_v)
            {
                if (spawnedCount >= maxDen)
                {
                    break;
                }
                Vector2 localuv = new Vector2(start_x + stride * sub_u, start_z + stride * sub_v);
                float   noise   = Mathf.PerlinNoise(localuv.x, localuv.y) * pixelSize;
                float   xOffset = stride * sub_u + noise;
                float   zOffset = stride * sub_v + noise;
                Vector3 top     = new Vector3(start_x + xOffset, maxH, start_z + zOffset);
                if (Physics.Raycast(top, Vector3.down, out hit, 2 * maxH, layerMask))
                {
                    Vector2 noisexy      = detailLayer.noiseSpread * localuv;
                    float   spread_noise = Mathf.PerlinNoise(noisexy.x, noisexy.y) * pixelSize;
                    float   width        = detailLayer.minWidth + (detailLayer.maxWidth - detailLayer.minWidth) * spread_noise;
                    float   height       = detailLayer.minHeight + (detailLayer.maxHeight - detailLayer.minHeight) * spread_noise;
                    Color   c            = detailLayer.dryColor + (detailLayer.healthyColor - detailLayer.dryColor) * spread_noise;
                    MTFileUtils.WriteVector3(ms, hit.point);
                    MTFileUtils.WriteVector3(ms, new Vector3(width, height, width));
                    MTFileUtils.WriteColor(ms, c);
                    ++spawnedCount;
                }
                else
                {
                    UnityEngine.Debug.LogWarning("SpawnOnePixel hits no terrain mesh");
                }
            }
        }
        return(spawnedCount);
    }
    // Start is called before the first frame update
    void Start()
    {
        MemoryStream ms         = new MemoryStream(Data.bytes);
        int          totalCount = MTFileUtils.ReadInt(ms);

        positions = new Vector3[totalCount];
        colors    = new Color[totalCount];
        int spawned = 0;

        while (ms.Position < ms.Length && spawned < totalCount)
        {
            ushort spawnedCount = MTFileUtils.ReadUShort(ms);
            for (int i = 0; i < spawnedCount; ++i)
            {
                positions[spawned] = MTFileUtils.ReadVector3(ms);
                var scale = MTFileUtils.ReadVector3(ms);
                colors[spawned] = MTFileUtils.ReadColor(ms);
                ++spawned;
            }
        }
        ms.Close();
    }
Beispiel #7
0
 private void Awake()
 {
     if (DataName == "")
     {
         return;
     }
     try
     {
         mHeader = MTFileUtils.LoadQuadTreeHeader(DataName);
         mRoot   = new MTQuadTreeNode(mHeader.QuadTreeDepth, mHeader.BoundMin, mHeader.BoundMax);
         foreach (var mh in mHeader.Meshes.Values)
         {
             mRoot.AddMesh(mh);
         }
         int gridMax = 1 << mHeader.QuadTreeDepth;
         mVisiblePatches = new MTArray <uint>(gridMax * gridMax);
         if (lodPolicy.Length < mHeader.LOD)
         {
             float[] policy = new float[mHeader.LOD];
             for (int i = 0; i < lodPolicy.Length; ++i)
             {
                 policy[i] = lodPolicy[i];
             }
             lodPolicy = policy;
         }
         lodPolicy[0] = Mathf.Clamp(lodPolicy[0], 0.5f * mRoot.Bound.size.x / gridMax, lodPolicy[0]);
         lodPolicy[lodPolicy.Length - 1] = float.MaxValue;
     }
     catch
     {
         mHeader = null;
         mRoot   = null;
         MTLog.LogError("MTLoader load quadtree header failed");
     }
     mCamera = GetComponent <Camera>();
 }
Beispiel #8
0
 public MTRuntimeMesh(int meshid, int lod, string dataName)
 {
     MeshID = meshid;
     mLOD   = new Mesh[lod];
     MTFileUtils.LoadMesh(mLOD, dataName, meshid);
 }
    private void EditorGrabDetails(string folderName, Terrain terrainTarget, int layer)
    {
        if (terrainTarget == null)
        {
            MTLog.LogError("no active terrain");
            return;
        }
        TerrainData data           = terrainTarget.terrainData;
        int         detailLayerCnt = data.detailPrototypes.Length;
        int         dataLen        = data.detailResolution * data.detailResolution;

        string[] savedAssets = new string[detailLayerCnt];
        Bounds   bound       = data.bounds;
        float    pixelSize   = bound.size.x / data.detailResolution;

        for (int i = 0; i < detailLayerCnt; ++i)
        {
            MemoryStream ms       = new MemoryStream();
            int          totalCnt = 0;
            MTFileUtils.WriteInt(ms, totalCnt);
            DetailPrototype proto = data.detailPrototypes[i];
            //prototype info
            //raw data
            int[,] dlayer = data.GetDetailLayer(0, 0, data.detailResolution, data.detailResolution, i);
            for (int u = 0; u < data.detailResolution; ++u)
            {
                for (int v = 0; v < data.detailResolution; ++v)
                {
                    ushort pixelDen = (ushort)dlayer[v, u];
                    //gen data inside
                    if (pixelDen <= 0)
                    {
                        continue;
                    }
                    //data count
                    long countOffset = ms.Position;
                    MTFileUtils.WriteUShort(ms, pixelDen);
                    int    subGridSize  = Mathf.CeilToInt(Mathf.Sqrt(pixelDen));
                    float  start_x      = bound.min.x + u * pixelSize;
                    float  start_z      = bound.min.z + v * pixelSize;
                    ushort spawnedCount = SpawnOnePixel(proto, layer, start_x, start_z, pixelSize, subGridSize, pixelDen, bound.max.y, ms);
                    if (countOffset != pixelDen)
                    {
                        long posCache = ms.Position;
                        ms.Position = countOffset;
                        MTFileUtils.WriteUShort(ms, spawnedCount);
                        ms.Position = posCache;
                    }
                    totalCnt += spawnedCount;
                    EditorUtility.DisplayProgressBar("bake details", "processing", (float)(u * data.detailResolution + v) / (data.detailResolution * data.detailResolution));
                }
            }
            ms.Position = 0;
            MTFileUtils.WriteInt(ms, totalCnt);
            savedAssets[i] = ExportDensity2Bytes(folderName, i, ms);
            ms.Close();
        }
        EditorUtility.ClearProgressBar();
        AssetDatabase.Refresh();

        //add componet and parameter
        GameObject prefabObj = new GameObject("detail_layers");

        prefabObj.transform.position = terrainTarget.transform.position;
        MTDetailBatchRenderer dr = prefabObj.AddComponent <MTDetailBatchRenderer>();

        dr.layers = new MTDetailBatchRenderer.ProtoLayerInfo[detailLayerCnt];
        for (int i = 0; i < detailLayerCnt; ++i)
        {
            DetailPrototype proto = data.detailPrototypes[i];
            if (savedAssets[i] == null || proto.prototype == null)
            {
                continue;
            }
            MeshFilter mf = proto.prototype.GetComponent <MeshFilter>();
            if (mf == null)
            {
                continue;
            }
            MeshRenderer mr = proto.prototype.GetComponent <MeshRenderer>();
            if (mr == null)
            {
                continue;
            }
            TextAsset asset = AssetDatabase.LoadAssetAtPath <TextAsset>(savedAssets[i]);
            dr.layers[i]            = new MTDetailBatchRenderer.ProtoLayerInfo();
            dr.layers[i].detailData = asset;
            dr.layers[i].mesh       = mf.sharedMesh;
            dr.layers[i].mat        = mr.sharedMaterial;
        }
        dr.bnds = bound;
        //dr.detailShader = AssetDatabase.LoadAssetAtPath<ComputeShader>("Assets/MightyTerrainMesh/Shaders/TerrainDetailMask");
        dr.detailDistance           = Terrain.activeTerrain.detailObjectDistance;
        dr.detailDensity            = Terrain.activeTerrain.detailObjectDensity;
        dr.detailResolution         = data.detailResolution;
        dr.detailResolutionPerPatch = data.detailResolutionPerPatch;

        string prefabPath = Path.Combine(folderName, "detail_layers.prefab");

        PrefabUtility.SaveAsPrefabAsset(prefabObj, prefabPath);
        DestroyImmediate(prefabObj);
        AssetDatabase.Refresh();
    }
    public BatchSplitor(byte[] data, Bounds bnd, Mesh mesh)
    {
        MemoryStream ms = new MemoryStream(data);

        TotalCount = MTFileUtils.ReadInt(ms);
        matrices   = new NativeArray <float4x4>(TotalCount, Allocator.Persistent);
        batchIds   = new NativeArray <int>(TotalCount, Allocator.Persistent);
        colors     = new Vector4[TotalCount];
        int spawned = 0;

        while (ms.Position < ms.Length && spawned < matrices.Length)
        {
            ushort spawnedCount = MTFileUtils.ReadUShort(ms);
            for (int i = 0; i < spawnedCount; ++i)
            {
                var pos   = MTFileUtils.ReadVector3(ms);
                var scale = MTFileUtils.ReadVector3(ms);
                var color = MTFileUtils.ReadColor(ms);
                matrices[spawned] = float4x4.TRS(pos, Quaternion.identity, scale);
                colors[spawned]   = color;
                batchIds[spawned] = 0;
                ++spawned;
            }
        }
        ms.Close();
        if (spawned != TotalCount)
        {
            Debug.LogError("terrain detail layer total count is different with spawned count");
        }
        //使用空间4叉树分batch
        if (TotalCount >= count_per_batch)
        {
            job             = new MTDetailBatchSeparateJob();
            job.batchIds    = batchIds;
            job.spawnMatrix = matrices;
            NativeArray <SeparateBound> bounds = new NativeArray <SeparateBound>(4, Allocator.TempJob);
            int offset = 0;
            SplitBounds(TotalCount, bnd.min, bnd.max, bounds, ref offset);
            job.bounds   = bounds;
            separateJobs = job.Schedule(TotalCount, 16);
            IsComplete   = false;
        }
        else
        {
            SplitedBatches = new BatchParameters[1];
            var param = new BatchParameters()
            {
                InstanceCount = TotalCount, Bnd = new Bounds(bnd.center, bnd.size)
            };
            for (int i = 0; i < matrices.Length; ++i)
            {
                param.Matrices.Add(matrices[i]);
                param.Colors.Add(colors[i]);
            }
            SplitedBatches[0] = param;
            LogResults();
            batchIds.Dispose();
            matrices.Dispose();
            IsComplete = true;
        }
    }