Skip to content

Commit

Permalink
close #115; UIEffectCapturedImage: Supports 'ScreenSpace - Overlay'
Browse files Browse the repository at this point in the history
  • Loading branch information
mob-sakai committed Aug 14, 2018
1 parent 65166ec commit 7fe79bb
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -125,24 +125,28 @@ public override void OnInspectorGUI()
GUILayout.Label("Debug");

if (GUILayout.Button("Capture", "ButtonLeft"))
UpdateTexture(true);
{
graphic.Release();
EditorApplication.delayCall += graphic.Capture;
}

EditorGUI.BeginDisabledGroup(!(target as UIEffectCapturedImage).capturedTexture);
if (GUILayout.Button("Release", "ButtonRight"))
UpdateTexture(false);
{
graphic.Release();
}
EditorGUI.EndDisabledGroup();
}

// Warning message for overlay rendering.
var graphic = (target as UIEffectCapturedImage);
if(graphic && graphic.canvas)
{
var canvas = graphic.canvas.rootCanvas;
if( canvas && canvas.renderMode != RenderMode.ScreenSpaceCamera)
if( canvas && canvas.renderMode == RenderMode.WorldSpace)
{
using (new GUILayout.HorizontalScope())
{
EditorGUILayout.HelpBox("'ScreenSpace - Overlay' and 'WorldSpace - Camera' render modes are not supported. Change render mode of root canvas to 'ScreenSpace - Camera'.", MessageType.Warning);
EditorGUILayout.HelpBox("'WorldSpace - Camera' render modes is not supported. Change render mode of root canvas.", MessageType.Warning);
if (GUILayout.Button("Canvas"))
{
Selection.activeGameObject = canvas.gameObject;
Expand Down Expand Up @@ -210,20 +214,5 @@ void DrawDesamplingRate(SerializedProperty sp)
GUILayout.Label(string.Format("{0}x{1}", w, h), EditorStyles.miniLabel);
}
}

/// <summary>
/// Updates the texture.
/// </summary>
void UpdateTexture(bool capture)
{
var current = target as UIEffectCapturedImage;
bool enable = current.enabled;
current.enabled = false;
current.Release();
if (capture)
current.Capture();

EditorApplication.delayCall += () => current.enabled = enable;
}
}
}
238 changes: 167 additions & 71 deletions Assets/Coffee/UIExtensions/UIEffect/Scripts/UIEffectCapturedImage.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections;
using System.Linq;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.Rendering;
Expand Down Expand Up @@ -110,7 +111,7 @@ public enum DesamplingRate
/// Captured texture.
/// </summary>
public RenderTexture capturedTexture { get { return m_TargetTexture ? m_TargetTexture : _rt; } }

/// <summary>
/// Blur iterations.
/// </summary>
Expand Down Expand Up @@ -185,6 +186,16 @@ public void GetDesamplingSize(DesamplingRate rate, out int w, out int h)
/// </summary>
public void Capture()
{
var rootCanvas = canvas.rootCanvas;
if (m_KeepCanvasSize)
{
var rootTransform = rootCanvas.transform as RectTransform;
var size = rootTransform.rect.size;
rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.x);
rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.y);
rectTransform.position = rootTransform.position;
}

// Camera for command buffer.
_camera = canvas.worldCamera ?? Camera.main;

Expand Down Expand Up @@ -224,82 +235,129 @@ public void Capture()
_rt.hideFlags = HideFlags.HideAndDontSave;
}
}
SetupCommandBuffer();
}

void SetupCommandBuffer()
{
if (_buffer != null)
{
return;
}

bool isOverlay = canvas.rootCanvas.renderMode == RenderMode.ScreenSpaceOverlay;
int w, h;
GetDesamplingSize(m_DesamplingRate, out w, out h);

var rtId = new RenderTargetIdentifier(m_TargetTexture ? m_TargetTexture : _rt);

// Material for effect.
Material mat = effectMaterial;

// Create command buffer.
if (_buffer == null)
_buffer = new CommandBuffer();
_buffer.name = mat ? mat.name : "noeffect";
if (_rt)
{
var rtId = new RenderTargetIdentifier(m_TargetTexture ? m_TargetTexture : _rt);
_rt.name = _buffer.name;
}

// Copy to temporary RT.
_buffer.GetTemporaryRT(s_CopyId, -1, -1, 0, m_FilterMode);

// Material for effect.
Material mat = effectMaterial;
if (isOverlay)
{
if (!s_renderedResult)
{
s_renderedResult = new Texture2D(Screen.width, Screen.height, TextureFormat.ARGB32, false, false);
s_renderedResult.filterMode = FilterMode.Point;
}
else if (s_renderedResult.width != Screen.width || s_renderedResult.height != Screen.height)
{
s_renderedResult.Resize(Screen.width, Screen.height, TextureFormat.ARGB32, false);
}

_buffer = new CommandBuffer();
_buffer.name = mat ? mat.name : "noeffect";
if (_rt)
#if UNITY_EDITOR
if (!Application.isPlaying)
{
_rt.name = _buffer.name;
RenderTexture.active = Resources.FindObjectsOfTypeAll<RenderTexture>().FirstOrDefault(x=>x.name == "GameView RT");
s_renderedResult.ReadPixels(new Rect(0, 0, s_renderedResult.width, s_renderedResult.height), 0, 0);
s_renderedResult.Apply(false, false);
RenderTexture.active = null;
}
#endif

// Copy to temporary RT.
_buffer.GetTemporaryRT(s_CopyId, -1, -1, 0, m_FilterMode);
_buffer.Blit(new RenderTargetIdentifier(s_renderedResult), s_CopyId);
}
else
{
_buffer.Blit(BuiltinRenderTextureType.CurrentActive, s_CopyId);
}

// Set properties.
_buffer.SetGlobalVector(s_EffectFactorId, new Vector4(toneLevel, 0));
_buffer.SetGlobalVector(s_ColorFactorId, new Vector4(effectColor.r, effectColor.g, effectColor.b, effectColor.a));
// Set properties.
_buffer.SetGlobalVector(s_EffectFactorId, new Vector4(toneLevel, 0));
_buffer.SetGlobalVector(s_ColorFactorId, new Vector4(effectColor.r, effectColor.g, effectColor.b, effectColor.a));

// Blit without effect.
if (!mat)
{
_buffer.Blit(s_CopyId, rtId);
_buffer.ReleaseTemporaryRT(s_CopyId);
}
// Blit with effect.
else
// Blit without effect.
if (!mat)
{
_buffer.Blit(s_CopyId, rtId);
_buffer.ReleaseTemporaryRT(s_CopyId);
}
// Blit with effect.
else
{
GetDesamplingSize(m_ReductionRate, out w, out h);
_buffer.GetTemporaryRT(s_EffectId1, w, h, 0, m_FilterMode);

// Apply base effect (copied screen -> effect1).
_buffer.Blit(s_CopyId, s_EffectId1, mat, 0);
_buffer.ReleaseTemporaryRT(s_CopyId);

// Iterate the operation.
if (m_BlurMode != BlurMode.None)
{
GetDesamplingSize(m_ReductionRate, out w, out h);
_buffer.GetTemporaryRT(s_EffectId1, w, h, 0, m_FilterMode);

// Apply base effect (copied screen -> effect1).
_buffer.Blit(s_CopyId, s_EffectId1, mat, 0);
_buffer.ReleaseTemporaryRT(s_CopyId);

// Iterate the operation.
if(m_BlurMode != BlurMode.None)
_buffer.GetTemporaryRT(s_EffectId2, w, h, 0, m_FilterMode);
for (int i = 0; i < m_BlurIterations; i++)
{
_buffer.GetTemporaryRT(s_EffectId2, w, h, 0, m_FilterMode);
for (int i = 0; i < m_BlurIterations; i++)
{
// Apply effect (effect1 -> effect2, or effect2 -> effect1).
_buffer.SetGlobalVector(s_EffectFactorId, new Vector4(blur, 0));
_buffer.Blit(s_EffectId1, s_EffectId2, mat, 1);
_buffer.SetGlobalVector(s_EffectFactorId, new Vector4(0, blur));
_buffer.Blit(s_EffectId2, s_EffectId1, mat, 1);
}
_buffer.ReleaseTemporaryRT(s_EffectId2);
// Apply effect (effect1 -> effect2, or effect2 -> effect1).
_buffer.SetGlobalVector(s_EffectFactorId, new Vector4(blur, 0));
_buffer.Blit(s_EffectId1, s_EffectId2, mat, 1);
_buffer.SetGlobalVector(s_EffectFactorId, new Vector4(0, blur));
_buffer.Blit(s_EffectId2, s_EffectId1, mat, 1);
}

_buffer.Blit(s_EffectId1, rtId);
_buffer.ReleaseTemporaryRT(s_EffectId1);
_buffer.ReleaseTemporaryRT(s_EffectId2);
}
}

// Add command buffer to camera.
_camera.AddCommandBuffer(kCameraEvent, _buffer);
_buffer.Blit(s_EffectId1, rtId);
_buffer.ReleaseTemporaryRT(s_EffectId1);
}

// StartCoroutine by CanvasScaler.
var rootCanvas = canvas.rootCanvas;
var scaler = rootCanvas.GetComponent<CanvasScaler>();
scaler.StartCoroutine(_CoUpdateTextureOnNextFrame());
if (m_KeepCanvasSize)
#if UNITY_EDITOR
// Start rendering for editor mode.
if (!Application.isPlaying)
{
var rootTransform = rootCanvas.transform as RectTransform;
var size = rootTransform.rect.size;
rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.x);
rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.y);
rectTransform.position = rootTransform.position;
_cameraEvent = CameraEvent.AfterEverything;
_camera.AddCommandBuffer(_cameraEvent, _buffer);
texture = null;
_SetDirty();

UnityEditor.EditorApplication.delayCall += () =>
{
_Release(false);
texture = capturedTexture;
_SetDirty();
};
return;
}
#endif

// Start rendering coroutine by CanvasScaler.
var scaler = canvas.rootCanvas.GetComponent<CanvasScaler>();
scaler.StartCoroutine(
isOverlay
? _CoUpdateTextureOnNextFrameOverlay()
: _CoUpdateTextureOnNextFrame()
);
}

/// <summary>
Expand All @@ -308,6 +366,8 @@ public void Capture()
public void Release()
{
_Release(true);
texture = null;
_SetDirty();
}

#if UNITY_EDITOR
Expand Down Expand Up @@ -361,7 +421,7 @@ protected void UpdateMaterial(bool ignoreInPlayMode)
{
material = null;
m_EffectMaterial = mat;
UnityEditor.EditorUtility.SetDirty(this);
_SetDirty();
}
}
#endif
Expand All @@ -371,12 +431,13 @@ protected void UpdateMaterial(bool ignoreInPlayMode)
//################################
// Private Members.
//################################
const CameraEvent kCameraEvent = CameraEvent.AfterEverything;
CameraEvent _cameraEvent = CameraEvent.AfterEverything;
Camera _camera;
RenderTexture _rt;
RenderTexture _rtToRelease;
CommandBuffer _buffer;

public Texture2D s_renderedResult;
static int s_CopyId;
static int s_EffectId1;
static int s_EffectId2;
Expand All @@ -392,26 +453,40 @@ void _Release(bool releaseRT)
if (releaseRT || m_TargetTexture)
{
texture = null;

if (_rt != null)
{
_rt.Release();
_rt = null;
}
_Release(ref _rt);
}

if (_buffer != null)
{
if (_camera != null)
_camera.RemoveCommandBuffer(kCameraEvent, _buffer);
_camera.RemoveCommandBuffer(_cameraEvent, _buffer);
_buffer.Release();
_buffer = null;
}

if (_rtToRelease)
_Release(ref _rtToRelease);
}

[System.Diagnostics.Conditional("UNITY_EDITOR")]
void _SetDirty()
{
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(this);
#endif
}

void _Release(ref RenderTexture obj)
{
if (obj)
{
_rtToRelease.Release();
_rtToRelease = null;
obj.Release();
#if UNITY_EDITOR
if(!Application.isPlaying)
DestroyImmediate(obj);
else
#endif
Destroy(obj);
obj = null;
}
}

Expand All @@ -420,10 +495,31 @@ void _Release(bool releaseRT)
/// </summary>
IEnumerator _CoUpdateTextureOnNextFrame()
{
// Add command buffer to camera.
_cameraEvent = CameraEvent.AfterEverything;
_camera.AddCommandBuffer(_cameraEvent, _buffer);
yield return new WaitForEndOfFrame();

_Release(false);
texture = m_TargetTexture ? m_TargetTexture : _rt;
}

/// <summary>
/// Set texture on next frame (for overlay).
/// </summary>
IEnumerator _CoUpdateTextureOnNextFrameOverlay()
{
// Add command buffer to camera.
yield return new WaitForEndOfFrame();
s_renderedResult.ReadPixels(new Rect(0, 0, s_renderedResult.width, s_renderedResult.height), 0, 0);
s_renderedResult.Apply(false, false);

_cameraEvent = CameraEvent.BeforeForwardOpaque;
_camera.AddCommandBuffer(_cameraEvent, _buffer);
texture = m_TargetTexture ? m_TargetTexture : _rt;

yield return new WaitForEndOfFrame();
_Release(false);
}
}
}

0 comments on commit 7fe79bb

Please sign in to comment.