Skip to content

Commit cb2035e

Browse files
authored
Merge pull request #541 from CesiumGS/no-normals-problems
Fix loading problems for models without normals
2 parents 5ca9a02 + 7903039 commit cb2035e

File tree

4 files changed

+85
-21
lines changed

4 files changed

+85
-21
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
- Fixed a bug that could cause a crash on AppDomain reloads.
88
- Fixed a bug that could cause a crash or incorrect textures when multiple `Cesium3DTileset` tiles referenced the same image by URL.
9+
- Fixed a bug that could cause incorrect colors in a model that did have vertex colors but did not have normals.
10+
- 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.
911
- Fixed a bug in the Abseil vcpkg overlay port that could cause linker errors on some systems.
1012

1113
## v1.14.0 - 2024-12-02

Tests/TestCesium3DTileset.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,47 @@ public IEnumerator SampleHeightMostDetailedFailsIfTilesetFailsToLoad()
156156

157157
Assert.IsTrue(result.warnings[0].Contains("failed to load"));
158158
}
159+
160+
[UnityTest]
161+
public IEnumerator UpgradeToLargerIndexType()
162+
{
163+
// This tileset has no normals, so we need to generate flat normals for it.
164+
// When we do that, an index buffer will need to change from uint16 to uint32.
165+
GameObject goGeoreference = new GameObject();
166+
goGeoreference.name = "Georeference";
167+
CesiumGeoreference georeference = goGeoreference.AddComponent<CesiumGeoreference>();
168+
169+
GameObject goTileset = new GameObject();
170+
goTileset.name = "Snowdon Towers No Normals";
171+
goTileset.transform.parent = goGeoreference.transform;
172+
173+
Cesium3DTileset tileset = goTileset.AddComponent<Cesium3DTileset>();
174+
CesiumCameraManager cameraManager = goTileset.AddComponent<CesiumCameraManager>();
175+
tileset.ionAccessToken = Environment.GetEnvironmentVariable("CESIUM_ION_TOKEN_FOR_TESTS") ?? "";
176+
tileset.ionAssetID = 2887128;
177+
178+
georeference.SetOriginLongitudeLatitudeHeight(-79.88602625, 40.02228799, 222.65);
179+
180+
GameObject goCamera = new GameObject();
181+
goCamera.name = "Camera";
182+
goCamera.transform.parent = goGeoreference.transform;
183+
184+
Camera camera = goCamera.AddComponent<Camera>();
185+
CesiumGlobeAnchor cameraAnchor = goCamera.AddComponent<CesiumGlobeAnchor>();
186+
187+
cameraManager.useMainCamera = false;
188+
cameraManager.useSceneViewCameraInEditor = false;
189+
cameraManager.additionalCameras.Add(camera);
190+
191+
camera.pixelRect = new Rect(0, 0, 128, 96);
192+
camera.fieldOfView = 60.0f;
193+
cameraAnchor.longitudeLatitudeHeight = new double3(-79.88593359, 40.02255615, 242.0224);
194+
camera.transform.LookAt(new Vector3(0.0f, 0.0f, 0.0f));
195+
196+
// Make sure we can load all tiles successfully.
197+
while (tileset.ComputeLoadProgress() < 100.0f)
198+
{
199+
yield return null;
200+
}
201+
}
159202
}

native~/Runtime/src/UnityPrepareRendererResources.cpp

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,11 @@ template <typename TIndex> struct CopyVertexColors {
161161
bool success = true;
162162
if (duplicateVertices) {
163163
for (size_t i = 0; success && i < vertexCount; ++i) {
164-
if (i >= colorView.size()) {
164+
TIndex vertexIndex = indices[i];
165+
if (vertexIndex < 0 || vertexIndex >= colorView.size()) {
165166
success = false;
166167
} else {
167168
Color32& packedColor = *reinterpret_cast<Color32*>(pWritePos);
168-
TIndex vertexIndex = indices[i];
169169
success = CopyVertexColors::convertColor(
170170
colorView[vertexIndex],
171171
packedColor);
@@ -347,6 +347,43 @@ void loadPrimitive(
347347
return;
348348
}
349349

350+
const CesiumGltf::Material* pMaterial =
351+
Model::getSafe(&gltf.materials, primitive.material);
352+
353+
primitiveInfo.isUnlit =
354+
pMaterial && pMaterial->hasExtension<ExtensionKhrMaterialsUnlit>();
355+
356+
bool hasNormals = false;
357+
bool computeFlatNormals = false;
358+
auto normalAccessorIt = primitive.attributes.find("NORMAL");
359+
AccessorView<UnityEngine::Vector3> normalView;
360+
if (normalAccessorIt != primitive.attributes.end()) {
361+
normalView =
362+
AccessorView<UnityEngine::Vector3>(gltf, normalAccessorIt->second);
363+
hasNormals = normalView.status() == AccessorViewStatus::Valid;
364+
} else if (
365+
!primitiveInfo.isUnlit && primitive.mode != MeshPrimitive::Mode::POINTS) {
366+
computeFlatNormals = hasNormals = true;
367+
}
368+
369+
// Check if we need to upgrade to a large index type to accommodate the
370+
// larger number of vertices we need for flat normals.
371+
if (computeFlatNormals && indexFormat == IndexFormat::UInt16 &&
372+
indexCount >= std::numeric_limits<uint16_t>::max()) {
373+
loadPrimitive<uint32_t>(
374+
meshData,
375+
primitiveInfo,
376+
gltf,
377+
node,
378+
mesh,
379+
primitive,
380+
transform,
381+
indicesView,
382+
IndexFormat::UInt32,
383+
positionView);
384+
return;
385+
}
386+
350387
meshData.SetIndexBufferParams(indexCount, indexFormat);
351388
const Unity::Collections::NativeArray1<TIndex>& dest =
352389
meshData.GetIndexData<TIndex>();
@@ -399,25 +436,7 @@ void loadPrimitive(
399436
descriptor[numberOfAttributes].stream = streamIndex;
400437
++numberOfAttributes;
401438

402-
const CesiumGltf::Material* pMaterial =
403-
Model::getSafe(&gltf.materials, primitive.material);
404-
405-
primitiveInfo.isUnlit =
406-
pMaterial && pMaterial->hasExtension<ExtensionKhrMaterialsUnlit>();
407-
408439
// Add the NORMAL attribute, if it exists.
409-
bool hasNormals = false;
410-
bool computeFlatNormals = false;
411-
auto normalAccessorIt = primitive.attributes.find("NORMAL");
412-
AccessorView<UnityEngine::Vector3> normalView;
413-
if (normalAccessorIt != primitive.attributes.end()) {
414-
normalView =
415-
AccessorView<UnityEngine::Vector3>(gltf, normalAccessorIt->second);
416-
hasNormals = normalView.status() == AccessorViewStatus::Valid;
417-
} else if (
418-
!primitiveInfo.isUnlit && primitive.mode != MeshPrimitive::Mode::POINTS) {
419-
computeFlatNormals = hasNormals = true;
420-
}
421440
if (hasNormals) {
422441
assert(numberOfAttributes < MAX_ATTRIBUTES);
423442
descriptor[numberOfAttributes].attribute = VertexAttribute::Normal;

native~/extern/cesium-native

Submodule cesium-native updated 387 files

0 commit comments

Comments
 (0)