5
5
#include " CesiumCommon.h"
6
6
#include " CesiumEncodedMetadataUtility.h"
7
7
#include " CesiumFeatureIdSet.h"
8
+ #include " CesiumGltfLinesComponent.h"
8
9
#include " CesiumGltfPointsComponent.h"
9
10
#include " CesiumGltfPrimitiveComponent.h"
10
11
#include " CesiumGltfTextures.h"
@@ -682,14 +683,21 @@ static void setUnlitNormals(
682
683
glm::dvec4 (
683
684
VecMath::createVector3D (FVector (positionBuffer.VertexPosition (i))),
684
685
1.0 ));
685
- glm::dvec3 normal = ellipsoid.geodeticSurfaceNormal (positionFixed);
686
+
687
+ glm::dvec3 surfaceNormal = ellipsoid.geodeticSurfaceNormal (positionFixed);
688
+
689
+ if (surfaceNormal == glm::dvec3 (0.0 )) {
690
+ // This can happen for tilesets georeferenced at the center of the earth,
691
+ // resulting in NaN normals. Manually assign a normal aligned with Z-up.
692
+ surfaceNormal = glm::dvec3 (0.0 , 0.0 , 1.0 );
693
+ }
686
694
687
695
normalBuffer.SetVertexTangents (
688
696
i,
689
697
FVector3f (0 .0f ),
690
698
FVector3f (0.0 ),
691
- FVector3f (VecMath::createVector (
692
- glm::normalize ( ellipsoidFixedToVertex * glm::dvec4 (normal , 0.0 )))));
699
+ FVector3f (VecMath::createVector (glm::normalize (
700
+ ellipsoidFixedToVertex * glm::dvec4 (surfaceNormal , 0.0 )))));
693
701
}
694
702
}
695
703
@@ -1259,36 +1267,6 @@ std::string getPrimitiveName(
1259
1267
return name;
1260
1268
}
1261
1269
1262
- // / Helper used to log only once per unsupported primitive mode.
1263
- struct PrimitiveModeLogger {
1264
- std::array<
1265
- std::atomic_bool,
1266
- (size_t )CesiumGltf::MeshPrimitive::Mode::TRIANGLE_FAN + 1 >
1267
- alreadyLogged;
1268
-
1269
- PrimitiveModeLogger ()
1270
- : alreadyLogged{
1271
- {{false }, {false }, {false }, {false }, {false }, {false }, {false }}} {}
1272
-
1273
- inline void OnUnsupportedMode (int32_t primMode) {
1274
- bool bPrintLog = false ;
1275
- if (primMode < 0 || primMode >= (int32_t )alreadyLogged.size ()) {
1276
- ensureMsgf (false , TEXT (" Unknown primitive mode %d!" ), primMode);
1277
- bPrintLog = true ;
1278
- } else if (!alreadyLogged[(size_t )primMode].exchange (true )) {
1279
- bPrintLog = true ;
1280
- }
1281
- if (bPrintLog) {
1282
- UE_LOG (
1283
- LogCesium,
1284
- Warning,
1285
- TEXT (" Primitive mode %d is not supported" ),
1286
- primMode);
1287
- }
1288
- }
1289
- };
1290
- static PrimitiveModeLogger UnsupportedPrimitiveLogger;
1291
-
1292
1270
template <class TIndexAccessor >
1293
1271
TArray<uint32>
1294
1272
getIndices (const TIndexAccessor& indicesView, int32 primitiveMode) {
@@ -1315,9 +1293,8 @@ getIndices(const TIndexAccessor& indicesView, int32 primitiveMode) {
1315
1293
}
1316
1294
break ;
1317
1295
case CesiumGltf::MeshPrimitive::Mode::TRIANGLE_FAN:
1318
- // The TRIANGLE_FAN primitive mode cannot be enabled without creating a
1319
- // custom render proxy, so the geometry must be emulated through separate
1320
- // triangles.
1296
+ // The TRIANGLE_FAN primitive mode is not supported in Unreal, so geometry
1297
+ // must be emulated through separate triangles.
1321
1298
indices.SetNum (
1322
1299
static_cast <TArray<uint32>::SizeType>(3 * (indicesView.size () - 2 )));
1323
1300
for (int32 i = 2 , j = 0 ; i < indicesView.size (); ++i, j += 3 ) {
@@ -1326,7 +1303,31 @@ getIndices(const TIndexAccessor& indicesView, int32 primitiveMode) {
1326
1303
indices[j + 2 ] = indicesView[i];
1327
1304
}
1328
1305
break ;
1306
+ case CesiumGltf::MeshPrimitive::Mode::LINE_LOOP:
1307
+ // The LINE_LOOP primitive mode is not supported in Unreal, so geometry must
1308
+ // be emulated through separate lines.
1309
+ indices.SetNum (
1310
+ static_cast <TArray<uint32>::SizeType>(2 * indicesView.size ()));
1311
+ for (int32 i = 0 , j = 0 ; i < indicesView.size (); ++i, j += 2 ) {
1312
+ // Loop to the first index once we reach the last line segment.
1313
+ size_t nextIndex = (i < indicesView.size () - 1 ) ? i + 1 : 0 ;
1314
+
1315
+ indices[j] = indicesView[i];
1316
+ indices[j + 1 ] = indicesView[nextIndex];
1317
+ }
1318
+ break ;
1319
+ case CesiumGltf::MeshPrimitive::Mode::LINE_STRIP:
1320
+ // The LINE_STRIP primitive mode is not supported in Unreal, so geometry
1321
+ // must be emulated through separate lines.
1322
+ indices.SetNum (
1323
+ static_cast <TArray<uint32>::SizeType>(2 * (indicesView.size () - 1 )));
1324
+ for (int32 i = 0 , j = 0 ; i < indicesView.size () - 1 ; ++i, j += 2 ) {
1325
+ indices[j] = indicesView[i];
1326
+ indices[j + 1 ] = indicesView[i + 1 ];
1327
+ }
1328
+ break ;
1329
1329
case CesiumGltf::MeshPrimitive::Mode::TRIANGLES:
1330
+ case CesiumGltf::MeshPrimitive::Mode::LINES:
1330
1331
case CesiumGltf::MeshPrimitive::Mode::POINTS:
1331
1332
default :
1332
1333
indices.SetNum (static_cast <TArray<uint32>::SizeType>(indicesView.size ()));
@@ -1358,18 +1359,6 @@ static void loadPrimitive(
1358
1359
CesiumGltf::MeshPrimitive& primitive =
1359
1360
mesh.primitives [options.primitiveIndex ];
1360
1361
1361
- switch (primitive.mode ) {
1362
- case CesiumGltf::MeshPrimitive::Mode::POINTS:
1363
- case CesiumGltf::MeshPrimitive::Mode::TRIANGLES:
1364
- case CesiumGltf::MeshPrimitive::Mode::TRIANGLE_STRIP:
1365
- case CesiumGltf::MeshPrimitive::Mode::TRIANGLE_FAN:
1366
- break ;
1367
- default :
1368
- // TODO: add support for other primitive types.
1369
- UnsupportedPrimitiveLogger.OnUnsupportedMode (primitive.mode );
1370
- return ;
1371
- }
1372
-
1373
1362
const std::string name = getPrimitiveName (model, mesh, primitive);
1374
1363
primitiveResult.name = name;
1375
1364
@@ -1426,14 +1415,14 @@ static void loadPrimitive(
1426
1415
!options.pMeshOptions ->pNodeOptions ->pModelOptions
1427
1416
->ignoreKhrMaterialsUnlit ;
1428
1417
1429
- // We can't calculate flat normals for points or lines, so we have to force
1430
- // them to be unlit if no normals are specified. Otherwise this causes a
1431
- // crash when attempting to calculate flat normals.
1432
1418
bool isTriangles =
1433
1419
primitive.mode == CesiumGltf::MeshPrimitive::Mode::TRIANGLES ||
1434
1420
primitive.mode == CesiumGltf::MeshPrimitive::Mode::TRIANGLE_FAN ||
1435
1421
primitive.mode == CesiumGltf::MeshPrimitive::Mode::TRIANGLE_STRIP;
1436
1422
1423
+ // We can't calculate flat normals for points or lines, so we have to force
1424
+ // them to be unlit if no normals are specified. Otherwise this causes a
1425
+ // crash when attempting to calculate flat normals.
1437
1426
if (!isTriangles && !hasNormals) {
1438
1427
primitiveResult.isUnlit = true ;
1439
1428
}
@@ -1536,12 +1525,23 @@ static void loadPrimitive(
1536
1525
// vertices shared by multiple triangles. If we don't have tangents, but
1537
1526
// need them, we need to use a tangent space generation algorithm which
1538
1527
// requires duplicated vertices.
1539
- bool normalsAreRequired = !primitiveResult.isUnlit ;
1528
+ bool normalsAreRequired = !primitiveResult.isUnlit && isTriangles ;
1540
1529
bool needToGenerateFlatNormals = normalsAreRequired && !hasNormals;
1541
1530
bool needToGenerateTangents = needsTangents && !hasTangents;
1542
1531
bool duplicateVertices = needToGenerateFlatNormals || needToGenerateTangents;
1543
- duplicateVertices = duplicateVertices &&
1544
- primitive.mode != CesiumGltf::MeshPrimitive::Mode::POINTS;
1532
+
1533
+ // Some primitive modes may require duplication of vertices anyways due to
1534
+ // the lack of support in Unreal.
1535
+ switch (primitive.mode ) {
1536
+ case CesiumGltf::MeshPrimitive::Mode::LINE_LOOP:
1537
+ case CesiumGltf::MeshPrimitive::Mode::LINE_STRIP:
1538
+ case CesiumGltf::MeshPrimitive::Mode::TRIANGLE_FAN:
1539
+ case CesiumGltf::MeshPrimitive::Mode::TRIANGLE_STRIP:
1540
+ duplicateVertices = true ;
1541
+ break ;
1542
+ default :
1543
+ break ;
1544
+ }
1545
1545
1546
1546
uint32 numVertices =
1547
1547
duplicateVertices ? uint32 (indices.Num ()) : uint32 (positionView.size ());
@@ -1707,16 +1707,14 @@ static void loadPrimitive(
1707
1707
FVector3f (normal.X , -normal.Y , normal.Z ));
1708
1708
}
1709
1709
}
1710
+ } else if (primitiveResult.isUnlit || !isTriangles) {
1711
+ setUnlitNormals (
1712
+ LODResources.VertexBuffers ,
1713
+ ellipsoid,
1714
+ transform * yInvertMatrix * scaleMatrix);
1710
1715
} else {
1711
- if (primitiveResult.isUnlit ) {
1712
- setUnlitNormals (
1713
- LODResources.VertexBuffers ,
1714
- ellipsoid,
1715
- transform * yInvertMatrix * scaleMatrix);
1716
- } else {
1717
- TRACE_CPUPROFILER_EVENT_SCOPE (Cesium::ComputeFlatNormals)
1718
- computeFlatNormals (LODResources.VertexBuffers );
1719
- }
1716
+ TRACE_CPUPROFILER_EVENT_SCOPE (Cesium::ComputeFlatNormals)
1717
+ computeFlatNormals (LODResources.VertexBuffers );
1720
1718
}
1721
1719
1722
1720
if (hasTangents) {
@@ -1753,13 +1751,12 @@ static void loadPrimitive(
1753
1751
1754
1752
FStaticMeshSectionArray& Sections = LODResources.Sections ;
1755
1753
FStaticMeshSection& section = Sections.AddDefaulted_GetRef ();
1756
- // This will be ignored if the primitive contains points.
1754
+ // This will be ignored if the primitive contains lines or points.
1757
1755
section.NumTriangles = indices.Num () / 3 ;
1758
1756
section.FirstIndex = 0 ;
1759
1757
section.MinVertexIndex = 0 ;
1760
1758
section.MaxVertexIndex = numVertices - 1 ;
1761
- section.bEnableCollision =
1762
- primitive.mode != CesiumGltf::MeshPrimitive::Mode::POINTS;
1759
+ section.bEnableCollision = isTriangles;
1763
1760
section.bCastShadow = true ;
1764
1761
section.MaterialIndex = 0 ;
1765
1762
@@ -1784,9 +1781,7 @@ static void loadPrimitive(
1784
1781
LODResources.bHasReversedDepthOnlyIndices = false ;
1785
1782
1786
1783
#if ENGINE_VERSION_5_5_OR_HIGHER
1787
- // UE 5.5 requires that we do this in order to avoid a crash when ray
1788
- // tracing is enabled.
1789
- if (primitive.mode != CesiumGltf::MeshPrimitive::Mode::POINTS) {
1784
+ if (isTriangles) {
1790
1785
// UE 5.5 requires that we do this in order to avoid a crash when ray
1791
1786
// tracing is enabled.
1792
1787
RenderData->InitializeRayTracingRepresentationFromRenderingLODs ();
@@ -1800,7 +1795,7 @@ static void loadPrimitive(
1800
1795
1801
1796
primitiveResult.transform = transform * yInvertMatrix * scaleMatrix;
1802
1797
1803
- if (primitive. mode != CesiumGltf::MeshPrimitive::Mode::POINTS &&
1798
+ if (isTriangles &&
1804
1799
options.pMeshOptions ->pNodeOptions ->pModelOptions ->createPhysicsMeshes ) {
1805
1800
if (numVertices != 0 && indices.Num () != 0 ) {
1806
1801
TRACE_CPUPROFILER_EVENT_SCOPE (Cesium::ChaosCook)
@@ -3040,6 +3035,7 @@ static void loadPrimitiveGameThreadPart(
3040
3035
3041
3036
UStaticMeshComponent* pMesh = nullptr ;
3042
3037
ICesiumPrimitive* pCesiumPrimitive = nullptr ;
3038
+
3043
3039
if (meshPrimitive.mode == CesiumGltf::MeshPrimitive::Mode::POINTS) {
3044
3040
UCesiumGltfPointsComponent* pPointMesh =
3045
3041
NewObject<UCesiumGltfPointsComponent>(pGltf, componentName);
@@ -3049,6 +3045,14 @@ static void loadPrimitiveGameThreadPart(
3049
3045
pPointMesh->Dimensions = loadResult.dimensions ;
3050
3046
pMesh = pPointMesh;
3051
3047
pCesiumPrimitive = pPointMesh;
3048
+ } else if (
3049
+ meshPrimitive.mode == CesiumGltf::MeshPrimitive::Mode::LINES ||
3050
+ meshPrimitive.mode == CesiumGltf::MeshPrimitive::Mode::LINE_LOOP ||
3051
+ meshPrimitive.mode == CesiumGltf::MeshPrimitive::Mode::LINE_STRIP) {
3052
+ UCesiumGltfLinesComponent* pLineMesh =
3053
+ NewObject<UCesiumGltfLinesComponent>(pGltf, componentName);
3054
+ pMesh = pLineMesh;
3055
+ pCesiumPrimitive = pLineMesh;
3052
3056
} else if (!instanceTransforms.empty ()) {
3053
3057
auto * pInstancedComponent =
3054
3058
NewObject<UCesiumGltfInstancedComponent>(pGltf, componentName);
@@ -3110,11 +3114,18 @@ static void loadPrimitiveGameThreadPart(
3110
3114
primData.pTilesetActor ->GetTranslucencySortPriority ();
3111
3115
3112
3116
pStaticMesh = NewObject<UStaticMesh>(pMesh, componentName);
3113
- // Not only does the concept of ray tracing a point cloud not make much
3114
- // sense, but if Unreal will crash trying to generate ray tracing
3115
- // information for a static mesh without triangles.
3116
- pStaticMesh->bSupportRayTracing =
3117
- meshPrimitive.mode != CesiumGltf::MeshPrimitive::Mode::POINTS;
3117
+ // Unreal will crash trying to generate ray tracing information for a static
3118
+ // mesh without triangles (and it doesn't make sense anyways!)
3119
+ switch (meshPrimitive.mode ) {
3120
+ case CesiumGltf::MeshPrimitive::Mode::TRIANGLES:
3121
+ case CesiumGltf::MeshPrimitive::Mode::TRIANGLE_FAN:
3122
+ case CesiumGltf::MeshPrimitive::Mode::TRIANGLE_STRIP:
3123
+ pStaticMesh->bSupportRayTracing = true ;
3124
+ break ;
3125
+ default :
3126
+ pStaticMesh->bSupportRayTracing = false ;
3127
+ break ;
3128
+ }
3118
3129
pMesh->SetStaticMesh (pStaticMesh);
3119
3130
3120
3131
pStaticMesh->SetFlags (
0 commit comments