Esempio n. 1
0
    private void ProcessTerrainCell(TreeSystemStructuredTrees cell, ref float colliderDistSqr)
    {
        TreeSystemStoredInstance[] treeInstances = cell.m_Instances;
        float x, y, z;

        for (int treeIndex = 0; treeIndex < treeInstances.Length; treeIndex++)
        {
            x = treeInstances[treeIndex].m_WorldPosition.x - m_CameraPosTemp.x;
            y = treeInstances[treeIndex].m_WorldPosition.y - m_CameraPosTemp.y;
            z = treeInstances[treeIndex].m_WorldPosition.z - m_CameraPosTemp.z;

            float distToTree = x * x + y * y + z * z;

            if (distToTree <= colliderDistSqr)
            {
                int hash = treeInstances[treeIndex].m_TreeHash;

                // Get a collider for the hash
                GameObject collider = GetColliderForPrototype(hash);

                if (collider != null)
                {
                    // Update it's transform values
                    collider.transform.position   = treeInstances[treeIndex].m_WorldPosition;
                    collider.transform.rotation   = Quaternion.Euler(0, treeInstances[treeIndex].m_WorldRotation * Mathf.Rad2Deg, 0);
                    collider.transform.localScale = treeInstances[treeIndex].m_WorldScale;

                    // Increment the active collider count
                    m_DataIssuedActiveColliders++;
                }
            }
        }
    }
Esempio n. 2
0
    private void ProcessTerrain(TreeSystemTerrain terrain, ref float treeDistSqr, ref float shadowDistSqr)
    {
        TreeSystemStructuredTrees[] cells = terrain.m_Cells;
        CullingGroup culling = terrain.m_CullingGroup;

        float x, y, z;

        // TODO: calculate based on bounds index the cells that we'll iterate like the grass system
        // We won't require to iterate all the cells but the neighbors of the current cell only

        // TODO: only get the data from the culling group API at the moment

        // Go bounds by bounds
        for (int cellIdx = 0; cellIdx < cells.Length; cellIdx++)
        {
            TreeSystemStructuredTrees cell = cells[cellIdx];

            // If we don't have any tree skip this cell
            if (cell.m_Instances.Length <= 0)
            {
                continue;
            }

            // And also check if the bounds are visible
            if (culling.IsVisible(cellIdx) == false)
            {
                continue;
            }

            // Get closest point to cell
            Vector3 pt = cell.m_BoundsBox.ClosestPoint(m_CameraPosTemp);

            x = pt.x - m_CameraPosTemp.x;
            y = pt.y - m_CameraPosTemp.y;
            z = pt.z - m_CameraPosTemp.z;

            float distToCell = x * x + y * y + z * z;

            if (distToCell < treeDistSqr && GeometryUtility.TestPlanesAABB(m_PlanesTemp, cell.m_BoundsBox))
            {
                // TODO: the same process when we are going to have terrain sub-cells
                ProcessTerrainCell(cell, ref treeDistSqr, ref shadowDistSqr);

                // If it's visible
                m_DataIssuedTerrainCells++;
            }
            // TODO: See for the case in which we are at the intersection of 4 cells and the cells are not visible to the frustum
            // BUT they have trees that 'might' cast shadows inside the frustum. Do that with a special thing that only checks the trees
            // for the shadow distance, and that's all
            // else if (m_ApplyShadowPoppingCorrection && distToCell < shadowDistSqr) { }
        }
    }
Esempio n. 3
0
    private void ProcessTerrain(TreeSystemTerrain terrain, ref float treeDistSqr)
    {
        TreeSystemStructuredTrees[] cells = terrain.m_Cells;

        float x, y, z;

        // TODO: calculate based on bounds index the cells that we'll iterate like the grass system
        // We won't require to iterate all the cells but the neighbors of the current cell only

        // Go bounds by bounds
        for (int cellIdx = 0; cellIdx < cells.Length; cellIdx++)
        {
            TreeSystemStructuredTrees cell = cells[cellIdx];

            // If we don't have any tree skip this cell
            if (cell.m_Instances.Length <= 0)
            {
                continue;
            }

            // Get closest point to cell
            Vector3 pt = cell.m_Bounds.ClosestPoint(m_CameraPosTemp);

            x = pt.x - m_CameraPosTemp.x;
            y = pt.y - m_CameraPosTemp.y;
            z = pt.z - m_CameraPosTemp.z;

            float distToCell = x * x + y * y + z * z;

            if (distToCell < treeDistSqr && GeometryUtility.TestPlanesAABB(m_PlanesTemp, cell.m_Bounds))
            {
                // TODO: the same process when we are going to have terrain sub-cells

                ProcessTerrainCell(cell, ref treeDistSqr);

                // If it's visible
                m_DataIssuedTerrainCells++;
            }
        }
    }
Esempio n. 4
0
    private void ProcessTerrain(TreeSystemTerrain terrain, ref float colliderDistSqr)
    {
        TreeSystemStructuredTrees[] cells = terrain.m_Cells;
        float x, y, z;

        for (int cellIdx = 0; cellIdx < cells.Length; cellIdx++)
        {
            TreeSystemStructuredTrees cell = cells[cellIdx];

            // Get closest point to cell
            Vector3 pt = cell.m_BoundsBox.ClosestPoint(m_CameraPosTemp);

            x = pt.x - m_CameraPosTemp.x;
            y = pt.y - m_CameraPosTemp.y;
            z = pt.z - m_CameraPosTemp.z;

            float distToCell = x * x + y * y + z * z;

            if (distToCell < colliderDistSqr)
            {
                ProcessTerrainCell(cell, ref colliderDistSqr);
            }
        }
    }
Esempio n. 5
0
    private void IssueDrawTrees(TreeSystemPrototypeData data, TreeSystemStructuredTrees trees, int[] indices, float[] dist, int count, bool shadowsOnly)
    {
        for (int i = 0; i < MAX_LOD_COUNT; i++)
        {
            m_MtxLODTempCount[i] = 0;
        }

        TreeSystemLODData[] lodData = data.m_LODData;

        TreeSystemStoredInstance[] treeInstances   = trees.m_Instances;
        TreeSystemLODInstance[]    lodInstanceData = trees.m_InstanceData;

        int maxLod3D = data.m_MaxLod3DIndex;

        // Build the batched stuff. We want to batch the same LOD and draw them using instancing
        for (int i = 0; i < count; i++)
        {
            ProcessLOD(ref lodData, ref maxLod3D, ref lodInstanceData[indices[i]], ref dist[i]);

            int idx             = indices[i];
            int currentLODLevel = lodInstanceData[idx].m_LODLevel;

            // Collect that LOD level
            if (currentLODLevel == 0)
            {
                m_MtxLODTemp_0[m_MtxLODTempCount[currentLODLevel]].m00 = treeInstances[idx].m_PositionMtx.m00;
                m_MtxLODTemp_0[m_MtxLODTempCount[currentLODLevel]].m01 = treeInstances[idx].m_PositionMtx.m01;
                m_MtxLODTemp_0[m_MtxLODTempCount[currentLODLevel]].m02 = treeInstances[idx].m_PositionMtx.m02;
                m_MtxLODTemp_0[m_MtxLODTempCount[currentLODLevel]].m03 = treeInstances[idx].m_PositionMtx.m03;
                m_MtxLODTemp_0[m_MtxLODTempCount[currentLODLevel]].m10 = treeInstances[idx].m_PositionMtx.m10;
                m_MtxLODTemp_0[m_MtxLODTempCount[currentLODLevel]].m11 = treeInstances[idx].m_PositionMtx.m11;
                m_MtxLODTemp_0[m_MtxLODTempCount[currentLODLevel]].m12 = treeInstances[idx].m_PositionMtx.m12;
                m_MtxLODTemp_0[m_MtxLODTempCount[currentLODLevel]].m13 = treeInstances[idx].m_PositionMtx.m13;
                m_MtxLODTemp_0[m_MtxLODTempCount[currentLODLevel]].m20 = treeInstances[idx].m_PositionMtx.m20;
                m_MtxLODTemp_0[m_MtxLODTempCount[currentLODLevel]].m21 = treeInstances[idx].m_PositionMtx.m21;
                m_MtxLODTemp_0[m_MtxLODTempCount[currentLODLevel]].m22 = treeInstances[idx].m_PositionMtx.m22;
                m_MtxLODTemp_0[m_MtxLODTempCount[currentLODLevel]].m23 = treeInstances[idx].m_PositionMtx.m23;

                m_MtxLODTranzDetail_0[m_MtxLODTempCount[currentLODLevel]] = lodInstanceData[idx].m_LODTransition;
                m_MtxLODTranzFull_0[m_MtxLODTempCount[currentLODLevel]]   = lodInstanceData[idx].m_LODFullFade;
            }
            else if (currentLODLevel == 1)
            {
                m_MtxLODTemp_1[m_MtxLODTempCount[currentLODLevel]].m00 = treeInstances[idx].m_PositionMtx.m00;
                m_MtxLODTemp_1[m_MtxLODTempCount[currentLODLevel]].m01 = treeInstances[idx].m_PositionMtx.m01;
                m_MtxLODTemp_1[m_MtxLODTempCount[currentLODLevel]].m02 = treeInstances[idx].m_PositionMtx.m02;
                m_MtxLODTemp_1[m_MtxLODTempCount[currentLODLevel]].m03 = treeInstances[idx].m_PositionMtx.m03;
                m_MtxLODTemp_1[m_MtxLODTempCount[currentLODLevel]].m10 = treeInstances[idx].m_PositionMtx.m10;
                m_MtxLODTemp_1[m_MtxLODTempCount[currentLODLevel]].m11 = treeInstances[idx].m_PositionMtx.m11;
                m_MtxLODTemp_1[m_MtxLODTempCount[currentLODLevel]].m12 = treeInstances[idx].m_PositionMtx.m12;
                m_MtxLODTemp_1[m_MtxLODTempCount[currentLODLevel]].m13 = treeInstances[idx].m_PositionMtx.m13;
                m_MtxLODTemp_1[m_MtxLODTempCount[currentLODLevel]].m20 = treeInstances[idx].m_PositionMtx.m20;
                m_MtxLODTemp_1[m_MtxLODTempCount[currentLODLevel]].m21 = treeInstances[idx].m_PositionMtx.m21;
                m_MtxLODTemp_1[m_MtxLODTempCount[currentLODLevel]].m22 = treeInstances[idx].m_PositionMtx.m22;
                m_MtxLODTemp_1[m_MtxLODTempCount[currentLODLevel]].m23 = treeInstances[idx].m_PositionMtx.m23;

                m_MtxLODTranzDetail_1[m_MtxLODTempCount[currentLODLevel]] = lodInstanceData[idx].m_LODTransition;
                m_MtxLODTranzFull_1[m_MtxLODTempCount[currentLODLevel]]   = lodInstanceData[idx].m_LODFullFade;
            }
            else if (currentLODLevel == 2)
            {
                m_MtxLODTemp_2[m_MtxLODTempCount[currentLODLevel]].m00 = treeInstances[idx].m_PositionMtx.m00;
                m_MtxLODTemp_2[m_MtxLODTempCount[currentLODLevel]].m01 = treeInstances[idx].m_PositionMtx.m01;
                m_MtxLODTemp_2[m_MtxLODTempCount[currentLODLevel]].m02 = treeInstances[idx].m_PositionMtx.m02;
                m_MtxLODTemp_2[m_MtxLODTempCount[currentLODLevel]].m03 = treeInstances[idx].m_PositionMtx.m03;
                m_MtxLODTemp_2[m_MtxLODTempCount[currentLODLevel]].m10 = treeInstances[idx].m_PositionMtx.m10;
                m_MtxLODTemp_2[m_MtxLODTempCount[currentLODLevel]].m11 = treeInstances[idx].m_PositionMtx.m11;
                m_MtxLODTemp_2[m_MtxLODTempCount[currentLODLevel]].m12 = treeInstances[idx].m_PositionMtx.m12;
                m_MtxLODTemp_2[m_MtxLODTempCount[currentLODLevel]].m13 = treeInstances[idx].m_PositionMtx.m13;
                m_MtxLODTemp_2[m_MtxLODTempCount[currentLODLevel]].m20 = treeInstances[idx].m_PositionMtx.m20;
                m_MtxLODTemp_2[m_MtxLODTempCount[currentLODLevel]].m21 = treeInstances[idx].m_PositionMtx.m21;
                m_MtxLODTemp_2[m_MtxLODTempCount[currentLODLevel]].m22 = treeInstances[idx].m_PositionMtx.m22;
                m_MtxLODTemp_2[m_MtxLODTempCount[currentLODLevel]].m23 = treeInstances[idx].m_PositionMtx.m23;

                m_MtxLODTranzDetail_2[m_MtxLODTempCount[currentLODLevel]] = lodInstanceData[idx].m_LODTransition;
                m_MtxLODTranzFull_2[m_MtxLODTempCount[currentLODLevel]]   = lodInstanceData[idx].m_LODFullFade;
            }
            else if (currentLODLevel == 3)
            {
                m_MtxLODTemp_3[m_MtxLODTempCount[currentLODLevel]].m00 = treeInstances[idx].m_PositionMtx.m00;
                m_MtxLODTemp_3[m_MtxLODTempCount[currentLODLevel]].m01 = treeInstances[idx].m_PositionMtx.m01;
                m_MtxLODTemp_3[m_MtxLODTempCount[currentLODLevel]].m02 = treeInstances[idx].m_PositionMtx.m02;
                m_MtxLODTemp_3[m_MtxLODTempCount[currentLODLevel]].m03 = treeInstances[idx].m_PositionMtx.m03;
                m_MtxLODTemp_3[m_MtxLODTempCount[currentLODLevel]].m10 = treeInstances[idx].m_PositionMtx.m10;
                m_MtxLODTemp_3[m_MtxLODTempCount[currentLODLevel]].m11 = treeInstances[idx].m_PositionMtx.m11;
                m_MtxLODTemp_3[m_MtxLODTempCount[currentLODLevel]].m12 = treeInstances[idx].m_PositionMtx.m12;
                m_MtxLODTemp_3[m_MtxLODTempCount[currentLODLevel]].m13 = treeInstances[idx].m_PositionMtx.m13;
                m_MtxLODTemp_3[m_MtxLODTempCount[currentLODLevel]].m20 = treeInstances[idx].m_PositionMtx.m20;
                m_MtxLODTemp_3[m_MtxLODTempCount[currentLODLevel]].m21 = treeInstances[idx].m_PositionMtx.m21;
                m_MtxLODTemp_3[m_MtxLODTempCount[currentLODLevel]].m22 = treeInstances[idx].m_PositionMtx.m22;
                m_MtxLODTemp_3[m_MtxLODTempCount[currentLODLevel]].m23 = treeInstances[idx].m_PositionMtx.m23;

                m_MtxLODTranzDetail_3[m_MtxLODTempCount[currentLODLevel]] = lodInstanceData[idx].m_LODTransition;
                m_MtxLODTranzFull_3[m_MtxLODTempCount[currentLODLevel]]   = lodInstanceData[idx].m_LODFullFade;
            }
            else if (currentLODLevel == 4)
            {
                m_MtxLODTemp_4[m_MtxLODTempCount[currentLODLevel]].m00 = treeInstances[idx].m_PositionMtx.m00;
                m_MtxLODTemp_4[m_MtxLODTempCount[currentLODLevel]].m01 = treeInstances[idx].m_PositionMtx.m01;
                m_MtxLODTemp_4[m_MtxLODTempCount[currentLODLevel]].m02 = treeInstances[idx].m_PositionMtx.m02;
                m_MtxLODTemp_4[m_MtxLODTempCount[currentLODLevel]].m03 = treeInstances[idx].m_PositionMtx.m03;
                m_MtxLODTemp_4[m_MtxLODTempCount[currentLODLevel]].m10 = treeInstances[idx].m_PositionMtx.m10;
                m_MtxLODTemp_4[m_MtxLODTempCount[currentLODLevel]].m11 = treeInstances[idx].m_PositionMtx.m11;
                m_MtxLODTemp_4[m_MtxLODTempCount[currentLODLevel]].m12 = treeInstances[idx].m_PositionMtx.m12;
                m_MtxLODTemp_4[m_MtxLODTempCount[currentLODLevel]].m13 = treeInstances[idx].m_PositionMtx.m13;
                m_MtxLODTemp_4[m_MtxLODTempCount[currentLODLevel]].m20 = treeInstances[idx].m_PositionMtx.m20;
                m_MtxLODTemp_4[m_MtxLODTempCount[currentLODLevel]].m21 = treeInstances[idx].m_PositionMtx.m21;
                m_MtxLODTemp_4[m_MtxLODTempCount[currentLODLevel]].m22 = treeInstances[idx].m_PositionMtx.m22;
                m_MtxLODTemp_4[m_MtxLODTempCount[currentLODLevel]].m23 = treeInstances[idx].m_PositionMtx.m23;

                m_MtxLODTranzDetail_4[m_MtxLODTempCount[currentLODLevel]] = lodInstanceData[idx].m_LODTransition;
                m_MtxLODTranzFull_4[m_MtxLODTempCount[currentLODLevel]]   = lodInstanceData[idx].m_LODFullFade;
            }

            m_MtxLODTempCount[currentLODLevel]++;
        }

        // Now that the data is built, issue it
        for (int i = 0; i <= maxLod3D; i++)
        {
            if (i == 0)
            {
                Draw3DLODInstanced(ref lodData[i], ref m_MtxLODTemp_0, ref m_MtxLODTranzDetail_0, ref m_MtxLODTranzFull_0, ref m_MtxLODTempCount[i], ref shadowsOnly);
            }
            else if (i == 1)
            {
                Draw3DLODInstanced(ref lodData[i], ref m_MtxLODTemp_1, ref m_MtxLODTranzDetail_1, ref m_MtxLODTranzFull_1, ref m_MtxLODTempCount[i], ref shadowsOnly);
            }
            else if (i == 2)
            {
                Draw3DLODInstanced(ref lodData[i], ref m_MtxLODTemp_2, ref m_MtxLODTranzDetail_2, ref m_MtxLODTranzFull_2, ref m_MtxLODTempCount[i], ref shadowsOnly);
            }
            else if (i == 3)
            {
                Draw3DLODInstanced(ref lodData[i], ref m_MtxLODTemp_3, ref m_MtxLODTranzDetail_3, ref m_MtxLODTranzFull_3, ref m_MtxLODTempCount[i], ref shadowsOnly);
            }
            else if (i == 4)
            {
                Draw3DLODInstanced(ref lodData[i], ref m_MtxLODTemp_4, ref m_MtxLODTranzDetail_4, ref m_MtxLODTranzFull_4, ref m_MtxLODTempCount[i], ref shadowsOnly);
            }
        }
    }
Esempio n. 6
0
    private void ProcessTerrainCell(TreeSystemStructuredTrees cell, ref float treeDistSqr, ref float shadowDistSqr)
    {
        // Draw all trees instanced in MAX_BATCH chunks
        int   tempIndexTree = 0;
        int   tempIndexShadow = 0;
        float x, y, z;

        // If we are completely inside frustum we don't need to AABB test each tree
        bool insideFrustum = TUtils.IsCompletelyInsideFrustum(m_PlanesTemp, TUtils.BoundsCorners(ref cell.m_BoundsBox, ref m_TempCorners));

        // If it is completely inside the frustum notify us
        if (insideFrustum)
        {
            m_DataIssuedTerrainCellsFull++;
        }

        // Tree instances
        TreeSystemStoredInstance[] treeInstances = cell.m_Instances;

        // TODO: Hm... if we take that hash it doesn't mean that it's the first visible one...
        int treeHash        = treeInstances[0].m_TreeHash;
        int currentTreeHash = treeHash;

        int shadowHash        = treeHash;
        int currentShadowHash = shadowHash;

        for (int treeIndex = 0; treeIndex < treeInstances.Length; treeIndex++)
        {
            // This is an order of magnitude faster than (treeInstances[treeIndex].m_WorldPosition - pos).sqrMagnitude
            // since it does not initiate with a ctor an extra vector during the computation
            x = treeInstances[treeIndex].m_WorldPosition.x - m_CameraPosTemp.x;
            y = treeInstances[treeIndex].m_WorldPosition.y - m_CameraPosTemp.y;
            z = treeInstances[treeIndex].m_WorldPosition.z - m_CameraPosTemp.z;

            float distToTree = x * x + y * y + z * z;

            if (insideFrustum)
            {
                // If we are completely inside the frustum we don't need to check each individual tree's bounds
                if (distToTree <= treeDistSqr)
                {
                    currentTreeHash = treeInstances[treeIndex].m_TreeHash;

                    if (tempIndexTree >= MAX_BATCH || treeHash != currentTreeHash)
                    {
                        // We're sure that they will not be shadows only
                        IssueDrawTrees(m_ManagedPrototypesIndexed[treeHash], cell, m_IdxTempMesh, m_DstTempMesh, tempIndexTree, false);
                        tempIndexTree = 0;

                        // Update the hash
                        treeHash = currentTreeHash;
                    }

                    m_IdxTempMesh[tempIndexTree] = treeIndex;
                    m_DstTempMesh[tempIndexTree] = Mathf.Sqrt(distToTree);
                    tempIndexTree++;

                    m_DataIssuedMeshTrees++;
                }
            }
            else
            {
                // TODO: In the future instead of 'GeometryUtility.TestPlanesAABB' have our own function that
                // checks if the object is within the shadow volume, that is if it casts shadow inside our frustum
                // Just generate our own set of planes that we'll use...

                // If we are not completely inside the frustum we need to check the bounds of each individual tree
                if (distToTree <= treeDistSqr && GeometryUtility.TestPlanesAABB(m_PlanesTemp, treeInstances[treeIndex].m_WorldBounds))
                {
                    currentTreeHash = treeInstances[treeIndex].m_TreeHash;

                    if (tempIndexTree >= MAX_BATCH || treeHash != currentTreeHash)
                    {
                        IssueDrawTrees(m_ManagedPrototypesIndexed[treeHash], cell, m_IdxTempMesh, m_DstTempMesh, tempIndexTree, false);
                        tempIndexTree = 0;

                        // Update the hash
                        treeHash = currentTreeHash;
                    }

                    m_IdxTempMesh[tempIndexTree] = treeIndex;
                    m_DstTempMesh[tempIndexTree] = Mathf.Sqrt(distToTree);
                    tempIndexTree++;

                    m_DataIssuedMeshTrees++;
                }
                // Same operation as above but with different matrices
                else if (m_Settings.m_ApplyShadowPoppingCorrection && distToTree < shadowDistSqr)
                {
                    // Even if we are invisible but within the shadow sitance still cast shadows...
                    // (not the most efficient method though, waiting for the complete one)

                    currentShadowHash = treeInstances[treeIndex].m_TreeHash;

                    if (tempIndexShadow >= MAX_BATCH || shadowHash != currentShadowHash)
                    {
                        IssueDrawTrees(m_ManagedPrototypesIndexed[shadowHash], cell, m_IdxTempShadow, m_DstTempShadow, tempIndexShadow, true);
                        tempIndexShadow = 0;

                        // Update the shadow hash
                        shadowHash = currentShadowHash;
                    }

                    m_IdxTempShadow[tempIndexShadow] = treeIndex;
                    m_DstTempShadow[tempIndexShadow] = Mathf.Sqrt(distToTree);
                    tempIndexShadow++;

                    m_DataIssuedShadows++;
                }
            }
        } // End cell tree iteration

        if (tempIndexTree > 0)
        {
            // Get a tree hash from the first element of the array so that we know for sure that we use the correct prototype data
            IssueDrawTrees(m_ManagedPrototypesIndexed[treeInstances[m_IdxTempMesh[0]].m_TreeHash], cell,
                           m_IdxTempMesh, m_DstTempMesh, tempIndexTree, false);

            tempIndexTree = 0;
        }

        if (tempIndexShadow > 0)
        {
            IssueDrawTrees(m_ManagedPrototypesIndexed[treeInstances[m_IdxTempShadow[0]].m_TreeHash], cell,
                           m_IdxTempShadow, m_DstTempShadow, tempIndexShadow, true);

            tempIndexShadow = 0;
        }
    }
Esempio n. 7
0
    private void ProcessTerrain(TreeSystemTerrain terrain, ref float treeDistSqr, ref float shadowDistSqr)
    {
        // Get only the visible cells around the player
        int     cellsCount   = terrain.m_CellCount;
        Vector3 terrainLocal = terrain.m_ManagedTerrainWorldToLocal.MultiplyPoint3x4(m_CameraPosTemp);
        Vector3 terrSize     = terrain.m_ManagedTerrainSizes;

        RowCol gridPos;

        GetTerrainGridIndex(out gridPos, terrainLocal, cellsCount, terrSize);

        // Get neighbors
        GetNeightbors(m_TempNeighbors, gridPos.m_Row, gridPos.m_Col, terrain.m_CellsStructured, ref cellsCount);

        if (m_TempNeighbors.Count <= 0)
        {
            return;
        }

        CullingGroup culling      = terrain.m_CullingGroup;
        bool         useOcclusion = m_Settings.m_UseOcclusion;

        // float x, y, z;

        // TODO: calculate based on bounds index the cells that we'll iterate like the grass system
        // We won't require to iterate all the cells but the neighbors of the current cell only

        // TODO: only get the data from the culling group API at the moment

        // Go bounds by bounds
        for (int cellIdx = 0; cellIdx < m_TempNeighbors.Count; cellIdx++)
        {
            TreeSystemStructuredTrees cell = m_TempNeighbors[cellIdx];

            // If we don't have any tree skip this cell
            if (cell.m_Instances.Length <= 0)
            {
                continue;
            }

            // And also check if the bounds are visible
            if (useOcclusion && culling.IsVisible(cellIdx) == false)
            {
                continue;
            }

            // Get closest point to cell

            /*
             * Vector3 pt = cell.m_BoundsBox.ClosestPoint(m_CameraPosTemp);
             *
             * x = pt.x - m_CameraPosTemp.x;
             * y = pt.y - m_CameraPosTemp.y;
             * z = pt.z - m_CameraPosTemp.z;
             *
             * float distToCell = x * x + y * y + z * z;
             */

            float distToCell = cell.m_BoundsBox.SqrDistance(m_CameraPosTemp);

            if (distToCell < treeDistSqr && GeometryUtility.TestPlanesAABB(m_PlanesTemp, cell.m_BoundsBox))
            {
                // TODO: the same process when we are going to have terrain sub-cells
                ProcessTerrainCell(cell, ref treeDistSqr, ref shadowDistSqr);

                // If it's visible
                m_DataIssuedTerrainCells++;
            }
            // TODO: See for the case in which we are at the intersection of 4 cells and the cells are not visible to the frustum
            // BUT they have trees that 'might' cast shadows inside the frustum. Do that with a special thing that only checks the trees
            // for the shadow distance, and that's all
            // else if (m_ApplyShadowPoppingCorrection && distToCell < shadowDistSqr) { }
        }
    }
Esempio n. 8
0
    private void BuildTreeTypeCellMesh(GameObject owner, TreeSystemStructuredTrees cell, List <TreeSystemStoredInstance> trees, TreeSystemPrototypeData data)
    {
        int[] originalTriangles = m_SystemQuad.triangles;

        RowCol pos = cell.m_Position;

        GameObject mesh = new GameObject();

        // Mark object as static
        GameObjectUtility.SetStaticEditorFlags(mesh, StaticEditorFlags.OccludeeStatic | StaticEditorFlags.ReflectionProbeStatic);

        mesh.transform.SetParent(owner.transform);
        mesh.name = "MeshCell[" + pos.m_Row + "_" + pos.m_Col + "_" + data.m_TreePrototype.name + "]";

        Vector3 worldScale = new Vector3(data.m_Size.x, data.m_Size.y, data.m_Size.x);

        // Set material
        MeshRenderer rend = mesh.AddComponent <MeshRenderer>();

        rend.sharedMaterial = data.m_BillboardBatchMaterial;

        MeshFilter filter = mesh.AddComponent <MeshFilter>();

        Mesh treeMesh = new Mesh();

        treeMesh.name = "TreeCell[" + pos.m_Row + "_" + pos.m_Col + "_" + data.m_TreePrototype.name + "]";

        List <Vector4> m_TempWorldPositions = new List <Vector4>();
        List <Vector3> m_TempWorldScales    = new List <Vector3>();
        List <Vector3> m_TempQuadVertices   = new List <Vector3>();
        List <Vector4> m_TempQuadTangents   = new List <Vector4>();
        List <Vector3> m_TempQuadNormals    = new List <Vector3>();
        List <int>     m_TempQuadIndices    = new List <int>();

        Bounds newBounds = new Bounds();

        newBounds.center = cell.m_BoundsBox.center;

        // TODO: populate mesh data
        for (int treeIndex = 0; treeIndex < trees.Count; treeIndex++)
        {
            Vector3 position = trees[treeIndex].m_WorldPosition;
            Vector3 scale    = trees[treeIndex].m_WorldScale;
            float   rot      = trees[treeIndex].m_WorldRotation;

            // Offset world position, by the grounding factor
            Vector3 instancePos = position;
            instancePos.y += data.m_Size.z;

            // Scale by the world scale too so that we don't have to do an extra multip
            Vector3 instanceScale = scale;
            instanceScale.Scale(worldScale);

            // Encapsulate bottom and top also
            newBounds.Encapsulate(instancePos);
            newBounds.Encapsulate(instancePos + new Vector3(0, data.m_Size.y, 0));

            // Add the world and scale data
            for (int index = 0; index < 4; index++)
            {
                Vector4 posAndRot = instancePos;
                posAndRot.w = rot;

                m_TempWorldPositions.Add(posAndRot);
                m_TempWorldScales.Add(instanceScale);
            }

            // Add stanard quad data
            m_TempQuadVertices.AddRange(m_SystemQuad.vertices);
            m_TempQuadTangents.AddRange(m_SystemQuad.tangents);
            m_TempQuadNormals.AddRange(m_SystemQuad.normals);

            // Calculate triangle indixes
            m_TempQuadIndices.AddRange(originalTriangles);
            for (int triIndex = 0; triIndex < 6; triIndex++)
            {
                // Just add to the triangles the existing triangles + the new indices
                m_TempQuadIndices[triIndex + 6 * treeIndex] = originalTriangles[triIndex] + 4 * treeIndex;
            }
        }

        treeMesh.Clear();

        // Set standard data
        treeMesh.SetVertices(m_TempQuadVertices);
        treeMesh.SetNormals(m_TempQuadNormals);
        treeMesh.SetTangents(m_TempQuadTangents);

        // Set the custom data
        treeMesh.SetUVs(1, m_TempWorldPositions);
        treeMesh.SetUVs(2, m_TempWorldScales);

        // Set triangles and do not calculate bounds
        treeMesh.SetTriangles(m_TempQuadIndices, 0, false);

        // Set the manually calculated bounds
        treeMesh.bounds = newBounds;

        treeMesh.UploadMeshData(true);

        // Set the mesh
        filter.mesh = treeMesh;
    }
Esempio n. 9
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);
    }
Esempio n. 10
0
    private void IssueDrawTrees(TreeSystemPrototypeData data, TreeSystemStructuredTrees trees, int[] indices, float[] dist, int count, bool shadowsOnly)
    {
        for (int i = 0; i < MAX_LOD_COUNT; i++)
        {
            m_MtxLODTempCount[i] = 0;
        }

        TreeSystemLODData[] lodData = data.m_LODData;

        TreeSystemStoredInstance[] treeInstances   = trees.m_Instances;
        TreeSystemLODInstance[]    lodInstanceData = trees.m_InstanceData;

        int maxLod3D = data.m_MaxLod3DIndex;

        // Process LOD so that we know what to batch
        for (int i = 0; i < count; i++)
        {
            ProcessLOD(ref lodData, ref maxLod3D, ref lodInstanceData[indices[i]], ref dist[i]);
        }

        if (m_Settings.m_UseInstancing)
        {
            // Build the batched stuff. We want to batch the same LOD and draw them using instancing
            for (int i = 0; i < count; i++)
            {
                int idx             = indices[i];
                int currentLODLevel = lodInstanceData[idx].m_LODLevel;

                // Collect that LOD level
                if (currentLODLevel == 0)
                {
                    m_MtxLODTemp_0[m_MtxLODTempCount[currentLODLevel]]        = treeInstances[idx].m_PositionMtx;
                    m_MtxLODTranzDetail_0[m_MtxLODTempCount[currentLODLevel]] = lodInstanceData[idx].m_LODTransition;
                    m_MtxLODTranzFull_0[m_MtxLODTempCount[currentLODLevel]]   = lodInstanceData[idx].m_LODFullFade;
                }
                else if (currentLODLevel == 1)
                {
                    m_MtxLODTemp_1[m_MtxLODTempCount[currentLODLevel]]        = treeInstances[idx].m_PositionMtx;
                    m_MtxLODTranzDetail_1[m_MtxLODTempCount[currentLODLevel]] = lodInstanceData[idx].m_LODTransition;
                    m_MtxLODTranzFull_1[m_MtxLODTempCount[currentLODLevel]]   = lodInstanceData[idx].m_LODFullFade;
                }
                else if (currentLODLevel == 2)
                {
                    m_MtxLODTemp_2[m_MtxLODTempCount[currentLODLevel]]        = treeInstances[idx].m_PositionMtx;
                    m_MtxLODTranzDetail_2[m_MtxLODTempCount[currentLODLevel]] = lodInstanceData[idx].m_LODTransition;
                    m_MtxLODTranzFull_2[m_MtxLODTempCount[currentLODLevel]]   = lodInstanceData[idx].m_LODFullFade;
                }
                else if (currentLODLevel == 3)
                {
                    m_MtxLODTemp_3[m_MtxLODTempCount[currentLODLevel]]        = treeInstances[idx].m_PositionMtx;
                    m_MtxLODTranzDetail_3[m_MtxLODTempCount[currentLODLevel]] = lodInstanceData[idx].m_LODTransition;
                    m_MtxLODTranzFull_3[m_MtxLODTempCount[currentLODLevel]]   = lodInstanceData[idx].m_LODFullFade;
                }
                else if (currentLODLevel == 4)
                {
                    m_MtxLODTemp_4[m_MtxLODTempCount[currentLODLevel]]        = treeInstances[idx].m_PositionMtx;
                    m_MtxLODTranzDetail_4[m_MtxLODTempCount[currentLODLevel]] = lodInstanceData[idx].m_LODTransition;
                    m_MtxLODTranzFull_4[m_MtxLODTempCount[currentLODLevel]]   = lodInstanceData[idx].m_LODFullFade;
                }

                m_MtxLODTempCount[currentLODLevel]++;

                // We don't instantiate the trees that are in a transition since they should be an exception
                if (currentLODLevel == maxLod3D && lodInstanceData[idx].m_LODFullFade < 1)
                {
                    DrawBillboardLOD(ref lodData[currentLODLevel + 1], ref lodInstanceData[idx], ref treeInstances[idx]);
                }
            }

            // Now that the data is built, issue it
            for (int i = 0; i <= maxLod3D; i++)
            {
                if (i == 0)
                {
                    Draw3DLODInstanced(ref lodData[i], ref m_MtxLODTemp_0, ref m_MtxLODTranzDetail_0, ref m_MtxLODTranzFull_0, ref m_MtxLODTempCount[i], ref shadowsOnly);
                }
                else if (i == 1)
                {
                    Draw3DLODInstanced(ref lodData[i], ref m_MtxLODTemp_1, ref m_MtxLODTranzDetail_1, ref m_MtxLODTranzFull_1, ref m_MtxLODTempCount[i], ref shadowsOnly);
                }
                else if (i == 2)
                {
                    Draw3DLODInstanced(ref lodData[i], ref m_MtxLODTemp_2, ref m_MtxLODTranzDetail_2, ref m_MtxLODTranzFull_2, ref m_MtxLODTempCount[i], ref shadowsOnly);
                }
                else if (i == 3)
                {
                    Draw3DLODInstanced(ref lodData[i], ref m_MtxLODTemp_3, ref m_MtxLODTranzDetail_3, ref m_MtxLODTranzFull_3, ref m_MtxLODTempCount[i], ref shadowsOnly);
                }
                else if (i == 4)
                {
                    Draw3DLODInstanced(ref lodData[i], ref m_MtxLODTemp_4, ref m_MtxLODTranzDetail_4, ref m_MtxLODTranzFull_4, ref m_MtxLODTempCount[i], ref shadowsOnly);
                }
            }
        }
        else
        {
            // Draw the processed lod
            for (int i = 0; i < count; i++)
            {
                int idx = indices[i];
                DrawProcessedLOD(ref lodData, ref maxLod3D, ref lodInstanceData[idx], ref treeInstances[idx], ref shadowsOnly);
            }
        }
    }
Esempio n. 11
0
    // 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);
    }
Esempio n. 12
0
    private void ProcessTerrainCell(TreeSystemStructuredTrees cell, ref float treeDistSqr)
    {
        // Draw all trees instanced in MAX_BATCH chunks
        int   tempIndex = 0;
        float x, y, z;

        // If we are completely inside frustum we don't need to AABB test each tree
        bool insideFrustum = TUtils.IsCompletelyInsideFrustum(m_PlanesTemp, TUtils.BoundsCorners(ref cell.m_Bounds, ref m_TempCorners));

        // Tree instances
        TreeSystemStoredInstance[] treeInstances = cell.m_Instances;

        // TODO: Hm... if we take that hash it doesn't mean that it's the first visible one...
        int treeHash        = treeInstances[0].m_TreeHash;
        int currentTreeHash = treeHash;

        for (int treeIndex = 0; treeIndex < treeInstances.Length; treeIndex++)
        {
            // 1.33 ms for 110k trees
            // This is an order of magnitude faster than (treeInstances[treeIndex].m_WorldPosition - pos).sqrMagnitude
            // since it does not initiate with a ctor an extra vector during the computation
            x = treeInstances[treeIndex].m_WorldPosition.x - m_CameraPosTemp.x;
            y = treeInstances[treeIndex].m_WorldPosition.y - m_CameraPosTemp.y;
            z = treeInstances[treeIndex].m_WorldPosition.z - m_CameraPosTemp.z;

            float distToTree = x * x + y * y + z * z;

            // 17 ms for 110k trees
            // float distToTree = (treeInstances[treeIndex].m_WorldPosition - pos).sqrMagnitude;

            if (insideFrustum)
            {
                // If we are completely inside the frustum we don't need to check each individual tree's bounds
                if (distToTree <= treeDistSqr)
                {
                    currentTreeHash = treeInstances[treeIndex].m_TreeHash;

                    if (tempIndex >= MAX_BATCH || treeHash != currentTreeHash)
                    {
                        IssueDrawTrees(m_ManagedPrototypesIndexed[treeHash], cell, m_IdxTemp, m_DstTemp, tempIndex);
                        tempIndex = 0;

                        // Update the hash
                        treeHash = currentTreeHash;
                    }

                    m_IdxTemp[tempIndex] = treeIndex;
                    m_DstTemp[tempIndex] = Mathf.Sqrt(distToTree);
                    tempIndex++;

                    m_DataIssuedMeshTrees++;
                }
            }
            else
            {
                // If we are not completely inside the frustum we need to check the bounds of each individual tree
                if (distToTree <= treeDistSqr && GeometryUtility.TestPlanesAABB(m_PlanesTemp, treeInstances[treeIndex].m_WorldBounds))
                {
                    currentTreeHash = treeInstances[treeIndex].m_TreeHash;

                    if (tempIndex >= MAX_BATCH || treeHash != currentTreeHash)
                    {
                        IssueDrawTrees(m_ManagedPrototypesIndexed[treeHash], cell, m_IdxTemp, m_DstTemp, tempIndex);
                        tempIndex = 0;

                        // Update the hash
                        treeHash = currentTreeHash;
                    }

                    m_IdxTemp[tempIndex] = treeIndex;
                    m_DstTemp[tempIndex] = Mathf.Sqrt(distToTree);
                    tempIndex++;

                    m_DataIssuedMeshTrees++;
                }
            }
        } // End cell tree iteration

        if (tempIndex > 0)
        {
            // Get a tree hash from the first element of the array so that we know for sure that we use the correc prototype data
            IssueDrawTrees(m_ManagedPrototypesIndexed[treeInstances[m_IdxTemp[0]].m_TreeHash], cell,
                           m_IdxTemp, m_DstTemp, tempIndex);

            tempIndex = 0;
        }
    }