Ejemplo n.º 1
0
    public void ExtractTreeLODPrototypeData()
    {
        TreeSystemPrototypeData[] proto = m_ManagedPrototypes;

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

            // 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;

                // Populate some data
                if (lod == lods.Length - 1)
                {
                    // It must be a billboard renderer tread it specially
                    d.m_IsBillboard = true;

                    d.m_Mesh = Instantiate(m_SystemQuad);
                    AssetDatabase.CreateAsset(d.m_Mesh,
                                              m_DataStorePath + "/" + prefab.name + "_Master_Billboard_Mesh_0.asset");

                    d.m_Materials = new Material[] { data.m_BillboardMasterMaterial };
                }
                else
                {
                    MeshRenderer rend   = lods[lod].renderers[0].gameObject.GetComponent <MeshRenderer>();
                    MeshFilter   filter = lods[lod].renderers[0].gameObject.GetComponent <MeshFilter>();

                    // Set the mesh we are drawing to the shared mesh
                    d.m_Mesh = Instantiate(filter.sharedMesh);
                    AssetDatabase.CreateAsset(d.m_Mesh,
                                              m_DataStorePath + "/" + prefab.name + "_Master_Tree_Mesh_LOD_" + lod + ".asset");

                    // Get the materials, create instances and set our SpeedTree master shader
                    d.m_Materials = rend.sharedMaterials;

                    for (int mat = 0; mat < d.m_Materials.Length; mat++)
                    {
                        d.m_Materials[mat]        = new Material(d.m_Materials[mat]);
                        d.m_Materials[mat].shader = m_TreeShaderMaster;

                        AssetDatabase.CreateAsset(d.m_Materials[mat],
                                                  m_DataStorePath + "/" + prefab.name + "_Master_Tree_Material_LOD" + lod + "_" + mat + ".mat");
                    }
                }
            }

            data.m_MaxLodIndex   = lodData.Length - 1;
            data.m_MaxLod3DIndex = lodData.Length - 2;
        }
    }
Ejemplo n.º 2
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;
        }
    }
Ejemplo n.º 3
0
    private void UpdateLODDataDistances(TreeSystemPrototypeData data)
    {
        LOD[] lods = data.m_TreePrototype.GetComponent <LODGroup>().GetLODs();
        TreeSystemLODData[] lodData = data.m_LODData;

        for (int i = 0; i < lodData.Length; i++)
        {
            // If it's the billboard move on
            if (i == lods.Length - 1)
            {
                continue;
            }

            TreeSystemLODData d = lodData[i];

            if (i == 0)
            {
                // If it's first 3D LOD
                d.m_StartDistance = 0;
                d.m_EndDistance   = ((1.0f - lods[i].screenRelativeTransitionHeight) * m_Settings.m_MaxTreeDistance);
            }
            else if (i == lodData.Length - 2)
            {
                // If it's last 3D LOD
                d.m_StartDistance = ((1.0f - lods[i - 1].screenRelativeTransitionHeight) * m_Settings.m_MaxTreeDistance);
                d.m_EndDistance   = m_Settings.m_MaxTreeDistance;
            }
            else
            {
                // If it's a LOD in between
                d.m_StartDistance = ((1.0f - lods[i - 1].screenRelativeTransitionHeight) * m_Settings.m_MaxTreeDistance);
                d.m_EndDistance   = ((1.0f - lods[i].screenRelativeTransitionHeight) * m_Settings.m_MaxTreeDistance);
            }
        }
    }
Ejemplo n.º 4
0
    public void Draw3DLOD(TreeSystemLODData data, ref TreeSystemLODInstance inst)
    {
        // data.m_Block.SetVector(system.m_ShaderIDFadeLOD, new Vector4(inst.m_LODTransition, inst.m_LODFullFade, 0, 0));

        for (int mat = 0; mat < data.m_Materials.Length; mat++)
        {
            Graphics.DrawMesh(data.m_Mesh, transform.localToWorldMatrix, data.m_Materials[mat], mat, null, mat, data.m_Block, true, true);
        }
    }
Ejemplo n.º 5
0
    private void GenerateRuntimePrototypeData(TreeSystemPrototypeData data)
    {
        // All stuff that we draw must have billboard renderers, that's why it's trees
        LOD[] lods = data.m_TreePrototype.GetComponent <LODGroup>().GetLODs();
        TreeSystemLODData[] lodData = data.m_LODData;

        // Set material's UV at runtime
        SetMaterialBillProps(data, data.m_BillboardBatchMaterial);
        SetMaterialBillProps(data, data.m_BillboardMasterMaterial);

        // Get the same tree stuff as the grass
        for (int i = 0; i < lodData.Length; i++)
        {
            if (lods[i].renderers.Length != 1)
            {
                Debug.LogError("Renderer length != 1! Problem!");
            }

            // Assume only one renderer
            TreeSystemLODData d = lodData[i];

            // If it's last element
            if (i == lods.Length - 1)
            {
                d.m_Block = new MaterialPropertyBlock();
            }
            else
            {
                d.m_Block = new MaterialPropertyBlock();

                GameObject weirdTree = Instantiate(lods[i].renderers[0].gameObject);
                weirdTree.hideFlags = HideFlags.HideAndDontSave;

                // Get the tree renderer
                d.m_TreeRenderer = weirdTree.GetComponent <MeshRenderer>();
                d.m_TreeRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;

                d.m_TreeRenderer.transform.SetParent(Camera.main.transform);
                d.m_TreeRenderer.transform.localPosition = new Vector3(0, 0, -2);
                d.m_TreeRenderer.transform.localScale    = new Vector3(0.1f, 0.1f, 0.1f);

                MeshFilter mf = d.m_TreeRenderer.GetComponent <MeshFilter>();

                // Get an instance mesh from the weird tree
                Mesh m = mf.mesh;

                // Set the new bounds so that it's always drawn
                Bounds b = m.bounds;
                b.Expand(50.0f);
                m.bounds = b;
                mf.mesh  = m;
            }
        }

        // Update the LOD distances
        UpdateLODDataDistances(data);
    }
Ejemplo n.º 6
0
    public void Draw3DLOD(ref TreeSystemLODData data, ref TreeSystemLODInstance lodInst, ref TreeSystemStoredInstance inst)
    {
        data.m_Block.SetVector(m_ShaderIDFadeLOD, new Vector4(lodInst.m_LODTransition, lodInst.m_LODFullFade, 0, 0));

        for (int mat = 0; mat < data.m_Materials.Length; mat++)
        {
            Graphics.DrawMesh(data.m_Mesh, inst.m_PositionMtx, data.m_Materials[mat], 0, null, mat, data.m_Block, true, true);
            m_DataIssuesDrawCalls++;
        }
    }
Ejemplo n.º 7
0
    public void ExtractTreeLODPrototypeData()
    {
        TreeSystemPrototypeData[] proto = m_ManagedPrototypes;

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

            if (prefab.GetComponent <LODGroup>() == null)
            {
                Debug.LogError("Prototype: " + prefab.name + " does not have a LOD group! Please fix and regenerate, or the system will break!");
                continue;
            }

            // 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;

                if (lods[lod].renderers[0].gameObject.GetComponent <BillboardRenderer>())
                {
                    continue;
                }

                MeshRenderer rend   = lods[lod].renderers[0].gameObject.GetComponent <MeshRenderer>();
                MeshFilter   filter = lods[lod].renderers[0].gameObject.GetComponent <MeshFilter>();

                // Set the mesh we are drawing to the shared mesh
                d.m_Mesh = Instantiate(filter.sharedMesh);
                AssetDatabase.CreateAsset(d.m_Mesh,
                                          m_DataStorePath + "/" + prefab.name + "_Master_Tree_Mesh_LOD_" + lod + ".asset");

                // Get the materials, create instances and set our SpeedTree master shader
                d.m_Materials = rend.sharedMaterials;

                for (int mat = 0; mat < d.m_Materials.Length; mat++)
                {
                    d.m_Materials[mat]        = new Material(d.m_Materials[mat]);
                    d.m_Materials[mat].shader = m_TreeShaderMaster;

                    AssetDatabase.CreateAsset(d.m_Materials[mat],
                                              m_DataStorePath + "/" + prefab.name + "_Master_Tree_Material_LOD" + lod + "_" + mat + ".mat");
                }
            }

            data.m_MaxLod3DIndex = lodData.Length - 2;
        }
    }
Ejemplo n.º 8
0
    public void Draw3DLOD(ref TreeSystemLODData data, ref TreeSystemLODInstance lodInst, ref TreeSystemStoredInstance inst)
    {
        m_TempLOD[0] = lodInst.m_LODTransition;
        data.m_Block.SetFloatArray(m_ShaderIDFadeLODDetail, m_TempLOD);
        m_TempLOD[0] = lodInst.m_LODFullFade;
        data.m_Block.SetFloatArray(m_ShaderIDFadeLODFull, m_TempLOD);

        for (int mat = 0; mat < data.m_Materials.Length; mat++)
        {
            Graphics.DrawMesh(data.m_Mesh, inst.m_PositionMtx, data.m_Materials[mat], m_UsedLayerId, m_UsedCamera, mat, data.m_Block, true, true);

            m_DataIssuesDrawCalls++;
        }
    }
Ejemplo n.º 9
0
    public void Draw3DLOD(ref TreeSystemLODData data, ref TreeSystemLODInstance lodInst, ref TreeSystemStoredInstance inst, ref bool shadowsOnly)
    {
        m_TempLOD[0] = lodInst.m_LODTransition;
        data.m_Block.SetFloatArray(m_ShaderIDFadeLODDetail, m_TempLOD);
        m_TempLOD[0] = lodInst.m_LODFullFade;
        data.m_Block.SetFloatArray(m_ShaderIDFadeLODFull, m_TempLOD);

        for (int mat = 0; mat < data.m_Materials.Length; mat++)
        {
            Graphics.DrawMesh(data.m_Mesh, inst.m_PositionMtx, data.m_Materials[mat], m_UsedLayerId, m_Settings.m_UsedCamera, mat, data.m_Block,
                              shadowsOnly == false ? UnityEngine.Rendering.ShadowCastingMode.On : UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly,
                              true);

            m_DataIssuesDrawCalls++;
        }
    }
Ejemplo n.º 10
0
    public void DrawBillboardLOD(ref TreeSystemLODData data, ref TreeSystemLODInstance lodInst, ref TreeSystemStoredInstance inst)
    {
        data.m_Block.SetVector(m_ShaderIDFadeLOD, new Vector4(lodInst.m_LODTransition, 1.0f - lodInst.m_LODFullFade, 0, 0));

        // Set extra scale and stuff
        Vector4 extra = inst.m_WorldScale;

        extra.w = inst.m_WorldRotation;
        data.m_Block.SetVector(m_ShaderIDBillboardScaleRotation, extra);

        for (int mat = 0; mat < data.m_Materials.Length; mat++)
        {
            Graphics.DrawMesh(data.m_Mesh, inst.m_PositionMtx, data.m_Materials[mat], 0, null, mat, data.m_Block, true, true);
            m_DataIssuesDrawCalls++;
        }
    }
Ejemplo n.º 11
0
    public void Draw3DLODInstanced(ref TreeSystemLODData data, ref Matrix4x4[] positions, ref int count)
    {
        if (count > 0)
        {
            // TODO: set the array stuff
            data.m_Block.SetVector(m_ShaderIDFadeLOD, new Vector4(1, 1, 0, 0));

            for (int mat = 0; mat < data.m_Materials.Length; mat++)
            {
                Graphics.DrawMeshInstanced(data.m_Mesh, mat, data.m_Materials[mat], positions, count, data.m_Block,
                                           UnityEngine.Rendering.ShadowCastingMode.On, true);

                m_DataIssuesDrawCalls++;
            }
        }
    }
Ejemplo n.º 12
0
    public void Draw3DLODInstanced(ref TreeSystemLODData data, ref Matrix4x4[] positions, ref float[] lodDetail, ref float[] lodFull, ref int count)
    {
        if (count > 0)
        {
            data.m_Block.SetFloatArray(m_ShaderIDFadeLODDetail, lodDetail);
            data.m_Block.SetFloatArray(m_ShaderIDFadeLODFull, lodFull);

            for (int mat = 0; mat < data.m_Materials.Length; mat++)
            {
                Graphics.DrawMeshInstanced(data.m_Mesh, mat, data.m_Materials[mat], positions, count, data.m_Block,
                                           UnityEngine.Rendering.ShadowCastingMode.On, true, m_UsedLayerId, m_UsedCamera);

                m_DataIssuesDrawCalls++;
            }
        }
    }
Ejemplo n.º 13
0
    public void DrawBillboardLOD(ref TreeSystemLODData data, ref TreeSystemLODInstance lodInst, ref TreeSystemStoredInstance inst)
    {
        data.m_Block.SetVector(m_ShaderIDFadeBillboard, new Vector4(lodInst.m_LODTransition, 1.0f - lodInst.m_LODFullFade, 0, 0));

        // Set extra scale and stuff
        Vector4 extra = inst.m_WorldScale;

        extra.w = inst.m_WorldRotation;

        // Set positions used in shader
        data.m_Block.SetVector(m_ShaderIDBillboardScaleRotation, extra);

        m_BillboardTempPos.m03 = inst.m_WorldPosition.x;
        m_BillboardTempPos.m13 = inst.m_WorldPosition.y;
        m_BillboardTempPos.m23 = inst.m_WorldPosition.z;

        for (int mat = 0; mat < data.m_Materials.Length; mat++)
        {
            Graphics.DrawMesh(data.m_Mesh, m_BillboardTempPos, data.m_Materials[mat], m_UsedLayerId, m_Settings.m_UsedCamera, mat, data.m_Block, true, true);
            m_DataIssuesDrawCalls++;
        }
    }
Ejemplo n.º 14
0
    private void GenerateRuntimePrototypeData(TreeSystemPrototypeData data)
    {
        // All stuff that we draw must have billboard renderers, that's why it's trees
        LOD[] lods = data.m_TreePrototype.GetComponent <LODGroup>().GetLODs();
        TreeSystemLODData[] lodData = data.m_LODData;

        // Set material's UV at runtime
        SetMaterialBillProps(data, data.m_BillboardBatchMaterial);

        // Instantiate the last 3D lod
        GameObject weirdTree = Instantiate(lods[lods.Length - 2].renderers[0].gameObject);

        // weirdTree.hideFlags = HideFlags.HideAndDontSave;

        // Stick it to the camera
        weirdTree.transform.SetParent(Camera.main.transform);
        weirdTree.transform.localPosition = new Vector3(0, 0, -2);
        weirdTree.transform.localScale    = new Vector3(0.1f, 0.1f, 0.1f);

        // Expand the bounds
        MeshRenderer mr = weirdTree.GetComponent <MeshRenderer>();
        MeshFilter   mf = weirdTree.GetComponent <MeshFilter>();

        // Get an instance mesh from the weird tree
        Mesh m = mf.mesh;

        // Set the new bounds so that it's always drawn
        Bounds b = m.bounds; b.Expand(50.0f); m.bounds = b;

        mf.mesh = m;

        // Don't cast shadows
        mr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;

        // Get the same tree stuff as the grass
        for (int i = 0; i < lodData.Length; i++)
        {
            if (lods[i].renderers.Length != 1)
            {
                Debug.LogError("Renderer length != 1! Problem!");
            }

            // Assume only one renderer
            TreeSystemLODData d = lodData[i];

            // Add a new MBP and set the renderer from which we are going to copy the wind data from
            d.m_Block        = new MaterialPropertyBlock();
            d.m_TreeRenderer = mr;

            // Set the full array here because based on the docs, i'm not sure when is this going to be refreshed
            // Quote:
            // "The array length can't be changed once it has been added to the block. If you subsequently try
            // to set a longer array into the same property, the length will be capped to the original length and
            // the extra items you tried to assign will be ignored."
            // So, we're making sure that we have those MAX_BATCH count of floats
            d.m_Block.SetFloatArray(m_ShaderIDFadeLODDetail, new float[MAX_BATCH]);
            d.m_Block.SetFloatArray(m_ShaderIDFadeLODFull, new float[MAX_BATCH]);
        }

        // Update the LOD distances
        UpdateLODDataDistances(data);
    }
Ejemplo n.º 15
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;
        }
    }
Ejemplo n.º 16
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;
        }
    }