Cesium for Unreal
repository·main·Indexed 22 days ago
https://github.com/cesiumgs/cesium-unrealA plugin that integrates the 3D geospatial ecosystem into Unreal Engine, providing a high-accuracy WGS84 globe and support for streaming real-world 3D content such as terrain, imagery, and buildings using 3D Tiles and Cesium ion. The plugin supports multiple Unreal Engine versions (from 4.26 to 5.5) and provides development setup guides for Windows, Linux, and macOS.
What's inside Cesium for Unreal
- Use Unreal Insights to identify performance bottlenecks in your C++ code. It provides timing event scopes and thread activity tracking with minimal impact on application execution. It is best used alongside CPU sampling-based profilers to get a complete picture of performance.
Ensure MSVC compiler compatibility for Cesium for Unreal
mainCompiling Cesium for Unreal requires that the vcpkg-based third-party dependencies, the
cesium-nativecode, and the Cesium for Unreal plugin code itself are all compiled using the same (or compatible) versions of the MSVC compiler.Key Compatibility Rules:
- The compiler version used to link must be the same or newer than the newest compiler used to build any of the
.libfiles or object files being linked. - For maximum compatibility, released versions of Cesium for Unreal should ideally be built with the exact MSVC version used by the Epic Games build farm for that specific Unreal Engine version (e.g., v14.38.33130 for UE 5.6).
- You can install multiple toolchain versions simultaneously via the Visual Studio Installer by selecting specific versions under the "Individual Components" tab in "Compilers, build tools, and runtimes".
- The compiler version used to link must be the same or newer than the newest compiler used to build any of the
Standard units in Cesium for Unreal
mainTo avoid confusion when passing values, adhere to these unit standards:
- Distance/Length: Cesium for Unreal uses meters. (Note: Unreal Engine natively uses centimeters).
- Geospatial Coordinates: Longitude and latitude are expressed in degrees.
- Height: Height above the WGS84 ellipsoid is expressed in meters.
Handle property changes with Custom Versions
mainWhen a
UObjectproperty is replaced by a different type or logic, use Custom Versions to resolve differences during the loading process. This involves using anenum(defined inCesiumCustomVersion.h) to track the plugin's state.When to use Serialize vs PostLoad
Serialize: Use this for simple properties likebools orenums. You can intercept the value during the load/save process.PostLoad: Use this for properties that refer to other objects (e.g., pointers). These must be resolved inPostLoadbecause they may be overwritten later in the load process if handled inSerialize.
Implementation Workflow
- Create a New Version: Add a new entry to the
Versionsenum inCesiumCustomVersion.h. Place it between the last custom version andVersionPlusOne. - Deprecate the Old Property: Follow standard deprecation patterns and use
[CoreRedirects]if necessary. - Implement Logic:
- In
Serialize, useAr.UsingCustomVersion(FCesiumCustomVersion::GUID)andAr.CustomVer(...)to check the version and set the new property based on the old one. - In
PostLoad, useGetLinkerCustomVersion(FCesiumCustomVersion::GUID)to check the version and resolve pointer-based properties.
- In
// Example: Handling a version change in Serialize void UCesiumWebMapTileServiceRasterOverlay::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar.UsingCustomVersion(FCesiumCustomVersion::GUID); const int32 CesiumVersion = Ar.CustomVer(FCesiumCustomVersion::GUID); if (CesiumVersion < FCesiumCustomVersion::WebMapTileServiceProjectionAsEnum) { this->Projection = this->UseWebMercatorProjection_DEPRECATED ? ECesiumWebMapTileServiceRasterOverlayProjection::WebMercator : ECesiumWebMapTileServiceRasterOverlayProjection::Geographic; } } // Example: Handling a version change in PostLoad for pointers void ACesium3DTileset::PostLoad() { Super::PostLoad(); #if WITH_EDITOR const int32 CesiumVersion = this->GetLinkerCustomVersion(FCesiumCustomVersion::GUID); PRAGMA_DISABLE_DEPRECATION_WARNINGS if (CesiumVersion < FCesiumCustomVersion::CesiumIonServer) { this->CesiumIonServer = UCesiumIonServer::GetBackwardCompatibleServer( this->IonAssetEndpointUrl_DEPRECATED); } PRAGMA_ENABLE_DEPRECATION_WARNINGS #endif }Understand Property Tables and Encoding in v2.0
mainProperty tables (from
EXT_structural_metadata) define how metadata values apply to features.- Identification: Property tables are distinguished by their
name. If no name is provided, the component uses theclassname (e.g., abuildingsclass becomes abuildingsproperty table). - Property Details: Each property includes details like type,
normalizedstatus,offset, andscale. These details inform how the component encodes values into textures. - Encoding Details: You can manually set how a property is encoded to a texture and how it is retrieved.
- Fallback Behavior: If a property is listed in the description but missing from a specific model's property table, it falls back to default values (e.g., a missing scalar property will be encoded as all zeroes).
- Identification: Property tables are distinguished by their
Identify low use and fragmented use areas in Timings panel
mainWhen analyzing the
Timings panel, look for these two patterns to find optimization opportunities:Low Use Areas
These are regions where the application is running but not utilizing available resources (like background threads).
- How to find: Check
Game FramesinAll Tracks, disableCompact Mode, setDepth Limitto4 lanes, and zoom into periods where background workers are inactive. - Goal: Investigate why the CPU/threads are idle during these periods.
Fragmented Use Areas hese are regions where threads are active but inefficiently.
- How to find: Set
Depth LimittoUnlimitedand zoom into busy background workers. - What to look for: Gaps between work items where workers finish a task and then wait for more work.
- Goal: Aim to 'squish' work together to minimize inactivity and reduce total execution duration.
- How to find: Check
How multithreaded texture creation works in Cesium for Unreal
mainTo optimize memory and performance, Cesium for Unreal uses a specialized system for texture creation that handles shared images across different tiles:
- Shared Image Loading: When multiple tiles share a single image,
ExtensionImageAssetUnreal::getOrCreateis called. It uses a mutex to ensure only one thread performs the actual load. Other threads receive aSharedFuturethat resolves once the first thread completes the load, preventing redundant work and blocking. - Asynchronous GPU Uploads:
- For RHI's supporting async texture creation (e.g., Direct3D 11 and 12), the system uses
FCesiumPreCreatedRHITextureResource. The GPU upload is triggered immediately by the worker thread viaRHIAsyncCreateTexture2D. - For other RHIs, it uses
FCesiumCreateNewTextureResource, which queues a command to the render thread to perform the upload viaRHICreateTexture.
- For RHI's supporting async texture creation (e.g., Direct3D 11 and 12), the system uses
- Texture Resource Management: To allow the same pixel data to be used with different sampling settings (e.g., different mipmap or sRGB configurations) without duplicating memory, the system creates multiple
FTextureResourceinstances (likeFCesiumUseExistingTextureResource) that all reference a single underlyingFRHITexturevia reference counting.
- Shared Image Loading: When multiple tiles share a single image,
Core components of the Cesium for Unreal development environment
mainA full development environment for Cesium for Unreal consists of three primary components:
cesium-native: Engine-independent libraries for 3D Tiles and geospatial functionality. Most plugin functionality is built upon these.cesium-unreal: The source code for the Cesium for Unreal plugin itself.- An Unreal project: A project that consumes the plugin. The
cesium-unreal-samplesrepository is recommended for quick starts and regression testing.
Note: While
cesium-nativecan be developed independently, modifications to it must be carefully checked for breaking changes in thecesium-unrealAPI or build process.Organize source code into Runtime and Editor folders
mainWhen developing with or extending Cesium for Unreal, understand the distinction between the
RuntimeandEditorsource directories:Editorfolder: Contains elements used exclusively within the Unreal Editor (e.g., UI components or editor-only functionality). Warning: Do not place code here that is required for the application to run at runtime, as these files will not be included in a packaged build.Runtimefolder: Contains all logic required for the application to function. These classes are accessible to the Unreal Editor but are not exclusive to it.
Expose properties and functions to Unreal Engine
mainTo make C++ members accessible to the Unreal Editor or Blueprints, you must use specific macros:
Properties (
UPROPERTY)Use the
UPROPERTYmacro above member variables to expose them to the Editor UI or Blueprints.Functions (
UFUNCTION)Use the
UFUNCTIONmacro to make C++ functions accessible to Blueprints or as buttons in the Editor interface.Structs (
USTRUCT)Use
USTRUCTto expose C++ structs.USTRUCTs are not managed by Garbage Collection.- Use
USTRUCT(BlueprintType)to enable theMakenode in Blueprints. - To allow properties to appear in a
Breaknode, useBlueprintReadOnlyorBlueprintReadWritespecifiers.
Enums (
UENUM)Use
UENUMfor enum classes used in aUObjectcontext. These must be defined as anenum classofuint8type.UENUM() enum class EMyEnum : uint8 { ... };Use Public and Private subfolders within Runtime
mainThe
Runtimedirectory is further organized intoPublicandPrivatesubfolders to manage API visibility:Publicfolder: Should contain files related to the public API.Privatefolder: Contains implementation details, private classes, and functions that are not part of the public interface.
Dependency Rules:
- Files in
Privatecan reference files inPublic. - Files in
Publiccannot reference files inPrivate.
If a class in the
Publicfolder requires a type defined inPrivate(for example, as a member variable), you should use a forward declaration to avoid the dependency. If a forward declaration is not possible, you must move the required class to thePublicfolder, even if it is not intended to be part of the public API.Understand Metadata Value Types in EXT_structural_metadata
mainIn v2.0,
ECesiumMetadataTrueTypeis deprecated. Metadata types are now defined by theFCesiumMetadataValueTypestruct, which models theEXT_structural_metadataspecification.An
FCesiumMetadataValueTypeconsists of:- ECesiumMetadataType: The type of the class property (e.g., Scalar, Vec2, String).
- ECesiumMetadataComponentType: The component type (e.g., Float32, Uint8), applicable to scalar,
VECN, andMATNtypes. Set toNonefor others. - bIsArray: A boolean indicating if the property is an array of the specified type.