Cesium for Unreal 2.13.2
Loading...
Searching...
No Matches
CesiumSubLevelComponent.h
Go to the documentation of this file.
1// Copyright 2020-2024 CesiumGS, Inc. and Contributors
2
3#pragma once
4
5#include "Components/ActorComponent.h"
6#include "UObject/ObjectMacros.h"
7#include "CesiumSubLevelComponent.generated.h"
8
10class ALevelInstance;
12
13/**
14 * A component intended to be attached to a Level Instance Actor that turns that
15 * Level Instance into a Cesium sub-level. Only a single Cesium sub-level can be
16 * active (visible) at any given time.
17 *
18 * A globe (like the planet Earth) is an unusual sort of level in Unreal in that
19 * it has truly massive coordinate values and the "up" direction depends on
20 * where exactly on the globe you're located. Many things in the Unreal
21 * ecosystem, such as the gravity system, don't expect this situation and will
22 * have incorrect and surprising behavior when used on a globe.
23 *
24 * Cesium sub-levels help to mitigate this. Only one sub-level can be active at
25 * any given time, and when it is, that sub-level's origin becomes the origin of
26 * the Unreal world. Furthermore, at the origin location, Unreal's +X axis
27 * points East, its +Y axis points South, and its +Z axis points Up. Thus,
28 * within a sub-level, gravity works in the normal way that Unreal objects
29 * expect, and coordinate values stay relatively small. This allows you to use
30 * just about any Unreal object within a sub-level without worrying about
31 * surprising behavior.
32 *
33 * Globe-aware objects, particularly those with a "Cesium Globe Anchor"
34 * component attached to them, are allowed to exist outside sub-levels and even
35 * move between them. If all your objects are globe aware, there's no need to
36 * use sub-levels at all.
37 *
38 * In the Editor, the currently-active sub-level is selected by clicking the
39 * "Eye" icon next to the Level Instance in the Outliner.
40 *
41 * At runtime, the currently-active sub-level is selected by the Actor with a
42 * CesiumOriginShiftComponent attached to it. If this Actor is inside a
43 * sub-level's "Load Radius" that sub-level will be activated. If multiple
44 * sub-levels are in range, only the closest one will be activated.
45 */
46UCLASS(ClassGroup = Cesium, meta = (BlueprintSpawnableComponent))
47class CESIUMRUNTIME_API UCesiumSubLevelComponent : public UActorComponent {
48 GENERATED_BODY()
49
50public:
51 /**
52 * Gets whether this sub-level is enabled. An enabled sub-level will be
53 * automatically loaded when the camera moves within its LoadRadius and
54 * no other levels are closer, and the Georeference will be updated so that
55 * this level's Longitude, Latitude, and Height become (0, 0, 0) in the Unreal
56 * World. A sub-level that is not enabled will be ignored by Cesium at
57 * runtime.
58 */
59 UFUNCTION(BlueprintGetter, Category = "Cesium")
60 bool GetEnabled() const;
61
62 /**
63 * Sets whether this sub-level is enabled. An enabled sub-level will be
64 * automatically loaded when the camera moves within its LoadRadius and
65 * no other levels are closer, and the Georeference will be updated so that
66 * this level's Longitude, Latitude, and Height become (0, 0, 0) in the Unreal
67 * World. A sub-level that is not enabled will be ignored by Cesium at
68 * runtime.
69 */
70 UFUNCTION(BlueprintSetter, Category = "Cesium")
71 void SetEnabled(bool value);
72
73 /**
74 * Gets the longitude of the georeference origin for this sub-level in
75 * degrees, in the range [-180, 180]. When this sub-level is active, the
76 * CesiumGeoreference will adopt this origin.
77 */
78 UFUNCTION(BlueprintGetter, Category = "Cesium")
79 double GetOriginLongitude() const;
80
81 /**
82 * Sets the longitude of the georeference origin for this sub-level in
83 * degrees, in the range [-180, 180]. When this sub-level is active, the
84 * CesiumGeoreference will adopt this origin.
85 */
86 UFUNCTION(BlueprintSetter, Category = "Cesium")
87 void SetOriginLongitude(double value);
88
89 /**
90 * Gets the latitude of the georeference origin for this sub-level in degrees,
91 * in the range [-90, 90]. When this sub-level is active, the
92 * CesiumGeoreference will adopt this origin.
93 */
94 UFUNCTION(BlueprintGetter, Category = "Cesium")
95 double GetOriginLatitude() const;
96
97 /**
98 * Sets the latitude of the georeference origin for this sub-level in degrees,
99 * in the range [-90, 90]. When this sub-level is active, the
100 * CesiumGeoreference will adopt this origin.
101 */
102 UFUNCTION(BlueprintSetter, Category = "Cesium")
103 void SetOriginLatitude(double value);
104
105 /**
106 * Gets the height of the georeference origin for this sub-level in meters
107 * above the ellipsoid. This height should not be confused with a height
108 * above Mean Sea Level. When this sub-level is active, the CesiumGeoreference
109 * will adopt this origin.
110 */
111 UFUNCTION(BlueprintGetter, Category = "Cesium")
112 double GetOriginHeight() const;
113
114 /**
115 * Sets the height of the georeference origin for this sub-level in meters
116 * above the ellipsoid. This height should not be confused with a height
117 * above Mean Sea Level. When this sub-level is active, the CesiumGeoreference
118 * will adopt this origin.
119 */
120 UFUNCTION(BlueprintSetter, Category = "Cesium")
121 void SetOriginHeight(double value);
122
123 /**
124 * Gets how close to the sub-level local origin, in meters, the camera needs
125 * to be to load the level.
126 */
127 UFUNCTION(BlueprintGetter, Category = "Cesium")
128 double GetLoadRadius() const;
129
130 /**
131 * Sets how close to the sub-level local origin, in meters, the camera needs
132 * to be to load the level.
133 */
134 UFUNCTION(BlueprintSetter, Category = "Cesium")
135 void SetLoadRadius(double value);
136
137 /**
138 * Gets the designated georeference actor controlling how the actor's
139 * coordinate system relates to the coordinate system in this Unreal Engine
140 * level.
141 *
142 * If this is null, the sub-level will find and use the first Georeference
143 * Actor in the level, or create one if necessary. To get the active/effective
144 * Georeference from Blueprints or C++, use ResolvedGeoreference instead.
145 */
146 UFUNCTION(BlueprintGetter, Category = "Cesium")
147 TSoftObjectPtr<ACesiumGeoreference> GetGeoreference() const;
148
149 /**
150 * Sets the designated georeference actor controlling how the actor's
151 * coordinate system relates to the coordinate system in this Unreal Engine
152 * level.
153 *
154 * If this is null, the sub-level will find and use the first Georeference
155 * Actor in the level, or create one if necessary. To get the active/effective
156 * Georeference from Blueprints or C++, use ResolvedGeoreference instead.
157 */
158 UFUNCTION(BlueprintSetter, Category = "Cesium")
159 void SetGeoreference(TSoftObjectPtr<ACesiumGeoreference> NewGeoreference);
160
161 /**
162 * Gets the resolved georeference, just like calling the ResolveGeoreference
163 * property, except that it will return null if a georeference has not yet
164 * been resolved.
165 */
166 UFUNCTION(BlueprintGetter, Category = "Cesium")
167 ACesiumGeoreference* GetResolvedGeoreference() const;
168
169 /**
170 * Resolves the Cesium Georeference to use with this components. Returns
171 * the value of the Georeference property if it is set. Otherwise, finds a
172 * Georeference in the World and returns it, creating it if necessary. The
173 * resolved Georeference is cached so subsequent calls to this function will
174 * return the same instance, unless ForceReresolve is true.
175 */
176 UFUNCTION(BlueprintCallable, Category = "Cesium")
177 ACesiumGeoreference* ResolveGeoreference(bool bForceReresolve = false);
178
179 /**
180 * Sets the longitude (X), latitude (Y), and height (Z) of this sub-level's
181 * georeference origin. When this sub-level is active, the CesiumGeoreference
182 * will adopt this origin. Longitude and latitude are in degrees. Height is in
183 * meters above the ellipsoid, which should not be confused with meters
184 * above Mean Sea Level.
185 */
186 UFUNCTION(BlueprintCallable, Category = "Cesium")
187 void SetOriginLongitudeLatitudeHeight(const FVector& longitudeLatitudeHeight);
188
189#if WITH_EDITOR
190 /**
191 * Places the georeference origin at the origin of the sub-level and sets the
192 * Level Instance's Location to (0,0,0). This improves the precision of the
193 * objects in the sub-level as well as makes the Load Radius more sensible.
194 *
195 * If your sub-level has any Cesium3DTilesets, Cesium for Unreal will enter
196 * Edit mode for the sub-level and the Cesium3DTilesets' transformations will
197 * be updated based on the new georeference origin. You should Commit this
198 * change.
199 *
200 * Warning: Before clicking, ensure that all non-Cesium objects in the
201 * persistent level are georeferenced with the "CesiumGeoreferenceComponent"
202 * or attached to an actor with that component. Ensure that static actors only
203 * exist in georeferenced sub-levels.
204 */
205 UFUNCTION(CallInEditor, Category = "Cesium")
206 void PlaceGeoreferenceOriginAtSubLevelOrigin();
207
208 /**
209 * Places the sub-level's origin at the camera's current location. Rotates
210 * the globe so the current longitude/latitude/height of the camera is at the
211 * Unreal origin of this sub-level. The camera is also teleported to the new
212 * Unreal origin and rotated so that the view direction is maintained.
213 *
214 * This function is similar to "Place Georeference Origin Here" on the
215 * CesiumGeoreference, except that this moves the georeference origin while
216 * also ensuring that the sub-level content stays in the same place on the
217 * globe by adjusting the Level Instance's transform.
218 *
219 * If your sub-level has any Cesium3DTilesets, Cesium for Unreal will enter
220 * Edit mode for the sub-level and the Cesium3DTilesets' transformations will
221 * be updated based on the new georeference origin. You should Commit this
222 * change.
223 *
224 * Warning: Before clicking, ensure that all non-Cesium objects in the
225 * persistent level are georeferenced with the "CesiumGlobeAnchorComponent"
226 * or attached to an actor with that component. Ensure that static actors only
227 * exist in georeferenced sub-levels.
228 */
229 UFUNCTION(CallInEditor, Category = "Cesium")
230 void PlaceGeoreferenceOriginHere();
231#endif
232
233 /**
234 * If this sub-level is currently the active one, this method will copy its
235 * origin to the georeference's origin. Otherwise, it does nothing.
236 */
238
239 virtual void BeginDestroy() override;
240 virtual void OnComponentCreated() override;
241
242#if WITH_EDITOR
243 virtual void
244 PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
245#endif
246
247protected:
248 virtual void BeginPlay() override;
249
250 /**
251 * Called when a component is registered. This can be viewed as "enabling"
252 * this Component on the Actor to which it is attached.
253 *
254 * In the Editor, this is called in a many different situations, such as on
255 * changes to properties.
256 */
257 virtual void OnRegister() override;
258
259 /**
260 * Called when a component is unregistered. This can be viewed as
261 * "disabling" this Component on the Actor to which it is attached.
262 *
263 * In the Editor, this is called in a many different situations, such as on
264 * changes to properties.
265 */
266 virtual void OnUnregister() override;
267
268#if WITH_EDITOR
269 /**
270 * Called by the Editor to check if it's ok to edit a property on this object.
271 * Used to disable all fields on this component when editing the sub-level
272 * instance that this component is attached to.
273 */
274 virtual bool CanEditChange(const FProperty* InProperty) const override;
275#endif
276
277private:
278 /**
279 * Whether this sub-level is enabled. An enabled sub-level will be
280 * automatically loaded when the camera moves within its LoadRadius and
281 * no other levels are closer, and the Georeference will be updated so that
282 * this level's Longitude, Latitude, and Height become (0, 0, 0) in the Unreal
283 * World. A sub-level that is not enabled will be ignored by Cesium at
284 * runtime.
285 */
286 UPROPERTY(
287 EditAnywhere,
288 BlueprintReadWrite,
289 Category = "Cesium",
290 BlueprintGetter = GetEnabled,
291 BlueprintSetter = SetEnabled,
292 meta = (AllowPrivateAccess = true))
293 bool Enabled = true;
294
295 /**
296 * The latitude of the georeference origin for this sub-level in degrees, in
297 * the range [-90, 90]. When this sub-level is active, the CesiumGeoreference
298 * will adopt this origin.
299 */
300 UPROPERTY(
301 EditAnywhere,
302 BlueprintReadWrite,
303 Category = "Cesium",
304 BlueprintGetter = GetOriginLatitude,
305 BlueprintSetter = SetOriginLatitude,
306 meta = (ClampMin = -90.0, ClampMax = 90.0, AllowPrivateAccess = true))
307 double OriginLatitude = 39.736401;
308
309 /**
310 * The longitude of the georeference origin for this sub-level in degrees, in
311 * the range [-180, 180]. When this sub-level is active, the
312 * CesiumGeoreference will adopt this origin.
313 */
314 UPROPERTY(
315 EditAnywhere,
316 BlueprintReadWrite,
317 Category = "Cesium",
318 BlueprintGetter = GetOriginLongitude,
319 BlueprintSetter = SetOriginLongitude,
320 meta = (ClampMin = -180.0, ClampMax = 180.0, AllowPrivateAccess = true))
321 double OriginLongitude = -105.25737;
322
323 /**
324 * The height of the georeference origin for this sub-level in meters above
325 * the ellipsoid. This height should not be confused with a height above
326 * Mean Sea Level. When this sub-level is active, the CesiumGeoreference will
327 * adopt this origin.
328 */
329 UPROPERTY(
330 EditAnywhere,
331 BlueprintReadWrite,
332 Category = "Cesium",
333 BlueprintGetter = GetOriginHeight,
334 BlueprintSetter = SetOriginHeight,
335 meta = (AllowPrivateAccess = true))
336 double OriginHeight = 2250.0;
337
338 /**
339 * How close to the sub-level local origin, in meters, the camera needs to be
340 * to load the level.
341 */
342 UPROPERTY(
343 EditAnywhere,
344 BlueprintReadWrite,
345 Category = "Cesium",
346 BlueprintGetter = GetLoadRadius,
347 BlueprintSetter = SetLoadRadius,
348 meta = (ClampMin = 0.0, AllowPrivateAccess = true))
349 double LoadRadius = 1000.0;
350
351 /**
352 * The designated georeference actor controlling how the actor's
353 * coordinate system relates to the coordinate system in this Unreal Engine
354 * level.
355 *
356 * If this is null, the sub-level will find and use the first Georeference
357 * Actor in the level, or create one if necessary. To get the active/effective
358 * Georeference from Blueprints or C++, use ResolvedGeoreference instead.
359 */
360 UPROPERTY(
361 EditAnywhere,
362 BlueprintReadWrite,
363 BlueprintGetter = GetGeoreference,
364 BlueprintSetter = SetGeoreference,
365 Category = "Cesium",
366 Meta = (AllowPrivateAccess))
367 TSoftObjectPtr<ACesiumGeoreference> Georeference;
368
369 /**
370 * The resolved georeference used by this sub-level. This is not serialized
371 * because it may point to a Georeference in the PersistentLevel while this
372 * Actor is in a sub-level. If the Georeference property is specified,
373 * however then this property will have the same value.
374 *
375 * This property will be null before ResolveGeoreference is called.
376 */
377 UPROPERTY(
378 Transient,
379 VisibleAnywhere,
380 BlueprintReadOnly,
381 BlueprintGetter = GetResolvedGeoreference,
382 Category = "Cesium",
383 Meta = (AllowPrivateAccess))
384 ACesiumGeoreference* ResolvedGeoreference = nullptr;
385
386 /**
387 * Gets the sub-level switch component with which this sub-level is
388 * associated. Calling this method will call ResolveGeoreference to resolve
389 * the georeference, if it's not already resolved.
390 */
391 UCesiumSubLevelSwitcherComponent* _getSwitcher() noexcept;
392
393 /**
394 * Gets the Level Instance Actor to which this component is attached. If this
395 * component is not attached to a Level Instance Actor, this method logs a
396 * warning and returns nullptr.
397 */
398 ALevelInstance* _getLevelInstance() const noexcept;
399
400 /**
401 * Invalidates the cached resolved georeference, unsubscribing from it and
402 * setting it to null. The next time ResolveGeoreference is called, the
403 * Georeference will be re-resolved and re-subscribed.
404 */
405 void _invalidateResolvedGeoreference();
406
407 void PlaceOriginAtEcef(const FVector& NewOriginEcef);
408};
Controls how global geospatial coordinates are mapped to coordinates in the Unreal Engine level.
A component intended to be attached to a Level Instance Actor that turns that Level Instance into a C...
virtual void OnUnregister() override
Called when a component is unregistered.
virtual void OnRegister() override
Called when a component is registered.
virtual void OnComponentCreated() override
virtual void BeginDestroy() override
virtual void BeginPlay() override
void UpdateGeoreferenceIfSubLevelIsActive()
If this sub-level is currently the active one, this method will copy its origin to the georeference's...
Manages the asynchronous switching between sub-levels, making sure that a previous sub-level is hidde...