| 1831 | } |
| 1832 | |
| 1833 | void SceneBuilder::createMeshGroups() |
| 1834 | { |
| 1835 | FALCOR_ASSERT(mMeshGroups.empty()); |
| 1836 | |
| 1837 | // This function sorts meshes into groups based on their properties. |
| 1838 | // The scene will build one BLAS per mesh group for raytracing. |
| 1839 | // Note that a BLAS may be referenced by multiple TLAS instances. |
| 1840 | // |
| 1841 | // The sorting criteria are: |
| 1842 | // - Non-instanced static meshes are all placed in the same group (BLAS). |
| 1843 | // The vertices are pre-transformed in the BLAS and the TLAS instance has an identity transform. |
| 1844 | // This ensures fast traversal for the static parts of a scene independent of the scene hierarchy. |
| 1845 | // - Non-instanced dynamic meshes (skinned and/or animated) are sorted into groups (BLASes) with the same transform. |
| 1846 | // The idea is that all parts of a dynamic object that move together go in the same BLAS and the TLAS instance applies the transform. |
| 1847 | // - Instanced meshes are sorted into groups (BLASes) with identical instances. |
| 1848 | // The idea is that all parts of an instanced object go in the same BLAS and the TLAS instances apply the transforms. |
| 1849 | // Note that dynamic (skinned) meshes currently cannot be instanced due to limitations in the scene structures. See #1118. |
| 1850 | // TODO: Add build flag to turn off pre-transformation to world space. |
| 1851 | |
| 1852 | // Classify non-instanced meshes. |
| 1853 | // The non-instanced dynamic meshes are grouped based on what global matrix ID their transform is. |
| 1854 | // The non-instanced static meshes are placed in the same group. |
| 1855 | |
| 1856 | using meshList = std::vector<MeshID>; |
| 1857 | std::unordered_map<NodeID, meshList> nodeToMeshList; |
| 1858 | meshList staticMeshes; |
| 1859 | meshList staticDisplacedMeshes; |
| 1860 | meshList dynamicDisplacedMeshes; |
| 1861 | size_t nonInstancedMeshCount = 0; |
| 1862 | |
| 1863 | for (MeshID meshID{ 0 }; meshID.get() < (uint32_t)mMeshes.size(); ++meshID) |
| 1864 | { |
| 1865 | auto& mesh = mMeshes[meshID.get()]; |
| 1866 | if (mesh.instances.size() > 1) continue; // Only processing non-instanced meshes here |
| 1867 | |
| 1868 | FALCOR_ASSERT(mesh.instances.size() == 1); |
| 1869 | NodeID nodeID = *mesh.instances.begin(); |
| 1870 | |
| 1871 | // Mark displaced meshes. |
| 1872 | const auto& pMaterial = mSceneData.pMaterials->getMaterial(mesh.materialId); |
| 1873 | if (pMaterial->isDisplaced()) mesh.isDisplaced = true; |
| 1874 | |
| 1875 | if (mesh.isStatic && mesh.isDisplaced) staticDisplacedMeshes.push_back(meshID); |
| 1876 | else if (mesh.isStatic) staticMeshes.push_back(meshID); |
| 1877 | else if (!mesh.isStatic && mesh.isDisplaced) dynamicDisplacedMeshes.push_back(meshID); |
| 1878 | else nodeToMeshList[nodeID].push_back(meshID); |
| 1879 | nonInstancedMeshCount++; |
| 1880 | } |
| 1881 | |
| 1882 | // Validate that mesh counts add up. |
| 1883 | size_t nonInstancedDynamicMeshCount = 0; |
| 1884 | for (const auto& it : nodeToMeshList) nonInstancedDynamicMeshCount += it.second.size(); |
| 1885 | FALCOR_ASSERT(staticMeshes.size() + staticDisplacedMeshes.size() + dynamicDisplacedMeshes.size() + nonInstancedDynamicMeshCount == nonInstancedMeshCount); |
| 1886 | |
| 1887 | // Classify instanced meshes. |
| 1888 | // The instanced meshes are grouped based on their lists of instances. |
| 1889 | // Meshes with an identical set of instances can be placed together in a BLAS. |
| 1890 | std::map<std::set<NodeID>, meshList> instancesToMeshList; |
nothing calls this directly
no test coverage detected