I'm trying to rotate the camera in Preview Render Utility around a cube. The following code does seem to be able to do this, but it never seems to be able to update the image while the user is in a mouse drag.
Is there any way to have the image update in real-time? Rather than delayed after a mouse drag.
This example is completely self-contained so if you create a MyEditor file in an Editor folder it should be possible to reproduce the problem I'm having.
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace Editor
{
public class MyEditor : EditorWindow
{
private const int ImageSize = 256;
private const float CameraDistance = 10f;
private static readonly Rect ImageDimension = new(0, 0, ImageSize, ImageSize);
private static readonly Vector3 DefaultCameraPosition = new(0, CameraDistance, 0);
private static Vector3 RotateAroundPivot(Vector3 point, Vector3 pivot, Vector3 angles)
{
return Quaternion.Euler(angles.y, -angles.x, 0) * (point -pivot) + pivot;
}
[MenuItem("Custom/My Editor")]
public static void Popup()
{
MyEditor editor = GetWindow<MyEditor>();
editor.titleContent = new GUIContent("My Custom Editor");
}
private PreviewRenderUtility _previewUtility;
private Image _image;
private bool _mouseIsDown;
private Vector3 _previousMousePosition;
private Vector3 _totalRotation;
public void OnEnable()
{
// setup basic Preview Render Utility
_previewUtility ??= new PreviewRenderUtility();
_previewUtility.camera.farClipPlane *= 2;
Transform transform = _previewUtility.camera.transform;
transform.position = DefaultCameraPosition;
transform.LookAt(Vector3.zero);
// Add the cube to the scene
GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
obj.transform.localScale = new Vector3(0.1f,0.1f,0.1f);
_previewUtility.AddSingleGO(obj);
}
public void OnDisable()
{
if (_previewUtility is not null)
{
_previewUtility.Cleanup();
_previewUtility = null;
}
}
private void CreateGUI()
{
// Create Image
_image = new Image();
rootVisualElement.Add(_image);
// Setup Mouse Handlers for image
// note image should be focusable for image to receive all event types
_image.RegisterCallback<PointerDownEvent>(OnPointerDownHandler);
_image.RegisterCallback<PointerMoveEvent>(OnPointerMoveHandler);
_image.RegisterCallback<PointerUpEvent>(OnPointerUpHandler);
// create and assign Render Texture to Image
_previewUtility.BeginPreview(ImageDimension, GUIStyle.none);
_previewUtility.camera.Render();
_image.image = _previewUtility.EndPreview();
}
private void OnPointerDownHandler(PointerDownEvent evt)
{
// start dragging
_mouseIsDown = true;
_previousMousePosition = evt.position;
}
private void OnPointerMoveHandler(PointerMoveEvent evt)
{
// If the mouse is not down do nothing
if (!_mouseIsDown)
{
return;
}
// Calculate delta and add it to the total rotation
Vector3 delta = evt.position - _previousMousePosition;
_previousMousePosition = evt.position;
_totalRotation += delta;
// pivot camera around (0, 0, 0)
_previewUtility.camera.transform.position = RotateAroundPivot(DefaultCameraPosition, Vector3.zero, _totalRotation);
_previewUtility.camera.transform.LookAt(Vector3.zero);
// Render new camera location - seems to lag
_previewUtility.BeginPreview(ImageDimension, GUIStyle.none);
_previewUtility.camera.Render();
_previewUtility.EndAndDrawPreview(ImageDimension);
}
private void OnPointerUpHandler(PointerUpEvent evt)
{
_mouseIsDown = false;
}
}
}