Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
## [3.0.4] - 2024-05-22
### Changed
- Prevent Unity from throwing an exception when using the file explorer to change the output file path in a recorder preset.
- Disallow `ActiveCamera` from being selected with SRP-based projects as a camera source.
- Display an error message and prevent Recorder from starting if MainCamera is selected while the main camera is missing from the project.
- Better handle error messages when using a Tagged Camera while the tag is missing from the project or not assigned to the camera.

### Fixed
- Ensure that camera's rotation is retained when recording monoscopic 360 views.
- Ensure an alpha channel is added when the Editor targets a mobile platform.
  • Loading branch information
Unity Technologies committed May 22, 2024
1 parent d8e5193 commit e73d4c3
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 62 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ All notable changes to this package will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.0.4] - 2024-05-22
### Changed
- Prevent Unity from throwing an exception when using the file explorer to change the output file path in a recorder preset.
- Disallow `ActiveCamera` from being selected with SRP-based projects as a camera source.
- Display an error message and prevent Recorder from starting if MainCamera is selected while the main camera is missing from the project.
- Better handle error messages when using a Tagged Camera while the tag is missing from the project or not assigned to the camera.

### Fixed
- Ensure that camera's rotation is retained when recording monoscopic 360 views.
- Ensure an alpha channel is added when the Editor targets a mobile platform.

## [3.0.3] - 2021-11-08
### Added
Expand Down
3 changes: 3 additions & 0 deletions Documentation~/InclCaptureOptionsTargetedCamera.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
These properties appear when you set **Source** to **Targeted Camera**.

>[!NOTE]
>* You can't capture images from a Targeted Camera if you are using a URP 2D Renderer, due to a [known limitation](KnownIssues.md#targeted-camera-recording-is-not-available-with-urp-2d-renderer). As an alternative, you can capture from the Game View or from a Render Texture Asset.
![](Images/CaptureOptionsTargetedCamera.png)

|Property||Function|
Expand Down
26 changes: 26 additions & 0 deletions Documentation~/KnownIssues.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ This page lists some known issues and limitations that you might experience with

**Workaround:** The recommended use case is to limit yourself to one Movie recording at a time. Ensure that you have only one active Movie Recorder in the Recorder window and no Movie Recorder Clips in Timeline, or vice-versa. If you need to keep concurrent recordings for some reason, you can still set up lower resolutions or try different encoders (for instance, the MP4 encoding step is much faster than the ProRes one).

#### Targeted Camera recording is not available with URP 2D Renderer
**Limitation:** Recorder cannot capture images from a Targeted Camera in URP 2D projects. A capture pass that Recorder requires is missing in the renderer.

**Workaround:** As an alternative, you can capture from the Game View or from a Render Texture Asset.

#### ActiveCamera recording not available with SRPs

**Limitation:** The use of a Scriptable Render Pipeline ([SRP](https://docs.unity3d.com/Manual/ScriptableRenderPipeline.html)) in your project prevents you from setting ActiveCamera as the source of the recording in the [Movie Recorder](RecorderMovie.md#targeted-camera-source-properties) and the [Image Sequence Recorder](RecorderImage.md#targeted-camera-source-properties). This render pipeline limitation applies to all SRPs including Unity's High Definition Render Pipeline ([HDRP](https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@latest)) and Universal Render Pipeline ([URP](https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@latest)). For the same reason, the [AOV Recorder](RecorderAOV.md#source-camera), which requires HDRP, doesn't include the ActiveCamera option by design.
Expand Down Expand Up @@ -36,6 +41,14 @@ This page lists some known issues and limitations that you might experience with

**Workaround:** If you need to record a Beauty pass with TAA enabled on your recording camera, you should record it through its own recording session, separately from any other AOVs.

#### Recorder does not capture any custom cursors

**Known issue:** When you record a video where you use a custom cursor set with [Cursor.SetCursor](https://docs.unity3d.com/ScriptReference/Cursor.SetCursor.html), the cursor doesn't appear in the recordings.

**Workaround:** To make sure that the Recorder captures your custom cursor, you have to:
- Set the **Input Source** to **GameView**.
- Call `Cursor.SetCursor` with [`CursorMode.ForceSoftware`](https://docs.unity3d.com/ScriptReference/CursorMode.ForceSoftware.html).

<a name="360-view"></a>
#### 360 View recording issues and limitations

Expand All @@ -46,3 +59,16 @@ The Recorder doesn't fully support 360 View recording. Here is a list of known i
* If you record a 360 View through a Physical Camera, the rendered image is not equirectangular, which makes the output media unusable. To work around the issue, use a regular Camera for the recording.

* The Recorder doesn't support stereoscopic recording in projects that use any Scriptable Render Pipelines (SRPs). The **Stereo Separation** property has no effect on the recorded views, which makes the rendering identical for both eyes.

#### Different Cameras with different Display targets lead to black output

**Known issue:** Certain camera outputs are black when cameras have different TargetDisplays. This occurs when you set up recorders with **Targeted Camera** as the **Input Source**.
The Game view triggers the render loop of all cameras that target the same Display number. If no Game view is configured for a specific Display number that is set on a Camera, it does not render.

**Workaround:** Open another Game view and set it to the Display number that you need to capture.

#### Impossible to capture multiple Game views at the same time

**Known issue:** Recorder does not handle a configuration with mutiple Game views as **Input Source**. Recorder assumes that there is only one Game view and gets the one that has the focus at the moment the Editor enters the Play Mode.

**Workaround:** Set the **Input Source** to **Targeted Camera** or **Render Texture Asset**.
69 changes: 33 additions & 36 deletions Editor/Sources/OutputPathDrawer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,36 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten
var fullPath = OutputPath.GetFullPath((OutputPath.Root)m_RootProperty.intValue, m_LeafProperty.stringValue,
m_AbsolutePathProperty.stringValue);

if (!target.forceAssetsFolder)
var tooltip = "Select the output location through your file browser";
var folder = fullPath;

if (target.forceAssetsFolder)
{
tooltip = "Select the output location in Unity Assets through your file browser";
folder = Application.dataPath;
}

var folderPanelBtnClicked = GUI.Button(btnRect, new GUIContent("...", tooltip));

if (pathType == OutputPath.Root.Absolute && m_AbsolutePathProperty.stringValue == "")
{
// Empty absolute path: force absolute path root to the first drive found
m_AbsolutePathProperty.stringValue = DriveInfo.GetDrives().First().RootDirectory.FullName;
}

EditorGUI.indentLevel = indent;
EditorGUI.EndProperty();

if (folderPanelBtnClicked)
{
if (GUI.Button(btnRect, new GUIContent("...", "Select the output location through your file browser")))
var newPath = EditorUtility.OpenFolderPanel("Select output location", folder, "");
if (!string.IsNullOrEmpty(newPath))
{
var newPath = EditorUtility.OpenFolderPanel("Select output location", fullPath, "");
if (!string.IsNullOrEmpty(newPath))
if (target.forceAssetsFolder && !newPath.Contains(Application.dataPath))
EditorUtility.DisplayDialog("Invalid Path",
"Selected path " + newPath + " must be in the Unity Assets directory",
"Ok");
else
{
var newValue = OutputPath.FromPath(newPath);
m_RootProperty.intValue = (int)newValue.root;
Expand All @@ -70,40 +94,13 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten
m_LeafProperty.stringValue = newValue.leaf;
}
}
}
else
{
if (GUI.Button(btnRect, new GUIContent("...", "Select the output location in Unity Assets through your file browser")))
{
var newPath = EditorUtility.OpenFolderPanel("Select output location",
Application.dataPath, "");
if (!string.IsNullOrEmpty(newPath))
{
if (!newPath.Contains(Application.dataPath))
EditorUtility.DisplayDialog("Invalid Path",
"Selected path " + newPath + " must be in the Unity Assets directory",
"Ok");
else
{
var newValue = OutputPath.FromPath(newPath);
m_RootProperty.intValue = (int)newValue.root;
if (newValue.root == OutputPath.Root.Absolute)
m_AbsolutePathProperty.stringValue = newValue.leaf;
else
m_LeafProperty.stringValue = newValue.leaf;
}
}
}
}

if (pathType == OutputPath.Root.Absolute && m_AbsolutePathProperty.stringValue == "")
{
// Empty absolute path: force absolute path root to the first drive found
m_AbsolutePathProperty.stringValue = DriveInfo.GetDrives().First().RootDirectory.FullName;
}
m_RootProperty.serializedObject.ApplyModifiedProperties();
m_AbsolutePathProperty.serializedObject.ApplyModifiedProperties();
m_LeafProperty.serializedObject.ApplyModifiedProperties();

EditorGUI.indentLevel = indent;
EditorGUI.EndProperty();
GUIUtility.ExitGUI();
}
}
}
}
18 changes: 5 additions & 13 deletions Editor/Sources/Recorders/_Inputs/Camera/CameraInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -298,21 +298,13 @@ protected internal override void NewFrameStarting(RecordingSession session)
{
var tag = ((CameraInputSettings)settings).CameraTag;

try
{
var objs = GameObject.FindGameObjectsWithTag(tag);
var objs = GameObject.FindGameObjectsWithTag(tag);

var cams = objs.Select(obj => obj.GetComponent<Camera>()).Where(c => c != null);
if (cams.Count() > 1)
Debug.LogWarning("More than one camera has the requested target tag '" + tag + "'");
var cams = objs.Select(obj => obj.GetComponent<Camera>()).Where(c => c != null);
if (cams.Count() > 1)
Debug.LogWarning("More than one camera has the requested target tag '" + tag + "'");

TargetCamera = cams.FirstOrDefault();
}
catch (UnityException)
{
Debug.LogWarning("No camera has the requested target tag '" + tag + "'");
TargetCamera = null;
}
TargetCamera = cams.FirstOrDefault();

break;
}
Expand Down
34 changes: 32 additions & 2 deletions Editor/Sources/Recorders/_Inputs/Camera/CameraInputSettings.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using UnityEngine;
using UnityEngine.Rendering;

Expand All @@ -13,6 +14,8 @@ namespace UnityEditor.Recorder.Input
[Serializable]
public class CameraInputSettings : StandardImageInputSettings
{
internal const string k_UnsupportedCameraSourceError = "ActiveCamera is only compatible with the Legacy Render Pipeline.";

/// <summary>
/// Indicates the Camera input type.
/// </summary>
Expand Down Expand Up @@ -73,8 +76,35 @@ protected internal override Type InputType
protected internal override void CheckForErrors(List<string> errors)
{
base.CheckForErrors(errors);
if (Source == ImageSource.TaggedCamera && string.IsNullOrEmpty(CameraTag))
errors.Add("Missing tag for camera selection");

if (Source == ImageSource.TaggedCamera)
{
if (string.IsNullOrEmpty(CameraTag))
errors.Add("Missing tag for camera selection");
else
{
try
{
var objs = GameObject.FindGameObjectsWithTag(CameraTag);
var cams = objs.Select(obj => obj.GetComponent<Camera>()).Where(c => c != null);

if (cams.Count() == 0)
errors.Add("No camera has the requested target tag '" + CameraTag + "'");
}
catch (UnityException)
{
errors.Add("The requested target tag '" + CameraTag + "' does not exist in the project");
}
}
}
else if (Source == ImageSource.MainCamera && Camera.main == null)
{
errors.Add("There is no MainCamera in the project");
}
else if (Source == ImageSource.ActiveCamera && !UnityHelpers.UsingLegacyRP())
{
errors.Add(k_UnsupportedCameraSourceError);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten
{
--EditorGUI.indentLevel;
Initialize(property);
if (UnityHelpers.UsingHDRP())
if (!UnityHelpers.UsingLegacyRP())
{
m_SupportedSources = ImageSource.MainCamera | ImageSource.TaggedCamera;
}
Expand Down
3 changes: 2 additions & 1 deletion Editor/Sources/Recorders/_Inputs/Camera360/Camera360Input.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ protected internal override void NewFrameReady(RecordingSession session)
}
else
{
targetCamera.RenderToCubemap(m_Cubemap1, 63, Camera.MonoOrStereoscopicEye.Mono);
targetCamera.stereoSeparation = 0;
targetCamera.RenderToCubemap(m_Cubemap1, 63, Camera.MonoOrStereoscopicEye.Left);
m_Cubemap1.ConvertToEquirect(OutputRenderTexture);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ class RenderTextureSampler : BaseRenderTextureInput
Material m_accumulateMaterial;
Material m_normalizeMaterial;

RenderTextureFormat m_InternalGraphicsFormat;
RenderTextureReadWrite m_InternalGraphicsReadWrite;

class HookedCamera
{
public Camera camera;
Expand Down Expand Up @@ -163,20 +166,31 @@ protected internal override void BeginRecording(RecordingSession session)

m_normalizeMaterial = new Material(normalizeShader) { hideFlags = HideFlags.DontSave };

m_renderRT = new RenderTexture(m_renderWidth, m_renderHeight, 24, RenderTextureFormat.DefaultHDR,
RenderTextureReadWrite.Linear) { wrapMode = TextureWrapMode.Clamp };
m_InternalGraphicsReadWrite = RenderTextureReadWrite.sRGB;
m_InternalGraphicsFormat = RenderTextureFormat.ARGBHalf;
ImageRecorderSettings s = session.settings as ImageRecorderSettings;
if (s != null && s.CanCaptureHDRFrames() && s.CaptureHDR)
{
m_InternalGraphicsReadWrite = RenderTextureReadWrite.Linear;
m_InternalGraphicsFormat = RenderTextureFormat.DefaultHDR;
}

m_renderRT = new RenderTexture(m_renderWidth, m_renderHeight, 24, m_InternalGraphicsFormat, m_InternalGraphicsReadWrite)
{
wrapMode = TextureWrapMode.Clamp
};

for (int i = 0; i < 2; ++i)
{
m_accumulateRTs[i] = new RenderTexture(m_renderWidth, m_renderHeight, 0, RenderTextureFormat.DefaultHDR, RenderTextureReadWrite.Linear)
m_accumulateRTs[i] = new RenderTexture(m_renderWidth, m_renderHeight, 0, m_InternalGraphicsFormat, m_InternalGraphicsReadWrite)
{
wrapMode = TextureWrapMode.Clamp
};

m_accumulateRTs[i].Create();
}

var rt = new RenderTexture(OutputWidth, OutputHeight, 0, RenderTextureFormat.DefaultHDR, RenderTextureReadWrite.Linear);
var rt = new RenderTexture(OutputWidth, OutputHeight, 0, m_InternalGraphicsFormat, m_InternalGraphicsReadWrite);
rt.Create();
OutputRenderTexture = rt;
m_samples = new Vector2[(int)rtsSettings.SuperSampling];
Expand Down Expand Up @@ -213,7 +227,7 @@ protected internal override void NewFrameStarting(RecordingSession session)
continue;

hookedCam = new HookedCamera() { camera = cam, textureBackup = cam.targetTexture };
var camRT = new RenderTexture((int)(m_renderWidth * cam.rect.width), (int)(m_renderHeight * cam.rect.height), 24, RenderTextureFormat.DefaultHDR, RenderTextureReadWrite.Linear);
var camRT = new RenderTexture((int)(m_renderWidth * cam.rect.width), (int)(m_renderHeight * cam.rect.height), 24, m_InternalGraphicsFormat, m_InternalGraphicsReadWrite);
cam.targetTexture = camRT;
m_hookedCameras.Add(hookedCam);
sort = true;
Expand Down
12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "com.unity.recorder",
"displayName": "Recorder",
"version": "3.0.3",
"version": "3.0.4",
"unity": "2019.4",
"unityRelease": "1f1",
"dependencies": {
Expand All @@ -23,15 +23,19 @@
"layer"
],
"relatedPackages": {
"com.unity.recorder.tests": "3.0.3"
"com.unity.recorder.tests": "3.0.4"
},
"_upm": {
"changelog": "### Changed\n- Prevent Unity from throwing an exception when using the file explorer to change the output file path in a recorder preset.\n- Disallow `ActiveCamera` from being selected with SRP-based projects as a camera source.\n- Display an error message and prevent Recorder from starting if MainCamera is selected while the main camera is missing from the project.\n- Better handle error messages when using a Tagged Camera while the tag is missing from the project or not assigned to the camera.\n\n### Fixed\n- Ensure that camera's rotation is retained when recording monoscopic 360 views.\n- Ensure an alpha channel is added when the Editor targets a mobile platform."
},
"upmCi": {
"footprint": "9aa807f7e2d8b874343dfcb9574166ea011e5327"
"footprint": "f528a67a783618bb1d186559abc2aef4e9e6bbd5"
},
"documentationUrl": "https://docs.unity3d.com/Packages/[email protected]/manual/index.html",
"repository": {
"url": "https://github.cds.internal.unity3d.com/unity/com.unity.recorder.git",
"type": "git",
"revision": "52d2b7e77e6832f279e4de2172226475c5465729"
"revision": "4c9f2aee426214deb37c7d9defbdbed235e3f3c1"
},
"samples": [
{
Expand Down

0 comments on commit e73d4c3

Please sign in to comment.