コード例 #1
0
ファイル: Treeifier.cs プロジェクト: TimPungr/ContractKiller
    public void GenerateTreePrototypeData()
    {
        List <string>     prefabNames = new List <string>();
        List <GameObject> prefabs     = new List <GameObject>();

        System.Array.ForEach(m_ItemsToExtract, (x) => { prefabNames.Add(x.m_ItemPrefab.name); prefabs.Add(x.m_ItemPrefab); });

        if (TerrainUtils.TreeHashCheck(prefabNames.ToArray()))
        {
            Debug.LogError("Tree name hash collision, fix!");
            return;
        }

        GameObject[] proto = prefabs.ToArray();
        List <TreeSystemPrototypeData> managed = new List <TreeSystemPrototypeData>();

        for (int i = 0; i < proto.Length; i++)
        {
            GameObject prefab = proto[i];

            if (PrefabUtility.GetPrefabType(prefab) != PrefabType.ModelPrefab ||
                prefab.GetComponent <LODGroup>() == null ||
                prefab.GetComponentInChildren <BillboardRenderer>() == null)
            {
                Debug.LogError("Invalid prefab: " + prefab.name + ". Make sure that it is a SpeedTree, that it contains a 'LODGroup' and that it has a 'BillboardRenderer' component.");
                continue;
            }

            TreeSystemPrototypeData data = new TreeSystemPrototypeData();
            data.m_TreePrototype = prefab;
            // Use hash here instead of the old index
            data.m_TreePrototypeHash = TUtils.GetStableHashCode(prefab.name);

            // Instantiate LOD data that is going to be populated at runtime
            LOD[] lods = prefab.GetComponent <LODGroup>().GetLODs();
            TreeSystemLODData[] lodData = new TreeSystemLODData[lods.Length];
            // Generate some partial LOD data that doesn't have to be calculated at runtime
            data.m_LODData = lodData;

            for (int lod = 0; lod < lodData.Length; lod++)
            {
                TreeSystemLODData d = new TreeSystemLODData();
                lodData[lod] = d;
            }

            data.m_MaxLod3DIndex = lodData.Length - 2;

            managed.Add(data);
        }

        m_ManagedPrototypes = managed.ToArray();

        // Try and set the prototypes to our tree system
        TreeSystem t = FindObjectOfType <TreeSystem>();

        if (t)
        {
            t.m_ManagedPrototypes = m_ManagedPrototypes;
        }
    }
コード例 #2
0
    /**
     * Checks whether there is a collision within the tree's hashes that has to be remedied
     *
     * @return False in case there is no collision and true if there is a collision
     */
    public static bool TreeHashCheck(string[] prefabNames)
    {
        HashSet <int> set = new HashSet <int>();

        foreach (string prefab in prefabNames)
        {
            if (set.Contains(TUtils.GetStableHashCode(prefab)))
            {
                return(true);
            }

            set.Add(TUtils.GetStableHashCode(prefab));
        }

        return(false);
    }
コード例 #3
0
    /**
     * Checks whether there is a collision within the tree's hashes that has to be remedied
     *
     * @return False in case there is no collision and true if there is a collision
     */
    public static bool TreeHashCheck(Terrain mainTerrain)
    {
        HashSet <int> set = new HashSet <int>();

        TreePrototype[] p = mainTerrain.terrainData.treePrototypes;

        for (int i = 0; i < p.Length; i++)
        {
            if (set.Contains(TUtils.GetStableHashCode(p[i].prefab.name)))
            {
                return(true);
            }

            set.Add(TUtils.GetStableHashCode(p[i].prefab.name));
        }

        return(false);
    }
コード例 #4
0
    public void GenerateTreePrototypeData()
    {
        if (TerrainUtils.TreeHashCheck(m_MainManagedTerrain))
        {
            Log.e("Tree name hash collision, fix!");
            return;
        }

        TreePrototype[] proto = m_MainManagedTerrain.terrainData.treePrototypes;

        List <TreeSystemPrototypeData> managed = new List <TreeSystemPrototypeData>();

        for (int i = 0; i < proto.Length; i++)
        {
            if (ShouldUsePrefab(proto[i].prefab) >= 0)
            {
                GameObject prefab = proto[i].prefab;

                TreeSystemPrototypeData data = new TreeSystemPrototypeData();
                data.m_TreePrototype = prefab;
                // Use hash here instead of the old index
                data.m_TreePrototypeHash = TUtils.GetStableHashCode(proto[i].prefab.name);

                if (m_UseXMLData)
                {
                    TextAsset textData = AssetDatabase.LoadAssetAtPath <TextAsset>(m_TreeXMLStorePath + "/" + proto[i].prefab.name + ".xml");

                    if (textData != null)
                    {
                        data.m_TreeBillboardData = textData;
                    }
                    else
                    {
                        Debug.LogError("Could not find XML data for: " + data.m_TreePrototype.name);
                    }
                }

                // Instantiate LOD data that is going to be populated at runtime
                LOD[] lods = prefab.GetComponent <LODGroup>().GetLODs();
                TreeSystemLODData[] lodData = new TreeSystemLODData[lods.Length];
                // Generate some partial LOD data that doesn't have to be calculated at runtime
                data.m_LODData = lodData;

                for (int lod = 0; lod < lodData.Length; lod++)
                {
                    TreeSystemLODData d = new TreeSystemLODData();
                    lodData[lod] = d;
                }

                data.m_MaxLodIndex   = lodData.Length - 1;
                data.m_MaxLod3DIndex = lodData.Length - 2;

                managed.Add(data);
            }
        }

        m_ManagedPrototypes = managed.ToArray();

        // Try and set the prototypes to our tree system
        TreeSystem t = FindObjectOfType <TreeSystem>();

        if (t)
        {
            t.m_ManagedPrototypes = m_ManagedPrototypes;
        }
    }
コード例 #5
0
    private TreeSystemTerrain ProcessTerrain(Terrain terrain, int cellSize, GameObject cellHolder)
    {
        TreeSystemTerrain systemTerrain = new TreeSystemTerrain();

        // Set system terrain data
        systemTerrain.m_ManagedTerrain       = terrain;
        systemTerrain.m_ManagedTerrainBounds = terrain.GetComponent <TerrainCollider>().bounds;
        systemTerrain.m_CellCount            = TerrainUtils.GetCellCount(terrain, cellSize);
        systemTerrain.m_CellSize             = cellSize;

        int cellCount;

        BoxCollider[,] collidersBox;
        SphereCollider[,] collidersSphere;

        // Gridify terrain
        TerrainUtils.Gridify(terrain, cellSize, out cellCount, out collidersBox, out collidersSphere, cellHolder, null);

        // Temporary structured data
        TreeSystemStructuredTrees[,] str           = new TreeSystemStructuredTrees[cellCount, cellCount];
        List <TreeSystemStoredInstance>[,] strInst = new List <TreeSystemStoredInstance> [cellCount, cellCount];
        List <TreeSystemStructuredTrees> list = new List <TreeSystemStructuredTrees>();

        // Insantiate the required data
        for (int r = 0; r < cellCount; r++)
        {
            for (int c = 0; c < cellCount; c++)
            {
                TreeSystemStructuredTrees s = new TreeSystemStructuredTrees();

                // Set the bounds, all in world space
                s.m_BoundsBox    = collidersBox[r, c].bounds;
                s.m_BoundsSphere = new TreeSystemBoundingSphere(s.m_BoundsBox.center, collidersSphere[r, c].radius);

                // Set it's new position
                s.m_Position = new RowCol(r, c);

                str[r, c]     = s;
                strInst[r, c] = new List <TreeSystemStoredInstance>();

                list.Add(s);
            }
        }

        TreeInstance[]  terrainTreeInstances = terrain.terrainData.treeInstances;
        TreePrototype[] terrainTreeProto     = terrain.terrainData.treePrototypes;

        Vector3 sizes = terrain.terrainData.size;

        for (int i = 0; i < terrainTreeInstances.Length; i++)
        {
            GameObject proto = terrainTreeProto[terrainTreeInstances[i].prototypeIndex].prefab;

            if (ShouldUsePrefab(proto) < 0)
            {
                continue;
            }

            // Get bounds for that mesh
            Bounds b = proto.transform.Find(proto.name + "_LOD0").gameObject.GetComponent <MeshFilter>().sharedMesh.bounds;

            // Calculate this from normalized terrain space to terrain's local space so that our row/col info are correct.
            // Do the same when testing for cell row/col in which the player is, transform to terrain local space
            Vector3 pos = TerrainUtils.TerrainToTerrainPos(terrainTreeInstances[i].position, terrain);
            int     row = Mathf.Clamp(Mathf.FloorToInt(pos.x / sizes.x * cellCount), 0, cellCount - 1);
            int     col = Mathf.Clamp(Mathf.FloorToInt(pos.z / sizes.z * cellCount), 0, cellCount - 1);

            pos = TerrainUtils.TerrainToWorldPos(terrainTreeInstances[i].position, terrain);
            Vector3 scale = new Vector3(terrainTreeInstances[i].widthScale, terrainTreeInstances[i].heightScale, terrainTreeInstances[i].widthScale);
            float   rot   = terrainTreeInstances[i].rotation;
            int     hash  = TUtils.GetStableHashCode(proto.name);

            Matrix4x4 mtx = Matrix4x4.TRS(pos, Quaternion.Euler(0, rot * Mathf.Rad2Deg, 0), scale);

            TreeSystemStoredInstance inst = new TreeSystemStoredInstance();

            inst.m_TreeHash      = hash;
            inst.m_PositionMtx   = mtx;
            inst.m_WorldPosition = pos;
            inst.m_WorldScale    = scale;
            inst.m_WorldRotation = rot;
            inst.m_WorldBounds   = TUtils.LocalToWorld(ref b, ref mtx);

            strInst[row, col].Add(inst);
        }

        // Generate the mesh that contain all the billboards
        for (int r = 0; r < cellCount; r++)
        {
            for (int c = 0; c < cellCount; c++)
            {
                if (strInst[r, c].Count <= 0)
                {
                    continue;
                }

                // Sort based on the tree hash so that we don't have to do many dictionary look-ups
                strInst[r, c].Sort((x, y) => x.m_TreeHash.CompareTo(y.m_TreeHash));

                // Set the new instances
                str[r, c].m_Instances = strInst[r, c].ToArray();

                // Build the meshes for each cell based on tree type
                List <TreeSystemStoredInstance> singleType = new List <TreeSystemStoredInstance>();
                int lastHash = strInst[r, c][0].m_TreeHash;

                foreach (TreeSystemStoredInstance inst in strInst[r, c])
                {
                    // If we have a new hash, consume all the existing instances
                    if (inst.m_TreeHash != lastHash)
                    {
                        TreeSystemPrototypeData data = GetPrototypeWithHash(lastHash);
                        BuildTreeTypeCellMesh(cellHolder, str[r, c], singleType, data);
                        singleType.Clear();

                        // Update the hash
                        lastHash = inst.m_TreeHash;
                    }

                    // Add them to a list and when the hash changes begin the next generation
                    singleType.Add(inst);
                }

                if (singleType.Count > 0)
                {
                    TreeSystemPrototypeData data = GetPrototypeWithHash(singleType[0].m_TreeHash);
                    BuildTreeTypeCellMesh(cellHolder, str[r, c], singleType, data);
                    singleType.Clear();
                }
            }
        }

        // Set the cells that contain the trees to the system terrain
        systemTerrain.m_Cells = list.ToArray();

        // Return it
        return(systemTerrain);
    }
コード例 #6
0
    public void GenerateTreePrototypeData()
    {
        if (TerrainUtils.TreeHashCheck(m_MainManagedTerrain))
        {
            Debug.LogError("Tree name hash collision, fix!");
            return;
        }

        GameObject[] proto = m_TreeToExtractPrefabs;
        List <TreeSystemPrototypeData> managed = new List <TreeSystemPrototypeData>();

        for (int i = 0; i < proto.Length; i++)
        {
            GameObject prefab = proto[i];

            if (PrefabUtility.GetPrefabType(prefab) != PrefabType.ModelPrefab ||
                prefab.GetComponent <LODGroup>() == null ||
                prefab.GetComponentInChildren <BillboardRenderer>() == null)
            {
                Debug.LogError("Invalid prefab: " + prefab.name + ". Make sure that it is a SpeedTree, that it contains a 'LODGroup' and that it has a 'BillboardRenderer' component.");
                continue;
            }

            TreeSystemPrototypeData data = new TreeSystemPrototypeData();
            data.m_TreePrototype = prefab;
            // Use hash here instead of the old index
            data.m_TreePrototypeHash = TUtils.GetStableHashCode(prefab.name);

            if (m_UseXMLData)
            {
                TextAsset textData = AssetDatabase.LoadAssetAtPath <TextAsset>(m_TreeXMLStorePath + "/" + prefab.name + ".xml");

                if (textData != null)
                {
                    data.m_TreeBillboardData = textData;
                }
                else
                {
                    Debug.LogError("Could not find XML data for: " + data.m_TreePrototype.name);
                }
            }

            // Instantiate LOD data that is going to be populated at runtime
            LOD[] lods = prefab.GetComponent <LODGroup>().GetLODs();
            TreeSystemLODData[] lodData = new TreeSystemLODData[lods.Length];
            // Generate some partial LOD data that doesn't have to be calculated at runtime
            data.m_LODData = lodData;

            for (int lod = 0; lod < lodData.Length; lod++)
            {
                TreeSystemLODData d = new TreeSystemLODData();
                lodData[lod] = d;
            }

            data.m_MaxLodIndex   = lodData.Length - 1;
            data.m_MaxLod3DIndex = lodData.Length - 2;

            managed.Add(data);
        }

        m_ManagedPrototypes = managed.ToArray();

        // Try and set the prototypes to our tree system
        TreeSystem t = FindObjectOfType <TreeSystem>();

        if (t)
        {
            t.m_ManagedPrototypes = m_ManagedPrototypes;
        }
    }
コード例 #7
0
ファイル: Treeifier.cs プロジェクト: TimPungr/ContractKiller
    // TODO: see from the list which trees fit in here
    private TreeSystemTerrain ProcessTerrain(Terrain terrain, int cellSize, GameObject cellHolder, List <GameObject> extraTrees)
    {
        TreeSystemTerrain systemTerrain = new TreeSystemTerrain();

        // Set system terrain data
        systemTerrain.m_ManagedTerrain             = terrain;
        systemTerrain.m_ManagedTerrainBounds       = terrain.GetComponent <TerrainCollider>().bounds;
        systemTerrain.m_ManagedTerrainLocalToWorld = terrain.transform.localToWorldMatrix;
        systemTerrain.m_ManagedTerrainWorldToLocal = terrain.transform.worldToLocalMatrix;
        systemTerrain.m_ManagedTerrainSizes        = terrain.terrainData.size;

        systemTerrain.m_CellCount = TerrainUtils.GetCellCount(terrain, cellSize);
        systemTerrain.m_CellSize  = cellSize;

        int cellCount;

        BoxCollider[,] collidersBox;
        SphereCollider[,] collidersSphere;

        // Gridify terrain
        TerrainUtils.Gridify(terrain, cellSize, out cellCount, out collidersBox, out collidersSphere, cellHolder, null);

        // Temporary structured data
        TreeSystemStructuredTrees[,] str           = new TreeSystemStructuredTrees[cellCount, cellCount];
        List <TreeSystemStoredInstance>[,] strInst = new List <TreeSystemStoredInstance> [cellCount, cellCount];
        List <TreeSystemStructuredTrees> list = new List <TreeSystemStructuredTrees>();

        // Insantiate the required data
        for (int r = 0; r < cellCount; r++)
        {
            for (int c = 0; c < cellCount; c++)
            {
                TreeSystemStructuredTrees s = new TreeSystemStructuredTrees();

                // Set the bounds, all in world space
                s.m_BoundsBox    = collidersBox[r, c].bounds;
                s.m_BoundsSphere = new TreeSystemBoundingSphere(s.m_BoundsBox.center, collidersSphere[r, c].radius);

                // Set it's new position
                s.m_Position = new RowCol(r, c);

                str[r, c]     = s;
                strInst[r, c] = new List <TreeSystemStoredInstance>();

                list.Add(s);
            }
        }

        // Delete cells since they might cause physics problems
        if (m_DeleteCellsAfterGridify)
        {
            for (int i = 0; i < cellCount; i++)
            {
                for (int j = 0; j < cellCount; j++)
                {
                    DestroyImmediate(collidersBox[i, j].gameObject);
                }
            }
        }

        int treeInstancesCount = 0, treeExtraCount = 0;

        TreeInstance[]  terrainTreeInstances = terrain.terrainData.treeInstances;
        TreePrototype[] terrainTreeProto     = terrain.terrainData.treePrototypes;

        Vector3 sizes = terrain.terrainData.size;

        for (int i = 0; i < terrainTreeInstances.Length; i++)
        {
            GameObject proto = terrainTreeProto[terrainTreeInstances[i].prototypeIndex].prefab;

            if (ShouldUsePrefab(proto) < 0)
            {
                continue;
            }

            treeInstancesCount++;

            // Get bounds for that mesh
            Bounds b = proto.transform.Find(proto.name + "_LOD0").gameObject.GetComponent <MeshFilter>().sharedMesh.bounds;

            // Calculate this from normalized terrain space to terrain's local space so that our row/col info are correct.
            // Do the same when testing for cell row/col in which the player is, transform to terrain local space
            Vector3 pos = TerrainUtils.TerrainToTerrainPos(terrainTreeInstances[i].position, terrain);
            int     row = Mathf.Clamp(Mathf.FloorToInt(pos.x / sizes.x * cellCount), 0, cellCount - 1);
            int     col = Mathf.Clamp(Mathf.FloorToInt(pos.z / sizes.z * cellCount), 0, cellCount - 1);

            pos = TerrainUtils.TerrainToWorldPos(terrainTreeInstances[i].position, terrain);
            Vector3 scale = new Vector3(terrainTreeInstances[i].widthScale, terrainTreeInstances[i].heightScale, terrainTreeInstances[i].widthScale);
            float   rot   = terrainTreeInstances[i].rotation;
            int     hash  = TUtils.GetStableHashCode(proto.name);

            Matrix4x4 mtx = Matrix4x4.TRS(pos, Quaternion.Euler(0, rot * Mathf.Rad2Deg, 0), scale);

            TreeSystemStoredInstance inst = new TreeSystemStoredInstance();

            inst.m_TreeHash      = hash;
            inst.m_PositionMtx   = mtx;
            inst.m_WorldPosition = pos;
            inst.m_WorldScale    = scale;
            inst.m_WorldRotation = rot;
            inst.m_WorldBounds   = TUtils.LocalToWorld(ref b, ref mtx);

            strInst[row, col].Add(inst);
        }

        List <GameObject> containedTrees = new List <GameObject>();

        // Change if we're going to use something diff than 50 for max extent
        Bounds terrainExtendedBounds = systemTerrain.m_ManagedTerrainBounds;

        terrainExtendedBounds.Expand(new Vector3(0, 50, 0));

        // Same as a instance with minor diferences
        for (int i = 0; i < extraTrees.Count; i++)
        {
            GameObject treeInstance = extraTrees[i];

            // If the terrain contains the stuff
            if (terrainExtendedBounds.Contains(treeInstance.transform.position) == false)
            {
                continue;
            }

            treeExtraCount++;

            // Add the tree to the list of trees for removal
            containedTrees.Add(treeInstance);

            // Owner
            GameObject proto = GetPrefabOwner(treeInstance);

            // Get bounds for that mesh
            Bounds b = proto.transform.Find(proto.name + "_LOD0").gameObject.GetComponent <MeshFilter>().sharedMesh.bounds;

            // Calculate this from normalized terrain space to terrain's local space so that our row/col info are correct.
            // Do the same when testing for cell row/col in which the player is, transform to terrain local space
            Vector3 pos = TerrainUtils.TerrainToTerrainPos(TerrainUtils.WorldPosToTerrain(treeInstance.transform.position, terrain), terrain);

            int row = Mathf.Clamp(Mathf.FloorToInt(pos.x / sizes.x * cellCount), 0, cellCount - 1);
            int col = Mathf.Clamp(Mathf.FloorToInt(pos.z / sizes.z * cellCount), 0, cellCount - 1);

            pos = treeInstance.transform.position;
            Vector3 scale = treeInstance.transform.localScale;
            float   rot   = treeInstance.transform.rotation.eulerAngles.y * Mathf.Deg2Rad;

            // Set the hash
            int hash = TUtils.GetStableHashCode(proto.name);

            // Set the mtx
            Matrix4x4 mtx = Matrix4x4.TRS(pos, Quaternion.Euler(0, rot * Mathf.Rad2Deg, 0), scale);

            TreeSystemStoredInstance inst = new TreeSystemStoredInstance();

            inst.m_TreeHash      = hash;
            inst.m_PositionMtx   = mtx;
            inst.m_WorldPosition = pos;
            inst.m_WorldScale    = scale;
            inst.m_WorldRotation = rot;
            inst.m_WorldBounds   = TUtils.LocalToWorld(ref b, ref mtx);

            strInst[row, col].Add(inst);
        }

        // Remove the items from the extra trees
        foreach (GameObject tree in containedTrees)
        {
            extraTrees.Remove(tree);
        }

        // Generate the mesh that contain all the billboards
        for (int r = 0; r < cellCount; r++)
        {
            for (int c = 0; c < cellCount; c++)
            {
                if (strInst[r, c].Count <= 0)
                {
                    continue;
                }

                // Sort based on the tree hash so that we don't have to do many dictionary look-ups
                strInst[r, c].Sort((x, y) => x.m_TreeHash.CompareTo(y.m_TreeHash));

                // Set the new instances
                str[r, c].m_Instances = strInst[r, c].ToArray();

                // Build the meshes for each cell based on tree type
                List <TreeSystemStoredInstance> singleType = new List <TreeSystemStoredInstance>();
                int lastHash = strInst[r, c][0].m_TreeHash;

                foreach (TreeSystemStoredInstance inst in strInst[r, c])
                {
                    // If we have a new hash, consume all the existing instances
                    if (inst.m_TreeHash != lastHash)
                    {
                        TreeSystemPrototypeData data = GetPrototypeWithHash(lastHash);

                        if (ShouldBuildBillboardBatch(data.m_TreePrototype))
                        {
                            BuildTreeTypeCellMesh(cellHolder, str[r, c], singleType, data);
                        }

                        singleType.Clear();

                        // Update the hash
                        lastHash = inst.m_TreeHash;
                    }

                    // Add them to a list and when the hash changes begin the next generation
                    singleType.Add(inst);
                }

                if (singleType.Count > 0)
                {
                    TreeSystemPrototypeData data = GetPrototypeWithHash(singleType[0].m_TreeHash);

                    if (ShouldBuildBillboardBatch(data.m_TreePrototype))
                    {
                        BuildTreeTypeCellMesh(cellHolder, str[r, c], singleType, data);
                    }

                    singleType.Clear();
                }
            }
        }

        // Set the cells that contain the trees to the system terrain
        systemTerrain.m_Cells = list.ToArray();

        // Print extraction data
        Debug.Log("Extracted for terrain: " + terrain.name + " instance trees: " + treeInstancesCount + " extra trees: " + treeExtraCount);

        // Return it
        return(systemTerrain);
    }