Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for rendering points #1037

Merged
merged 8 commits into from Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.md
@@ -1,5 +1,9 @@
# Change Log

### v1.23.0 - 2023-03-01

- Added support for rendering point clouds (`pnts`).

### v1.22.0 - 2023-02-01

##### Additions :tada:
Expand Down
83 changes: 47 additions & 36 deletions Source/CesiumRuntime/Private/CesiumGltfComponent.cpp
Expand Up @@ -21,6 +21,7 @@
#include "CesiumGltf/ExtensionModelExtFeatureMetadata.h"
#include "CesiumGltf/PropertyType.h"
#include "CesiumGltf/TextureInfo.h"
#include "CesiumGltfPointsComponent.h"
#include "CesiumGltfPrimitiveComponent.h"
#include "CesiumMaterialUserData.h"
#include "CesiumRasterOverlays.h"
Expand Down Expand Up @@ -697,8 +698,9 @@ static void loadPrimitive(
const MeshPrimitive& primitive = *options.pPrimitive;

if (primitive.mode != MeshPrimitive::Mode::TRIANGLES &&
primitive.mode != MeshPrimitive::Mode::TRIANGLE_STRIP) {
// TODO: add support for primitive types other than triangles.
primitive.mode != MeshPrimitive::Mode::TRIANGLE_STRIP &&
primitive.mode != MeshPrimitive::Mode::POINTS) {
// TODO: add support for other primitive types.
UE_LOG(
LogCesium,
Warning,
Expand Down Expand Up @@ -769,7 +771,7 @@ static void loadPrimitive(
LogCesium,
Warning,
TEXT(
"%s: Invalid normal buffer. Flat normal will be auto-generated instead"),
"%s: Invalid normal buffer. Flat normals will be auto-generated instead."),
UTF8_TO_TCHAR(name.c_str()));
}
}
Expand Down Expand Up @@ -864,7 +866,8 @@ static void loadPrimitive(
}

TArray<uint32> indices;
if (primitive.mode == MeshPrimitive::Mode::TRIANGLES) {
if (primitive.mode == MeshPrimitive::Mode::TRIANGLES ||
primitive.mode == MeshPrimitive::Mode::POINTS) {
TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::CopyIndices)
indices.SetNum(static_cast<TArray<uint32>::SizeType>(indicesView.size()));

Expand Down Expand Up @@ -895,6 +898,8 @@ static void loadPrimitive(
// need them, we need to use a tangent space generation algorithm which
// requires duplicated vertices.
bool duplicateVertices = !hasNormals || (needsTangents && !hasTangents);
duplicateVertices =
duplicateVertices && primitive.mode != MeshPrimitive::Mode::POINTS;

TArray<FStaticMeshBuildVertex> StaticMeshBuildVertices;
StaticMeshBuildVertices.SetNum(
Expand Down Expand Up @@ -1162,14 +1167,14 @@ static void loadPrimitive(
#endif

FStaticMeshSection& section = Sections.AddDefaulted_GetRef();
section.bEnableCollision = true;

// This will be ignored if the primitive contains points.
section.NumTriangles = indices.Num() / 3;
section.FirstIndex = 0;
section.MinVertexIndex = 0;
section.MaxVertexIndex = StaticMeshBuildVertices.Num() - 1;
section.bEnableCollision = true;
section.bEnableCollision = primitive.mode != MeshPrimitive::Mode::POINTS;
section.bCastShadow = true;
section.MaterialIndex = 0;

// Note that we're reversing the order of the indices, because the change
// from the glTF right-handed to the Unreal left-handed coordinate system
Expand Down Expand Up @@ -1211,27 +1216,27 @@ static void loadPrimitive(
primitiveResult.RenderData = std::move(RenderData);
primitiveResult.transform = transform;
primitiveResult.pMaterial = &material;

section.MaterialIndex = 0;

primitiveResult.pCollisionMesh = nullptr;

if (StaticMeshBuildVertices.Num() != 0 && indices.Num() != 0) {
if (primitive.mode != MeshPrimitive::Mode::POINTS) {
if (StaticMeshBuildVertices.Num() != 0 && indices.Num() != 0) {
#if PHYSICS_INTERFACE_PHYSX
TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::PhysXCook)
PxTriangleMesh* createdCollisionMesh = nullptr;
BuildPhysXTriangleMeshes(
createdCollisionMesh,
primitiveResult.uvInfo,
options.pMeshOptions->pNodeOptions->pModelOptions->pPhysXCookingModule,
StaticMeshBuildVertices,
indices);
primitiveResult.pCollisionMesh.Reset(createdCollisionMesh);
TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::PhysXCook)
PxTriangleMesh* createdCollisionMesh = nullptr;
BuildPhysXTriangleMeshes(
createdCollisionMesh,
primitiveResult.uvInfo,
options.pMeshOptions->pNodeOptions->pModelOptions
->pPhysXCookingModule,
StaticMeshBuildVertices,
indices);
primitiveResult.pCollisionMesh.Reset(createdCollisionMesh);
#else
TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::ChaosCook)
primitiveResult.pCollisionMesh =
BuildChaosTriangleMeshes(StaticMeshBuildVertices, indices);
TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::ChaosCook)
primitiveResult.pCollisionMesh =
BuildChaosTriangleMeshes(StaticMeshBuildVertices, indices);
#endif
}
}

// load primitive metadata
Expand Down Expand Up @@ -1873,8 +1878,13 @@ static void loadPrimitiveGameThreadPart(
TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::LoadPrimitive)

FName meshName = createSafeName(loadResult.name, "");
UCesiumGltfPrimitiveComponent* pMesh =
NewObject<UCesiumGltfPrimitiveComponent>(pGltf, meshName);
UCesiumGltfPrimitiveComponent* pMesh;
if (loadResult.pMeshPrimitive->mode == MeshPrimitive::Mode::POINTS) {
pMesh = NewObject<UCesiumGltfPointsComponent>(pGltf, meshName);
} else {
pMesh = NewObject<UCesiumGltfPrimitiveComponent>(pGltf, meshName);
}

pMesh->overlayTextureCoordinateIDToUVIndex =
loadResult.overlayTextureCoordinateIDToUVIndex;
pMesh->textureCoordinateMap = std::move(loadResult.textureCoordinateMap);
Expand Down Expand Up @@ -1941,13 +1951,16 @@ static void loadPrimitiveGameThreadPart(
? pGltf->BaseMaterialWithTranslucency
: pGltf->BaseMaterial;
#else
UMaterialInterface* pBaseMaterial =
(loadResult.onlyWater || !loadResult.onlyLand)
? pGltf->BaseMaterialWithWater
: (is_in_blend_mode(loadResult) && pbr.baseColorFactor.size() > 3 &&
pbr.baseColorFactor[3] < 0.996) // 1. - 1. / 256.
? pGltf->BaseMaterialWithTranslucency
: pGltf->BaseMaterial;
UMaterialInterface* pBaseMaterial;
if (loadResult.onlyWater || !loadResult.onlyLand) {
pBaseMaterial = pGltf->BaseMaterialWithWater;
} else {
pBaseMaterial =
(is_in_blend_mode(loadResult) && pbr.baseColorFactor.size() > 3 &&
pbr.baseColorFactor[3] < 0.996) // 1. - 1. / 256.
? pGltf->BaseMaterialWithTranslucency
: pGltf->BaseMaterial;
}
#endif

UMaterialInstanceDynamic* pMaterial = UMaterialInstanceDynamic::Create(
Expand Down Expand Up @@ -2107,8 +2120,6 @@ static void loadPrimitiveGameThreadPart(

pMesh->SetMobility(pGltf->Mobility);

// pMesh->bDrawMeshCollisionIfComplex = true;
// pMesh->bDrawMeshCollisionIfSimple = true;
pMesh->SetupAttachment(pGltf);
pMesh->RegisterComponent();
}
Expand Down Expand Up @@ -2358,8 +2369,8 @@ void UCesiumGltfComponent::DetachRasterTile(
UMaterialInstanceDynamic* pMaterial,
UCesiumMaterialUserData* pCesiumData) {
// If this material uses material layers and has the Cesium user data,
// clear the parameters on each material layer that maps to this overlay
// tile.
// clear the parameters on each material layer that maps to this
// overlay tile.
if (pCesiumData) {
FString name(
UTF8_TO_TCHAR(rasterTile.getOverlay().getName().c_str()));
Expand Down
114 changes: 114 additions & 0 deletions Source/CesiumRuntime/Private/CesiumGltfPointsComponent.cpp
@@ -0,0 +1,114 @@
// Copyright 2020-2021 CesiumGS, Inc. and Contributors

#include "CesiumGltfPointsComponent.h"
#include "Engine/StaticMesh.h"

class FGltfPointsSceneProxy final : public FPrimitiveSceneProxy {
public:
SIZE_T GetTypeHash() const override {
static size_t UniquePointer;
return reinterpret_cast<size_t>(&UniquePointer);
}

FGltfPointsSceneProxy(
UCesiumGltfPointsComponent* InComponent,
ERHIFeatureLevel::Type InFeatureLevel)
: FPrimitiveSceneProxy(InComponent) {
const auto RenderData = InComponent->GetStaticMesh()->GetRenderData();
LODResources = &RenderData->LODResources[0];
VertexFactory = &RenderData->LODVertexFactories[0].VertexFactory;
Material = InComponent->GetMaterial(0);
MaterialRelevance =
InComponent->GetMaterialRelevance(GetScene().GetFeatureLevel());
}

virtual ~FGltfPointsSceneProxy() {}

virtual void DrawStaticElements(FStaticPrimitiveDrawInterface* PDI) override {
if (!HasViewDependentDPG()) {
FMeshBatch Mesh;
CreateMesh(Mesh);
PDI->DrawMesh(Mesh, FLT_MAX);
}
}

virtual void GetDynamicMeshElements(
const TArray<const FSceneView*>& Views,
const FSceneViewFamily& ViewFamily,
uint32 VisibilityMap,
FMeshElementCollector& Collector) const override {
QUICK_SCOPE_CYCLE_COUNTER(STAT_GltfPointsSceneProxy_GetDynamicMeshElements);

for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) {
if (VisibilityMap & (1 << ViewIndex)) {
const FSceneView* View = Views[ViewIndex];
FMeshBatch& Mesh = Collector.AllocateMesh();
CreateMesh(Mesh);
Collector.AddMesh(ViewIndex, Mesh);
}
}
}

virtual FPrimitiveViewRelevance
GetViewRelevance(const FSceneView* View) const override {
FPrimitiveViewRelevance Result;
Result.bDrawRelevance = IsShown(View);
if (HasViewDependentDPG()) {
Result.bDynamicRelevance = true;
} else {
Result.bStaticRelevance = true;
}

Result.bRenderCustomDepth = ShouldRenderCustomDepth();
Result.bRenderInMainPass = ShouldRenderInMainPass();
Result.bRenderInDepthPass = ShouldRenderInDepthPass();
Result.bUsesLightingChannels =
GetLightingChannelMask() != GetDefaultLightingChannelMask();
Result.bShadowRelevance = IsShadowCast(View);
Result.bVelocityRelevance =
IsMovable() & Result.bOpaque & Result.bRenderInMainPass;

MaterialRelevance.SetPrimitiveViewRelevance(Result);

return Result;
}

virtual uint32 GetMemoryFootprint(void) const override {
return (sizeof(*this) + GetAllocatedSize());
}

private:
FLocalVertexFactory* VertexFactory;
FStaticMeshLODResources* LODResources;
UMaterialInterface* Material;
FMaterialRelevance MaterialRelevance;

void CreateMesh(FMeshBatch& Mesh) const {
Mesh.VertexFactory = VertexFactory;
Mesh.MaterialRenderProxy = Material->GetRenderProxy();
Mesh.ReverseCulling = IsLocalToWorldDeterminantNegative();
Mesh.Type = PT_PointList;
Mesh.DepthPriorityGroup = SDPG_World;
Mesh.LODIndex = 0;
Mesh.bCanApplyViewModeOverrides = false;
Mesh.bUseAsOccluder = false;
Mesh.bWireframe = false;

auto pIndexBuffer = &LODResources->IndexBuffer;
FMeshBatchElement& BatchElement = Mesh.Elements[0];
BatchElement.IndexBuffer = pIndexBuffer;
BatchElement.NumPrimitives = pIndexBuffer->GetNumIndices();
BatchElement.FirstIndex = 0;
BatchElement.MinVertexIndex = 0;
BatchElement.MaxVertexIndex = BatchElement.NumPrimitives - 1;
}
};

// Sets default values for this component's properties
UCesiumGltfPointsComponent::UCesiumGltfPointsComponent() {}

UCesiumGltfPointsComponent::~UCesiumGltfPointsComponent() {}

FPrimitiveSceneProxy* UCesiumGltfPointsComponent::CreateSceneProxy() {
return new FGltfPointsSceneProxy(this, GetScene()->GetFeatureLevel());
}
19 changes: 19 additions & 0 deletions Source/CesiumRuntime/Private/CesiumGltfPointsComponent.h
@@ -0,0 +1,19 @@
// Copyright 2020-2021 CesiumGS, Inc. and Contributors
Copy link
Contributor Author

@j9liu j9liu Feb 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just copied this from the CesiumGltfPrimitiveComponent file -- should we update this for 2023?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha yeah we should update it everywhere. But that can be a separate PR. It's unfortunate that Epic's marketplace guidelines require us to put this nonsense in every file.
https://www.unrealengine.com/en-US/marketplace-guidelines#262b


#pragma once

#include "CesiumGltfPrimitiveComponent.h"
#include "CesiumGltfPointsComponent.generated.h"

UCLASS()
class UCesiumGltfPointsComponent : public UCesiumGltfPrimitiveComponent {
GENERATED_BODY()

public:
// Sets default values for this component's properties
UCesiumGltfPointsComponent();
virtual ~UCesiumGltfPointsComponent();

// Override UPrimitiveComponent interface.
virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
};
3 changes: 0 additions & 3 deletions Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.cpp
Expand Up @@ -13,9 +13,6 @@

// Sets default values for this component's properties
UCesiumGltfPrimitiveComponent::UCesiumGltfPrimitiveComponent() {
// Set this component to be initialized when the game starts, and to be ticked
// every frame. You can turn these features off to improve performance if you
// don't need them.
PrimaryComponentTick.bCanEverTick = false;
pModel = nullptr;
pMeshPrimitive = nullptr;
Expand Down
2 changes: 2 additions & 0 deletions Source/CesiumRuntime/Public/Cesium3DTileset.h
Expand Up @@ -693,6 +693,8 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor {
* Disabling this option will improve the performance of tile loading, but it
* will no longer be possible to collide with the tileset since the physics
* meshes will not be created.
*
* Physics meshes cannot be generated for primitives containing points.
*/
UPROPERTY(
EditAnywhere,
Expand Down
2 changes: 1 addition & 1 deletion extern/cesium-native
Submodule cesium-native updated 27 files
+6 −0 CHANGES.md
+1 −0 Cesium3DTilesSelection/CMakeLists.txt
+1 −1 Cesium3DTilesSelection/src/B3dmToGltfConverter.cpp
+133 −40 Cesium3DTilesSelection/src/BatchTableToGltfFeatureMetadata.cpp
+7 −1 Cesium3DTilesSelection/src/BatchTableToGltfFeatureMetadata.h
+1,636 −0 Cesium3DTilesSelection/src/PntsToGltfConverter.cpp
+17 −0 Cesium3DTilesSelection/src/PntsToGltfConverter.h
+2 −21 Cesium3DTilesSelection/src/QuantizedMeshLoader.cpp
+2 −0 Cesium3DTilesSelection/src/registerAllTileContentTypes.cpp
+21 −0 Cesium3DTilesSelection/test/ConvertTileToGltf.h
+1,245 −0 Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp
+480 −16 Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtFeatureMetadata.cpp
+ Cesium3DTilesSelection/test/data/PointCloud/pointCloudBatched.pnts
+ Cesium3DTilesSelection/test/data/PointCloud/pointCloudConstantRGBA.pnts
+ Cesium3DTilesSelection/test/data/PointCloud/pointCloudDraco.pnts
+ Cesium3DTilesSelection/test/data/PointCloud/pointCloudDracoBatched.pnts
+ Cesium3DTilesSelection/test/data/PointCloud/pointCloudDracoPartial.pnts
+ Cesium3DTilesSelection/test/data/PointCloud/pointCloudNormals.pnts
+ Cesium3DTilesSelection/test/data/PointCloud/pointCloudNormalsOctEncoded.pnts
+ Cesium3DTilesSelection/test/data/PointCloud/pointCloudPositionsOnly.pnts
+ Cesium3DTilesSelection/test/data/PointCloud/pointCloudQuantized.pnts
+ Cesium3DTilesSelection/test/data/PointCloud/pointCloudRGB.pnts
+ Cesium3DTilesSelection/test/data/PointCloud/pointCloudRGB565.pnts
+ Cesium3DTilesSelection/test/data/PointCloud/pointCloudRGBA.pnts
+ Cesium3DTilesSelection/test/data/PointCloud/pointCloudWithPerPointProperties.pnts
+82 −0 CesiumUtility/include/CesiumUtility/AttributeCompression.h
+69 −0 CesiumUtility/test/TestAttributeCompression.cpp