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