123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916 |
- /**
- * 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 Live2D.Cubism.Core;
- using Live2D.Cubism.Rendering.Masking;
- using System;
- using UnityEngine;
- using UnityEngine.Rendering;
- namespace Live2D.Cubism.Rendering
- {
- /// <summary>
- /// Wrapper for drawing <see cref="CubismDrawable"/>s.
- /// </summary>
- [ExecuteInEditMode, RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
- public sealed class CubismRenderer : MonoBehaviour
- {
- /// <summary>
- /// <see cref="LocalSortingOrder"/> backing field.
- /// </summary>
- [SerializeField, HideInInspector]
- private int _localSortingOrder;
- /// <summary>
- /// Local sorting order.
- /// </summary>
- public int LocalSortingOrder
- {
- get
- {
- return _localSortingOrder;
- }
- set
- {
- // Return early if same value given.
- if (value == _localSortingOrder)
- {
- return;
- }
- // Store value.
- _localSortingOrder = value;
- // Apply it.
- ApplySorting();
- }
- }
- /// <summary>
- /// <see cref="Color"/> backing field.
- /// </summary>
- [SerializeField, HideInInspector]
- private Color _color = Color.white;
- /// <summary>
- /// Color.
- /// </summary>
- public Color Color
- {
- get { return _color; }
- set
- {
- // Return early if same value given.
- if (value == _color)
- {
- return;
- }
- // Store value.
- _color = value;
- // Apply color.
- ApplyVertexColors();
- }
- }
- /// <summary>
- /// <see cref="UnityEngine.Material"/>.
- /// </summary>
- public Material Material
- {
- get
- {
- #if UNITY_EDITOR
- if (!Application.isPlaying)
- {
- return MeshRenderer.sharedMaterial;
- }
- #endif
- return MeshRenderer.material;
- }
- set
- {
- #if UNITY_EDITOR
- if (!Application.isPlaying)
- {
- MeshRenderer.sharedMaterial = value;
- return;
- }
- #endif
- MeshRenderer.material = value;
- }
- }
- /// <summary>
- /// <see cref="MainTexture"/> backing field.
- /// </summary>
- [SerializeField, HideInInspector]
- private Texture2D _mainTexture;
- /// <summary>
- /// <see cref="MeshRenderer"/>'s main texture.
- /// </summary>
- public Texture2D MainTexture
- {
- get { return _mainTexture; }
- set
- {
- // Return early if same value given and main texture is valid.
- if (value == _mainTexture && _mainTexture != null)
- {
- return;
- }
- // Store value.
- _mainTexture = (value != null)
- ? value
- : Texture2D.whiteTexture;
- // Apply it.
- ApplyMainTexture();
- }
- }
- /// <summary>
- /// Meshes.
- /// </summary>
- /// <remarks>
- /// Double buffering dynamic meshes increases performance on mobile, so we double-buffer them here.
- /// </remarks>
- private Mesh[] Meshes { get; set; }
- /// <summary>
- /// Index of front buffer mesh.
- /// </summary>
- private int FrontMesh { get; set; }
- /// <summary>
- /// Index of back buffer mesh..
- /// </summary>
- private int BackMesh { get; set; }
- /// <summary>
- /// <see cref="UnityEngine.Mesh"/>.
- /// </summary>
- public Mesh Mesh
- {
- get { return Meshes[FrontMesh]; }
- }
- /// <summary>
- /// <see cref="MeshFilter"/> backing field.
- /// </summary>
- [NonSerialized]
- private MeshFilter _meshFilter;
- /// <summary>
- /// <see cref="UnityEngine.MeshFilter"/>.
- /// </summary>
- public MeshFilter MeshFilter
- {
- get
- {
- return _meshFilter;
- }
- }
- /// <summary>
- /// <see cref="MeshRenderer"/> backing field.
- /// </summary>
- [NonSerialized]
- private MeshRenderer _meshRenderer;
- /// <summary>
- /// <see cref="UnityEngine.MeshRenderer"/>.
- /// </summary>
- public MeshRenderer MeshRenderer
- {
- get
- {
- return _meshRenderer;
- }
- }
- #region Interface For CubismRenderController
- /// <summary>
- /// <see cref="SortingMode"/> backing field.
- /// </summary>
- [SerializeField, HideInInspector]
- private CubismSortingMode _sortingMode;
- /// <summary>
- /// Sorting mode.
- /// </summary>
- private CubismSortingMode SortingMode
- {
- get { return _sortingMode; }
- set { _sortingMode = value; }
- }
- /// <summary>
- /// <see cref="SortingOrder"/> backing field.
- /// </summary>
- [SerializeField, HideInInspector]
- private int _sortingOrder;
- /// <summary>
- /// Sorting mode.
- /// </summary>
- private int SortingOrder
- {
- get { return _sortingOrder; }
- set { _sortingOrder = value; }
- }
- /// <summary>
- /// <see cref="RenderOrder"/> backing field.
- /// </summary>
- [SerializeField, HideInInspector]
- private int _renderOrder;
- /// <summary>
- /// Sorting mode.
- /// </summary>
- private int RenderOrder
- {
- get { return _renderOrder; }
- set { _renderOrder = value; }
- }
- /// <summary>
- /// <see cref="DepthOffset"/> backing field.
- /// </summary>
- [SerializeField, HideInInspector]
- private float _depthOffset = 0.00001f;
- /// <summary>
- /// Offset to apply in case of depth sorting.
- /// </summary>
- private float DepthOffset
- {
- get { return _depthOffset; }
- set { _depthOffset = value; }
- }
- /// <summary>
- /// <see cref="Opacity"/> backing field.
- /// </summary>
- [SerializeField, HideInInspector]
- private float _opacity;
- /// <summary>
- /// Opacity.
- /// </summary>
- private float Opacity
- {
- get { return _opacity; }
- set { _opacity = value; }
- }
- /// <summary>
- /// Buffer for vertex colors.
- /// </summary>
- private Color[] VertexColors { get; set; }
- /// <summary>
- /// Allows tracking of what vertex data was updated last swap.
- /// </summary>
- private SwapInfo LastSwap { get; set; }
- /// <summary>
- /// Allows tracking of what vertex data will be swapped.
- /// </summary>
- private SwapInfo ThisSwap { get; set; }
- /// <summary>
- /// Swaps mesh buffers.
- /// </summary>
- /// <remarks>
- /// Make sure to manually call this method in case you changed the <see cref="Color"/>.
- /// </remarks>
- public void SwapMeshes()
- {
- // Perform internal swap.
- BackMesh = FrontMesh;
- FrontMesh = (FrontMesh == 0) ? 1 : 0;
- var mesh = Meshes[FrontMesh];
- // Update colors.
- Meshes[BackMesh].colors = VertexColors;
- // Update swap info.
- LastSwap = ThisSwap;
- ResetSwapInfoFlags();
- // Apply swap.
- #if UNITY_EDITOR
- if (!Application.isPlaying)
- {
- MeshFilter.mesh = mesh;
- return;
- }
- #endif
- MeshFilter.mesh = mesh;
- }
- /// <summary>
- /// Updates visibility.
- /// </summary>
- public void UpdateVisibility()
- {
- if (LastSwap.DidBecomeVisible)
- {
- MeshRenderer.enabled = true;
- }
- else if (LastSwap.DidBecomeInvisible)
- {
- MeshRenderer.enabled = false;
- }
- ResetVisibilityFlags();
- }
- /// <summary>
- /// Updates render order.
- /// </summary>
- public void UpdateRenderOrder()
- {
- if (LastSwap.NewRenderOrder)
- {
- ApplySorting();
- }
- ResetRenderOrderFlag();
- }
- /// <summary>
- /// Updates sorting layer.
- /// </summary>
- /// <param name="newSortingLayer">New sorting layer.</param>
- internal void OnControllerSortingLayerDidChange(int newSortingLayer)
- {
- MeshRenderer.sortingLayerID = newSortingLayer;
- }
- /// <summary>
- /// Updates sorting mode.
- /// </summary>
- /// <param name="newSortingMode">New sorting mode.</param>
- internal void OnControllerSortingModeDidChange(CubismSortingMode newSortingMode)
- {
- SortingMode = newSortingMode;
- ApplySorting();
- }
- /// <summary>
- /// Updates sorting order.
- /// </summary>
- /// <param name="newSortingOrder">New sorting order.</param>
- internal void OnControllerSortingOrderDidChange(int newSortingOrder)
- {
- SortingOrder = newSortingOrder;
- ApplySorting();
- }
- /// <summary>
- /// Updates depth offset.
- /// </summary>
- /// <param name="newDepthOffset"></param>
- internal void OnControllerDepthOffsetDidChange(float newDepthOffset)
- {
- DepthOffset = newDepthOffset;
- ApplySorting();
- }
- /// <summary>
- /// Sets the opacity.
- /// </summary>
- /// <param name="newOpacity">New opacity.</param>
- internal void OnDrawableOpacityDidChange(float newOpacity)
- {
- Opacity = newOpacity;
- ApplyVertexColors();
- }
- /// <summary>
- /// Updates render order.
- /// </summary>
- /// <param name="newRenderOrder">New render order.</param>
- internal void OnDrawableRenderOrderDidChange(int newRenderOrder)
- {
- RenderOrder = newRenderOrder;
- SetNewRenderOrder();
- }
- /// <summary>
- /// Sets the <see cref="UnityEngine.Mesh.vertices"/>.
- /// </summary>
- /// <param name="newVertexPositions">Vertex positions to set.</param>
- internal void OnDrawableVertexPositionsDidChange(Vector3[] newVertexPositions)
- {
- var mesh = Mesh;
- // Apply positions and update bounds.
- mesh.vertices = newVertexPositions;
- mesh.RecalculateBounds();
- // Set swap flag.
- SetNewVertexPositions();
- }
- /// <summary>
- /// Sets visibility.
- /// </summary>
- /// <param name="newVisibility">New visibility.</param>
- internal void OnDrawableVisiblityDidChange(bool newVisibility)
- {
- // Set swap flag if visible.
- if (newVisibility)
- {
- BecomeVisible();
- }
- else
- {
- BecomeInvisible();
- }
- }
- /// <summary>
- /// Sets mask properties.
- /// </summary>
- /// <param name="newMaskProperties">Value to set.</param>
- internal void OnMaskPropertiesDidChange(CubismMaskProperties newMaskProperties)
- {
- MeshRenderer.GetPropertyBlock(SharedPropertyBlock);
- // Write properties.
- SharedPropertyBlock.SetTexture(CubismShaderVariables.MaskTexture, newMaskProperties.Texture);
- SharedPropertyBlock.SetVector(CubismShaderVariables.MaskTile, newMaskProperties.Tile);
- SharedPropertyBlock.SetVector(CubismShaderVariables.MaskTransform, newMaskProperties.Transform);
- MeshRenderer.SetPropertyBlock(SharedPropertyBlock);
- }
- /// <summary>
- /// Sets model opacity.
- /// </summary>
- /// <param name="newModelOpacity">Opacity to set.</param>
- internal void OnModelOpacityDidChange(float newModelOpacity)
- {
- _meshRenderer.GetPropertyBlock(SharedPropertyBlock);
- // Write property.
- SharedPropertyBlock.SetFloat(CubismShaderVariables.ModelOpacity, newModelOpacity);
- MeshRenderer.SetPropertyBlock(SharedPropertyBlock);
- }
- #endregion
- /// <summary>
- /// <see cref="SharedPropertyBlock"/> backing field.
- /// </summary>
- private static MaterialPropertyBlock _sharedPropertyBlock;
- /// <summary>
- /// <see cref="MaterialPropertyBlock"/> that can be shared on the main script thread.
- /// </summary>
- private static MaterialPropertyBlock SharedPropertyBlock
- {
- get
- {
- // Lazily initialize.
- if (_sharedPropertyBlock == null)
- {
- _sharedPropertyBlock = new MaterialPropertyBlock();
- }
- return _sharedPropertyBlock;
- }
- }
- /// <summary>
- /// Applies main texture for rendering.
- /// </summary>
- private void ApplyMainTexture()
- {
- MeshRenderer.GetPropertyBlock(SharedPropertyBlock);
- // Write property.
- SharedPropertyBlock.SetTexture(CubismShaderVariables.MainTexture, MainTexture);
- MeshRenderer.SetPropertyBlock(SharedPropertyBlock);
- }
- /// <summary>
- /// Applies sorting.
- /// </summary>
- private void ApplySorting()
- {
- // Sort by order.
- if (SortingMode.SortByOrder())
- {
- MeshRenderer.sortingOrder = SortingOrder + ((SortingMode == CubismSortingMode.BackToFrontOrder)
- ? (RenderOrder + LocalSortingOrder)
- : -(RenderOrder + LocalSortingOrder));
- transform.localPosition = Vector3.zero;
- return;
- }
- // Sort by depth.
- var offset = (SortingMode == CubismSortingMode.BackToFrontZ)
- ? -DepthOffset
- : DepthOffset;
- MeshRenderer.sortingOrder = SortingOrder + LocalSortingOrder;
- transform.localPosition = new Vector3(0f, 0f, RenderOrder * offset);
- }
- /// <summary>
- /// Uploads mesh vertex colors.
- /// </summary>
- public void ApplyVertexColors()
- {
- var vertexColors = VertexColors;
- var color = Color;
- color.a *= Opacity;
- for (var i = 0; i < vertexColors.Length; ++i)
- {
- vertexColors[i] = color;
- }
- // Set swap flag.
- SetNewVertexColors();
- }
- /// <summary>
- /// Initializes the mesh renderer.
- /// </summary>
- private void TryInitializeMeshRenderer()
- {
- if (_meshRenderer == null)
- {
- _meshRenderer = GetComponent<MeshRenderer>();
- // Lazily add component.
- if (_meshRenderer == null)
- {
- _meshRenderer = gameObject.AddComponent<MeshRenderer>();
- _meshRenderer.hideFlags = HideFlags.HideInInspector;
- _meshRenderer.receiveShadows = false;
- _meshRenderer.shadowCastingMode = ShadowCastingMode.Off;
- _meshRenderer.lightProbeUsage = LightProbeUsage.BlendProbes;
- }
- }
- }
- /// <summary>
- /// Initializes the mesh filter.
- /// </summary>
- private void TryInitializeMeshFilter()
- {
- if (_meshFilter == null)
- {
- _meshFilter = GetComponent<MeshFilter>();
- // Lazily add component.
- if (_meshFilter == null)
- {
- _meshFilter = gameObject.AddComponent<MeshFilter>();
- _meshFilter.hideFlags = HideFlags.HideInInspector;
- }
- }
- }
- /// <summary>
- /// Initializes the mesh if necessary.
- /// </summary>
- private void TryInitializeMesh()
- {
- // Only create mesh if necessary.
- // HACK 'Mesh.vertex > 0' makes sure mesh is recreated in case of runtime instantiation.
- if (Meshes != null && Mesh.vertexCount > 0)
- {
- return;
- }
- // Create mesh for attached drawable.
- var drawable = GetComponent<CubismDrawable>();
- if (Meshes == null)
- {
- Meshes = new Mesh[2];
- }
- for (var i = 0; i < 2; ++i)
- {
- var mesh = new Mesh
- {
- name = drawable.name,
- vertices = drawable.VertexPositions,
- uv = drawable.VertexUvs,
- triangles = drawable.Indices
- };
- mesh.MarkDynamic();
- mesh.RecalculateBounds();
- // Store mesh.
- Meshes[i] = mesh;
- }
- }
- /// <summary>
- /// Initializes vertex colors.
- /// </summary>
- private void TryInitializeVertexColor()
- {
- var mesh = Mesh;
- VertexColors = new Color[mesh.vertexCount];
- for (var i = 0; i < VertexColors.Length; ++i)
- {
- VertexColors[i] = Color;
- VertexColors[i].a *= Opacity;
- }
- }
- /// <summary>
- /// Initializes the main texture if possible.
- /// </summary>
- private void TryInitializeMainTexture()
- {
- if (MainTexture == null)
- {
- MainTexture = null;
- }
- ApplyMainTexture();
- }
- /// <summary>
- /// Initializes components if possible.
- /// </summary>
- public void TryInitialize()
- {
- TryInitializeMeshRenderer();
- TryInitializeMeshFilter();
- TryInitializeMesh();
- TryInitializeVertexColor();
- TryInitializeMainTexture();
- ApplySorting();
- }
- #region Swap Info
- /// <summary>
- /// Sets <see cref="NewVertexPositions"/>.
- /// </summary>
- private void SetNewVertexPositions()
- {
- var swapInfo = ThisSwap;
- swapInfo.NewVertexPositions = true;
- ThisSwap = swapInfo;
- }
- /// <summary>
- /// Sets <see cref="NewVertexColors"/>.
- /// </summary>
- private void SetNewVertexColors()
- {
- var swapInfo = ThisSwap;
- swapInfo.NewVertexColors = true;
- ThisSwap = swapInfo;
- }
- /// <summary>
- /// Sets <see cref="DidBecomeVisible"/> on visible.
- /// </summary>
- private void BecomeVisible()
- {
- var swapInfo = ThisSwap;
- swapInfo.DidBecomeVisible = true;
- ThisSwap = swapInfo;
- }
- /// <summary>
- /// Sets <see cref="DidBecomeInvisible"/> on invisible.
- /// </summary>
- private void BecomeInvisible()
- {
- var swapInfo = ThisSwap;
- swapInfo.DidBecomeInvisible = true;
- ThisSwap = swapInfo;
- }
- /// <summary>
- /// Sets <see cref="SetNewRenderOrder"/>.
- /// </summary>
- private void SetNewRenderOrder()
- {
- var swapInfo = ThisSwap;
- swapInfo.NewRenderOrder = true;
- ThisSwap = swapInfo;
- }
- /// <summary>
- /// Resets flags.
- /// </summary>
- private void ResetSwapInfoFlags()
- {
- var swapInfo = ThisSwap;
- swapInfo.NewVertexColors = false;
- swapInfo.NewVertexPositions = false;
- swapInfo.DidBecomeVisible = false;
- swapInfo.DidBecomeInvisible = false;
- ThisSwap = swapInfo;
- }
- /// <summary>
- /// Reset visibility flags.
- /// </summary>
- private void ResetVisibilityFlags()
- {
- var swapInfo = LastSwap;
- swapInfo.DidBecomeVisible = false;
- swapInfo.DidBecomeInvisible = false;
- LastSwap = swapInfo;
- }
- /// <summary>
- /// Reset render order flag.
- /// </summary>
- private void ResetRenderOrderFlag()
- {
- var swapInfo = LastSwap;
- swapInfo.NewRenderOrder = false;
- LastSwap = swapInfo;
- }
- /// <summary>
- /// Allows tracking of <see cref="Mesh"/> data changed on a swap.
- /// </summary>
- private struct SwapInfo
- {
- /// <summary>
- /// Vertex positions were changed.
- /// </summary>
- public bool NewVertexPositions { get; set; }
- /// <summary>
- /// Vertex colors were changed.
- /// </summary>
- public bool NewVertexColors { get; set; }
- /// <summary>
- /// Visibility were changed to visible.
- /// </summary>
- public bool DidBecomeVisible { get; set; }
- /// <summary>
- /// Visibility were changed to invisible.
- /// </summary>
- public bool DidBecomeInvisible { get; set; }
- /// <summary>
- /// Render order were changed.
- /// </summary>
- public bool NewRenderOrder { get; set; }
- }
- #endregion
- #region Unity Events Handling
- /// <summary>
- /// Finalizes instance.
- /// </summary>
- private void OnDestroy()
- {
- if (Meshes == null)
- {
- return;
- }
- for (var i = 0; i < Meshes.Length; i++)
- {
- DestroyImmediate(Meshes[i]);
- }
- }
- #endregion
- }
- }
|