Skip to content

Commit

Permalink
Merge pull request #421 from raggnic/autonomous-cesium-camera
Browse files Browse the repository at this point in the history
Use a component to identify cesium camera
  • Loading branch information
j9liu authored Sep 18, 2024
2 parents b526595 + a88c595 commit 3837e0d
Show file tree
Hide file tree
Showing 10 changed files with 330 additions and 25 deletions.
10 changes: 10 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Change Log

## Next Version (not yet released)

##### Additions :tada:

- Added a new `CesiumCameraManager` component. It allows configuration of the cameras to use for Cesium3DTileset culling and level-of-detail.

##### Fixes :wrench:

- Fixed a bug that could cause a `NullReferenceException` when a `Cesium3DTileset` was not nested into a game object with a `CesiumGeoreference`.

## v1.12.0 - 2024-09-02

##### Breaking Changes :mega:
Expand Down
65 changes: 65 additions & 0 deletions Editor/CesiumCameraManagerEditor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using UnityEditor;
using UnityEngine;

namespace CesiumForUnity
{
[CustomEditor(typeof(CesiumCameraManager))]
public class CesiumCameraManagerEditor : Editor
{
private SerializedProperty _useMainCamera;
private SerializedProperty _useActiveSceneViewCameraInEditor;
private SerializedProperty _additionalCameras;

private void OnEnable()
{
this._useMainCamera =
this.serializedObject.FindProperty("_useMainCamera");
this._useActiveSceneViewCameraInEditor =
this.serializedObject.FindProperty("_useSceneViewCameraInEditor");
this._additionalCameras =
this.serializedObject.FindProperty("_additionalCameras");
}

public override void OnInspectorGUI()
{
this.serializedObject.Update();
EditorGUIUtility.labelWidth = CesiumEditorStyle.inspectorLabelWidth;
this.DrawProperties();
this.serializedObject.ApplyModifiedProperties();
}

private static readonly string useMainCameraTooltip = CesiumEditorUtility.FormatTooltip(@"
Whether the camera tagged `MainCamera` should be used for Cesium3DTileset
culling and level-of-detail.");

private static readonly string useActiveSceneViewCameraInEditorTooltip = CesiumEditorUtility.FormatTooltip(@"
Whether the camera associated with the Editor's active scene view should be
used for Cesium3DTileset culling and level-of-detail. In a game, this property has
no effect.");

private static readonly string additionalCamerasTooltip = CesiumEditorUtility.FormatTooltip(@"
Other Cameras to use for Cesium3DTileset culling and level-of-detail, in addition to
the ones controlled by the checkboxes above.
These additional cameras will be used even when they are disabled, which is useful for
creating a virtual camera that affects Cesium3DTileset loading without being used for
rendering.");

private void DrawProperties()
{
GUIContent useMainCameraContent = new GUIContent("Use MainCamera", useMainCameraTooltip);
EditorGUILayout.PropertyField(
this._useMainCamera, useMainCameraContent);

EditorGUI.BeginDisabledGroup(EditorApplication.isPlaying);
GUIContent useActiveSceneViewCameraInEditorContent = new GUIContent("Use Editor Scene View Camera", useActiveSceneViewCameraInEditorTooltip);
EditorGUILayout.PropertyField(
this._useActiveSceneViewCameraInEditor, useActiveSceneViewCameraInEditorContent);
EditorGUI.EndDisabledGroup();

GUIContent additionalCamerasContent = new GUIContent("Additional Cameras", additionalCamerasTooltip);
EditorGUILayout.PropertyField(
this._additionalCameras, additionalCamerasContent);
}
}
}
11 changes: 11 additions & 0 deletions Editor/CesiumCameraManagerEditor.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

105 changes: 105 additions & 0 deletions Runtime/CesiumCameraManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using Reinterop;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using UnityEngine;

namespace CesiumForUnity
{
/// <summary>
/// Manages the set of cameras that are used for Cesium3DTileset culling and level-of-detail.
/// </summary>
[DisallowMultipleComponent]
[AddComponentMenu("Cesium/Cesium Camera Manager")]
[Icon("Packages/com.cesium.unity/Editor/Resources/Cesium-24x24.png")]
public class CesiumCameraManager : MonoBehaviour
{
/// <summary>
/// Gets the instance suitable for use with the given game object.
/// </summary>
/// <remarks>
/// This method looks for an existing instance using `GetComponentInParent`. If it fails to find one, then
/// it will create one. When one is created, it be added to the same `GameObject` that has the
/// `CesiumGeoreference` (found using `GetComponentInParent` again) if there is one. If there is no
/// `CesiumGeoreference`, the instance is added to the originally-provided `GameObject`.
/// </remarks>
/// <param name="gameObject">The game object.</param>
/// <returns></returns>
public static CesiumCameraManager GetOrCreate(GameObject gameObject)
{
if (gameObject == null) throw new ArgumentNullException("gameObject");

CesiumCameraManager result = gameObject.GetComponentInParent<CesiumCameraManager>();
if (result == null)
return CesiumCameraManager.Create(gameObject);
else
return result;
}

private static CesiumCameraManager Create(GameObject gameObject)
{
// Add it to the same game object that has the CesiumGeoreference, if any.
// Otherwise, add it to the current game object.
CesiumGeoreference georeference = gameObject.GetComponentInParent<CesiumGeoreference>();
GameObject owner = georeference == null ? gameObject : georeference.gameObject;
if (owner == null) return null;

return owner.AddComponent<CesiumCameraManager>();
}

#region User-editable properties

[SerializeField]
private bool _useMainCamera = true;

/// <summary>
/// Determines whether the camera tagged `MainCamera` should be used for Cesium3DTileset
/// culling and level-of-detail.
/// </summary>
public bool useMainCamera
{
get => this._useMainCamera;
set
{
this._useMainCamera = value;
}
}

[SerializeField]
private bool _useSceneViewCameraInEditor = true;

/// <summary>
/// Determines whether the camera associated with the Editor's active scene view should be
/// used for Cesium3DTileset culling and level-of-detail. In a game, this property has
/// no effect.
/// </summary>
public bool useSceneViewCameraInEditor
{
get => this._useSceneViewCameraInEditor;
set
{
this._useSceneViewCameraInEditor = value;
}
}

[SerializeField]
private List<Camera> _additionalCameras = new List<Camera>();

/// <summary>
/// Other cameras to use for Cesium3DTileset culling and level-of-detail, in addition
/// to the ones controlled by <see cref="useMainCamera"/> and
/// <see cref="useSceneViewCameraInEditor"/>.
/// </summary>
/// <remarks>
/// These additional cameras will be used even when they are disabled, which is useful for
/// creating a virtual camera that affects Cesium3DTileset loading without being used
/// for rendering.
/// </remarks>
public List<Camera> additionalCameras
{
get => this._additionalCameras;
}

#endregion
}
}
11 changes: 11 additions & 0 deletions Runtime/CesiumCameraManager.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions Runtime/ConfigureReinterop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ internal partial class ConfigureReinterop
public void ExposeToCPP()
{
Camera c = Camera.main;

Transform t = c.transform;
Vector3 u = t.up;
Vector3 f = t.forward;
Expand Down Expand Up @@ -880,6 +881,15 @@ Cesium3DTilesetLoadFailureDetails tilesetDetails
length = float3x3Array.Length;
length = float4x4Array.Length;

CesiumCameraManager manager = CesiumCameraManager.GetOrCreate(go);
manager.useSceneViewCameraInEditor = false;
manager.useMainCamera = false;
Camera camera = null;
for (int i = 0; i < manager.additionalCameras.Count; ++i)
{
camera = manager.additionalCameras[i];
}

#if UNITY_EDITOR
SceneView sv = SceneView.lastActiveSceneView;
sv.pivot = sv.pivot;
Expand Down
90 changes: 74 additions & 16 deletions native~/Runtime/src/CameraManager.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
#include "CameraManager.h"

#include "Cesium3DTilesetImpl.h"
#include "CesiumGeoreferenceImpl.h"
#include "UnityTransforms.h"

#include <CesiumGeospatial/Ellipsoid.h>
#include <CesiumGeospatial/GlobeTransforms.h>
#include <CesiumUtility/Math.h>

#include <DotNet/CesiumForUnity/Cesium3DTileset.h>
#include <DotNet/CesiumForUnity/CesiumEllipsoid.h>
#include <DotNet/CesiumForUnity/CesiumGeoreference.h>
#include <DotNet/System/Collections/Generic/List1.h>
#include <DotNet/UnityEngine/Camera.h>
#include <DotNet/UnityEngine/GameObject.h>
#include <DotNet/UnityEngine/Matrix4x4.h>
Expand All @@ -26,6 +29,7 @@ using namespace CesiumGeospatial;
using namespace CesiumUtility;
using namespace DotNet::UnityEngine;
using namespace DotNet::CesiumForUnity;
using namespace DotNet;

#if UNITY_EDITOR
using namespace DotNet::UnityEditor;
Expand All @@ -39,7 +43,7 @@ ViewState unityCameraToViewState(
const CesiumGeoreference& georeference,
const LocalHorizontalCoordinateSystem* pCoordinateSystem,
const glm::dmat4& unityWorldToTileset,
Camera& camera) {
const Camera& camera) {
Transform transform = camera.transform();

Vector3 cameraPositionUnity = transform.position();
Expand Down Expand Up @@ -90,22 +94,13 @@ ViewState unityCameraToViewState(

} // namespace

std::vector<ViewState> CameraManager::getAllCameras(const GameObject& context) {
const LocalHorizontalCoordinateSystem* pCoordinateSystem = nullptr;

glm::dmat4 unityWorldToTileset =
UnityTransforms::fromUnity(context.transform().worldToLocalMatrix());

CesiumGeoreference georeferenceComponent =
context.GetComponentInParent<CesiumGeoreference>();
if (georeferenceComponent != nullptr) {
CesiumGeoreferenceImpl& georeference =
georeferenceComponent.NativeImplementation();
pCoordinateSystem =
&georeference.getCoordinateSystem(georeferenceComponent);
}
namespace {

std::vector<ViewState> result;
void addMainCamera(
std::vector<ViewState>& result,
const CesiumGeoreference& georeferenceComponent,
const CesiumGeospatial::LocalHorizontalCoordinateSystem* pCoordinateSystem,
const glm::dmat4& unityWorldToTileset) {
Camera camera = Camera::main();
if (camera != nullptr) {
result.emplace_back(unityCameraToViewState(
Expand All @@ -114,7 +109,13 @@ std::vector<ViewState> CameraManager::getAllCameras(const GameObject& context) {
unityWorldToTileset,
camera));
}
}

void addActiveSceneCameraInEditor(
std::vector<ViewState>& result,
const CesiumGeoreference& georeferenceComponent,
const CesiumGeospatial::LocalHorizontalCoordinateSystem* pCoordinateSystem,
const glm::dmat4& unityWorldToTileset) {
#if UNITY_EDITOR
if (!EditorApplication::isPlaying()) {
SceneView lastActiveEditorView = SceneView::lastActiveSceneView();
Expand All @@ -130,6 +131,63 @@ std::vector<ViewState> CameraManager::getAllCameras(const GameObject& context) {
}
}
#endif
}

} // namespace

/*static*/ std::vector<Cesium3DTilesSelection::ViewState>
CameraManager::getAllCameras(
const DotNet::CesiumForUnity::Cesium3DTileset& tileset,
const CesiumForUnityNative::Cesium3DTilesetImpl& impl) {
const LocalHorizontalCoordinateSystem* pCoordinateSystem = nullptr;

glm::dmat4 unityWorldToTileset =
UnityTransforms::fromUnity(tileset.transform().worldToLocalMatrix());

CesiumGeoreference georeferenceComponent =
tileset.gameObject().GetComponentInParent<CesiumGeoreference>();
if (georeferenceComponent != nullptr) {
CesiumGeoreferenceImpl& georeference =
georeferenceComponent.NativeImplementation();
pCoordinateSystem =
&georeference.getCoordinateSystem(georeferenceComponent);
}

std::vector<ViewState> result;

const CesiumCameraManager& cameraManager = impl.getCameraManager();

if (cameraManager == nullptr || cameraManager.useMainCamera()) {
addMainCamera(
result,
georeferenceComponent,
pCoordinateSystem,
unityWorldToTileset);
}

if (cameraManager == nullptr || cameraManager.useSceneViewCameraInEditor()) {
addActiveSceneCameraInEditor(
result,
georeferenceComponent,
pCoordinateSystem,
unityWorldToTileset);
}

if (cameraManager != nullptr) {
System::Collections::Generic::List1<Camera> cameras =
cameraManager.additionalCameras();
for (int32_t i = 0, len = cameras.Count(); i < len; ++i) {
Camera camera = cameras[i];
if (camera == nullptr)
continue;

result.emplace_back(unityCameraToViewState(
georeferenceComponent,
pCoordinateSystem,
unityWorldToTileset,
camera));
}
}

return result;
}
Expand Down
Loading

0 comments on commit 3837e0d

Please sign in to comment.