Skip to content

Commit

Permalink
[HDRP][Compositor] Fix edge cases when cameras are missing or deleted (
Browse files Browse the repository at this point in the history
…#2700)

* Fix warning spam related to cameras in compositor

* Fix null reference in AOVs

* Fix null reference when disabling camera in the compositor

* Reset target texture when disabling the compositor

* Update changelog + fix warning when output camera is deleted

* Fix issue when adding image layer without any cameras in the scene

* Fix error when disabling layer with no camera

Co-authored-by: sebastienlagarde <sebastien@unity3d.com>
  • Loading branch information
pmavridis and sebastienlagarde committed Nov 23, 2020
1 parent 29e7594 commit 4ace2cf
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 35 deletions.
1 change: 1 addition & 0 deletions com.unity.render-pipelines.high-definition/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Fixed NullReferenceException when loading multipel scene async
- Fixed missing alpha blend state properties in Axf shader and update default stencil properties
- Fixed normal buffer not bound to custom pass anymore.
- Fixed issues with camera management in the graphics compositor (cases 1292548, 1292549).

## [10.2.0] - 2020-10-19

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,10 @@ public float aspectRatio
{
get
{
if (m_Camera != null)
var compositor = CompositionManager.GetInstance();
if (compositor != null && compositor.outputCamera != null)
{
return (float)m_Camera.pixelWidth / m_Camera.pixelHeight;
return (float)compositor.outputCamera.pixelWidth / compositor.outputCamera.pixelHeight;
}
return 1.0f;
}
Expand Down Expand Up @@ -158,6 +159,9 @@ public static CompositorLayer CreateStackLayer(LayerType type = CompositorLayer.

if (newLayer.m_Type == LayerType.Image || newLayer.m_Type == LayerType.Video)
{
if (newLayer.m_Camera == null)
newLayer.m_Camera = CompositionManager.CreateCamera(layerName);

// Image and movie layers do not render any 3D objects
newLayer.m_OverrideCullingMask = true;
newLayer.m_CullingMask = 0;
Expand Down Expand Up @@ -200,10 +204,11 @@ public int pixelWidth
{
get
{
if (m_Camera)
var compositor = CompositionManager.GetInstance();
if (compositor && compositor.outputCamera)
{
float resScale = EnumToScale(m_ResolutionScale);
return (int)(resScale * m_Camera.pixelWidth);
return (int)(resScale * compositor.outputCamera.pixelWidth);
}
return 0;
}
Expand All @@ -212,10 +217,11 @@ public int pixelHeight
{
get
{
if (m_Camera)
var compositor = CompositionManager.GetInstance();
if (compositor && compositor.outputCamera)
{
float resScale = EnumToScale(m_ResolutionScale);
return (int)(resScale * m_Camera.pixelHeight);
return (int)(resScale * compositor.outputCamera.pixelHeight);
}
return 0;
}
Expand All @@ -227,13 +233,6 @@ public void Init(string layerID = "")
m_LayerName = layerID;
}

// Compositor output layers (that allocate the render targets) also need a reference camera, just to get the reference pixel width/height
// Note: Movie & image layers are rendered at the output resolution (and not the movie/image resolution). This is required to have post-processing effects like film grain at full res.
if (m_Camera == null)
{
m_Camera = CompositionManager.GetSceneCamera();
}

var compositor = CompositionManager.GetInstance();

// Create a new camera if necessary or use the one specified by the user
Expand All @@ -244,7 +243,7 @@ public void Init(string layerID = "")
// - is not shared between layers
// - is not used in an mage/video layer (in this case the camera is not exposed at all, so it makes sense to let the compositor manage it)
// - it does not force-clear the RT (the first layer of a stack, even if disabled by the user), still clears the RT
bool shouldClear = !enabled && m_LayerPositionInStack == 0;
bool shouldClear = !enabled && m_LayerPositionInStack == 0 && m_Camera;
bool isImageOrVideo = (m_Type == LayerType.Image || m_Type == LayerType.Video);
if (!isImageOrVideo && !hasLayerOverrides && !shouldClear && !compositor.IsThisCameraShared(m_Camera))
{
Expand Down Expand Up @@ -527,14 +526,17 @@ internal void CopyInternalCameraData()

// Copy/update the camera data (but preserve the camera depth/draw-order [case 1264552])
var drawOrder = m_LayerCamera.depth;
m_LayerCamera.CopyFrom(m_Camera);
m_LayerCamera.depth = drawOrder;

var cameraDataOrig = m_Camera.GetComponent<HDAdditionalCameraData>();
var cameraData = m_LayerCamera.GetComponent<HDAdditionalCameraData>();
if (cameraDataOrig)
if (m_Camera)
{
cameraDataOrig.CopyTo(cameraData);
m_LayerCamera.CopyFrom(m_Camera);
m_LayerCamera.depth = drawOrder;

var cameraDataOrig = m_Camera.GetComponent<HDAdditionalCameraData>();
var cameraData = m_LayerCamera.GetComponent<HDAdditionalCameraData>();
if (cameraDataOrig)
{
cameraDataOrig.CopyTo(cameraData);
}
}
}

Expand Down Expand Up @@ -606,15 +608,18 @@ public bool ValidateRTSize(int referenceWidth, int referenceHeight)

public void SetupClearColor()
{
m_LayerCamera.enabled = true;
m_LayerCamera.cullingMask = 0;
var cameraData = m_LayerCamera.GetComponent<HDAdditionalCameraData>();
var cameraDataOrig = m_Camera.GetComponent<HDAdditionalCameraData>();
if (m_LayerCamera && m_Camera)
{
m_LayerCamera.enabled = true;
m_LayerCamera.cullingMask = 0;
var cameraData = m_LayerCamera.GetComponent<HDAdditionalCameraData>();
var cameraDataOrig = m_Camera.GetComponent<HDAdditionalCameraData>();

cameraData.clearColorMode = cameraDataOrig.clearColorMode;
cameraData.clearDepth = true;
cameraData.clearColorMode = cameraDataOrig.clearColorMode;
cameraData.clearDepth = true;

m_ClearsBackGround = true;
m_ClearsBackGround = true;
}
}

public void AddInputFilter(CompositionFilter filter)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ public bool enableOutput
{
layer.camera.enabled = value;
}
else
{
// The target texture was managed by the compositor, reset it so the user can se the camera output
if (layer.camera && value == false)
layer.camera.targetTexture = null;
}
}
}
}
Expand Down Expand Up @@ -107,9 +113,9 @@ public float aspectRatio
{
get
{
if (m_InputLayers.Count > 0)
if (m_OutputCamera)
{
return m_InputLayers[0].aspectRatio;
return (float)m_OutputCamera.pixelWidth / m_OutputCamera.pixelHeight;
}
return 1.0f;
}
Expand Down Expand Up @@ -257,7 +263,6 @@ bool ValidateAndFixRuntime()
{
if (m_OutputCamera == null)
{
Debug.Log("No camera was found");
return false;
}

Expand Down Expand Up @@ -434,10 +439,13 @@ public void SetupLayerPriorities()
public void OnAfterAssemblyReload()
{
// Bug? : After assembly reload, the customRender callback is dropped, so set it again
var cameraData = m_OutputCamera.GetComponent<HDAdditionalCameraData>();
if (cameraData && !cameraData.hasCustomRender)
if (m_OutputCamera)
{
cameraData.customRender += CustomRender;
var cameraData = m_OutputCamera.GetComponent<HDAdditionalCameraData>();
if (cameraData && !cameraData.hasCustomRender)
{
cameraData.customRender += CustomRender;
}
}
}

Expand Down Expand Up @@ -837,10 +845,22 @@ static public Camera GetSceneCamera()
return camera;
}
}
Debug.LogWarning("Camera not found");

return null;
}

static public Camera CreateCamera(string cameraName)
{
var newCameraGameObject = new GameObject(cameraName)
{
hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy | HideFlags.HideAndDontSave
};
var newCamera = newCameraGameObject.AddComponent<Camera>();
newCameraGameObject.AddComponent<HDAdditionalCameraData>();

return newCamera;
}

static public CompositionManager GetInstance() =>
s_CompositorInstance ?? (s_CompositorInstance = GameObject.FindObjectOfType(typeof(CompositionManager), true) as CompositionManager);

Expand Down

0 comments on commit 4ace2cf

Please sign in to comment.