From 966a5e966260f3468d56acd503171a9908a7e654 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Mon, 23 Dec 2024 17:45:21 +1100 Subject: [PATCH] Upgrade to UINT32 indices when necessary. --- CHANGES.md | 2 + Tests/TestCesium3DTileset.cs | 43 +++++++++++++++ .../src/UnityPrepareRendererResources.cpp | 55 +++++++++++++------ native~/extern/cesium-native | 2 +- 4 files changed, 83 insertions(+), 19 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 51d33e96..8d2ca5b0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,8 @@ ##### Fixes :wrench: - Fixed a bug that could cause a crash or incorrect textures when multiple `Cesium3DTileset` tiles referenced the same image by URL. +- Fixed a bug that could cause incorrect colors in a model that did have vertex colors but did not have normals. +- Fixed a bug that could cause a hang when attempting to load a model with UINT16 indices where generating flat normals required more than 2^16 vertices. ## v1.14.0 - 2024-12-02 diff --git a/Tests/TestCesium3DTileset.cs b/Tests/TestCesium3DTileset.cs index 3a174a4c..df440ab7 100644 --- a/Tests/TestCesium3DTileset.cs +++ b/Tests/TestCesium3DTileset.cs @@ -156,4 +156,47 @@ public IEnumerator SampleHeightMostDetailedFailsIfTilesetFailsToLoad() Assert.IsTrue(result.warnings[0].Contains("failed to load")); } + + [UnityTest] + public IEnumerator UpgradeToLargerIndexType() + { + // This tileset has no normals, so we need to generate flat normals for it. + // When we do that, an index buffer will need to change from uint16 to uint32. + GameObject goGeoreference = new GameObject(); + goGeoreference.name = "Georeference"; + CesiumGeoreference georeference = goGeoreference.AddComponent(); + + GameObject goTileset = new GameObject(); + goTileset.name = "Snowdon Towers No Normals"; + goTileset.transform.parent = goGeoreference.transform; + + Cesium3DTileset tileset = goTileset.AddComponent(); + CesiumCameraManager cameraManager = goTileset.AddComponent(); + tileset.ionAccessToken = Environment.GetEnvironmentVariable("CESIUM_ION_TOKEN_FOR_TESTS") ?? ""; + tileset.ionAssetID = 2887128; + + georeference.SetOriginLongitudeLatitudeHeight(-79.88602625, 40.02228799, 222.65); + + GameObject goCamera = new GameObject(); + goCamera.name = "Camera"; + goCamera.transform.parent = goGeoreference.transform; + + Camera camera = goCamera.AddComponent(); + CesiumGlobeAnchor cameraAnchor = goCamera.AddComponent(); + + cameraManager.useMainCamera = false; + cameraManager.useSceneViewCameraInEditor = false; + cameraManager.additionalCameras.Add(camera); + + camera.pixelRect = new Rect(0, 0, 128, 96); + camera.fieldOfView = 60.0f; + cameraAnchor.longitudeLatitudeHeight = new double3(-79.88593359, 40.02255615, 242.0224); + camera.transform.LookAt(new Vector3(0.0f, 0.0f, 0.0f)); + + // Make sure we can load all tiles successfully. + while (tileset.ComputeLoadProgress() < 100.0f) + { + yield return null; + } + } } \ No newline at end of file diff --git a/native~/Runtime/src/UnityPrepareRendererResources.cpp b/native~/Runtime/src/UnityPrepareRendererResources.cpp index 51adfccb..141c921c 100644 --- a/native~/Runtime/src/UnityPrepareRendererResources.cpp +++ b/native~/Runtime/src/UnityPrepareRendererResources.cpp @@ -347,6 +347,43 @@ void loadPrimitive( return; } + const CesiumGltf::Material* pMaterial = + Model::getSafe(&gltf.materials, primitive.material); + + primitiveInfo.isUnlit = + pMaterial && pMaterial->hasExtension(); + + bool hasNormals = false; + bool computeFlatNormals = false; + auto normalAccessorIt = primitive.attributes.find("NORMAL"); + AccessorView normalView; + if (normalAccessorIt != primitive.attributes.end()) { + normalView = + AccessorView(gltf, normalAccessorIt->second); + hasNormals = normalView.status() == AccessorViewStatus::Valid; + } else if ( + !primitiveInfo.isUnlit && primitive.mode != MeshPrimitive::Mode::POINTS) { + computeFlatNormals = hasNormals = true; + } + + // Check if we need to upgrade to a large index type to accommodate the + // larger number of vertices we need for flat normals. + if (computeFlatNormals && indexFormat == IndexFormat::UInt16 && + indexCount >= std::numeric_limits::max()) { + loadPrimitive( + meshData, + primitiveInfo, + gltf, + node, + mesh, + primitive, + transform, + indicesView, + IndexFormat::UInt32, + positionView); + return; + } + meshData.SetIndexBufferParams(indexCount, indexFormat); const Unity::Collections::NativeArray1& dest = meshData.GetIndexData(); @@ -399,25 +436,7 @@ void loadPrimitive( descriptor[numberOfAttributes].stream = streamIndex; ++numberOfAttributes; - const CesiumGltf::Material* pMaterial = - Model::getSafe(&gltf.materials, primitive.material); - - primitiveInfo.isUnlit = - pMaterial && pMaterial->hasExtension(); - // Add the NORMAL attribute, if it exists. - bool hasNormals = false; - bool computeFlatNormals = false; - auto normalAccessorIt = primitive.attributes.find("NORMAL"); - AccessorView normalView; - if (normalAccessorIt != primitive.attributes.end()) { - normalView = - AccessorView(gltf, normalAccessorIt->second); - hasNormals = normalView.status() == AccessorViewStatus::Valid; - } else if ( - !primitiveInfo.isUnlit && primitive.mode != MeshPrimitive::Mode::POINTS) { - computeFlatNormals = hasNormals = true; - } if (hasNormals) { assert(numberOfAttributes < MAX_ATTRIBUTES); descriptor[numberOfAttributes].attribute = VertexAttribute::Normal; diff --git a/native~/extern/cesium-native b/native~/extern/cesium-native index 1ece56de..bf99d52e 160000 --- a/native~/extern/cesium-native +++ b/native~/extern/cesium-native @@ -1 +1 @@ -Subproject commit 1ece56deca0cb068e720ae67ae716fe80ec231ac +Subproject commit bf99d52e650469b29fca9674c40524fb6c06adba