Example #1
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;
        }
    }
Example #2
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;
        }
    }