예제 #1
0
    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
    void Awake()
    {
        Instance = this;

        // Get the non-alloc version of the plane extraction
        MethodInfo info = typeof(GeometryUtility).GetMethod("Internal_ExtractPlanes", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(Plane[]), typeof(Matrix4x4) }, null);

        ExtractPlanes = Delegate.CreateDelegate(typeof(Action <Plane[], Matrix4x4>), info) as Action <Plane[], Matrix4x4>;

        // Set maximum tree distance
        Shader.SetGlobalFloat("_TreeSystemDistance", m_Settings.m_MaxTreeDistance);

        m_ShaderIDFadeLOD = Shader.PropertyToID("master_LODFade");
        m_ShaderIDBillboardScaleRotation = Shader.PropertyToID("_InstanceScaleRotation");

        // Generate runtime data
        for (int i = 0; i < m_ManagedPrototypes.Length; i++)
        {
            GenerateRuntimePrototypeData(m_ManagedPrototypes[i]);
        }

        // Build the dictionary based on the index
        m_ManagedPrototypesIndexed = new Dictionary <int, TreeSystemPrototypeData>();
        for (int i = 0; i < m_ManagedPrototypes.Length; i++)
        {
            m_ManagedPrototypesIndexed.Add(m_ManagedPrototypes[i].m_TreePrototypeHash, m_ManagedPrototypes[i]);
        }
    }
예제 #3
0
    void Start()
    {
        system    = FindObjectOfType <TreeSystem>();
        protoData = system.m_ManagedPrototypes[0];

        THRESHOLD    = system.GetTreeTanzitionThreshold();
        procDistance = system.GetTreeDistance() - THRESHOLD;
    }
예제 #4
0
    void Awake()
    {
        Instance = this;

        m_UsedLayerId = LayerMask.NameToLayer(m_Settings.m_UsedLayer);

        // Get the non-alloc version of the plane extraction
        MethodInfo info = typeof(GeometryUtility).GetMethod("Internal_ExtractPlanes", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(Plane[]), typeof(Matrix4x4) }, null);

        ExtractPlanes = Delegate.CreateDelegate(typeof(Action <Plane[], Matrix4x4>), info) as Action <Plane[], Matrix4x4>;

        // Set maximum tree distance
        Shader.SetGlobalFloat("_TreeSystemDistance", m_Settings.m_MaxTreeDistance);

        m_ShaderIDFadeLODFull   = Shader.PropertyToID("master_LODFadeFull");
        m_ShaderIDFadeLODDetail = Shader.PropertyToID("master_LODFadeDetail");
        m_ShaderIDFadeBillboard = Shader.PropertyToID("master_LODFade");

        m_ShaderIDBillboardScaleRotation = Shader.PropertyToID("_InstanceScaleRotation");

        // We need matrices as 'indentity'
        m_MtxLODTemp_0 = new Matrix4x4[MAX_BATCH];
        m_MtxLODTemp_1 = new Matrix4x4[MAX_BATCH];
        m_MtxLODTemp_2 = new Matrix4x4[MAX_BATCH];
        m_MtxLODTemp_3 = new Matrix4x4[MAX_BATCH];
        m_MtxLODTemp_4 = new Matrix4x4[MAX_BATCH];

        for (int i = 0; i < MAX_BATCH; i++)
        {
            m_MtxLODTemp_0[i] = Matrix4x4.identity;
            m_MtxLODTemp_1[i] = Matrix4x4.identity;
            m_MtxLODTemp_2[i] = Matrix4x4.identity;
            m_MtxLODTemp_3[i] = Matrix4x4.identity;
            m_MtxLODTemp_4[i] = Matrix4x4.identity;
        }

        // Generate runtime data
        for (int i = 0; i < m_ManagedPrototypes.Length; i++)
        {
            GenerateRuntimePrototypeData(m_ManagedPrototypes[i]);
        }

        // Build the dictionary based on the index
        m_ManagedPrototypesIndexed = new Dictionary <int, TreeSystemPrototypeData>();
        for (int i = 0; i < m_ManagedPrototypes.Length; i++)
        {
            m_ManagedPrototypesIndexed.Add(m_ManagedPrototypes[i].m_TreePrototypeHash, m_ManagedPrototypes[i]);
        }

        // If we don't have tree colliders initialize them
        if (!m_TreeColliders)
        {
            m_TreeColliders = gameObject.AddComponent <TreeColliders>();
            m_TreeColliders.m_OwnerSystem = this;
        }
    }
예제 #5
0
        // Constructor
        public Tree(TreeSystem treeSystem, string levelUid, Texture2D barkTexture, List <List <Texture2D> > leafTextures, XElement data)
        {
            _treeSystem          = treeSystem;
            _levelUid            = levelUid;
            _leafTextures        = leafTextures;
            _barkTexture         = barkTexture;
            _angle               = Loader.loadFloat(data.Attribute("angle"), 0f);
            _seed                = Loader.loadInt(data.Attribute("seed"), 12345);
            _age                 = Loader.loadFloat(data.Attribute("age"), 0f);
            _internodeHalfLength = Loader.loadFloat(data.Attribute("internode_half_length"), 0.5f);
            _internodeLength     = _internodeHalfLength * 2f;
            _maxShootLength      = Loader.loadInt(data.Attribute("max_shoot_length"), 4);
            _maxBaseHalfWidth    = Loader.loadFloat(data.Attribute("max_base_half_width"), 0.25f);
            _perceptionAngle     = Loader.loadFloat(data.Attribute("perception_angle"), 0.6f);
            _perceptionRadius    = Loader.loadFloat(data.Attribute("perception_radius"), 4f);
            _occupancyRadius     = Loader.loadFloat(data.Attribute("occupancy_radius"), 1f);
            _lateralAngle        = Loader.loadFloat(data.Attribute("lateral_angle"), 0.6f);
            _fullExposure        = Loader.loadFloat(data.Attribute("full_exposure"), 1f);
            _penumbraA           = Loader.loadFloat(data.Attribute("penumbra_a"), 1f);
            _penumbraB           = Loader.loadFloat(data.Attribute("penumbra_b"), 2f);
            _optimalGrowthWeight = Loader.loadFloat(data.Attribute("optimal_growth_weight"), 1f);
            _tropismWeight       = Loader.loadFloat(data.Attribute("tropism_weight"), 1f);
            _tropism             = Loader.loadVector2(data.Attribute("tropism"), Vector2.Zero);
            _position            = Loader.loadVector2(data.Attribute("position"), Vector2.Zero);
            _layerDepth          = Loader.loadFloat(data.Attribute("layer_depth"), 0.1f);
            _entityId            = int.Parse(data.Attribute("id").Value);

            _vertices = new VertexPositionColorTexture[MAX_VERTICES];
            for (int i = 0; i < MAX_VERTICES; i++)
            {
                _vertices[i].Color = Color.White;
            }
            _random            = new Random(_seed);
            _internodeLengthSq = _internodeLength * _internodeLength;
            _aabb            = new AABB();
            _aabb.LowerBound = _position;
            _aabb.UpperBound = _position;

            // Calculate root position
            float rootAngle = _angle + (StasisMathHelper.pi);

            _rootPosition = _position + new Vector2((float)Math.Cos(rootAngle), (float)Math.Sin(rootAngle)) * 5f;

            // Calculate anchor normals
            float anchorAngle = _angle - (StasisMathHelper.pi * 0.5f);

            _anchorNormal = new Vector2((float)Math.Cos(anchorAngle), (float)Math.Sin(anchorAngle));

            // Create first metamer
            _rootMetamer        = new Metamer(this, null, BudType.TERMINAL, BudState.DORMANT, BudState.DEAD, _angle, true);
            _rootMetamer.isTail = true;
        }
예제 #6
0
파일: Tree.cs 프로젝트: klutch/StasisEngine
        // Constructor
        public Tree(TreeSystem treeSystem, string levelUid, Texture2D barkTexture, List<List<Texture2D>> leafTextures, XElement data)
        {
            _treeSystem = treeSystem;
            _levelUid = levelUid;
            _leafTextures = leafTextures;
            _barkTexture = barkTexture;
            _angle = Loader.loadFloat(data.Attribute("angle"), 0f);
            _seed = Loader.loadInt(data.Attribute("seed"), 12345);
            _age = Loader.loadFloat(data.Attribute("age"), 0f);
            _internodeHalfLength = Loader.loadFloat(data.Attribute("internode_half_length"), 0.5f);
            _internodeLength = _internodeHalfLength * 2f;
            _maxShootLength = Loader.loadInt(data.Attribute("max_shoot_length"), 4);
            _maxBaseHalfWidth = Loader.loadFloat(data.Attribute("max_base_half_width"), 0.25f);
            _perceptionAngle = Loader.loadFloat(data.Attribute("perception_angle"), 0.6f);
            _perceptionRadius = Loader.loadFloat(data.Attribute("perception_radius"), 4f);
            _occupancyRadius = Loader.loadFloat(data.Attribute("occupancy_radius"), 1f);
            _lateralAngle = Loader.loadFloat(data.Attribute("lateral_angle"), 0.6f);
            _fullExposure = Loader.loadFloat(data.Attribute("full_exposure"), 1f);
            _penumbraA = Loader.loadFloat(data.Attribute("penumbra_a"), 1f);
            _penumbraB = Loader.loadFloat(data.Attribute("penumbra_b"), 2f);
            _optimalGrowthWeight = Loader.loadFloat(data.Attribute("optimal_growth_weight"), 1f);
            _tropismWeight = Loader.loadFloat(data.Attribute("tropism_weight"), 1f);
            _tropism = Loader.loadVector2(data.Attribute("tropism"), Vector2.Zero);
            _position = Loader.loadVector2(data.Attribute("position"), Vector2.Zero);
            _layerDepth = Loader.loadFloat(data.Attribute("layer_depth"), 0.1f);
            _entityId = int.Parse(data.Attribute("id").Value);

            _vertices = new VertexPositionColorTexture[MAX_VERTICES];
            for (int i = 0; i < MAX_VERTICES; i++)
            {
                _vertices[i].Color = Color.White;
            }
            _random = new Random(_seed);
            _internodeLengthSq = _internodeLength * _internodeLength;
            _aabb = new AABB();
            _aabb.LowerBound = _position;
            _aabb.UpperBound = _position;

            // Calculate root position
            float rootAngle = _angle + (StasisMathHelper.pi);
            _rootPosition = _position + new Vector2((float)Math.Cos(rootAngle), (float)Math.Sin(rootAngle)) * 5f;

            // Calculate anchor normals
            float anchorAngle = _angle - (StasisMathHelper.pi * 0.5f);
            _anchorNormal = new Vector2((float)Math.Cos(anchorAngle), (float)Math.Sin(anchorAngle));

            // Create first metamer
            _rootMetamer = new Metamer(this, null, BudType.TERMINAL, BudState.DORMANT, BudState.DEAD, _angle, true);
            _rootMetamer.isTail = true;
        }
예제 #7
0
    void Start()
    {
        if (!m_OwnerSystem)
        {
            m_OwnerSystem = FindObjectOfType <TreeSystem>();
        }
        if (!m_WatchedTransform)
        {
            m_WatchedTransform = Camera.main.transform;
        }

        m_CollisionDistance        = m_OwnerSystem.m_Settings.m_ColliderSetDistance;
        m_CollisionRefreshDistance = m_OwnerSystem.m_Settings.m_ColliderRefreshDistance;

        m_LastPosition = m_WatchedTransform.position;

        m_ColliderHolder = new GameObject("TreeSystemColliderHolder");
    }
예제 #8
0
    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();

        TreeSystem system = target as TreeSystem;

        GUILayout.Space(20);

        if (GUILayout.Button("Apply Settings"))
        {
            system.SetTreeDistance(system.m_Settings.m_MaxTreeDistance);
            system.SetMandatoryShadowDistance(system.m_Settings.m_ShadowDrawDistance);

            system.SetApplyColliders(system.m_Settings.m_ApplyTreeColliders);
            system.SetCollisionDistance(system.m_Settings.m_ColliderSetDistance);
            system.SetCollisionRefreshDistance(system.m_Settings.m_ColliderRefreshDistance);
        }
    }
예제 #9
0
        public void RunForDepth2Other()
        {
            var system = new TreeSystem();
            var gate   = new Gate(false);
            var lgate  = new Gate(true);

            gate.LeftNode = lgate;
            var rgate = new Gate(true);

            gate.RightNode = rgate;
            var c1 = new Container();

            lgate.LeftNode = c1;
            var c2 = new Container()
            {
                ContainerNumber = 1
            };

            lgate.RightNode = c2;
            var c3 = new Container()
            {
                ContainerNumber = 2
            };

            rgate.LeftNode = c3;
            var c4 = new Container()
            {
                ContainerNumber = 3
            };

            rgate.RightNode = c4;
            system.Tree     = gate;
            system.Containers.Add(c1);
            system.Containers.Add(c2);
            system.Containers.Add(c3);
            system.Containers.Add(c4);
            GateRunner gr = new GateRunner();
            int        s  = gr.RunSystem(system);

            s.Should().Be(1);
        }
예제 #10
0
        public void RunForDepth1()
        {
            var system     = new TreeSystem();
            var gate       = new Gate(true);
            var lcontainer = new Container();

            gate.LeftNode = lcontainer;
            var rcontainer = new Container()
            {
                ContainerNumber = 1
            };

            gate.RightNode = rcontainer;
            system.Tree    = gate;
            system.Containers.Add(lcontainer);
            system.Containers.Add(rcontainer);
            GateRunner gr = new GateRunner();
            int        s  = gr.RunSystem(system);

            s.Should().Be(1);
        }
            private void CopyDataTo(long position, DataFile targetDataFile, long targetPosition, long size)
            {
                // If transactions are the same (data is being copied within the same
                // transaction context).
                TreeSystemStack targetStack;
                TreeSystemStack sourceStack;
                // Keys
                Key targetKey = targetDataFile.key;
                Key sourceKey = key;

                bool modifyPosOnShift = false;

                if (targetDataFile.Transaction == Transaction)
                {
                    // We set the source and target stack to the same
                    sourceStack = targetDataFile.stack;
                    targetStack = sourceStack;
                    // If same transaction and target_position is before the position we
                    // set the modify_pos_on_shift boolean.  This will update the absolute
                    // position when data is copied.
                    modifyPosOnShift = (targetPosition <= position);
                }
                else
                {
                    // Otherwise, set the target stack to the target file's stack
                    sourceStack = stack;
                    targetStack = targetDataFile.stack;
                }


                // Compact the key we are copying from, and in the destination,
                transaction.CompactNodeKey(sourceKey);
                targetDataFile.CompactNodeKey(targetKey);


                // The process works as follows;
                // 1. If we are not positioned at the start of a leaf, copy all data up
                //    to the next leaf to the target.
                // 2. Split the target leaf at the new position if the leaf can be
                //    split into 2 leaf nodes.
                // 3. Copy every full leaf to the target as a new leaf element.
                // 4. If there is any remaining data to copy, insert it into the target.

                // Set up for the position
                sourceStack.SetupForPosition(sourceKey, position);
                // If we aren't at the start of the leaf, then copy the data to the
                // target.
                int leafOff = sourceStack.LeafOffset;

                if (leafOff > 0)
                {
                    // We copy the remaining data in the leaf to the target
                    // The amount of data to copy from the leaf to the target
                    int to_copy = (int)Math.Min(size, sourceStack.LeafSize - leafOff);
                    if (to_copy > 0)
                    {
                        // Read into a buffer
                        byte[] buf = new byte[to_copy];
                        sourceStack.CurrentLeaf.Read(leafOff, buf, 0, to_copy);
                        // Make enough room to insert this data in the target
                        targetStack.ShiftData(targetKey, targetPosition, to_copy);
                        // Update the position if necessary
                        if (modifyPosOnShift)
                        {
                            position += to_copy;
                        }
                        // Write the data to the target stack
                        targetStack.WriteFrom(targetKey, targetPosition, buf, 0, to_copy);
                        // Increment the pointers
                        position       += to_copy;
                        targetPosition += to_copy;
                        size           -= to_copy;
                    }
                }

                // If this is true, the next iteration will use the byte buffer leaf copy
                // routine.  Set if a link to a node failed for whatever reason.
                bool useByteBufferCopyForNext = false;

                // The loop
                while (size > 0)
                {
                    // We now know we are at the start of a leaf with data left to copy.
                    sourceStack.SetupForPosition(sourceKey, position);
                    // Lets assert that
                    if (sourceStack.LeafOffset != 0)
                    {
                        throw new ApplicationException("Expected to be at the start of a leaf.");
                    }

                    // If the source is a heap node or we are copying less than the data
                    // that's in the leaf then we use the standard shift and write.
                    TreeLeaf currentLeaf = sourceStack.CurrentLeaf;
                    // Check the leaf size isn't 0
                    if (currentLeaf.Length <= 0)
                    {
                        throw new ApplicationException("Leaf is empty.");
                    }
                    // If the remaining copy is less than the size of the leaf we are
                    // copying from, we just do a byte array copy
                    if (useByteBufferCopyForNext || size < currentLeaf.Length)
                    {
                        // Standard copy through a byte[] buf,
                        useByteBufferCopyForNext = false;
                        int toCopy = (int)Math.Min(size, currentLeaf.Length);
                        // Read into a buffer
                        byte[] buf = new byte[toCopy];
                        currentLeaf.Read(0, buf, 0, toCopy);
                        // Make enough room in the target
                        targetStack.ShiftData(targetKey, targetPosition, toCopy);
                        if (modifyPosOnShift)
                        {
                            position += toCopy;
                        }
                        // Write the data and finish
                        targetStack.WriteFrom(targetKey, targetPosition, buf, 0, toCopy);
                        // Update pointers
                        position       += toCopy;
                        targetPosition += toCopy;
                        size           -= toCopy;
                    }
                    else
                    {
                        // We need to copy a complete leaf node,
                        // If the leaf is on the heap, write it out
                        if (transaction.IsHeapNode(currentLeaf.Id))
                        {
                            sourceStack.WriteLeafOnly(sourceKey);
                            // And update any vars
                            currentLeaf = sourceStack.CurrentLeaf;
                        }

                        // Ok, source current leaf isn't on the heap, and we are copying a
                        // complete leaf node, so we are elegible to play with pointers to
                        // copy the data.
                        targetStack.SetupForPosition(targetKey, targetPosition);
                        bool insertNextBefore = false;
                        // Does the target key exist?
                        bool targetKeyExists = targetStack.CurrentLeafKey.Equals(targetKey);
                        if (targetKeyExists)
                        {
                            // If the key exists, is target_position at the end of the span?
                            insertNextBefore = targetStack.LeafOffset < targetStack.CurrentLeaf.Length;
                        }

                        // If target isn't currently on a boundary
                        if (!targetStack.IsAtEndOfKeyData &&
                            targetStack.LeafOffset != 0)
                        {
                            // If we aren't on a boundary we need to split the target leaf
                            targetStack.SplitLeaf(targetKey, targetPosition);
                        }
                        // If the key exists we set up the position to the previous left
                        // to insert the new leaf, otherwise we set it up to the default
                        // position to insert.

                        // Copy the leaf,
                        // Try to link to this leaf
                        bool linkSuccessful = TreeSystem.LinkLeaf(targetKey, currentLeaf.Id);
                        // If the link was successful,
                        if (linkSuccessful)
                        {
                            // Insert the leaf into the tree
                            targetStack.InsertLeaf(targetKey, currentLeaf, insertNextBefore);
                            // Update the pointers
                            int copiedSize = currentLeaf.Length;
                            // Update if we inserting stuff before
                            if (modifyPosOnShift)
                            {
                                position += copiedSize;
                            }
                            position       += copiedSize;
                            targetPosition += copiedSize;
                            size           -= copiedSize;
                        }
                        // If the link was not successful,
                        else
                        {
                            // We loop back and use the byte buffer copy,
                            useByteBufferCopyForNext = true;
                        }
                    }
                }
            }
예제 #12
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;
        }
    }
예제 #13
0
    public void ExtractXMLTreePrototypeData()
    {
        TreeSystemPrototypeData[] data = m_ManagedPrototypes;

        for (int i = 0; i < data.Length; i++)
        {
            TreeSystemPrototypeData d = data[i];

            if (d.m_TreePrototype == null)
            {
                Log.e("Nothing set for data at index: " + i);
                continue;
            }

            // Get the protorype's billboard asset
            BillboardRenderer bill      = d.m_TreePrototype.GetComponentInChildren <BillboardRenderer>();
            BillboardAsset    billAsset = bill.billboard;

            // Set sizes
            d.m_Size = new Vector3(billAsset.width, billAsset.height, billAsset.bottom);

            // Parse the XML
            if (!d.m_TreeBillboardData && m_UseXMLData)
            {
                Debug.LogError("We are using XML data and we don't have any custom XML data! Switch 'UseXMLData' off!");
                continue;
            }

            if (m_UseXMLData)
            {
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(d.m_TreeBillboardData.text);

                if (doc["SpeedTreeRaw"]["Billboards"]["Vertical"] == null || doc["SpeedTreeRaw"]["Billboards"]["Horizontal"] == null)
                {
                    Debug.Log("Missing tree XML data for: " + d.m_TreePrototype.name);
                }
                else
                {
                    // Should be multiple of 4
                    d.m_VertBillboardUVs = ExtractBillboards(doc["SpeedTreeRaw"]["Billboards"]["Vertical"], true).ToArray();
                    d.m_HorzBillboardUVs = ExtractBillboards(doc["SpeedTreeRaw"]["Billboards"]["Horizontal"], false).ToArray();
                }
            }
            else
            {
                // TODO: support for non-XML
                Vector4[] uvs = billAsset.GetImageTexCoords();

                // Ussualy 16
                d.m_VertBillboardUVs = new Vector2[uvs.Length * 4];
                // Just set the first UV's just to have something
                d.m_HorzBillboardUVs = new Vector2[4];

                for (int uvIdx = 0, billUv = 0; uvIdx < uvs.Length; uvIdx++, billUv += 4)
                {
                    Vector4 extract = uvs[uvIdx];

                    if (uvIdx == 0)
                    {
                        d.m_HorzBillboardUVs[0] = new Vector2(extract.x, extract.y);
                        d.m_HorzBillboardUVs[1] = new Vector2(extract.x, extract.y) + new Vector2(0, Mathf.Abs(extract.w));
                        d.m_HorzBillboardUVs[2] = new Vector2(extract.x, extract.y) + new Vector2(-extract.z, Mathf.Abs(extract.w));
                        d.m_HorzBillboardUVs[3] = new Vector2(extract.x, extract.y) + new Vector2(-extract.z, 0);
                    }

                    // We are rotated
                    if (extract.w < 0)
                    {
                        d.m_VertBillboardUVs[billUv + 0] = new Vector2(extract.x, extract.y);
                        d.m_VertBillboardUVs[billUv + 1] = new Vector2(extract.x, extract.y) + new Vector2(0, Mathf.Abs(extract.w));
                        d.m_VertBillboardUVs[billUv + 2] = new Vector2(extract.x, extract.y) + new Vector2(-extract.z, Mathf.Abs(extract.w));
                        d.m_VertBillboardUVs[billUv + 3] = new Vector2(extract.x, extract.y) + new Vector2(-extract.z, 0);
                    }
                    else
                    {
                        d.m_VertBillboardUVs[billUv + 0] = new Vector2(extract.x, extract.y);
                        d.m_VertBillboardUVs[billUv + 1] = new Vector2(extract.x, extract.y) + new Vector2(extract.z, 0);
                        d.m_VertBillboardUVs[billUv + 2] = new Vector2(extract.x, extract.y) + new Vector2(extract.z, extract.w);
                        d.m_VertBillboardUVs[billUv + 3] = new Vector2(extract.x, extract.y) + new Vector2(0, extract.w);
                    }
                }
            }

            Vector4 size = d.m_Size;
            size.w = 1;

            // Create the material with the texture references
            Material billboardMaterialBatch = new Material(m_BillboardShaderBatch);
            billboardMaterialBatch.SetTexture("_MainTex", bill.billboard.material.GetTexture("_MainTex"));
            billboardMaterialBatch.SetTexture("_BumpMap", bill.billboard.material.GetTexture("_BumpMap"));
            billboardMaterialBatch.SetVector("_Size", size);
            Material billboardMaterialMaster = new Material(m_BillboardShaderMaster);
            billboardMaterialMaster.SetTexture("_MainTex", bill.billboard.material.GetTexture("_MainTex"));
            billboardMaterialMaster.SetTexture("_BumpMap", bill.billboard.material.GetTexture("_BumpMap"));
            billboardMaterialMaster.SetVector("_Size", size);

            // Replace, don't delete
            // AssetDatabase.DeleteAsset(m_DataStorePath + "/" + d.m_TreePrototype.name + "_Mat.mat");
            AssetDatabase.CreateAsset(billboardMaterialBatch,
                                      m_DataStorePath + "/" + d.m_TreePrototype.name + "_Bill_Batch_Mat.mat");
            AssetDatabase.CreateAsset(billboardMaterialMaster,
                                      m_DataStorePath + "/" + d.m_TreePrototype.name + "_Bill_Master_Mat.mat");

            // Set the material
            d.m_BillboardBatchMaterial  = billboardMaterialBatch;
            d.m_BillboardMasterMaterial = billboardMaterialMaster;

            // Set billboard data
            TreeSystem.SetMaterialBillProps(d, d.m_BillboardBatchMaterial);
            TreeSystem.SetMaterialBillProps(d, d.m_BillboardMasterMaterial);
        }

        AssetDatabase.Refresh();
    }
예제 #14
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;
        }
    }
예제 #15
0
    public void ExtractXMLTreePrototypeData()
    {
        TreeSystemPrototypeData[] data = m_ManagedPrototypes;

        for (int i = 0; i < data.Length; i++)
        {
            TreeSystemPrototypeData d = data[i];

            if (d.m_TreePrototype == null)
            {
                Debug.LogError("Nothing set for data at index: " + i);
                continue;
            }

            // Get the protorype's billboard asset
            BillboardRenderer bill = d.m_TreePrototype.GetComponentInChildren <BillboardRenderer>();

            if (bill == null)
            {
                Debug.LogError("Prototype: " + d.m_TreePrototype.name + " does not contain a billboard renderer! Items without billboard renderers are not supported at the moment!");
                continue;
            }

            BillboardAsset billAsset = bill.billboard;

            // Set sizes
            d.m_Size = new Vector3(billAsset.width, billAsset.height, billAsset.bottom);


            Vector4[] uvs = billAsset.GetImageTexCoords();

            // Ussualy 16
            d.m_VertBillboardUVs = new Vector2[uvs.Length * 4];
            // Just set the first UV's just to have something
            d.m_HorzBillboardUVs = new Vector2[4];

            for (int uvIdx = 0, billUv = 0; uvIdx < uvs.Length; uvIdx++, billUv += 4)
            {
                Vector4 extract = uvs[uvIdx];

                if (uvIdx == 0)
                {
                    d.m_HorzBillboardUVs[0] = new Vector2(extract.x, extract.y);
                    d.m_HorzBillboardUVs[1] = new Vector2(extract.x, extract.y) + new Vector2(0, Mathf.Abs(extract.w));
                    d.m_HorzBillboardUVs[2] = new Vector2(extract.x, extract.y) + new Vector2(-extract.z, Mathf.Abs(extract.w));
                    d.m_HorzBillboardUVs[3] = new Vector2(extract.x, extract.y) + new Vector2(-extract.z, 0);
                }

                // We are rotated
                if (extract.w < 0)
                {
                    d.m_VertBillboardUVs[billUv + 0] = new Vector2(extract.x, extract.y);
                    d.m_VertBillboardUVs[billUv + 1] = new Vector2(extract.x, extract.y) + new Vector2(0, Mathf.Abs(extract.w));
                    d.m_VertBillboardUVs[billUv + 2] = new Vector2(extract.x, extract.y) + new Vector2(-extract.z, Mathf.Abs(extract.w));
                    d.m_VertBillboardUVs[billUv + 3] = new Vector2(extract.x, extract.y) + new Vector2(-extract.z, 0);
                }
                else
                {
                    d.m_VertBillboardUVs[billUv + 0] = new Vector2(extract.x, extract.y);
                    d.m_VertBillboardUVs[billUv + 1] = new Vector2(extract.x, extract.y) + new Vector2(extract.z, 0);
                    d.m_VertBillboardUVs[billUv + 2] = new Vector2(extract.x, extract.y) + new Vector2(extract.z, extract.w);
                    d.m_VertBillboardUVs[billUv + 3] = new Vector2(extract.x, extract.y) + new Vector2(0, extract.w);
                }
            }

            Vector4 size = d.m_Size;
            size.w = 1;

            // Create the material with the texture references
            Material billboardMaterialBatch = new Material(m_BillboardShaderBatch);
            billboardMaterialBatch.SetTexture("_MainTex", bill.billboard.material.GetTexture("_MainTex"));
            billboardMaterialBatch.SetTexture("_BumpMap", bill.billboard.material.GetTexture("_BumpMap"));
            billboardMaterialBatch.SetVector("_Size", size);

            // Replace, don't delete
            // AssetDatabase.DeleteAsset(m_DataStorePath + "/" + d.m_TreePrototype.name + "_Mat.mat");
            AssetDatabase.CreateAsset(billboardMaterialBatch,
                                      m_DataStorePath + "/" + d.m_TreePrototype.name + "_Bill_Batch_Mat.mat");

            // Set the material
            d.m_BillboardBatchMaterial = billboardMaterialBatch;

            // Set billboard data
            TreeSystem.SetMaterialBillProps(d, d.m_BillboardBatchMaterial);
        }

        AssetDatabase.Refresh();
    }