Flatkit 추가 및 설정

This commit is contained in:
2026-01-25 11:27:33 +09:00
parent 05233497e7
commit cf16910a32
1938 changed files with 408633 additions and 244 deletions

View File

@@ -0,0 +1,284 @@
using UnityEngine;
using UnityEngine.Rendering.Universal;
#if UNITY_2022_3_OR_NEWER
using ExternPropertyAttributes;
namespace FlatKit {
public class FlatKitOutline : ScriptableRendererFeature {
[Tooltip("To create new settings use 'Create > FlatKit > Outline Settings'.")]
[Expandable]
public OutlineSettings settings;
private Material _effectMaterial;
private ScreenRenderPass _fullScreenPass;
private bool _requiresColor;
private bool _injectedBeforeTransparents;
private ScriptableRenderPassInput _requirements = ScriptableRenderPassInput.Color;
private const string ShaderName = "Hidden/FlatKit/OutlineWrap";
private static int edgeColor => Shader.PropertyToID("_EdgeColor");
private static int thickness => Shader.PropertyToID("_Thickness");
private static int depthThresholdMin => Shader.PropertyToID("_DepthThresholdMin");
private static int depthThresholdMax => Shader.PropertyToID("_DepthThresholdMax");
private static int normalThresholdMin => Shader.PropertyToID("_NormalThresholdMin");
private static int normalThresholdMax => Shader.PropertyToID("_NormalThresholdMax");
private static int colorThresholdMin => Shader.PropertyToID("_ColorThresholdMin");
private static int colorThresholdMax => Shader.PropertyToID("_ColorThresholdMax");
private static int fadeRangeStart => Shader.PropertyToID("_FadeRangeStart");
private static int fadeRangeEnd => Shader.PropertyToID("_FadeRangeEnd");
/// <summary>
/// Access the runtime effect material to override outline parameters at runtime
/// without mutating the Settings asset.
///
/// Shader (2022.3+ path): "Hidden/FlatKit/OutlineWrap"
///
/// Common shader properties/keywords:
/// - Floats: _Thickness, _DepthThresholdMin/_Max, _NormalThresholdMin/_Max, _ColorThresholdMin/_Max,
/// _FadeRangeStart, _FadeRangeEnd
/// - Colors: _EdgeColor
/// - Keywords: OUTLINE_USE_DEPTH, OUTLINE_USE_NORMALS, OUTLINE_USE_COLOR,
/// OUTLINE_ONLY, RESOLUTION_INVARIANT_THICKNESS, OUTLINE_FADE_OUT
///
/// Note: Inspector changes on the Settings asset may overwrite your values if applied later.
/// </summary>
public Material EffectMaterial => _effectMaterial;
public override void Create() {
// Settings.
{
if (settings == null) return;
settings.onSettingsChanged = null;
settings.onReset = null;
settings.onSettingsChanged += SetMaterialProperties;
settings.onReset += SetMaterialProperties;
}
// Material.
{
#if UNITY_EDITOR
settings.effectMaterial = SubAssetMaterial.GetOrCreate(settings, ShaderName);
if (settings.effectMaterial == null) return;
#endif
_effectMaterial = settings.effectMaterial;
SetMaterialProperties();
}
{
_fullScreenPass = new ScreenRenderPass {
renderPassEvent = settings.renderEvent,
};
_requirements = ScriptableRenderPassInput.Color; // Needed for the full-screen blit.
if (settings.useDepth) _requirements |= ScriptableRenderPassInput.Depth;
if (settings.useNormals) _requirements |= ScriptableRenderPassInput.Normal;
if (settings.fadeWithDistance) _requirements |= ScriptableRenderPassInput.Depth;
ScriptableRenderPassInput modifiedRequirements = _requirements;
_requiresColor = (_requirements & ScriptableRenderPassInput.Color) != 0;
_injectedBeforeTransparents = settings.renderEvent <= RenderPassEvent.BeforeRenderingTransparents;
if (_requiresColor && !_injectedBeforeTransparents) {
modifiedRequirements ^= ScriptableRenderPassInput.Color;
}
_fullScreenPass.ConfigureInput(modifiedRequirements);
}
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) {
if (settings == null || !settings.applyInSceneView && renderingData.cameraData.isSceneViewCamera) return;
if (renderingData.cameraData.isPreviewCamera) return;
if (_effectMaterial == null) return;
_fullScreenPass.Setup(_effectMaterial, _requiresColor, _injectedBeforeTransparents, "Flat Kit Outline",
renderingData);
renderer.EnqueuePass(_fullScreenPass);
}
protected override void Dispose(bool disposing) {
_fullScreenPass?.Dispose();
}
private void SetMaterialProperties() {
if (_effectMaterial == null) return;
const string depthKeyword = "OUTLINE_USE_DEPTH";
RendererFeatureUtils.SetKeyword(_effectMaterial, depthKeyword, settings.useDepth);
const string normalsKeyword = "OUTLINE_USE_NORMALS";
RendererFeatureUtils.SetKeyword(_effectMaterial, normalsKeyword, settings.useNormals);
const string colorKeyword = "OUTLINE_USE_COLOR";
RendererFeatureUtils.SetKeyword(_effectMaterial, colorKeyword, settings.useColor);
const string outlineOnlyKeyword = "OUTLINE_ONLY";
RendererFeatureUtils.SetKeyword(_effectMaterial, outlineOnlyKeyword, settings.outlineOnly);
const string resolutionInvariantKeyword = "RESOLUTION_INVARIANT_THICKNESS";
RendererFeatureUtils.SetKeyword(_effectMaterial, resolutionInvariantKeyword, settings.resolutionInvariant);
const string fadeWithDistanceKeyword = "OUTLINE_FADE_OUT";
RendererFeatureUtils.SetKeyword(_effectMaterial, fadeWithDistanceKeyword, settings.fadeWithDistance);
_effectMaterial.SetColor(edgeColor, settings.edgeColor);
_effectMaterial.SetFloat(thickness, settings.thickness);
_effectMaterial.SetFloat(depthThresholdMin, settings.minDepthThreshold);
_effectMaterial.SetFloat(depthThresholdMax, settings.maxDepthThreshold);
_effectMaterial.SetFloat(normalThresholdMin, settings.minNormalsThreshold);
_effectMaterial.SetFloat(normalThresholdMax, settings.maxNormalsThreshold);
_effectMaterial.SetFloat(colorThresholdMin, settings.minColorThreshold);
_effectMaterial.SetFloat(colorThresholdMax, settings.maxColorThreshold);
_effectMaterial.SetFloat(fadeRangeStart, settings.fadeRangeStart);
_effectMaterial.SetFloat(fadeRangeEnd, settings.fadeRangeEnd);
}
}
}
#else
namespace FlatKit {
public class FlatKitOutline : ScriptableRendererFeature {
[Tooltip("To create new settings use 'Create > FlatKit > Outline Settings'.")]
public OutlineSettings settings;
[SerializeField, HideInInspector]
private Material _effectMaterial;
private BlitTexturePass _blitTexturePass;
private static readonly string OutlineShaderName = "Hidden/FlatKit/OutlineFilter";
private static readonly int EdgeColor = Shader.PropertyToID("_EdgeColor");
private static readonly int Thickness = Shader.PropertyToID("_Thickness");
private static readonly int DepthThresholdMin = Shader.PropertyToID("_DepthThresholdMin");
private static readonly int DepthThresholdMax = Shader.PropertyToID("_DepthThresholdMax");
private static readonly int NormalThresholdMin = Shader.PropertyToID("_NormalThresholdMin");
private static readonly int NormalThresholdMax = Shader.PropertyToID("_NormalThresholdMax");
private static readonly int ColorThresholdMin = Shader.PropertyToID("_ColorThresholdMin");
private static readonly int ColorThresholdMax = Shader.PropertyToID("_ColorThresholdMax");
/// <summary>
/// Access the runtime effect material to override outline parameters at runtime
/// without mutating the Settings asset.
///
/// Shader (legacy path): "Hidden/FlatKit/OutlineFilter"
///
/// Common shader properties/keywords:
/// - Floats: _Thickness, _DepthThresholdMin/_Max, _NormalThresholdMin/_Max, _ColorThresholdMin/_Max
/// - Colors: _EdgeColor
/// - Keywords: OUTLINE_USE_DEPTH, OUTLINE_USE_NORMALS, OUTLINE_USE_COLOR,
/// OUTLINE_ONLY, RESOLUTION_INVARIANT_THICKNESS
///
/// Note: Inspector changes on the Settings asset may overwrite your values if applied later.
/// </summary>
public Material EffectMaterial => _effectMaterial;
public override void Create() {
#if UNITY_EDITOR
if (_effectMaterial == null) {
SubAssetMaterial.AlwaysInclude(BlitTexturePass.CopyEffectShaderName);
SubAssetMaterial.AlwaysInclude(OutlineShaderName);
}
#endif
if (settings == null) {
return;
}
if (!CreateMaterials()) {
return;
}
SetMaterialProperties();
_blitTexturePass ??=
new BlitTexturePass(_effectMaterial, settings.useDepth, settings.useNormals, useColor: true);
}
protected override void Dispose(bool disposing) {
_blitTexturePass.Dispose();
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) {
#if UNITY_EDITOR
if (renderingData.cameraData.isPreviewCamera) return;
if (!settings.applyInSceneView && renderingData.cameraData.cameraType == CameraType.SceneView) return;
#endif
SetMaterialProperties();
_blitTexturePass.Setup(renderingData);
_blitTexturePass.renderPassEvent = settings.renderEvent;
renderer.EnqueuePass(_blitTexturePass);
}
private bool CreateMaterials() {
if (_effectMaterial == null) {
var effectShader = Shader.Find(OutlineShaderName);
var blitShader = Shader.Find(BlitTexturePass.CopyEffectShaderName);
if (effectShader == null || blitShader == null) return false;
_effectMaterial = UnityEngine.Rendering.CoreUtils.CreateEngineMaterial(effectShader);
}
return _effectMaterial != null;
}
private void SetMaterialProperties() {
if (_effectMaterial == null) {
return;
}
const string depthKeyword = "OUTLINE_USE_DEPTH";
if (settings.useDepth) {
_effectMaterial.EnableKeyword(depthKeyword);
} else {
_effectMaterial.DisableKeyword(depthKeyword);
}
const string normalsKeyword = "OUTLINE_USE_NORMALS";
if (settings.useNormals) {
_effectMaterial.EnableKeyword(normalsKeyword);
} else {
_effectMaterial.DisableKeyword(normalsKeyword);
}
const string colorKeyword = "OUTLINE_USE_COLOR";
if (settings.useColor) {
_effectMaterial.EnableKeyword(colorKeyword);
} else {
_effectMaterial.DisableKeyword(colorKeyword);
}
const string outlineOnlyKeyword = "OUTLINE_ONLY";
if (settings.outlineOnly) {
_effectMaterial.EnableKeyword(outlineOnlyKeyword);
} else {
_effectMaterial.DisableKeyword(outlineOnlyKeyword);
}
const string resolutionInvariantKeyword = "RESOLUTION_INVARIANT_THICKNESS";
if (settings.resolutionInvariant) {
_effectMaterial.EnableKeyword(resolutionInvariantKeyword);
} else {
_effectMaterial.DisableKeyword(resolutionInvariantKeyword);
}
_effectMaterial.SetColor(EdgeColor, settings.edgeColor);
_effectMaterial.SetFloat(Thickness, settings.thickness);
_effectMaterial.SetFloat(DepthThresholdMin, settings.minDepthThreshold);
_effectMaterial.SetFloat(DepthThresholdMax, settings.maxDepthThreshold);
_effectMaterial.SetFloat(NormalThresholdMin, settings.minNormalsThreshold);
_effectMaterial.SetFloat(NormalThresholdMax, settings.maxNormalsThreshold);
_effectMaterial.SetFloat(ColorThresholdMin, settings.minColorThreshold);
_effectMaterial.SetFloat(ColorThresholdMax, settings.maxColorThreshold);
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1cca7768aaaea4b0081f14e7f9d4b5ad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,109 @@
#ifndef FLAT_KIT_OUTLINE_INCLUDED
#define FLAT_KIT_OUTLINE_INCLUDED
TEXTURE2D_X (_BlitTexture);
SAMPLER (sampler_BlitTexture);
float Linear01Depth(float z)
{
const float isOrtho = unity_OrthoParams.w;
const float isPers = 1.0 - unity_OrthoParams.w;
z *= _ZBufferParams.x;
return (1.0 - isOrtho * z) / (isPers * z + _ZBufferParams.y);
}
float SampleDepth(float2 uv)
{
const float d = SampleSceneDepth(uv);
return Linear01Depth(d);
}
float4 SampleCameraColor(float2 uv)
{
return SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_BlitTexture, UnityStereoTransformScreenSpaceTex(uv));
}
void Outline_float(float2 UV, out float4 Out)
{
float4 original = SampleCameraColor(UV);
const float offset_positive = +ceil(_Thickness * 0.5f);
const float offset_negative = -floor(_Thickness * 0.5f);
#if RESOLUTION_INVARIANT_THICKNESS
const float screen_ratio = _ScreenSize.x / _ScreenSize.y;
const float2 texel_size = 1.0 / 800.0 * float2(1.0, screen_ratio);
#else
const float2 texel_size = _ScreenSize.zw;
#endif
float left = texel_size.x * offset_negative;
float right = texel_size.x * offset_positive;
float top = texel_size.y * offset_negative;
float bottom = texel_size.y * offset_positive;
const float2 uv0 = UV + float2(left, top);
const float2 uv1 = UV + float2(right, bottom);
const float2 uv2 = UV + float2(right, top);
const float2 uv3 = UV + float2(left, bottom);
#ifdef OUTLINE_USE_DEPTH
const float d0 = SampleDepth(uv0);
const float d1 = SampleDepth(uv1);
const float d2 = SampleDepth(uv2);
const float d3 = SampleDepth(uv3);
const float depth_threshold_scale = 300.0f;
float d = length(float2(d1 - d0, d3 - d2)) * depth_threshold_scale;
d = smoothstep(_DepthThresholdMin, _DepthThresholdMax, d);
#else
float d = 0.0f;
#endif // OUTLINE_USE_DEPTH
#ifdef OUTLINE_USE_NORMALS
const float3 n0 = SampleSceneNormals(uv0);
const float3 n1 = SampleSceneNormals(uv1);
const float3 n2 = SampleSceneNormals(uv2);
const float3 n3 = SampleSceneNormals(uv3);
const float3 nd1 = n1 - n0;
const float3 nd2 = n3 - n2;
float n = sqrt(dot(nd1, nd1) + dot(nd2, nd2));
n = smoothstep(_NormalThresholdMin, _NormalThresholdMax, n);
#else
float n = 0.0f;
#endif // OUTLINE_USE_NORMALS
#ifdef OUTLINE_USE_COLOR
const float3 c0 = SampleCameraColor(uv0).rgb;
const float3 c1 = SampleCameraColor(uv1).rgb;
const float3 c2 = SampleCameraColor(uv2).rgb;
const float3 c3 = SampleCameraColor(uv3).rgb;
const float3 cd1 = c1 - c0;
const float3 cd2 = c3 - c2;
float c = sqrt(dot(cd1, cd1) + dot(cd2, cd2));
c = smoothstep(_ColorThresholdMin, _ColorThresholdMax, c);
#else
float c = 0;
#endif // OUTLINE_USE_COLOR
const float g = max(d, max(n, c));
#ifdef OUTLINE_FADE_OUT
const float linear_depth = LinearEyeDepth(SampleSceneDepth(UV), _ZBufferParams);
const float fade = smoothstep(_FadeRangeEnd, _FadeRangeStart, linear_depth);
_EdgeColor.a *= fade;
#endif // OUTLINE_FADE_OUT
#ifdef OUTLINE_ONLY
original.rgb = lerp(1.0 - _EdgeColor.rgb, _EdgeColor.rgb, g * _EdgeColor.a);
#endif // OUTLINE_ONLY
float4 output;
output.rgb = lerp(original.rgb, _EdgeColor.rgb, g * _EdgeColor.a);
output.a = original.a;
Out = output;
}
#endif // FLAT_KIT_OUTLINE_INCLUDED

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 55858e4cd94d48b0a267735f29dd1e5e
timeCreated: 1691384044

View File

@@ -0,0 +1,201 @@
using System;
using ExternPropertyAttributes;
using UnityEngine;
using UnityEngine.Rendering.Universal;
using Debug = UnityEngine.Debug;
// ReSharper disable RedundantDefaultMemberInitializer
#if UNITY_2022_3_OR_NEWER
namespace FlatKit {
[CreateAssetMenu(fileName = "OutlineSettings", menuName = "FlatKit/Outline Settings")]
public class OutlineSettings : ScriptableObject {
[Space] // Expandable.
[Tooltip("The color of the lines. Alpha is used for transparency, " +
"0 means fully transparent and 1 means fully opaque lines.")]
public Color edgeColor = Color.white;
[Range(0, 5)]
[Tooltip("The width of the lines in screen space. If 'Resolution Invariant' is disabled, " +
"this is the width in pixels. Otherwise, it is a relative width.")]
public int thickness = 1;
[Tooltip("If enabled, the line width will stay constant regardless of the rendering resolution. " +
"However, some of the lines may appear blurry.")]
public bool resolutionInvariant = false;
[Tooltip("If enabled, the outline will become more transparent the further away it is from the camera.")]
public bool fadeWithDistance = false;
[ShowIf(nameof(fadeWithDistance))]
[Label(" Start")]
[Tooltip("The distance from the camera at which the outline starts to fade. The value is in world units.")]
public float fadeRangeStart = 10f;
[ShowIf(nameof(fadeWithDistance))]
[Label(" End")]
[Tooltip("The distance from the camera at which the outline is fully transparent. The value is in world units.")]
public float fadeRangeEnd = 50f;
[HorizontalLine]
[Tooltip("Whether to use depth information to draw outlines. This adds lines around objects that are in front of " +
"other objects.")]
public bool useDepth = true;
[ShowIf(nameof(useDepth))]
[Label(" Min Threshold")]
[Min(0)]
[Tooltip("Minimum distance between two pixels to be considered an edge. The outline is drawn almost transparent.")]
public float minDepthThreshold = 0.1f;
[ShowIf(nameof(useDepth))]
[Label(" Max Threshold")]
[Min(0)]
[Tooltip("Maximum distance between two pixels to be considered an edge. The outline is drawn fully opaque.")]
public float maxDepthThreshold = 0.25f;
[HorizontalLine(1, EColor.Translucent)]
[Tooltip("Whether to use world-space normals information to draw outlines. This adds lines " +
"on sharp edges of objects.")]
public bool useNormals = false;
[ShowIf(nameof(useNormals))]
[Label(" Min Threshold")]
[Min(0)]
[Tooltip("Minimum angle between two normals to be considered an edge. The outline is drawn almost transparent.")]
public float minNormalsThreshold = 0.1f;
[ShowIf(nameof(useNormals))]
[Label(" Max Threshold")]
[Min(0)]
[Tooltip("Maximum angle between two normals to be considered an edge. The outline is drawn fully opaque.")]
public float maxNormalsThreshold = 0.25f;
[HorizontalLine(1, EColor.Translucent)]
[Tooltip("Whether to use color information to draw outlines. This adds lines where the color of the object " +
"changes.")]
public bool useColor = false;
[ShowIf(nameof(useColor))]
[Label(" Min Threshold")]
[Min(0)]
[Tooltip("Minimum difference in color between two pixels to be considered an edge. The outline is drawn almost " +
"transparent.")]
public float minColorThreshold = 0.1f;
[ShowIf(nameof(useColor))]
[Label(" Max Threshold")]
[Min(0)]
[Tooltip("Maximum difference in color between two pixels to be considered an edge. The outline is drawn fully " +
"opaque.")]
public float maxColorThreshold = 0.25f;
[HorizontalLine]
[Tooltip("The render stage at which the effect is applied. To exclude transparent objects, like water or UI " +
"elements, set this to \"Before Transparent\".")]
public RenderPassEvent renderEvent = RenderPassEvent.BeforeRenderingPostProcessing;
[Tooltip("Only draw the outline, replacing the original color with a complimentary color.")]
public bool outlineOnly = false;
[Tooltip("Whether the effect should be applied in the Scene view as well as in the Game view. Please keep in " +
"mind that Unity always renders the scene view with the default Renderer settings of the URP config.")]
public bool applyInSceneView = true;
[HideInInspector]
public Material effectMaterial;
internal Action onSettingsChanged;
internal Action onReset;
private void OnValidate() {
if (minDepthThreshold > maxDepthThreshold + float.Epsilon) {
Debug.LogWarning("<b>[Flat Kit]</b> Outline configuration error: <b>'Min Depth Threshold'</b> must not " +
"be greater than <b>'Max Depth Threshold'</b>");
}
if (minNormalsThreshold > maxNormalsThreshold + float.Epsilon) {
Debug.LogWarning("<b>[Flat Kit]</b> Outline configuration error: <b>'Min Normals Threshold'</b> must not " +
"be greater than <b>'Max Normals Threshold'</b>");
}
if (minColorThreshold > maxColorThreshold + float.Epsilon) {
Debug.LogWarning("<b>[Flat Kit]</b> Outline configuration error: <b>'Min Color Threshold'</b> must not " +
"be greater than <b>'Max Color Threshold'</b>");
}
fadeRangeStart = Mathf.Max(0f, Mathf.Min(fadeRangeStart, fadeRangeEnd));
fadeRangeEnd = Mathf.Max(fadeRangeStart, Mathf.Min(fadeRangeEnd, 1000f));
onSettingsChanged?.Invoke();
}
private void Reset() {
onReset?.Invoke();
}
private void OnDestroy() {
onSettingsChanged = null;
onReset = null;
}
}
}
#else
namespace FlatKit {
[CreateAssetMenu(fileName = "OutlineSettings", menuName = "FlatKit/Outline Settings")]
public class OutlineSettings : ScriptableObject {
public Color edgeColor = Color.white;
[Range(0, 5)]
public int thickness = 1;
[Tooltip("If enabled, the line width will stay constant regardless of the rendering resolution. " +
"However, some of the lines may appear blurry.")]
public bool resolutionInvariant = false;
[Space]
public bool useDepth = true;
public bool useNormals = false;
public bool useColor = false;
[Header("Advanced settings")]
public float minDepthThreshold = 0f;
public float maxDepthThreshold = 0.25f;
[Space]
public float minNormalsThreshold = 0f;
public float maxNormalsThreshold = 0.25f;
[Space]
public float minColorThreshold = 0f;
public float maxColorThreshold = 0.25f;
[Space, Tooltip("The render stage at which the effect is applied. To exclude transparent objects, " +
"like water or UI elements, set this to \"Before Transparent\".")]
public RenderPassEvent renderEvent = RenderPassEvent.BeforeRenderingPostProcessing;
public bool outlineOnly = false;
[Tooltip("Whether the effect should be applied in the Scene view as well as in the Game view. Please keep in " +
"mind that Unity always renders the scene view with the default Renderer settings of the URP config.")]
public bool applyInSceneView = true;
private void OnValidate() {
if (minDepthThreshold > maxDepthThreshold + float.Epsilon) {
Debug.LogWarning("<b>[Flat Kit]</b> Outline configuration error: 'Min Depth Threshold' must not " +
"be greater than 'Max Depth Threshold'");
}
if (minNormalsThreshold > maxNormalsThreshold + float.Epsilon) {
Debug.LogWarning("<b>[Flat Kit]</b> Outline configuration error: 'Min Normals Threshold' must not " +
"be greater than 'Max Normals Threshold'");
}
if (minColorThreshold > maxColorThreshold + float.Epsilon) {
Debug.LogWarning("<b>[Flat Kit]</b> Outline configuration error: 'Min Color Threshold' must not " +
"be greater than 'Max Color Threshold'");
}
}
}
}
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 130791d3e20646d2b6d81688877b0909
timeCreated: 1585531463

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: f968e7540d632cc40b5ca8b340a3e718
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3}