Files
StoryGame_Unity/Assets/Live2D/Cubism/Rendering/CubismRendererUsingBlendMode.cs

920 lines
34 KiB
C#

/**
* 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.URP;
using Live2D.Cubism.Rendering.Util;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
namespace Live2D.Cubism.Rendering
{
/// <summary>
/// Partial class that describes processing related to the rendering method added in Cubism 5.3 and later.
/// </summary>
public partial class CubismRenderer
{
#region Values
/// <summary>
/// High precision mask tile for mask rendering.
/// </summary>
private static Vector4 HighPrecisionMaskTile = new Vector4(
0, // Channel R
0, // Column
0, // Row
1 // Size
);
/// <summary>
/// Vertices for offscreen rendering.
/// </summary>
internal static Vector3[] OffscreenVertices = new Vector3[]
{
new Vector3(-1, -1, 0),
new Vector3(1, -1, 0),
new Vector3(1, 1, 0),
new Vector3(-1, 1, 0)
};
/// <summary>
/// UVs for offscreen rendering.
/// </summary>
internal static Vector2[] OffscreenUVs = new Vector2[]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(1, 1),
new Vector2(0, 1)
};
/// <summary>
/// Triangle indices for offscreen rendering.
/// </summary>
internal static int[] OffscreenTriangle = new int[] { 0, 1, 2, 0, 2, 3 };
/// <summary>
/// Masks used by this renderer.
/// </summary>
[SerializeField, HideInInspector]
private CubismRenderer[] _masks;
/// <summary>
/// Transform values for mask rendering.
/// </summary>
private Vector4 _maskTransform;
/// <summary>
/// Bounds that contain all masks.
/// </summary>
private Bounds _maskBounds;
#if UNITY_EDITOR
/// <summary>
/// Whether <see cref="_masks"/> have null.
/// </summary>
private bool _haveMasksNull;
#endif
/// <summary>
/// Index of the draw object.
/// </summary>
public int DrawObjectUnmanagedIndex { get; set; }
/// <summary>
/// <see cref="CubismOffscreen"/>.
/// </summary>
public CubismOffscreen Offscreen { get; set; }
/// <summary>
/// Color blend types.
/// </summary>
[SerializeField]
public BlendTypes.ColorBlend ColorBlendType;
/// <summary>
/// Alpha blend types.
/// </summary>
[SerializeField]
public BlendTypes.AlphaBlend AlphaBlendType;
/// <summary>
/// Type of draw object this renderer is used for.
/// </summary>
[SerializeField]
public CubismModelTypes.DrawObjectType DrawObjectType;
/// <summary>
/// Whether this is the last draw object in the model.
/// </summary>
internal bool IsLastDrawObjectInModel;
/// <summary>
/// <see cref="OffscreenFrameBuffer"/>'s backing field.
/// </summary>
private RenderTexture _offscreenFrameBuffer;
/// <summary>
/// Offscreen render texture used for rendering.
/// </summary>
public RenderTexture OffscreenFrameBuffer
{
get
{
if (!_offscreenFrameBuffer
&& RenderController.CurrentFrameBuffer
&& (RenderController.OffscreenRenderers?.Length ?? 0) > 0)
{
_offscreenFrameBuffer = CubismOffscreenRenderTextureManager.GetInstance().GetOffscreenRenderTexture(
RenderController.CurrentFrameBuffer);
}
return _offscreenFrameBuffer;
}
set
{
if (_offscreenFrameBuffer != null)
{
CubismOffscreenRenderTextureManager.GetInstance().StopUsingRenderTexture(RenderController, _offscreenFrameBuffer);
_offscreenFrameBuffer = null;
}
_offscreenFrameBuffer = value;
}
}
/// <summary>
/// <see cref="OffsetScale"/>'s backing field.
/// </summary>
[SerializeField, HideInInspector]
private Vector4 _offsetScale = new Vector4(0, 0, 1, 1);
/// <summary>
/// <see cref="Quaternion"/>'s backing field.
/// </summary>
[SerializeField, HideInInspector]
private Vector4 _quaternion = Vector4.zero;
/// <summary>
/// <see cref="ZOffset"/>'s backing field.
/// </summary>
[SerializeField, HideInInspector]
private float _zOffset = 0.0f;
/// <summary>
/// Offscreen mesh used for rendering.
/// </summary>
private Mesh _offscreenMesh;
/// <summary>
/// Previous offscreen unmanaged index.
/// </summary>
private int _previousOffscreenUnmanagedIndex;
/// <summary>
/// Whether to skip rendering for this draw object.
/// </summary>
public bool SkipRendering
{
get;
set;
}
#endregion
#region Interface For CubismRenderController
/// <summary>
/// Sets draw object's render order.
/// </summary>
/// <param name="newRenderOrder"></param>
internal void SetDrawObjectRenderOrder(int newRenderOrder)
{
if (RenderOrder == newRenderOrder) return;
RenderOrder = newRenderOrder;
ApplySorting();
}
#endregion
/// <summary>
/// Sorting direction at the last sorting.
/// </summary>
internal Vector3 LastDirection;
/// <summary>
/// Whether the direction has been updated since the last sorting.
/// </summary>
/// <returns>True if the direction has changed, false otherwise.</returns>
internal bool DidUpdateDirectionFromLastSorted(Vector3 cameraPosition)
{
return LastDirection != (transform.position - cameraPosition);
}
/// <summary>
/// Distance from the active camera.
/// </summary>
internal float DistanceToCamera;
/// <summary>
/// Calculates the distance by projecting the vector from camera to renderer onto the camera's forward direction.
/// </summary>
/// <param name="cameraPosition">Position of the camera.</param>
/// <param name="cameraForward">Forward direction of the camera (normalized vector).</param>
internal void CalculateDistanceToCamera(Vector3 cameraPosition, Vector3 cameraForward)
{
// Vector from cameraPosition to transform.position
var directionToRenderer = transform.position - cameraPosition;
LastDirection = directionToRenderer;
// Project the vector onto the camera's forward direction
var projection = Vector3.Project(directionToRenderer, cameraForward);
// The magnitude of the projected vector is the distance along the camera's forward direction
// Formula: projection = dot(directionToRenderer, cameraForward) * cameraForward
// Distance = |projection| = |dot(directionToRenderer, cameraForward)|
DistanceToCamera = projection.magnitude;
}
/// <summary>
/// <see cref="PropertyBlock"/> backing field.
/// </summary>
private MaterialPropertyBlock _propertyBlock;
/// <summary>
/// <see cref="MaterialPropertyBlock"/>
/// </summary>
private MaterialPropertyBlock PropertyBlock
{
get
{
// Lazily initialize.
if (_propertyBlock == null)
{
_propertyBlock = new MaterialPropertyBlock();
}
return _propertyBlock;
}
}
/// <summary>
/// Applies common rendering texture for rendering.
/// </summary>
/// <param name="passData">Pass data containing render controllers and camera data.</param>
private void ApplyBlendedRenderTexture(CubismRenderPassFeature.CubismRenderPass.PassData passData)
{
if (!RenderController?.CurrentFrameBuffer)
{
return;
}
var property = PropertyBlock;
MeshRenderer.GetPropertyBlock(property);
// Write property.
property.SetTexture(CubismShaderVariables.RenderTexture, passData.CommonTemporaryTextureHandle);
MeshRenderer.SetPropertyBlock(property);
}
/// <summary>
/// Adds this renderer to the command buffer for rendering.
/// </summary>
/// <param name="buffer">Command buffer to record draw commands.</param>
/// <param name="passData">Pass data containing render controllers and camera data.</param>
public void DrawObject(CommandBuffer buffer, CubismRenderPassFeature.CubismRenderPass.PassData passData)//, RenderTexture frameBuffer)
{
if (!MeshRenderer)
{
return;
}
switch (DrawObjectType)
{
case CubismModelTypes.DrawObjectType.Offscreen:
// Set offscreen frame buffer.
SetOffscreen(buffer, passData);
break;
case CubismModelTypes.DrawObjectType.Drawable:
// Draw a drawable.
DrawDrawable(buffer, passData);
break;
}
}
/// <summary>
/// Applies transform properties to the material property block.
/// </summary>
private void ApplyTransform()
{
var property = PropertyBlock;
MeshRenderer.GetPropertyBlock(property);
// Set offset and scale from transform.
var offsetScale = _offsetScale;
offsetScale.Set(RenderController.transform.localPosition.x + transform.localPosition.x, RenderController.transform.localPosition.y + transform.localPosition.y,
RenderController.transform.localScale.x * transform.localScale.x, RenderController.transform.localScale.y * transform.localScale.y);
_offsetScale = offsetScale;
// Write property.
property.SetVector(CubismShaderVariables.OffsetScale, _offsetScale);
// Set rotation from transform.
var combinedRotation = RenderController.transform.localRotation * transform.localRotation;
_quaternion.Set(combinedRotation.x, combinedRotation.y, combinedRotation.z, combinedRotation.w);
// Write property.
property.SetVector(CubismShaderVariables.RotationQuaternion, _quaternion);
// Set z offset from transform.
_zOffset = RenderController.transform.localPosition.z + transform.localPosition.z;
// Write property.
property.SetFloat(CubismShaderVariables.ZOffset, _zOffset);
MeshRenderer.SetPropertyBlock(property);
}
/// <summary>
/// Sets the offscreen frame buffer for rendering.
/// </summary>
/// <param name="buffer">Command buffer to record draw commands.</param>
/// <param name="passData">Pass data containing render controllers and camera data.</param>
private void SetOffscreen(CommandBuffer buffer, CubismRenderPassFeature.CubismRenderPass.PassData passData)
{
var currentOffscreenUnmanagedIndex = RenderController.CurrentOffscreenUnmanagedIndex;
SubmitDrawToParentOffscreen(ref passData, ref currentOffscreenUnmanagedIndex,
buffer, this);
// Ready the render target to the offscreen frame buffer.
OffscreenFrameBuffer = CubismOffscreenRenderTextureManager.GetInstance().GetOffscreenRenderTexture(passData.CommonRenderingTextureHandle);
// Set current frame buffer to offscreen frame buffer.
buffer.SetRenderTarget(OffscreenFrameBuffer);
// Clear the offscreen frame buffer.
buffer.ClearRenderTarget(false, true, Color.clear);
// Set up for drawing to offscreen.
RenderController.CurrentFrameBuffer = OffscreenFrameBuffer;
RenderController.CurrentOffscreenUnmanagedIndex = Offscreen.UnmanagedIndex;
}
/// <summary>
/// Gets the bounds that can contain all masks.
/// </summary>
/// <returns></returns>
private Bounds GetMaskBounds()
{
// If there are no masks, return empty bounds.
if (_masks == null
|| _masks.Length < 1)
{
return new Bounds();
}
var min = _masks[0]?.Mesh?.bounds.min ?? Vector3.zero;
var max = _masks[0]?.Mesh?.bounds.max ?? Vector3.zero;
for (var i = 1; i < _masks.Length; ++i)
{
// Skip if the mask is null.
if (!_masks[i])
{
continue;
}
var boundsI = _masks[i].Mesh.bounds;
if (boundsI.min.x < min.x)
{
min.x = boundsI.min.x;
}
if (boundsI.max.x > max.x)
{
max.x = boundsI.max.x;
}
if (boundsI.min.y < min.y)
{
min.y = boundsI.min.y;
}
if (boundsI.max.y > max.y)
{
max.y = boundsI.max.y;
}
}
var bounds = _maskBounds;
bounds.SetMinMax(min, max);
_maskBounds = bounds;
return _maskBounds;
}
/// <summary>
/// Calculates the transform values for mask rendering based on mask bounds.
/// </summary>
private void CalcMaskTransform()
{
// Compute bounds and scale.
var bounds = GetMaskBounds();
var scale = (bounds.size.x > bounds.size.y)
? bounds.size.x
: bounds.size.y;
// Compute mask transform.
var maskTransform = _maskTransform;
maskTransform.Set(
bounds.center.x, // Offset X
bounds.center.y, // Offset Y
1.0f / scale, // Scale
0 // Dummy, unused.
);
_maskTransform = maskTransform;
}
/// <summary>
/// Draws the mask.
/// </summary>
/// <param name="buffer">Command buffer to record draw commands.</param>
/// <param name="passData">Pass data containing render controllers and camera data.</param>
internal void DrawMasks(CommandBuffer buffer, CubismRenderPassFeature.CubismRenderPass.PassData passData)
{
// If the model doesn't have masks, return.
if (!RenderController.HasMask)
{
return;
}
#if UNITY_EDITOR
// If the masks have null, try to initialize them.
if (_haveMasksNull)
{
TryInitializeMasks();
_haveMasksNull = false;
}
#endif
if (_masks?.Length > 0)
{
var maskTexture = passData.MaskTextureHandle;
buffer.SetRenderTarget(maskTexture);
buffer.ClearRenderTarget(true, true, Color.clear);
// Calculate mask transform.
CalcMaskTransform();
// Draw the masks.
for (var maskIndex = 0; maskIndex < _masks.Length; maskIndex++)
{
var mask = _masks[maskIndex];
if (!mask)
{
#if UNITY_EDITOR
_haveMasksNull = true;
#endif
continue;
}
switch (DrawObjectType)
{
case CubismModelTypes.DrawObjectType.Drawable:
mask.PropertyBlock.SetTexture(CubismShaderVariables.MainTexture, mask.MainTexture);
mask.PropertyBlock.SetVector(CubismShaderVariables.MaskTile, HighPrecisionMaskTile);
mask.PropertyBlock.SetVector(CubismShaderVariables.MaskTransform, _maskTransform);
// Draw the mesh with the material.
buffer.DrawMesh(
mask.Mesh,
Matrix4x4.identity,
mask.Drawable.IsDoubleSided
? CubismBuiltinMaterials.Mask
: CubismBuiltinMaterials.MaskCulling,
0,
0,
mask.PropertyBlock);
break;
case CubismModelTypes.DrawObjectType.Offscreen:
mask.PropertyBlock.SetTexture(CubismShaderVariables.MainTexture, mask.MainTexture);
mask.ApplyTransform();
// Draw the mesh with the material.
buffer.DrawMesh(
mask.Mesh,
Matrix4x4.identity,
CubismBuiltinMaterials.OffscreenMask,
0,
0,
mask.PropertyBlock);
break;
default:
Debug.LogWarning("Unknown DrawObjectType.");
break;
}
}
ApplyMask(maskTexture);
}
}
/// <summary>
/// Submits the offscreen frame buffer and draws to the parent offscreen if necessary.
/// </summary>
/// <param name="passData">Pass data containing render controllers and camera data.</param>
/// <param name="currentOffscreenUnmanagedIndex">Current offscreen's unmanaged index.</param>
/// <param name="buffer">Command buffer to record draw commands.</param>
/// <param name="targetRenderer">Current target rendering object.</param>
private void SubmitDrawToParentOffscreen(ref CubismRenderPassFeature.CubismRenderPass.PassData passData, ref int currentOffscreenUnmanagedIndex,
CommandBuffer buffer, CubismRenderer targetRenderer)
{
if (passData == null
|| RenderController.CurrentFrameBuffer == (RenderTexture)passData.CommonRenderingTextureHandle
|| currentOffscreenUnmanagedIndex == -1)
{
return;
}
// Get the current offscreen renderer.
CubismRenderer offscreenRenderer = null;
for (var offscreenRendererIndex = 0; offscreenRendererIndex < RenderController.OffscreenRenderers.Length; offscreenRendererIndex++)
{
if (RenderController.OffscreenRenderers[offscreenRendererIndex].Offscreen.UnmanagedIndex !=
currentOffscreenUnmanagedIndex)
{
continue;
}
offscreenRenderer = RenderController.OffscreenRenderers[offscreenRendererIndex];
break;
}
var currentOwnerIndex = offscreenRenderer?.Offscreen.OwnerIndex ?? -1;
if (currentOwnerIndex == -1)
{
// Fail silently if the offscreen renderer is not found.
return;
}
var targetParentIndex = -1;
RenderTexture previousOffscreen = null;
switch (targetRenderer.DrawObjectType)
{
case CubismModelTypes.DrawObjectType.Drawable:
targetParentIndex = targetRenderer.Drawable.ParentPartIndex;
break;
case CubismModelTypes.DrawObjectType.Offscreen:
// Check target renderer's offscreen owner type.
targetParentIndex = RenderController.Model.Parts[targetRenderer.Offscreen.OwnerIndex].UnmanagedParentIndex;
break;
default:
// If the draw object type is not drawable or offscreen, return.
return;
}
// If targetRenderer isn't child of the current offscreen renderer.
while (targetParentIndex != -1)
{
// If the target parent index is the same as the current owner index, return.
if (targetParentIndex == RenderController.Model.Parts[currentOwnerIndex].UnmanagedIndex)
{
return;
}
targetParentIndex = RenderController.Model.Parts[targetParentIndex].UnmanagedParentIndex;
}
var parentIndex = RenderController.Model.Parts[currentOwnerIndex].UnmanagedParentIndex;
// Find the offscreen renderer with the previous offscreen unmanaged index.
while (parentIndex != -1)
{
var part = RenderController.Model.Parts[parentIndex];
if (part.OffscreenIndex != -1)
{
for (var offscreenRendererIndex = 0; offscreenRendererIndex < RenderController.OffscreenRenderers.Length; offscreenRendererIndex++)
{
var element = RenderController.OffscreenRenderers[offscreenRendererIndex];
if (!element.isActiveAndEnabled
|| !element.MeshRenderer.enabled
|| element.Offscreen.UnmanagedIndex != part.OffscreenIndex)
{
continue;
}
previousOffscreen = RenderController.OffscreenRenderers[offscreenRendererIndex].OffscreenFrameBuffer;
_previousOffscreenUnmanagedIndex = part.OffscreenIndex;
break;
}
}
parentIndex = RenderController.Model.Parts[parentIndex].UnmanagedParentIndex;
if (!previousOffscreen)
{
continue;
}
break;
}
// Try to get the root part offscreen if there is no parent offscreen.
if (!previousOffscreen && RenderController.HasRootPartOffscreen)
{
var offscreenRenderers = RenderController.OffscreenRenderers;
for (var offscreenIndex = 0; offscreenIndex < offscreenRenderers.Length; offscreenIndex++)
{
if (offscreenRenderers[offscreenIndex].Offscreen.UnmanagedIndex != 0)
{
continue;
}
previousOffscreen = offscreenRenderers[offscreenIndex].OffscreenFrameBuffer;
break;
}
}
// If there is no parent offscreen, use the common rendering texture.
if (!previousOffscreen)
{
previousOffscreen = passData.CommonRenderingTextureHandle;
}
if (previousOffscreen == offscreenRenderer?.OffscreenFrameBuffer)
{
return;
}
// If It can copy the parent offscreen, copy it to the current offscreen renderer.
DrawOffscreen(buffer, previousOffscreen, offscreenRenderer, passData);
offscreenRenderer.OffscreenFrameBuffer = null;
RenderController.CurrentFrameBuffer = previousOffscreen;
currentOffscreenUnmanagedIndex = _previousOffscreenUnmanagedIndex;
// If the current offscreen is the parent of the target renderer, draw to the parent offscreen.
SubmitDrawToParentOffscreen(ref passData, ref currentOffscreenUnmanagedIndex,
buffer, targetRenderer);
}
/// <summary>
/// Renders a drawable.
/// </summary>
/// <param name="buffer">Command buffer to record draw commands.</param>
/// <param name="passData">Pass data containing render controllers and camera data.</param>
private void DrawDrawable(CommandBuffer buffer, CubismRenderPassFeature.CubismRenderPass.PassData passData)
{
if (!RenderController)
{
return;
}
if (RenderController.CurrentOffscreenUnmanagedIndex != -1)
{
var currentOffscreenOwnerUnmanagedIndex = RenderController.CurrentOffscreenUnmanagedIndex;
SubmitDrawToParentOffscreen(ref passData, ref currentOffscreenOwnerUnmanagedIndex,
buffer, this);
RenderController.CurrentOffscreenUnmanagedIndex = currentOffscreenOwnerUnmanagedIndex;
}
// Mask rendering.
DrawMasks(buffer, passData);
// Set property block.
ApplyMainTexture();
ApplyBlendedRenderTexture(passData);
ApplyScreenColor();
ApplyMultiplyColor();
ApplyVertexColors();
ApplyTransform();
// In the case of color blending before Cubism 5.2.
if ((ColorBlendType == BlendTypes.ColorBlend.Normal
&& AlphaBlendType == BlendTypes.AlphaBlend.Over)
|| ColorBlendType == BlendTypes.ColorBlend.Add
|| ColorBlendType == BlendTypes.ColorBlend.Multiply)
{
// If the current frame buffer is different from the common rendering texture, update it.
// HACK: Assumes that the size has already been corrected in the `SetOffscreen()` function for cases where drawing occurs to the offscreen.
if (!RenderController.CurrentFrameBuffer
|| RenderController.CurrentFrameBuffer.width != ((RenderTexture)passData.CameraDepthTextureHandle).width
|| RenderController.CurrentFrameBuffer.height != ((RenderTexture)passData.CameraDepthTextureHandle).height)
{
RenderController.CurrentFrameBuffer = passData.CommonRenderingTextureHandle;
}
// Set render target with depth buffer for proper depth testing
buffer.SetRenderTarget(RenderController.CurrentFrameBuffer, passData.CameraDepthTextureHandle);
// Draw the mesh with the material.
buffer.DrawMesh(Mesh, Matrix4x4.identity, DrawMaterial ?? Material, 0, 0, PropertyBlock);
return;
}
// Blit to temporary texture.
buffer.Blit(RenderController.CurrentFrameBuffer, passData.CommonTemporaryTextureHandle);
// Set temporary render target.
buffer.SetRenderTarget(RenderController.CurrentFrameBuffer, passData.CameraDepthTextureHandle);
// Draw the mesh with the material.
buffer.DrawMesh(Mesh, Matrix4x4.identity, DrawMaterial ?? Material, 0, 0, PropertyBlock);
}
/// <summary>
/// Copies the current drawable to the parent offscreen.
/// </summary>
/// <param name="buffer">Command buffer to record draw commands.</param>
/// <param name="previousOffscreen">Previous offscreen render texture.</param>
/// <param name="currentOffscreenRenderer">Current offscreen renderer.</param>
/// <param name="passData">Pass data containing render controllers and camera data.</param>
internal void DrawOffscreen(CommandBuffer buffer, RenderTexture previousOffscreen, CubismRenderer currentOffscreenRenderer, CubismRenderPassFeature.CubismRenderPass.PassData passData)
{
if (previousOffscreen == null
|| currentOffscreenRenderer == null)
{
return;
}
// Draw the mesh with the material.
currentOffscreenRenderer.DrawOffscreenMesh(buffer, previousOffscreen, passData);
}
/// <summary>
/// Draws the mesh for offscreen rendering.
/// </summary>
/// <param name="buffer">Command buffer to record draw commands.</param>
/// <param name="previousOffscreen">Previous offscreen render texture.</param>
/// <param name="passData">Pass data containing render controllers and camera data.</param>
internal void DrawOffscreenMesh(CommandBuffer buffer, RenderTexture previousOffscreen, CubismRenderPassFeature.CubismRenderPass.PassData passData)
{
// Mask rendering.
DrawMasks(buffer, passData);
ApplyPropertyForOffscreen(previousOffscreen);
// In the case of color blending before Cubism 5.2.
if ((ColorBlendType == BlendTypes.ColorBlend.Normal
&& AlphaBlendType == BlendTypes.AlphaBlend.Over)
|| ColorBlendType == BlendTypes.ColorBlend.Add
|| ColorBlendType == BlendTypes.ColorBlend.Multiply)
{
buffer.SetRenderTarget(previousOffscreen, passData.CameraDepthTextureHandle);
// Draw the mesh with the material.
buffer.DrawMesh(Mesh, Matrix4x4.identity, DrawMaterial ?? Material, 0, 0, PropertyBlock);
return;
}
// Set temporary render target.
buffer.SetRenderTarget(passData.CommonTemporaryTextureHandle, passData.CameraDepthTextureHandle);
// Clear the render target.
buffer.ClearRenderTarget(false, true, Color.clear);
// Draw the mesh with the material.
buffer.DrawMesh(Mesh, Matrix4x4.identity, DrawMaterial ?? Material, 0, 0, PropertyBlock);
// Blit to previous offscreen.
buffer.Blit(passData.CommonTemporaryTextureHandle, previousOffscreen);
}
/// <summary>
/// Applies properties for offscreen rendering.
/// </summary>
/// <param name="previousOffscreen">Previous offscreen render texture.</param>
private void ApplyPropertyForOffscreen(RenderTexture previousOffscreen)
{
var property = PropertyBlock;
MeshRenderer.GetPropertyBlock(property);
// Write property.
property.SetTexture(CubismShaderVariables.MainTexture, OffscreenFrameBuffer);
property.SetTexture(CubismShaderVariables.RenderTexture, previousOffscreen);
property.SetColor(CubismShaderVariables.MultiplyColor, MultiplyColor);
property.SetColor(CubismShaderVariables.ScreenColor, ScreenColor);
property.SetFloat(CubismShaderVariables.OffscreenOpacity, Offscreen.Opacity);
var reversedZ = SystemInfo.usesReversedZBuffer ? CubismRenderPassFeature.GEqual : CubismRenderPassFeature.LEqual;
property.SetInt(CubismShaderVariables.ReversedZ, reversedZ);
MeshRenderer.SetPropertyBlock(property);
}
/// <summary>
/// Applies mask texture for rendering.
/// </summary>
/// <param name="maskTextureHandle">Texture handle for the mask texture.</param>
private void ApplyMask(TextureHandle maskTextureHandle)
{
MeshRenderer.GetPropertyBlock(PropertyBlock);
// Write property.
PropertyBlock.SetTexture(CubismShaderVariables.MaskTexture, maskTextureHandle);
if (DrawObjectType == CubismModelTypes.DrawObjectType.Drawable)
{
PropertyBlock.SetVector(CubismShaderVariables.MaskTile, HighPrecisionMaskTile);
PropertyBlock.SetVector(CubismShaderVariables.MaskTransform, _maskTransform);
}
MeshRenderer.SetPropertyBlock(PropertyBlock);
}
/// <summary>
/// Initializes masks if possible.
/// </summary>
private void TryInitializeMasks()
{
if (!RenderController.HasMask)
{
return;
}
CubismDrawable[] maskDrawables = null;
switch (DrawObjectType)
{
case CubismModelTypes.DrawObjectType.Drawable:
_masks = new CubismRenderer[Drawable.Masks.Length];
maskDrawables = Drawable.Masks;
break;
case CubismModelTypes.DrawObjectType.Offscreen:
_masks = new CubismRenderer[Offscreen.Masks.Length];
maskDrawables = Offscreen.Masks;
break;
default:
Debug.LogWarning($"{name} has unknown DrawObjectType.");
return;
}
for (var maskIndex = 0; maskIndex < maskDrawables.Length; maskIndex++)
{
for (var drawableRendererIndex = 0; drawableRendererIndex < RenderController.DrawableRenderers.Length; drawableRendererIndex++)
{
if (RenderController.DrawableRenderers[drawableRendererIndex].Drawable.UnmanagedIndex != maskDrawables[maskIndex].UnmanagedIndex)
{
continue;
}
_masks[maskIndex] = RenderController.DrawableRenderers[drawableRendererIndex];
break;
}
}
}
/// <summary>
/// Initializes the draw object based on its type.
/// </summary>
private void InitializeDrawObject()
{
switch (DrawObjectType)
{
case CubismModelTypes.DrawObjectType.Drawable:
{
Drawable = GetComponent<CubismDrawable>();
DrawObjectUnmanagedIndex = Drawable.UnmanagedIndex;
break;
}
case CubismModelTypes.DrawObjectType.Offscreen:
{
Offscreen = GetComponent<CubismOffscreen>();
DrawObjectUnmanagedIndex = Offscreen.UnmanagedIndex;
break;
}
default:
DrawObjectUnmanagedIndex = -1;
break;
}
}
/// <summary>
/// Called after all <see cref="CubismRenderer"/> are initialized.
/// </summary>
public void OnAfterAllRendererInitialize()
{
TryInitializeMasks();
}
}
}