live2D (sdk가 6.5 미지원으로 sprite로 대응)
This commit is contained in:
@@ -0,0 +1,440 @@
|
||||
/**
|
||||
* Copyright(c) Live2D Inc. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by the Live2D Open Software license
|
||||
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
|
||||
namespace Live2D.Cubism.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Class for managing offscreen render textures.
|
||||
/// </summary>
|
||||
public class CubismOffscreenRenderTextureManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Tag of the GameObject that holds <see cref="CubismCommonRenderTextureController"/> script.
|
||||
/// </summary>
|
||||
private static readonly string RenderTextureControllerName = "CubismRenderTextureController";
|
||||
|
||||
/// <summary>
|
||||
/// Default number of offscreen render textures.
|
||||
/// </summary>
|
||||
private static readonly int OffscreenRenderTextureDefaultCount = 0;
|
||||
|
||||
/// <summary>
|
||||
/// instance of the <see cref="CubismOffscreenRenderTextureManager"/>.
|
||||
/// </summary>
|
||||
private static CubismOffscreenRenderTextureManager Instance;
|
||||
|
||||
public static CubismOffscreenRenderTextureManager GetInstance()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
// Initialize the singleton instance.
|
||||
Instance = new CubismOffscreenRenderTextureManager();
|
||||
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
// Check if the CubismRenderTextureController is already instantiated.
|
||||
Instance._isRenderTextureControllerInstantiated = GameObject.Find(RenderTextureControllerName) != null;
|
||||
}
|
||||
}
|
||||
|
||||
return Instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Container for render texture and its usage status.
|
||||
/// </summary>
|
||||
private struct RenderTextureContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// Render texture.
|
||||
/// </summary>
|
||||
public RenderTexture RenderTexture;
|
||||
|
||||
/// <summary>
|
||||
/// Is in use.
|
||||
/// </summary>
|
||||
public bool InUse;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Render texture containers.
|
||||
/// </summary>
|
||||
private RenderTextureContainer[] _offscreenRenderTextureContainers;
|
||||
|
||||
/// <summary>
|
||||
/// Previous frame active render texture count.
|
||||
/// </summary>
|
||||
private int _previousActiveRenderTextureCount;
|
||||
|
||||
/// <summary>
|
||||
/// Current active render texture count.
|
||||
/// </summary>
|
||||
private int _currentActiveRenderTextureCount;
|
||||
|
||||
/// <summary>
|
||||
/// CubismRenderTextureController already instantiated?
|
||||
/// </summary>
|
||||
private bool _isRenderTextureControllerInstantiated;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="HasResetThisFrame"/>'s backing field.
|
||||
/// </summary>
|
||||
private bool _hasResetThisFrame;
|
||||
|
||||
/// <summary>
|
||||
/// Did reset _previousActiveRenderTextureCount this frame?
|
||||
/// </summary>
|
||||
public bool HasResetThisFrame
|
||||
{
|
||||
get
|
||||
{
|
||||
return _hasResetThisFrame;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_hasResetThisFrame = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the render texture needs to be resized or recreated to match the base texture.
|
||||
/// </summary>
|
||||
/// <param name="renderTexture">The render texture to check.</param>
|
||||
/// <param name="baseTexture">Base render texture to compare against.</param>
|
||||
/// <returns>True if the render texture needs to be resized or recreated.</returns>
|
||||
private static bool NeedsResizeOrRecreate(RenderTexture renderTexture, RenderTexture baseTexture)
|
||||
{
|
||||
return !renderTexture.IsCreated()
|
||||
|| renderTexture.width != baseTexture.width
|
||||
|| renderTexture.height != baseTexture.height
|
||||
|| renderTexture.format != baseTexture.format
|
||||
|| renderTexture.antiAliasing != baseTexture.antiAliasing
|
||||
|| renderTexture.wrapMode != TextureWrapMode.Repeat
|
||||
|| renderTexture.filterMode != FilterMode.Point;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new render texture for the offscreen render.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the render texture.</param>
|
||||
/// <param name="baseTexture">Base render texture to use for creating a new render texture.</param>
|
||||
/// <returns>The new render texture.</returns>
|
||||
private RenderTexture CreateOffscreenRenderTexture(string name, RenderTexture baseTexture)
|
||||
{
|
||||
var renderTexture = new RenderTexture(baseTexture)
|
||||
{
|
||||
name = name,
|
||||
wrapMode = TextureWrapMode.Repeat,
|
||||
filterMode = FilterMode.Point
|
||||
};
|
||||
|
||||
renderTexture.Create();
|
||||
return renderTexture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the offscreen render texture manager.
|
||||
/// </summary>
|
||||
/// <param name="baseTexture">Base render texture to use for initialization.</param>
|
||||
private void Initialize(RenderTexture baseTexture)
|
||||
{
|
||||
if (Application.isPlaying && !_isRenderTextureControllerInstantiated)
|
||||
{
|
||||
var prefab = Resources.Load<GameObject>($"Live2D/Cubism/Prefabs/{RenderTextureControllerName}");
|
||||
|
||||
var failedLog = string.Empty;
|
||||
if (prefab)
|
||||
{
|
||||
// Instantiate the controller GameObject from the prefab.
|
||||
var instance = GameObject.Instantiate(prefab);
|
||||
if (instance)
|
||||
{
|
||||
instance.name = RenderTextureControllerName;
|
||||
GameObject.DontDestroyOnLoad(instance);
|
||||
|
||||
_isRenderTextureControllerInstantiated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Failed to instantiate prefab.
|
||||
failedLog =
|
||||
$"{nameof(CubismOffscreenRenderTextureManager)}: Failed to instantiate prefab.";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
failedLog = $"{nameof(CubismOffscreenRenderTextureManager)}: Prefab not found in Resources/Live2D/Cubism/Prefabs/{RenderTextureControllerName}";
|
||||
}
|
||||
|
||||
if (!_isRenderTextureControllerInstantiated)
|
||||
{
|
||||
Debug.LogWarning(failedLog);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Release existing render textures.
|
||||
if (_offscreenRenderTextureContainers != null)
|
||||
{
|
||||
for (var i = 0; i < _offscreenRenderTextureContainers.Length; ++i)
|
||||
{
|
||||
_offscreenRenderTextureContainers[i].RenderTexture.Release();
|
||||
}
|
||||
}
|
||||
|
||||
// Create default number of render textures.
|
||||
_offscreenRenderTextureContainers = new RenderTextureContainer[OffscreenRenderTextureDefaultCount];
|
||||
for (var i = 0; i < OffscreenRenderTextureDefaultCount; ++i)
|
||||
{
|
||||
_offscreenRenderTextureContainers[i] = new RenderTextureContainer
|
||||
{
|
||||
RenderTexture = CreateOffscreenRenderTexture("OffscreenRenderTexture_" + i, baseTexture),
|
||||
InUse = false
|
||||
};
|
||||
}
|
||||
|
||||
_previousActiveRenderTextureCount = 0;
|
||||
_currentActiveRenderTextureCount = 0;
|
||||
_hasResetThisFrame = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the previous active render texture count at the beginning of each frame.
|
||||
/// This should be called once per frame before any CubismRenderController OnLateUpdate.
|
||||
/// </summary>
|
||||
public void ResetPreviousActiveCount()
|
||||
{
|
||||
if (!_hasResetThisFrame)
|
||||
{
|
||||
_previousActiveRenderTextureCount = 0;
|
||||
_hasResetThisFrame = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all offscreen render textures.
|
||||
/// </summary>
|
||||
/// <param name="commandBuffer">Command buffer.</param>
|
||||
public void ClearRenderTextures(CommandBuffer commandBuffer)
|
||||
{
|
||||
for (var i = 0; i < _offscreenRenderTextureContainers?.Length; i++)
|
||||
{
|
||||
if (!_offscreenRenderTextureContainers[i].RenderTexture)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
commandBuffer.SetRenderTarget(_offscreenRenderTextureContainers[i].RenderTexture);
|
||||
commandBuffer.ClearRenderTarget(true, true, Color.clear);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an offscreen render texture.
|
||||
/// </summary>
|
||||
/// <param name="baseTexture">Base render texture to use for getting or creating an offscreen render texture.</param>
|
||||
/// <returns>An offscreen render texture.</returns>
|
||||
public RenderTexture GetOffscreenRenderTexture(RenderTexture baseTexture)
|
||||
{
|
||||
// Initialize if not yet.
|
||||
if (_offscreenRenderTextureContainers == null)
|
||||
{
|
||||
Initialize(baseTexture);
|
||||
}
|
||||
|
||||
_currentActiveRenderTextureCount++;
|
||||
|
||||
// Update the maximum count for this frame
|
||||
_previousActiveRenderTextureCount = _currentActiveRenderTextureCount > _previousActiveRenderTextureCount
|
||||
? _currentActiveRenderTextureCount
|
||||
: _previousActiveRenderTextureCount;
|
||||
|
||||
// Search for an unused render texture.
|
||||
for (var i = 0; i < _offscreenRenderTextureContainers?.Length; ++i)
|
||||
{
|
||||
if (_offscreenRenderTextureContainers[i].InUse
|
||||
|| !_offscreenRenderTextureContainers[i].RenderTexture)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Resize if the size is different.
|
||||
if (NeedsResizeOrRecreate(_offscreenRenderTextureContainers[i].RenderTexture, baseTexture))
|
||||
{
|
||||
_offscreenRenderTextureContainers[i].RenderTexture.Release();
|
||||
_offscreenRenderTextureContainers[i].RenderTexture.width = baseTexture.width;
|
||||
_offscreenRenderTextureContainers[i].RenderTexture.height = baseTexture.height;
|
||||
_offscreenRenderTextureContainers[i].RenderTexture.format = baseTexture.format;
|
||||
_offscreenRenderTextureContainers[i].RenderTexture.antiAliasing = baseTexture.antiAliasing;
|
||||
_offscreenRenderTextureContainers[i].RenderTexture.wrapMode = TextureWrapMode.Repeat;
|
||||
_offscreenRenderTextureContainers[i].RenderTexture.filterMode = FilterMode.Point;
|
||||
_offscreenRenderTextureContainers[i].RenderTexture.Create();
|
||||
}
|
||||
_offscreenRenderTextureContainers[i].InUse = true;
|
||||
|
||||
// Return the found render texture.
|
||||
return _offscreenRenderTextureContainers[i].RenderTexture;
|
||||
}
|
||||
|
||||
// If no unused render texture is found, create a new one.
|
||||
return CreateContainer(baseTexture).RenderTexture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new render texture container.
|
||||
/// </summary>
|
||||
/// <param name="baseTexture">Base render texture to use for creating a new container.</param>
|
||||
/// <returns>The new render texture container.</returns>
|
||||
private RenderTextureContainer CreateContainer(RenderTexture baseTexture)
|
||||
{
|
||||
if (_offscreenRenderTextureContainers == null)
|
||||
{
|
||||
Initialize(baseTexture);
|
||||
|
||||
// If still null.
|
||||
if (_offscreenRenderTextureContainers == null
|
||||
|| _offscreenRenderTextureContainers.Length < 1)
|
||||
{
|
||||
// Create the first container.
|
||||
_offscreenRenderTextureContainers = new RenderTextureContainer[1];
|
||||
_offscreenRenderTextureContainers[0] = new RenderTextureContainer
|
||||
{
|
||||
RenderTexture = CreateOffscreenRenderTexture("OffscreenRenderTexture_0", baseTexture),
|
||||
InUse = false
|
||||
};
|
||||
}
|
||||
|
||||
_offscreenRenderTextureContainers[0].InUse = true;
|
||||
|
||||
// Return the first container.
|
||||
return _offscreenRenderTextureContainers[0];
|
||||
}
|
||||
|
||||
Array.Resize(ref _offscreenRenderTextureContainers, _offscreenRenderTextureContainers.Length + 1);
|
||||
_offscreenRenderTextureContainers[^1] = new RenderTextureContainer
|
||||
{
|
||||
RenderTexture = CreateOffscreenRenderTexture("OffscreenRenderTexture_" + (_offscreenRenderTextureContainers.Length - 1), baseTexture),
|
||||
InUse = true
|
||||
};
|
||||
|
||||
return _offscreenRenderTextureContainers[^1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End use the specified render texture.
|
||||
/// </summary>
|
||||
/// <param name="renderController">CubismRenderController.</param>
|
||||
/// <param name="renderTexture">Use RenderTexture.</param>
|
||||
public void StopUsingRenderTexture(CubismRenderController renderController, RenderTexture renderTexture)
|
||||
{
|
||||
// If not initialized, do nothing.
|
||||
if (_offscreenRenderTextureContainers == null
|
||||
|| !renderController)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Search for the specified render texture.
|
||||
for (var i = 0; i < _offscreenRenderTextureContainers.Length; ++i)
|
||||
{
|
||||
if (_offscreenRenderTextureContainers[i].RenderTexture != renderTexture
|
||||
|| !_offscreenRenderTextureContainers[i].RenderTexture)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Mark as not in use.
|
||||
_offscreenRenderTextureContainers[i].InUse = false;
|
||||
|
||||
_currentActiveRenderTextureCount--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End use all render textures.
|
||||
/// </summary>
|
||||
public void StopUsingAllRenderTextures()
|
||||
{
|
||||
// If not initialized, do nothing.
|
||||
if (_offscreenRenderTextureContainers == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark all render textures as not in use.
|
||||
for (var i = 0; i < _offscreenRenderTextureContainers.Length; ++i)
|
||||
{
|
||||
_offscreenRenderTextureContainers[i].InUse = false;
|
||||
}
|
||||
|
||||
_currentActiveRenderTextureCount = 0;
|
||||
_hasResetThisFrame = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release stale render textures that are not used in the previous frame.
|
||||
/// </summary>
|
||||
public void ReleaseStaleRenderTextures()
|
||||
{
|
||||
// If not initialized, do nothing.
|
||||
if (_offscreenRenderTextureContainers == null
|
||||
|| _offscreenRenderTextureContainers.Length <= _previousActiveRenderTextureCount
|
||||
|| HasResetThisFrame)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var newSize = Math.Max(OffscreenRenderTextureDefaultCount, _previousActiveRenderTextureCount);
|
||||
|
||||
// Release unused render textures beyond the _previousActiveRenderTextureCount.
|
||||
for (var i = newSize; i < _offscreenRenderTextureContainers.Length; i++)
|
||||
{
|
||||
_offscreenRenderTextureContainers[i].RenderTexture.Release();
|
||||
_offscreenRenderTextureContainers[i].RenderTexture = null;
|
||||
}
|
||||
|
||||
// Resize the array to keep only the active render textures.
|
||||
Array.Resize(ref _offscreenRenderTextureContainers, newSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release all offscreen render textures.
|
||||
/// </summary>
|
||||
public void Release()
|
||||
{
|
||||
// If not initialized, do nothing.
|
||||
if (_offscreenRenderTextureContainers == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Release all render textures.
|
||||
for (var i = 0; i < _offscreenRenderTextureContainers.Length; ++i)
|
||||
{
|
||||
if (_offscreenRenderTextureContainers[i].RenderTexture != null)
|
||||
{
|
||||
_offscreenRenderTextureContainers[i].RenderTexture.Release();
|
||||
_offscreenRenderTextureContainers[i].RenderTexture = null;
|
||||
}
|
||||
_offscreenRenderTextureContainers[i].InUse = false;
|
||||
}
|
||||
|
||||
_offscreenRenderTextureContainers = null;
|
||||
_previousActiveRenderTextureCount = 0;
|
||||
_currentActiveRenderTextureCount = 0;
|
||||
_hasResetThisFrame = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user