ADD : 요요 보스 레이드 기능 페이셜 필터 강화 기능 ik 포인트 해결
This commit is contained in:
parent
3929be8974
commit
074c11eb8a
@ -4,12 +4,57 @@ using UnityEngine;
|
|||||||
[CustomEditor(typeof(OptitrackSkeletonAnimator_Mingle))]
|
[CustomEditor(typeof(OptitrackSkeletonAnimator_Mingle))]
|
||||||
public class OptitrackSkeletonAnimatorEditor : Editor
|
public class OptitrackSkeletonAnimatorEditor : Editor
|
||||||
{
|
{
|
||||||
|
private static readonly string[] k_FilterLabels = { "Off", "Low", "Medium", "High", "Custom" };
|
||||||
|
|
||||||
public override void OnInspectorGUI()
|
public override void OnInspectorGUI()
|
||||||
{
|
{
|
||||||
DrawDefaultInspector();
|
DrawDefaultInspector();
|
||||||
|
|
||||||
var anim = (OptitrackSkeletonAnimator_Mingle)target;
|
var anim = (OptitrackSkeletonAnimator_Mingle)target;
|
||||||
|
|
||||||
|
// 필터 강도 버튼 나열
|
||||||
|
EditorGUILayout.Space(4);
|
||||||
|
EditorGUILayout.LabelField("필터 강도", EditorStyles.boldLabel);
|
||||||
|
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
for (int i = 0; i < k_FilterLabels.Length; i++)
|
||||||
|
{
|
||||||
|
var strength = (OptitrackSkeletonAnimator_Mingle.FilterStrength)i;
|
||||||
|
bool isSelected = anim.filterStrength == strength;
|
||||||
|
|
||||||
|
var prevBgBtn = GUI.backgroundColor;
|
||||||
|
GUI.backgroundColor = isSelected ? new Color(0.4f, 0.7f, 1f) : Color.white;
|
||||||
|
|
||||||
|
if (GUILayout.Button(k_FilterLabels[i], GUILayout.Height(24)))
|
||||||
|
{
|
||||||
|
Undo.RecordObject(anim, "Change Filter Strength");
|
||||||
|
anim.SetFilterStrength(strength);
|
||||||
|
EditorUtility.SetDirty(anim);
|
||||||
|
}
|
||||||
|
|
||||||
|
GUI.backgroundColor = prevBgBtn;
|
||||||
|
}
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
// Custom일 때 슬라이더 표시
|
||||||
|
if (anim.filterStrength == OptitrackSkeletonAnimator_Mingle.FilterStrength.Custom)
|
||||||
|
{
|
||||||
|
EditorGUI.indentLevel++;
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
float minCutoff = EditorGUILayout.Slider("Min Cutoff (Hz)", anim.filterMinCutoff, 0.1f, 10f);
|
||||||
|
float beta = EditorGUILayout.Slider("Beta", anim.filterBeta, 0f, 5f);
|
||||||
|
float maxCutoff = EditorGUILayout.Slider("Max Cutoff (Hz)", anim.filterMaxCutoff, 5f, 120f);
|
||||||
|
if (EditorGUI.EndChangeCheck())
|
||||||
|
{
|
||||||
|
Undo.RecordObject(anim, "Change Filter Custom Values");
|
||||||
|
anim.filterMinCutoff = minCutoff;
|
||||||
|
anim.filterBeta = beta;
|
||||||
|
anim.filterMaxCutoff = maxCutoff;
|
||||||
|
EditorUtility.SetDirty(anim);
|
||||||
|
}
|
||||||
|
EditorGUI.indentLevel--;
|
||||||
|
}
|
||||||
|
|
||||||
// 연결 상태 배지
|
// 연결 상태 배지
|
||||||
EditorGUILayout.Space(8);
|
EditorGUILayout.Space(8);
|
||||||
var prevBg = GUI.backgroundColor;
|
var prevBg = GUI.backgroundColor;
|
||||||
|
|||||||
@ -33,19 +33,53 @@ public class OptitrackSkeletonAnimator_Mingle : MonoBehaviour
|
|||||||
[Tooltip("에디터에서 캡처한 T-포즈 데이터. 비어 있으면 런타임 CacheRestPose()를 사용합니다.")]
|
[Tooltip("에디터에서 캡처한 T-포즈 데이터. 비어 있으면 런타임 CacheRestPose()를 사용합니다.")]
|
||||||
public OptitrackRestPoseData RestPoseAsset;
|
public OptitrackRestPoseData RestPoseAsset;
|
||||||
|
|
||||||
|
public enum FilterStrength { Off, Low, Medium, High, Custom }
|
||||||
|
|
||||||
[Header("본 1€ 필터 (속도 적응형 저역통과)")]
|
[Header("본 1€ 필터 (속도 적응형 저역통과)")]
|
||||||
[Tooltip("활성화 시 빠른 움직임은 그대로, 정지/느린 움직임의 노이즈를 제거합니다.\n단순 EMA보다 모션 보존이 훨씬 우수합니다.")]
|
[HideInInspector]
|
||||||
public bool enableBoneFilter = true;
|
public FilterStrength filterStrength = FilterStrength.Medium;
|
||||||
[Tooltip("최소 차단 주파수 (Hz). 정지 시 노이즈 제거 강도. 낮을수록 강함. 권장: 2~4 Hz")]
|
|
||||||
[Range(0.1f, 10f)]
|
[HideInInspector] public float filterMinCutoff = 3.0f;
|
||||||
public float filterMinCutoff = 3.0f;
|
[HideInInspector] public float filterBeta = 1.5f;
|
||||||
[Tooltip("속도 계수. 빠른 동작에서 cutoff 상승 속도. 높을수록 지연 감소. 권장: 0.5~2.0")]
|
[HideInInspector] public float filterMaxCutoff = 15.0f;
|
||||||
[Range(0f, 5f)]
|
|
||||||
public float filterBeta = 1.5f;
|
// 프리셋별 파라미터 (minCutoff, beta, maxCutoff)
|
||||||
[Tooltip("최대 차단 주파수 상한 (Hz). 빠른 동작에서도 이 이상 주파수는 항상 제거됩니다.\n" +
|
private static readonly (float minCutoff, float beta, float maxCutoff)[] k_FilterPresets =
|
||||||
"MagicaCloth2 지터가 빠른 동작에서 발생하면 낮추세요. 권장: 10~20 Hz")]
|
{
|
||||||
[Range(5f, 120f)]
|
(0f, 0f, 0f), // Off (사용 안 함)
|
||||||
public float filterMaxCutoff = 15.0f;
|
(5.0f, 2.0f, 25.0f), // Low
|
||||||
|
(3.0f, 1.5f, 15.0f), // Medium
|
||||||
|
(1.5f, 0.8f, 10.0f), // High
|
||||||
|
(0f, 0f, 0f), // Custom (프리셋 적용 안 함)
|
||||||
|
};
|
||||||
|
|
||||||
|
[HideInInspector] public bool enableBoneFilter = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 런타임에서 필터 강도를 변경합니다. StreamDeck/핫키 등에서 호출.
|
||||||
|
/// </summary>
|
||||||
|
public void SetFilterStrength(FilterStrength strength)
|
||||||
|
{
|
||||||
|
filterStrength = strength;
|
||||||
|
if (strength != FilterStrength.Off && strength != FilterStrength.Custom)
|
||||||
|
{
|
||||||
|
var preset = k_FilterPresets[(int)strength];
|
||||||
|
filterMinCutoff = preset.minCutoff;
|
||||||
|
filterBeta = preset.beta;
|
||||||
|
filterMaxCutoff = preset.maxCutoff;
|
||||||
|
}
|
||||||
|
// 프리셋 전환 시 필터 상태 리셋 (이전 값과 불연속 방지)
|
||||||
|
m_filterStates.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 현재 프리셋에서 다음 프리셋으로 순환. 버튼 하나로 Off→Low→Medium→High→Custom→Off...
|
||||||
|
/// </summary>
|
||||||
|
public void CycleFilterStrength()
|
||||||
|
{
|
||||||
|
int next = ((int)filterStrength + 1) % System.Enum.GetValues(typeof(FilterStrength)).Length;
|
||||||
|
SetFilterStrength((FilterStrength)next);
|
||||||
|
}
|
||||||
|
|
||||||
private OptitrackSkeletonDefinition m_skeletonDef;
|
private OptitrackSkeletonDefinition m_skeletonDef;
|
||||||
private string previousSkeletonName;
|
private string previousSkeletonName;
|
||||||
@ -239,6 +273,9 @@ public class OptitrackSkeletonAnimator_Mingle : MonoBehaviour
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 필터 활성화 상태 동기화 (프리셋 값은 SetFilterStrength()에서만 적용)
|
||||||
|
enableBoneFilter = filterStrength != FilterStrength.Off;
|
||||||
|
|
||||||
// MirrorMode 변경 감지 → 필터 상태 리셋 (불연속 튐 방지)
|
// MirrorMode 변경 감지 → 필터 상태 리셋 (불연속 튐 방지)
|
||||||
bool currentMirrorMode = StreamingClient != null && StreamingClient.MirrorMode;
|
bool currentMirrorMode = StreamingClient != null && StreamingClient.MirrorMode;
|
||||||
if (currentMirrorMode != m_lastMirrorMode)
|
if (currentMirrorMode != m_lastMirrorMode)
|
||||||
|
|||||||
@ -17,6 +17,9 @@ public class StreamingleFacialReceiverEditor : Editor
|
|||||||
private VisualElement statusContainer;
|
private VisualElement statusContainer;
|
||||||
private VisualElement emaFields;
|
private VisualElement emaFields;
|
||||||
private VisualElement euroFields;
|
private VisualElement euroFields;
|
||||||
|
private VisualElement medianEuroFields;
|
||||||
|
private VisualElement sharedPortInfo;
|
||||||
|
private Label masterStatusValue;
|
||||||
|
|
||||||
public override VisualElement CreateInspectorGUI()
|
public override VisualElement CreateInspectorGUI()
|
||||||
{
|
{
|
||||||
@ -40,6 +43,9 @@ public class StreamingleFacialReceiverEditor : Editor
|
|||||||
portButtonsContainer = root.Q("portButtonsContainer");
|
portButtonsContainer = root.Q("portButtonsContainer");
|
||||||
emaFields = root.Q("emaFields");
|
emaFields = root.Q("emaFields");
|
||||||
euroFields = root.Q("euroFields");
|
euroFields = root.Q("euroFields");
|
||||||
|
medianEuroFields = root.Q("medianEuroFields");
|
||||||
|
sharedPortInfo = root.Q("sharedPortInfo");
|
||||||
|
masterStatusValue = root.Q<Label>("masterStatusValue");
|
||||||
|
|
||||||
// Auto-find button
|
// Auto-find button
|
||||||
var autoFindBtn = root.Q<Button>("autoFindBtn");
|
var autoFindBtn = root.Q<Button>("autoFindBtn");
|
||||||
@ -50,7 +56,7 @@ public class StreamingleFacialReceiverEditor : Editor
|
|||||||
// Build dynamic port buttons
|
// Build dynamic port buttons
|
||||||
RebuildPortButtons();
|
RebuildPortButtons();
|
||||||
|
|
||||||
// Track filterMode for conditional visibility of EMA/Euro fields
|
// Track filterMode for conditional visibility of filter fields
|
||||||
var filterModeProp = serializedObject.FindProperty("filterMode");
|
var filterModeProp = serializedObject.FindProperty("filterMode");
|
||||||
UpdateFilterModeVisibility(filterModeProp.enumValueIndex);
|
UpdateFilterModeVisibility(filterModeProp.enumValueIndex);
|
||||||
|
|
||||||
@ -59,6 +65,15 @@ public class StreamingleFacialReceiverEditor : Editor
|
|||||||
UpdateFilterModeVisibility(prop.enumValueIndex);
|
UpdateFilterModeVisibility(prop.enumValueIndex);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Track useSharedPort for info visibility
|
||||||
|
var sharedPortProp = serializedObject.FindProperty("useSharedPort");
|
||||||
|
UpdateSharedPortVisibility(sharedPortProp.boolValue);
|
||||||
|
|
||||||
|
root.TrackPropertyValue(sharedPortProp, prop =>
|
||||||
|
{
|
||||||
|
UpdateSharedPortVisibility(prop.boolValue);
|
||||||
|
});
|
||||||
|
|
||||||
// Track availablePorts and activePortIndex changes to rebuild port buttons
|
// Track availablePorts and activePortIndex changes to rebuild port buttons
|
||||||
var portsProp = serializedObject.FindProperty("availablePorts");
|
var portsProp = serializedObject.FindProperty("availablePorts");
|
||||||
root.TrackPropertyValue(portsProp, _ => RebuildPortButtons());
|
root.TrackPropertyValue(portsProp, _ => RebuildPortButtons());
|
||||||
@ -74,11 +89,19 @@ public class StreamingleFacialReceiverEditor : Editor
|
|||||||
|
|
||||||
private void UpdateFilterModeVisibility(int modeIndex)
|
private void UpdateFilterModeVisibility(int modeIndex)
|
||||||
{
|
{
|
||||||
// FilterMode: 0=None, 1=EMA, 2=OneEuro
|
// FilterMode: 0=None, 1=EMA, 2=OneEuro, 3=MedianOneEuro
|
||||||
if (emaFields != null)
|
if (emaFields != null)
|
||||||
emaFields.style.display = modeIndex == 1 ? DisplayStyle.Flex : DisplayStyle.None;
|
emaFields.style.display = modeIndex == 1 ? DisplayStyle.Flex : DisplayStyle.None;
|
||||||
if (euroFields != null)
|
if (euroFields != null)
|
||||||
euroFields.style.display = modeIndex == 2 ? DisplayStyle.Flex : DisplayStyle.None;
|
euroFields.style.display = modeIndex == 2 ? DisplayStyle.Flex : DisplayStyle.None;
|
||||||
|
if (medianEuroFields != null)
|
||||||
|
medianEuroFields.style.display = modeIndex == 3 ? DisplayStyle.Flex : DisplayStyle.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateSharedPortVisibility(bool useShared)
|
||||||
|
{
|
||||||
|
if (sharedPortInfo != null)
|
||||||
|
sharedPortInfo.style.display = useShared ? DisplayStyle.Flex : DisplayStyle.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RebuildPortButtons()
|
private void RebuildPortButtons()
|
||||||
@ -189,5 +212,30 @@ public class StreamingleFacialReceiverEditor : Editor
|
|||||||
statusContainer.AddToClassList("facial-status-container--visible");
|
statusContainer.AddToClassList("facial-status-container--visible");
|
||||||
else if (!isPlaying && statusContainer.ClassListContains("facial-status-container--visible"))
|
else if (!isPlaying && statusContainer.ClassListContains("facial-status-container--visible"))
|
||||||
statusContainer.RemoveFromClassList("facial-status-container--visible");
|
statusContainer.RemoveFromClassList("facial-status-container--visible");
|
||||||
|
|
||||||
|
// 마스터 상태 업데이트 (플레이 모드에서만)
|
||||||
|
if (isPlaying && masterStatusValue != null && receiver != null && receiver.useSharedPort)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var status = StreamingleFacialUdpMaster.Instance.GetPortStatus();
|
||||||
|
if (status.TryGetValue(receiver.LOCAL_PORT, out int count))
|
||||||
|
{
|
||||||
|
masterStatusValue.text = $"Port {receiver.LOCAL_PORT}: {count} Receiver(s)";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
masterStatusValue.text = "Not connected";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
masterStatusValue.text = "---";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (masterStatusValue != null)
|
||||||
|
{
|
||||||
|
masterStatusValue.text = receiver != null && receiver.useSharedPort ? "Play 모드에서 활성화" : "---";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,6 +72,39 @@
|
|||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---- Shared Port (Master Mode) ---- */
|
||||||
|
|
||||||
|
.facial-shared-port-info {
|
||||||
|
padding: 6px 8px;
|
||||||
|
margin-top: 4px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
background-color: rgba(99, 102, 241, 0.1);
|
||||||
|
border-radius: 4px;
|
||||||
|
border-left-width: 3px;
|
||||||
|
border-left-color: rgba(99, 102, 241, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.facial-info-text {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #94a3b8;
|
||||||
|
-unity-font-style: italic;
|
||||||
|
white-space: normal;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.facial-master-status-row {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.facial-master-status-value {
|
||||||
|
-unity-font-style: bold;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #a5b4fc;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---- Port Hot-Swap ---- */
|
/* ---- Port Hot-Swap ---- */
|
||||||
|
|
||||||
.facial-active-port-row {
|
.facial-active-port-row {
|
||||||
@ -137,6 +170,19 @@
|
|||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#medianEuroFields {
|
||||||
|
padding-left: 16px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.facial-filter-separator-label {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #64748b;
|
||||||
|
-unity-text-align: middle-center;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---- Facial Intensity ---- */
|
/* ---- Facial Intensity ---- */
|
||||||
|
|
||||||
.facial-separator {
|
.facial-separator {
|
||||||
|
|||||||
@ -21,6 +21,20 @@
|
|||||||
</ui:Foldout>
|
</ui:Foldout>
|
||||||
</ui:VisualElement>
|
</ui:VisualElement>
|
||||||
|
|
||||||
|
<!-- Shared Port (Master Mode) -->
|
||||||
|
<ui:VisualElement class="section">
|
||||||
|
<ui:Foldout text="Shared Port (Master Mode)" value="true" class="section-foldout">
|
||||||
|
<uie:PropertyField binding-path="useSharedPort" label="Use Shared Port"/>
|
||||||
|
<ui:VisualElement name="sharedPortInfo" class="facial-shared-port-info">
|
||||||
|
<ui:Label text="같은 포트에 여러 Receiver를 연결하여 동일한 모캡 데이터를 공유 수신합니다." class="facial-info-text"/>
|
||||||
|
</ui:VisualElement>
|
||||||
|
<ui:VisualElement name="masterStatusRow" class="facial-master-status-row">
|
||||||
|
<ui:Label text="Master Status" class="facial-port-label"/>
|
||||||
|
<ui:Label name="masterStatusValue" text="---" class="facial-master-status-value"/>
|
||||||
|
</ui:VisualElement>
|
||||||
|
</ui:Foldout>
|
||||||
|
</ui:VisualElement>
|
||||||
|
|
||||||
<!-- Port Hot-Swap (port buttons built dynamically in C#) -->
|
<!-- Port Hot-Swap (port buttons built dynamically in C#) -->
|
||||||
<ui:VisualElement class="section">
|
<ui:VisualElement class="section">
|
||||||
<ui:Foldout text="Port Hot-Swap" value="true" class="section-foldout">
|
<ui:Foldout text="Port Hot-Swap" value="true" class="section-foldout">
|
||||||
@ -51,6 +65,15 @@
|
|||||||
<uie:PropertyField binding-path="euroBeta" label="Beta (Speed Coeff)"/>
|
<uie:PropertyField binding-path="euroBeta" label="Beta (Speed Coeff)"/>
|
||||||
<uie:PropertyField binding-path="euroDCutoff" label="D Cutoff (Hz)"/>
|
<uie:PropertyField binding-path="euroDCutoff" label="D Cutoff (Hz)"/>
|
||||||
</ui:VisualElement>
|
</ui:VisualElement>
|
||||||
|
<!-- Median+Euro Filter Fields -->
|
||||||
|
<ui:VisualElement name="medianEuroFields">
|
||||||
|
<uie:PropertyField binding-path="medianWindowSize" label="Median Window Size"/>
|
||||||
|
<ui:Label text="── OneEuro Params ──" class="facial-filter-separator-label"/>
|
||||||
|
<uie:PropertyField binding-path="euroMinCutoff" label="Min Cutoff (Hz)"/>
|
||||||
|
<uie:PropertyField binding-path="euroBeta" label="Beta (Speed Coeff)"/>
|
||||||
|
<uie:PropertyField binding-path="euroDCutoff" label="D Cutoff (Hz)"/>
|
||||||
|
<ui:Label text="Median(스파이크제거) → OneEuro(적응형스무딩)" class="facial-info-text"/>
|
||||||
|
</ui:VisualElement>
|
||||||
</ui:Foldout>
|
</ui:Foldout>
|
||||||
</ui:VisualElement>
|
</ui:VisualElement>
|
||||||
|
|
||||||
|
|||||||
46
Assets/External/StreamingleFacial/FacialFilterUtils.cs
vendored
Normal file
46
Assets/External/StreamingleFacial/FacialFilterUtils.cs
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Median Filter - 임펄스 노이즈(스파이크) 제거에 탁월
|
||||||
|
/// 윈도우 내 중앙값을 출력하여 이상치를 자연스럽게 배제
|
||||||
|
///
|
||||||
|
/// OneEuroFilter 앞에 전처리로 사용하면 (MedianOneEuro 모드)
|
||||||
|
/// 스파이크 제거 + 적응형 스무딩의 조합으로 최고 품질의 필터링 가능
|
||||||
|
///
|
||||||
|
/// windowSize: 홀수 권장 (3=최소 지연, 5=일반, 7+=강한 스파이크 제거)
|
||||||
|
/// </summary>
|
||||||
|
public class MedianFilter
|
||||||
|
{
|
||||||
|
private readonly float[] buffer;
|
||||||
|
private readonly float[] sorted;
|
||||||
|
private int count;
|
||||||
|
private int writeIndex;
|
||||||
|
|
||||||
|
public MedianFilter(int windowSize = 5)
|
||||||
|
{
|
||||||
|
int size = Mathf.Max(3, windowSize | 1); // 홀수로 강제
|
||||||
|
buffer = new float[size];
|
||||||
|
sorted = new float[size];
|
||||||
|
count = 0;
|
||||||
|
writeIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Filter(float value)
|
||||||
|
{
|
||||||
|
buffer[writeIndex] = value;
|
||||||
|
writeIndex = (writeIndex + 1) % buffer.Length;
|
||||||
|
if (count < buffer.Length) count++;
|
||||||
|
|
||||||
|
// 현재 윈도우를 정렬하여 중앙값 반환
|
||||||
|
System.Array.Copy(buffer, sorted, count);
|
||||||
|
System.Array.Sort(sorted, 0, count);
|
||||||
|
|
||||||
|
return sorted[count / 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
writeIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Assets/External/StreamingleFacial/FacialFilterUtils.cs.meta
vendored
Normal file
2
Assets/External/StreamingleFacial/FacialFilterUtils.cs.meta
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1c90c541f662e9d489f79aa99fea0162
|
||||||
@ -3,6 +3,7 @@ using System.Net;
|
|||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
@ -21,6 +22,11 @@ public class StreamingleFacialReceiver : MonoBehaviour
|
|||||||
private string messageString = "";
|
private string messageString = "";
|
||||||
private string lastProcessedMessage = ""; // 이전 메시지 저장용
|
private string lastProcessedMessage = ""; // 이전 메시지 저장용
|
||||||
|
|
||||||
|
// ── 공유 포트 (마스터 모드) ──
|
||||||
|
[Header("Shared Port (Master Mode)")]
|
||||||
|
[Tooltip("활성화 시 UdpMaster를 통해 같은 포트의 데이터를 여러 Receiver가 공유 수신")]
|
||||||
|
public bool useSharedPort = true;
|
||||||
|
|
||||||
// 포트 핫스왑 시스템
|
// 포트 핫스왑 시스템
|
||||||
[Header("Port Hot-Swap")]
|
[Header("Port Hot-Swap")]
|
||||||
[Tooltip("사용 가능한 아이폰 포트 목록")]
|
[Tooltip("사용 가능한 아이폰 포트 목록")]
|
||||||
@ -31,11 +37,11 @@ public class StreamingleFacialReceiver : MonoBehaviour
|
|||||||
public int LOCAL_PORT => availablePorts != null && activePortIndex < availablePorts.Length ? availablePorts[activePortIndex] : 49983;
|
public int LOCAL_PORT => availablePorts != null && activePortIndex < availablePorts.Length ? availablePorts[activePortIndex] : 49983;
|
||||||
|
|
||||||
// 필터 모드 설정
|
// 필터 모드 설정
|
||||||
public enum FilterMode { None, EMA, OneEuro }
|
public enum FilterMode { None, EMA, OneEuro, MedianOneEuro }
|
||||||
|
|
||||||
[Header("Data Filtering")]
|
[Header("Data Filtering")]
|
||||||
[Tooltip("필터링 모드: None=필터없음, EMA=기존 스무딩+스파이크, OneEuro=1€ 적응형 필터")]
|
[Tooltip("필터링 모드: None=필터없음, EMA=스무딩+스파이크, OneEuro=1€ 적응형, Kalman=칼만필터, MedianOneEuro=메디안+1€ 복합")]
|
||||||
public FilterMode filterMode = FilterMode.OneEuro;
|
public FilterMode filterMode = FilterMode.MedianOneEuro;
|
||||||
|
|
||||||
// EMA 필터 설정 (기존 호환)
|
// EMA 필터 설정 (기존 호환)
|
||||||
[Header("EMA Filter Settings")]
|
[Header("EMA Filter Settings")]
|
||||||
@ -67,16 +73,26 @@ public class StreamingleFacialReceiver : MonoBehaviour
|
|||||||
[Range(0.1f, 5f)]
|
[Range(0.1f, 5f)]
|
||||||
public float euroDCutoff = 1.0f;
|
public float euroDCutoff = 1.0f;
|
||||||
|
|
||||||
// Euro 필터 인스턴스 (블렌드쉐이프별)
|
// Median+OneEuro 복합 필터 설정
|
||||||
|
[Header("Median+Euro Filter Settings")]
|
||||||
|
[Tooltip("Median 윈도우 크기 (홀수). 스파이크 제거용. 3=최소 지연, 5=일반, 7+=강한 제거")]
|
||||||
|
[Range(3, 11)]
|
||||||
|
public int medianWindowSize = 5;
|
||||||
|
|
||||||
|
// ── 필터 인스턴스 ──
|
||||||
|
// Euro 필터
|
||||||
private Dictionary<string, OneEuroFilter> euroFilters = new Dictionary<string, OneEuroFilter>();
|
private Dictionary<string, OneEuroFilter> euroFilters = new Dictionary<string, OneEuroFilter>();
|
||||||
private float euroMinCutoffPrev, euroBetaPrev, euroDCutoffPrev;
|
private float euroMinCutoffPrev, euroBetaPrev, euroDCutoffPrev;
|
||||||
|
// EMA 필터링용 이전 값
|
||||||
// EMA 필터링용 이전 값 저장
|
|
||||||
private Dictionary<string, float> prevBlendShapeValues = new Dictionary<string, float>();
|
private Dictionary<string, float> prevBlendShapeValues = new Dictionary<string, float>();
|
||||||
|
// 연속 스파이크 추적
|
||||||
// 연속 스파이크 추적 (같은 방향으로 연속이면 실제 움직임)
|
|
||||||
private Dictionary<string, int> blendShapeSpikeCount = new Dictionary<string, int>();
|
private Dictionary<string, int> blendShapeSpikeCount = new Dictionary<string, int>();
|
||||||
private Dictionary<string, float> blendShapeSpikeDirection = new Dictionary<string, float>();
|
private Dictionary<string, float> blendShapeSpikeDirection = new Dictionary<string, float>();
|
||||||
|
// Median 필터 (MedianOneEuro용)
|
||||||
|
private Dictionary<string, MedianFilter> medianFilters = new Dictionary<string, MedianFilter>();
|
||||||
|
// MedianOneEuro용 Euro 필터 (별도 인스턴스)
|
||||||
|
private Dictionary<string, OneEuroFilter> medianEuroFilters = new Dictionary<string, OneEuroFilter>();
|
||||||
|
private int medianWindowSizePrev;
|
||||||
|
|
||||||
// 빠르게 변하는 BlendShape 목록 (눈 깜빡임, 입 등)
|
// 빠르게 변하는 BlendShape 목록 (눈 깜빡임, 입 등)
|
||||||
private static readonly HashSet<string> FastBlendShapes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
private static readonly HashSet<string> FastBlendShapes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||||
@ -153,6 +169,18 @@ public class StreamingleFacialReceiver : MonoBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 재접속 코루틴 중복 방지
|
||||||
|
private Coroutine reconnectCoroutine;
|
||||||
|
|
||||||
|
// ── 마스터 모드에서 호출되는 메서드 ──
|
||||||
|
/// <summary>
|
||||||
|
/// UdpMaster가 메시지를 분배할 때 호출. 직접 호출하지 마세요.
|
||||||
|
/// </summary>
|
||||||
|
public void SetMessageFromMaster(string msg)
|
||||||
|
{
|
||||||
|
messageString = msg;
|
||||||
|
}
|
||||||
|
|
||||||
// Start is called
|
// Start is called
|
||||||
void StartFunction()
|
void StartFunction()
|
||||||
{
|
{
|
||||||
@ -165,8 +193,16 @@ public class StreamingleFacialReceiver : MonoBehaviour
|
|||||||
// BlendShape 인덱스 캐싱 초기화
|
// BlendShape 인덱스 캐싱 초기화
|
||||||
InitializeBlendShapeCache();
|
InitializeBlendShapeCache();
|
||||||
|
|
||||||
//Recieve udp from iOS
|
if (useSharedPort)
|
||||||
CreateUdpServer();
|
{
|
||||||
|
// 마스터 모드: UdpMaster에 등록하여 공유 수신
|
||||||
|
StreamingleFacialUdpMaster.Instance.Register(LOCAL_PORT, this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 독립 모드: 자체 UDP 서버 생성
|
||||||
|
CreateUdpServer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,9 +284,12 @@ public class StreamingleFacialReceiver : MonoBehaviour
|
|||||||
if (euroFilters != null)
|
if (euroFilters != null)
|
||||||
{
|
{
|
||||||
foreach (var filter in euroFilters.Values)
|
foreach (var filter in euroFilters.Values)
|
||||||
{
|
|
||||||
filter.UpdateParams(euroMinCutoff, euroBeta, euroDCutoff);
|
filter.UpdateParams(euroMinCutoff, euroBeta, euroDCutoff);
|
||||||
}
|
}
|
||||||
|
if (medianEuroFilters != null)
|
||||||
|
{
|
||||||
|
foreach (var filter in medianEuroFilters.Values)
|
||||||
|
filter.UpdateParams(euroMinCutoff, euroBeta, euroDCutoff);
|
||||||
}
|
}
|
||||||
euroMinCutoffPrev = euroMinCutoff;
|
euroMinCutoffPrev = euroMinCutoff;
|
||||||
euroBetaPrev = euroBeta;
|
euroBetaPrev = euroBeta;
|
||||||
@ -446,6 +485,11 @@ public class StreamingleFacialReceiver : MonoBehaviour
|
|||||||
Debug.LogError($"[iFacialMocap] 데이터 수신 오류: {e.Message}");
|
Debug.LogError($"[iFacialMocap] 데이터 수신 오류: {e.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
// UDP 소켓이 닫힌 경우 (정상 종료 시 발생)
|
||||||
|
break;
|
||||||
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
// 스레드 종료 중이면 로그 생략
|
// 스레드 종료 중이면 로그 생략
|
||||||
@ -455,7 +499,6 @@ public class StreamingleFacialReceiver : MonoBehaviour
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CPU를 양보하는 Sleep 사용 (5ms 대기)
|
// CPU를 양보하는 Sleep 사용 (5ms 대기)
|
||||||
// Busy waiting 대신 Thread.Sleep으로 CPU 사용률 감소
|
|
||||||
Thread.Sleep(5);
|
Thread.Sleep(5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -488,7 +531,19 @@ public class StreamingleFacialReceiver : MonoBehaviour
|
|||||||
if (StartFlag == false)
|
if (StartFlag == false)
|
||||||
{
|
{
|
||||||
StartFlag = true;
|
StartFlag = true;
|
||||||
StopUDP();
|
|
||||||
|
if (useSharedPort)
|
||||||
|
{
|
||||||
|
// 마스터에서 해제
|
||||||
|
if (StreamingleFacialUdpMaster.Instance != null)
|
||||||
|
{
|
||||||
|
StreamingleFacialUdpMaster.Instance.Unregister(LOCAL_PORT, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StopUDP();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -501,20 +556,20 @@ public class StreamingleFacialReceiver : MonoBehaviour
|
|||||||
// UDP 종료
|
// UDP 종료
|
||||||
if (udp != null)
|
if (udp != null)
|
||||||
{
|
{
|
||||||
udp.Close();
|
try
|
||||||
udp.Dispose();
|
{
|
||||||
|
udp.Close();
|
||||||
|
udp.Dispose();
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
udp = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 스레드가 종료될 때까지 대기 (최대 100ms)
|
// 스레드가 종료될 때까지 대기 (최대 300ms)
|
||||||
if (thread != null && thread.IsAlive)
|
if (thread != null && thread.IsAlive)
|
||||||
{
|
{
|
||||||
thread.Join(100);
|
thread.Join(300);
|
||||||
|
thread = null;
|
||||||
// 그래도 종료되지 않으면 강제 종료
|
|
||||||
if (thread.IsAlive)
|
|
||||||
{
|
|
||||||
thread.Abort();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,38 +584,61 @@ public class StreamingleFacialReceiver : MonoBehaviour
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int oldPort = LOCAL_PORT;
|
||||||
activePortIndex = portIndex;
|
activePortIndex = portIndex;
|
||||||
Debug.Log($"[iFacialMocap] 포트 전환: {availablePorts[portIndex]}");
|
Debug.Log($"[iFacialMocap] 포트 전환: {availablePorts[portIndex]}");
|
||||||
Reconnect();
|
|
||||||
|
if (useSharedPort)
|
||||||
|
{
|
||||||
|
// 마스터 모드: 포트 전환 요청
|
||||||
|
StreamingleFacialUdpMaster.Instance.SwitchPort(oldPort, LOCAL_PORT, this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Reconnect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 페이셜 모션 캡처 재접속
|
/// 페이셜 모션 캡처 재접속 (프리징 없는 코루틴 방식)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Reconnect()
|
public void Reconnect()
|
||||||
|
{
|
||||||
|
if (reconnectCoroutine != null)
|
||||||
|
{
|
||||||
|
StopCoroutine(reconnectCoroutine);
|
||||||
|
}
|
||||||
|
reconnectCoroutine = StartCoroutine(ReconnectCoroutine());
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator ReconnectCoroutine()
|
||||||
{
|
{
|
||||||
Debug.Log("[iFacialMocap] 재접속 시도 중...");
|
Debug.Log("[iFacialMocap] 재접속 시도 중...");
|
||||||
|
|
||||||
try
|
if (useSharedPort)
|
||||||
{
|
{
|
||||||
// 기존 연결 종료
|
// 마스터 모드: 해제 후 재등록
|
||||||
|
StreamingleFacialUdpMaster.Instance.Unregister(LOCAL_PORT, this);
|
||||||
|
yield return null; // 1프레임 대기
|
||||||
|
StreamingleFacialUdpMaster.Instance.Register(LOCAL_PORT, this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 독립 모드: UDP 종료 후 코루틴으로 대기 (프리징 없음)
|
||||||
StopUDP();
|
StopUDP();
|
||||||
|
|
||||||
// 잠시 대기
|
// OS가 포트를 해제할 시간을 코루틴으로 대기 (메인 스레드 블로킹 없음)
|
||||||
Thread.Sleep(500);
|
yield return new WaitForSeconds(0.5f);
|
||||||
|
|
||||||
// 플래그 리셋
|
// 플래그 리셋
|
||||||
StartFlag = true;
|
StartFlag = true;
|
||||||
|
|
||||||
// 재시작
|
// 재시작
|
||||||
StartFunction();
|
StartFunction();
|
||||||
|
}
|
||||||
|
|
||||||
Debug.Log("[iFacialMocap] 재접속 완료");
|
reconnectCoroutine = null;
|
||||||
}
|
Debug.Log("[iFacialMocap] 재접속 완료");
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Debug.LogError($"[iFacialMocap] 재접속 실패: {e.Message}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -575,14 +653,21 @@ public class StreamingleFacialReceiver : MonoBehaviour
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// BlendShape 값 필터링: filterMode에 따라 EMA 또는 1€ Euro Filter 적용
|
/// BlendShape 값 필터링: filterMode에 따라 적절한 필터 적용
|
||||||
/// </summary>
|
/// </summary>
|
||||||
float FilterBlendShapeValue(string name, float rawValue)
|
float FilterBlendShapeValue(string name, float rawValue)
|
||||||
{
|
{
|
||||||
if (filterMode == FilterMode.OneEuro)
|
switch (filterMode)
|
||||||
return FilterOneEuro(name, rawValue);
|
{
|
||||||
|
case FilterMode.OneEuro:
|
||||||
return FilterEMA(name, rawValue);
|
return FilterOneEuro(name, rawValue);
|
||||||
|
case FilterMode.MedianOneEuro:
|
||||||
|
return FilterMedianOneEuro(name, rawValue);
|
||||||
|
case FilterMode.EMA:
|
||||||
|
return FilterEMA(name, rawValue);
|
||||||
|
default:
|
||||||
|
return rawValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -610,6 +695,48 @@ public class StreamingleFacialReceiver : MonoBehaviour
|
|||||||
return Mathf.Clamp(filter.Filter(rawValue, t), 0f, 100f);
|
return Mathf.Clamp(filter.Filter(rawValue, t), 0f, 100f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Median + OneEuro 복합 필터:
|
||||||
|
/// 1단계: Median 필터로 스파이크/이상치 제거
|
||||||
|
/// 2단계: OneEuro 필터로 적응형 스무딩
|
||||||
|
/// → 스파이크에 강하면서도 빠른 움직임에 반응하는 최고 품질 필터링
|
||||||
|
/// </summary>
|
||||||
|
float FilterMedianOneEuro(string name, float rawValue)
|
||||||
|
{
|
||||||
|
// Median 윈도우 크기 변경 감지 → 필터 재생성
|
||||||
|
if (medianWindowSizePrev != medianWindowSize)
|
||||||
|
{
|
||||||
|
medianFilters.Clear();
|
||||||
|
medianWindowSizePrev = medianWindowSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1단계: Median 필터
|
||||||
|
if (!medianFilters.TryGetValue(name, out var medianFilter))
|
||||||
|
{
|
||||||
|
medianFilter = new MedianFilter(medianWindowSize);
|
||||||
|
medianFilters[name] = medianFilter;
|
||||||
|
}
|
||||||
|
float medianValue = medianFilter.Filter(rawValue);
|
||||||
|
|
||||||
|
// 2단계: OneEuro 필터
|
||||||
|
float t = Time.time;
|
||||||
|
if (!medianEuroFilters.TryGetValue(name, out var euroFilter))
|
||||||
|
{
|
||||||
|
euroFilter = new OneEuroFilter(60f, euroMinCutoff, euroBeta, euroDCutoff);
|
||||||
|
medianEuroFilters[name] = euroFilter;
|
||||||
|
euroFilter.Filter(medianValue, t);
|
||||||
|
return medianValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 파라미터 변경 감지
|
||||||
|
if (euroMinCutoffPrev != euroMinCutoff || euroBetaPrev != euroBeta || euroDCutoffPrev != euroDCutoff)
|
||||||
|
{
|
||||||
|
SyncEuroParams();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Mathf.Clamp(euroFilter.Filter(medianValue, t), 0f, 100f);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// EMA 필터: 연속 스파이크 판별 + 카테고리별 임계값 + 프레임독립 EMA (기존 로직)
|
/// EMA 필터: 연속 스파이크 판별 + 카테고리별 임계값 + 프레임독립 EMA (기존 로직)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -704,4 +831,4 @@ public static class StreamingleFacialReceiverExtensions
|
|||||||
GetChildren(ob.gameObject, ref allChildren);
|
GetChildren(ob.gameObject, ref allChildren);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
249
Assets/External/StreamingleFacial/StreamingleFacialUdpMaster.cs
vendored
Normal file
249
Assets/External/StreamingleFacial/StreamingleFacialUdpMaster.cs
vendored
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 중앙 UDP 수신 매니저. 하나의 포트에서 수신한 데이터를 여러 StreamingleFacialReceiver에 분배.
|
||||||
|
/// 싱글톤으로 동작하며, Receiver가 Register 시 자동 생성됨.
|
||||||
|
///
|
||||||
|
/// 사용법:
|
||||||
|
/// StreamingleFacialReceiver에서 useSharedPort = true로 설정하면
|
||||||
|
/// 자동으로 이 마스터를 통해 UDP 데이터를 공유 수신합니다.
|
||||||
|
/// 같은 포트에 여러 Receiver를 등록하면 동일한 데이터를 모든 Receiver가 받습니다.
|
||||||
|
/// </summary>
|
||||||
|
public class StreamingleFacialUdpMaster : MonoBehaviour
|
||||||
|
{
|
||||||
|
private static StreamingleFacialUdpMaster _instance;
|
||||||
|
public static StreamingleFacialUdpMaster Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_instance == null)
|
||||||
|
{
|
||||||
|
var go = new GameObject("[StreamingleFacialUdpMaster]");
|
||||||
|
go.hideFlags = HideFlags.HideInHierarchy;
|
||||||
|
DontDestroyOnLoad(go);
|
||||||
|
_instance = go.AddComponent<StreamingleFacialUdpMaster>();
|
||||||
|
}
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PortListener
|
||||||
|
{
|
||||||
|
public int port;
|
||||||
|
public UdpClient udp;
|
||||||
|
public Thread thread;
|
||||||
|
public volatile bool isRunning;
|
||||||
|
public volatile string latestMessage = "";
|
||||||
|
public string lastDistributedMessage = "";
|
||||||
|
public readonly HashSet<StreamingleFacialReceiver> receivers = new HashSet<StreamingleFacialReceiver>();
|
||||||
|
public readonly object lockObj = new object();
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<int, PortListener> listeners = new Dictionary<int, PortListener>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Receiver를 지정 포트에 등록. 해당 포트의 리스너가 없으면 자동 생성.
|
||||||
|
/// </summary>
|
||||||
|
public void Register(int port, StreamingleFacialReceiver receiver)
|
||||||
|
{
|
||||||
|
if (!listeners.TryGetValue(port, out var listener))
|
||||||
|
{
|
||||||
|
listener = new PortListener { port = port };
|
||||||
|
listeners[port] = listener;
|
||||||
|
StartListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (listener.lockObj)
|
||||||
|
{
|
||||||
|
listener.receivers.Add(receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log($"[FacialUdpMaster] Port {port} 등록 (총 {listener.receivers.Count}개 Receiver)");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Receiver를 지정 포트에서 해제. 해당 포트에 Receiver가 없으면 리스너 종료.
|
||||||
|
/// </summary>
|
||||||
|
public void Unregister(int port, StreamingleFacialReceiver receiver)
|
||||||
|
{
|
||||||
|
if (!listeners.TryGetValue(port, out var listener)) return;
|
||||||
|
|
||||||
|
bool shouldStop = false;
|
||||||
|
lock (listener.lockObj)
|
||||||
|
{
|
||||||
|
listener.receivers.Remove(receiver);
|
||||||
|
shouldStop = listener.receivers.Count == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldStop)
|
||||||
|
{
|
||||||
|
StopListener(listener);
|
||||||
|
listeners.Remove(port);
|
||||||
|
Debug.Log($"[FacialUdpMaster] Port {port} 리스너 종료 (Receiver 없음)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 포트 변경 시 호출. 기존 포트 해제 → 새 포트 등록.
|
||||||
|
/// </summary>
|
||||||
|
public void SwitchPort(int oldPort, int newPort, StreamingleFacialReceiver receiver)
|
||||||
|
{
|
||||||
|
Unregister(oldPort, receiver);
|
||||||
|
Register(newPort, receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 특정 포트의 리스너를 재시작 (포트 문제 시 복구용)
|
||||||
|
/// </summary>
|
||||||
|
public void RestartPort(int port)
|
||||||
|
{
|
||||||
|
if (!listeners.TryGetValue(port, out var listener)) return;
|
||||||
|
|
||||||
|
StopListener(listener);
|
||||||
|
|
||||||
|
// 리스너 상태 리셋 후 재시작
|
||||||
|
listener.latestMessage = "";
|
||||||
|
listener.lastDistributedMessage = "";
|
||||||
|
StartListener(listener);
|
||||||
|
|
||||||
|
Debug.Log($"[FacialUdpMaster] Port {port} 리스너 재시작");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 현재 등록된 포트와 각 포트의 Receiver 수를 반환 (디버그용)
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<int, int> GetPortStatus()
|
||||||
|
{
|
||||||
|
var status = new Dictionary<int, int>();
|
||||||
|
foreach (var kvp in listeners)
|
||||||
|
{
|
||||||
|
status[kvp.Key] = kvp.Value.receivers.Count;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartListener(PortListener listener)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
listener.udp = new UdpClient(listener.port);
|
||||||
|
listener.udp.Client.ReceiveTimeout = 5;
|
||||||
|
listener.isRunning = true;
|
||||||
|
listener.thread = new Thread(() => ListenThread(listener))
|
||||||
|
{
|
||||||
|
IsBackground = true
|
||||||
|
};
|
||||||
|
listener.thread.Start();
|
||||||
|
Debug.Log($"[FacialUdpMaster] Port {listener.port} 수신 시작");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[FacialUdpMaster] Port {listener.port} 시작 실패: {e.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StopListener(PortListener listener)
|
||||||
|
{
|
||||||
|
listener.isRunning = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (listener.udp != null)
|
||||||
|
{
|
||||||
|
listener.udp.Close();
|
||||||
|
listener.udp.Dispose();
|
||||||
|
listener.udp = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
|
||||||
|
if (listener.thread != null && listener.thread.IsAlive)
|
||||||
|
{
|
||||||
|
listener.thread.Join(300);
|
||||||
|
listener.thread = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ListenThread(PortListener listener)
|
||||||
|
{
|
||||||
|
while (listener.isRunning)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IPEndPoint remoteEP = null;
|
||||||
|
byte[] data = listener.udp.Receive(ref remoteEP);
|
||||||
|
if (data != null && data.Length > 0)
|
||||||
|
{
|
||||||
|
listener.latestMessage = Encoding.ASCII.GetString(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SocketException e)
|
||||||
|
{
|
||||||
|
if (!listener.isRunning) break;
|
||||||
|
if (e.SocketErrorCode != SocketError.TimedOut)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[FacialUdpMaster] Port {listener.port} 수신 오류: {e.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if (!listener.isRunning) break;
|
||||||
|
Debug.LogError($"[FacialUdpMaster] Port {listener.port} 오류: {e.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.Sleep(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update()
|
||||||
|
{
|
||||||
|
foreach (var kvp in listeners)
|
||||||
|
{
|
||||||
|
var listener = kvp.Value;
|
||||||
|
string msg = listener.latestMessage;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(msg) || msg == listener.lastDistributedMessage)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
listener.lastDistributedMessage = msg;
|
||||||
|
|
||||||
|
lock (listener.lockObj)
|
||||||
|
{
|
||||||
|
foreach (var receiver in listener.receivers)
|
||||||
|
{
|
||||||
|
if (receiver != null && receiver.isActiveAndEnabled)
|
||||||
|
{
|
||||||
|
receiver.SetMessageFromMaster(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDestroy()
|
||||||
|
{
|
||||||
|
foreach (var kvp in listeners)
|
||||||
|
{
|
||||||
|
StopListener(kvp.Value);
|
||||||
|
}
|
||||||
|
listeners.Clear();
|
||||||
|
|
||||||
|
if (_instance == this)
|
||||||
|
_instance = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnApplicationQuit()
|
||||||
|
{
|
||||||
|
OnDestroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Assets/External/StreamingleFacial/StreamingleFacialUdpMaster.cs.meta
vendored
Normal file
2
Assets/External/StreamingleFacial/StreamingleFacialUdpMaster.cs.meta
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5f84ad022978ca14bb7fa383b1e86b3d
|
||||||
8
Assets/Resources/BossRaidWeb.meta
Normal file
8
Assets/Resources/BossRaidWeb.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 027db6e30adb2054687426649457fbbc
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/Resources/BossRaidWeb/bossraid_script.txt
(Stored with Git LFS)
Normal file
BIN
Assets/Resources/BossRaidWeb/bossraid_script.txt
(Stored with Git LFS)
Normal file
Binary file not shown.
7
Assets/Resources/BossRaidWeb/bossraid_script.txt.meta
Normal file
7
Assets/Resources/BossRaidWeb/bossraid_script.txt.meta
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a468efa52276a384db63282e727b704b
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/Resources/BossRaidWeb/bossraid_style.txt
(Stored with Git LFS)
Normal file
BIN
Assets/Resources/BossRaidWeb/bossraid_style.txt
(Stored with Git LFS)
Normal file
Binary file not shown.
7
Assets/Resources/BossRaidWeb/bossraid_style.txt.meta
Normal file
7
Assets/Resources/BossRaidWeb/bossraid_style.txt.meta
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: af43c7dd8dc851f4eaa92ccd2dfa3fa3
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/Resources/BossRaidWeb/bossraid_template.txt
(Stored with Git LFS)
Normal file
BIN
Assets/Resources/BossRaidWeb/bossraid_template.txt
(Stored with Git LFS)
Normal file
Binary file not shown.
7
Assets/Resources/BossRaidWeb/bossraid_template.txt.meta
Normal file
7
Assets/Resources/BossRaidWeb/bossraid_template.txt.meta
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f88baa51ad375d946a06b4217d25ddec
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/ResourcesData/Etc/Particle/Confetti.meta
Normal file
8
Assets/ResourcesData/Etc/Particle/Confetti.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 98485dcc15d43456ba5d755247e30747
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/Confetti/8colors.png
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/Confetti/8colors.png
(Stored with Git LFS)
Normal file
Binary file not shown.
90
Assets/ResourcesData/Etc/Particle/Confetti/8colors.png.meta
Normal file
90
Assets/ResourcesData/Etc/Particle/Confetti/8colors.png.meta
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4f7f159d7b449401197b9532fd225c70
|
||||||
|
TextureImporter:
|
||||||
|
internalIDToNameTable: []
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 10
|
||||||
|
mipmaps:
|
||||||
|
mipMapMode: 0
|
||||||
|
enableMipMap: 1
|
||||||
|
sRGBTexture: 1
|
||||||
|
linearTexture: 0
|
||||||
|
fadeOut: 0
|
||||||
|
borderMipMap: 0
|
||||||
|
mipMapsPreserveCoverage: 0
|
||||||
|
alphaTestReferenceValue: 0.5
|
||||||
|
mipMapFadeDistanceStart: 1
|
||||||
|
mipMapFadeDistanceEnd: 3
|
||||||
|
bumpmap:
|
||||||
|
convertToNormalMap: 0
|
||||||
|
externalNormalMap: 0
|
||||||
|
heightScale: 0.25
|
||||||
|
normalMapFilter: 0
|
||||||
|
isReadable: 0
|
||||||
|
streamingMipmaps: 0
|
||||||
|
streamingMipmapsPriority: 0
|
||||||
|
grayScaleToAlpha: 0
|
||||||
|
generateCubemap: 6
|
||||||
|
cubemapConvolution: 0
|
||||||
|
seamlessCubemap: 0
|
||||||
|
textureFormat: 1
|
||||||
|
maxTextureSize: 2048
|
||||||
|
textureSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
filterMode: -1
|
||||||
|
aniso: -1
|
||||||
|
mipBias: -100
|
||||||
|
wrapU: -1
|
||||||
|
wrapV: -1
|
||||||
|
wrapW: -1
|
||||||
|
nPOTScale: 1
|
||||||
|
lightmap: 0
|
||||||
|
compressionQuality: 50
|
||||||
|
spriteMode: 0
|
||||||
|
spriteExtrude: 1
|
||||||
|
spriteMeshType: 1
|
||||||
|
alignment: 0
|
||||||
|
spritePivot: {x: 0.5, y: 0.5}
|
||||||
|
spritePixelsToUnits: 100
|
||||||
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
spriteGenerateFallbackPhysicsShape: 1
|
||||||
|
alphaUsage: 1
|
||||||
|
alphaIsTransparency: 0
|
||||||
|
spriteTessellationDetail: -1
|
||||||
|
textureType: 0
|
||||||
|
textureShape: 1
|
||||||
|
singleChannelComponent: 0
|
||||||
|
maxTextureSizeSet: 0
|
||||||
|
compressionQualitySet: 0
|
||||||
|
textureFormatSet: 0
|
||||||
|
platformSettings:
|
||||||
|
- serializedVersion: 2
|
||||||
|
buildTarget: DefaultTexturePlatform
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
spriteSheet:
|
||||||
|
serializedVersion: 2
|
||||||
|
sprites: []
|
||||||
|
outline: []
|
||||||
|
physicsShape: []
|
||||||
|
bones: []
|
||||||
|
spriteID:
|
||||||
|
internalID: 0
|
||||||
|
vertices: []
|
||||||
|
indices:
|
||||||
|
edges: []
|
||||||
|
weights: []
|
||||||
|
secondaryTextures: []
|
||||||
|
spritePackingTag:
|
||||||
|
pSDRemoveMatte: 0
|
||||||
|
pSDShowRemoveMatteOption: 0
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
273
Assets/ResourcesData/Etc/Particle/Confetti/Confetti.cs
Normal file
273
Assets/ResourcesData/Etc/Particle/Confetti/Confetti.cs
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using Kayac;
|
||||||
|
|
||||||
|
public class Confetti : MonoBehaviour
|
||||||
|
{
|
||||||
|
[SerializeField] SkinnedInstancingRenderer instanceRenderer;
|
||||||
|
[SerializeField] int pieceCount = 500;
|
||||||
|
[SerializeField] float emitPiecePerSecond = 30f;
|
||||||
|
[SerializeField] bool emissionLooped = true;
|
||||||
|
[SerializeField] float positionRandomizeRadius;
|
||||||
|
[SerializeField] float velocityRandomizeRadius;
|
||||||
|
[SerializeField] float pieceWidth = 1f;
|
||||||
|
[SerializeField] float pieceLength = 1f;
|
||||||
|
[SerializeField] float normalBendRatio = 0.5f;
|
||||||
|
[SerializeField] float resistance = 5f;
|
||||||
|
[SerializeField] Vector3 gravity = new Vector3(0f, -9.81f, 0f);
|
||||||
|
[SerializeField] Vector3 wind = Vector3.zero;
|
||||||
|
[SerializeField] bool autoStart;
|
||||||
|
|
||||||
|
public int PieceCount { get { return pieceCount; } }
|
||||||
|
|
||||||
|
public float PositionRandomizeRadius
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return positionRandomizeRadius;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
positionRandomizeRadius = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float VelocityRandomizeRadius
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return velocityRandomizeRadius;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
velocityRandomizeRadius = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float PieceWidth
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return pieceWidth;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
pieceWidth = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float PieceLength
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return pieceLength;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
pieceLength = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float NormalBendRatio
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return normalBendRatio;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
normalBendRatio = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Resistance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return resistance;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
resistance = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 Gravity
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return gravity;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
gravity = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 Wind
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return wind;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
wind = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EmissionLooped
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return emissionLooped;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
emissionLooped = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float EmitPiecePerSecond
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return emitPiecePerSecond;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
emitPiecePerSecond = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Mesh originalMesh;
|
||||||
|
ConfettiPiece[] pieces;
|
||||||
|
int emitIndex;
|
||||||
|
float emitCarry; // 端数持ち越し
|
||||||
|
|
||||||
|
private void Start()
|
||||||
|
{
|
||||||
|
if (autoStart)
|
||||||
|
{
|
||||||
|
ManualStart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ManualStart(int pieceCountOverride = 0)
|
||||||
|
{
|
||||||
|
if (pieceCountOverride > 0)
|
||||||
|
{
|
||||||
|
pieceCount = pieceCountOverride;
|
||||||
|
}
|
||||||
|
originalMesh = new Mesh()
|
||||||
|
{
|
||||||
|
name = "original"
|
||||||
|
};
|
||||||
|
MeshGenerator.GenerateQuad(
|
||||||
|
originalMesh,
|
||||||
|
Vector3.zero,
|
||||||
|
new Vector3(1f, 0f, 0f),
|
||||||
|
new Vector3(0f, 0f, 1f),
|
||||||
|
Vector2.zero,
|
||||||
|
Vector2.zero,
|
||||||
|
doubleSided: true);
|
||||||
|
var uvOffsets = new Vector2[pieceCount];
|
||||||
|
for (int i = 0; i < pieceCount; i++)
|
||||||
|
{
|
||||||
|
uvOffsets[i] = new Vector2(Random.Range(0.125f, 1f), 0f);
|
||||||
|
}
|
||||||
|
instanceRenderer.ManualStart(originalMesh, uvOffsets.Length, uvOffsets);
|
||||||
|
// 実際にこの数で作れたとは限らないので確認して上書きする
|
||||||
|
pieceCount = instanceRenderer.Count;
|
||||||
|
pieces = new ConfettiPiece[pieceCount];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartEmission()
|
||||||
|
{
|
||||||
|
if (originalMesh == null)
|
||||||
|
{
|
||||||
|
ManualStart();
|
||||||
|
}
|
||||||
|
emitCarry = 0f;
|
||||||
|
for (int i = 0; i < pieces.Length; i++)
|
||||||
|
{
|
||||||
|
pieces[i].Init(
|
||||||
|
Vector3.zero,
|
||||||
|
Vector3.zero,
|
||||||
|
0f,
|
||||||
|
Quaternion.identity,
|
||||||
|
0f,
|
||||||
|
0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitPiece(int count)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var q = Quaternion.identity;
|
||||||
|
var qz = Quaternion.AngleAxis(Random.Range(-10f, 10f), new Vector3(0f, 0f, 1f));
|
||||||
|
var qy = Quaternion.AngleAxis(Random.Range(-180f, 180f), new Vector3(0f, 1f, 0f));
|
||||||
|
var qx = Quaternion.AngleAxis(Random.Range(-180f, 180f), new Vector3(1f, 0f, 0f));
|
||||||
|
q *= qz;
|
||||||
|
q *= qy;
|
||||||
|
q *= qx;
|
||||||
|
var position = new Vector3(
|
||||||
|
Random.Range(-positionRandomizeRadius, positionRandomizeRadius),
|
||||||
|
Random.Range(-positionRandomizeRadius, positionRandomizeRadius),
|
||||||
|
Random.Range(-positionRandomizeRadius, positionRandomizeRadius));
|
||||||
|
var velocity = new Vector3(
|
||||||
|
Random.Range(-velocityRandomizeRadius, velocityRandomizeRadius),
|
||||||
|
Random.Range(velocityRandomizeRadius, velocityRandomizeRadius),
|
||||||
|
Random.Range(-velocityRandomizeRadius, velocityRandomizeRadius));
|
||||||
|
var randomizedNormalBendRatio = Random.Range(normalBendRatio * 0.5f, normalBendRatio);
|
||||||
|
pieces[emitIndex].Init(
|
||||||
|
position,
|
||||||
|
velocity,
|
||||||
|
Time.deltaTime,
|
||||||
|
q,
|
||||||
|
pieceLength * 0.5f,
|
||||||
|
randomizedNormalBendRatio);
|
||||||
|
emitIndex++;
|
||||||
|
if (emitIndex >= pieces.Length)
|
||||||
|
{
|
||||||
|
emitIndex = 0;
|
||||||
|
if (!emissionLooped)
|
||||||
|
{
|
||||||
|
emitPiecePerSecond = 0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update()
|
||||||
|
{
|
||||||
|
if (pieces == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float dt = Time.deltaTime;
|
||||||
|
if (emitPiecePerSecond > 0f)
|
||||||
|
{
|
||||||
|
var countF = (emitPiecePerSecond * dt) + emitCarry;
|
||||||
|
var countI = (int)countF;
|
||||||
|
EmitPiece(countI);
|
||||||
|
emitCarry = countF - (float)countI;
|
||||||
|
}
|
||||||
|
|
||||||
|
float halfZSize = pieceLength * 0.5f;
|
||||||
|
for (int i = 0; i < pieces.Length; i++)
|
||||||
|
{
|
||||||
|
pieces[i].Update(dt, ref wind, ref gravity, resistance, halfZSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 行列反映
|
||||||
|
var poses = instanceRenderer.BeginUpdatePoses();
|
||||||
|
for (int i = 0; i < pieces.Length; i++)
|
||||||
|
{
|
||||||
|
pieces[i].GetTransform(ref poses[i], pieceLength, pieceWidth);
|
||||||
|
}
|
||||||
|
instanceRenderer.EndUpdatePoses();
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/ResourcesData/Etc/Particle/Confetti/Confetti.cs.meta
Normal file
11
Assets/ResourcesData/Etc/Particle/Confetti/Confetti.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c8afa2659287b4ab4a056bece52bb6ac
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
77
Assets/ResourcesData/Etc/Particle/Confetti/Confetti.mat
Normal file
77
Assets/ResourcesData/Etc/Particle/Confetti/Confetti.mat
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!21 &2100000
|
||||||
|
Material:
|
||||||
|
serializedVersion: 6
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name: Confetti
|
||||||
|
m_Shader: {fileID: 10752, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_ShaderKeywords:
|
||||||
|
m_LightmapFlags: 4
|
||||||
|
m_EnableInstancingVariants: 0
|
||||||
|
m_DoubleSidedGI: 0
|
||||||
|
m_CustomRenderQueue: -1
|
||||||
|
stringTagMap: {}
|
||||||
|
disabledShaderPasses: []
|
||||||
|
m_SavedProperties:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TexEnvs:
|
||||||
|
- _BumpMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailAlbedoMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailMask:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailNormalMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _EmissionMap:
|
||||||
|
m_Texture: {fileID: 2800000, guid: 4f447d9f9c5234f49b436e395e10e9a0, type: 3}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MainTex:
|
||||||
|
m_Texture: {fileID: 2800000, guid: 4f7f159d7b449401197b9532fd225c70, type: 3}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MetallicGlossMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _OcclusionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _ParallaxMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Floats:
|
||||||
|
- _BumpScale: 1
|
||||||
|
- _Cutoff: 0.5
|
||||||
|
- _DetailNormalMapScale: 1
|
||||||
|
- _DstBlend: 0
|
||||||
|
- _GlossMapScale: 1
|
||||||
|
- _Glossiness: 0.5
|
||||||
|
- _GlossyReflections: 1
|
||||||
|
- _Metallic: 0
|
||||||
|
- _Mode: 0
|
||||||
|
- _OcclusionStrength: 1
|
||||||
|
- _Parallax: 0.02
|
||||||
|
- _SmoothnessTextureChannel: 0
|
||||||
|
- _SpecularHighlights: 1
|
||||||
|
- _SrcBlend: 1
|
||||||
|
- _UVSec: 0
|
||||||
|
- _ZWrite: 1
|
||||||
|
m_Colors:
|
||||||
|
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
- _EmissionColor: {r: 0.5019608, g: 0.5019608, b: 0.5019608, a: 1}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d48b83c48ac2c48339a66b0dbdc5aeeb
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 0
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/Confetti/Confetti.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/Confetti/Confetti.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 514c7e149f71f456988bc9816d5ef692
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
99
Assets/ResourcesData/Etc/Particle/Confetti/ConfettiPiece.cs
Normal file
99
Assets/ResourcesData/Etc/Particle/Confetti/ConfettiPiece.cs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
struct ConfettiPiece
|
||||||
|
{
|
||||||
|
public void Init(
|
||||||
|
Vector3 position,
|
||||||
|
Vector3 velocity,
|
||||||
|
float deltaTime,
|
||||||
|
Quaternion orientation, //Z軸方向に
|
||||||
|
float halfZSize,
|
||||||
|
float normalBendRatio)
|
||||||
|
{
|
||||||
|
this.normalBendRatio = normalBendRatio;
|
||||||
|
this.orientation = orientation;
|
||||||
|
this.position = position;
|
||||||
|
var forward = orientation * new Vector3(0f, 0f, 1f);
|
||||||
|
var t = forward * halfZSize;
|
||||||
|
var dp = velocity * deltaTime;
|
||||||
|
prevPosition0 = position - t;
|
||||||
|
prevPosition1 = position + t;
|
||||||
|
prevPosition0 -= dp;
|
||||||
|
prevPosition1 -= dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(
|
||||||
|
float deltaTime,
|
||||||
|
ref Vector3 wind,
|
||||||
|
ref Vector3 gravity,
|
||||||
|
float resistance,
|
||||||
|
float halfZSize)
|
||||||
|
{
|
||||||
|
var forward = orientation * new Vector3(0f, 0f, 1f);
|
||||||
|
var t = forward * halfZSize;
|
||||||
|
var p0 = position - t;
|
||||||
|
var p1 = position + t;
|
||||||
|
// 相対的な風ベクトルを出す
|
||||||
|
var v0 = (p0 - prevPosition0) / deltaTime;
|
||||||
|
var v1 = (p1 - prevPosition1) / deltaTime;
|
||||||
|
var relativeWind0 = wind - v0;
|
||||||
|
var relativeWind1 = wind - v1;
|
||||||
|
// 頂点ごとの法線を生成
|
||||||
|
var n = orientation * new Vector3(0f, 1f, 0f);
|
||||||
|
// 曲げる
|
||||||
|
t = forward * normalBendRatio;
|
||||||
|
var n0 = n + t;
|
||||||
|
var n1 = n - t;
|
||||||
|
// 正規化。n1はn0と同じ長さなので長さを計算して使い回す
|
||||||
|
n0.Normalize();
|
||||||
|
n1.Normalize();
|
||||||
|
// 風ベクトルの法線方向成分を、加速度とする
|
||||||
|
var dot0 = Vector3.Dot(n0, relativeWind0);
|
||||||
|
var dot1 = Vector3.Dot(n1, relativeWind1);
|
||||||
|
if (dot0 < 0)
|
||||||
|
{
|
||||||
|
n0 = -n0;
|
||||||
|
dot0 = -dot0;
|
||||||
|
}
|
||||||
|
if (dot1 < 0)
|
||||||
|
{
|
||||||
|
n1 = -n1;
|
||||||
|
dot1 = -dot1;
|
||||||
|
}
|
||||||
|
var accel0 = n0 * (dot0 * resistance);
|
||||||
|
var accel1 = n1 * (dot1 * resistance);
|
||||||
|
// 重力を追加
|
||||||
|
accel0 += gravity;
|
||||||
|
accel1 += gravity;
|
||||||
|
// 独立に積分
|
||||||
|
var dt2 = deltaTime * deltaTime;
|
||||||
|
var dp0 = p0 - prevPosition0 + (accel0 * dt2);
|
||||||
|
var dp1 = p1 - prevPosition1 + (accel1 * dt2);
|
||||||
|
var nextP0 = p0 + dp0;
|
||||||
|
var nextP1 = p1 + dp1;
|
||||||
|
prevPosition0 = p0;
|
||||||
|
prevPosition1 = p1;
|
||||||
|
p0 = nextP0;
|
||||||
|
p1 = nextP1;
|
||||||
|
// 拘束
|
||||||
|
var newForward = (p1 - p0).normalized;
|
||||||
|
position = (p0 + p1) * 0.5f;
|
||||||
|
// 姿勢更新
|
||||||
|
// forward -> newForwardに向くような、回転軸右ベクタの回転を作用させる
|
||||||
|
var dq = Quaternion.FromToRotation(forward, newForward);
|
||||||
|
orientation = dq * orientation; // dqは時間的に後の回転だから、ベクタから遠い方、つまり前から乗算
|
||||||
|
orientation.Normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetTransform(
|
||||||
|
ref Matrix4x4 matrix,
|
||||||
|
float ZSize,
|
||||||
|
float XSize)
|
||||||
|
{
|
||||||
|
matrix.SetTRS(position, orientation, new Vector3(XSize, 1f, ZSize));
|
||||||
|
}
|
||||||
|
public Vector3 position;
|
||||||
|
Vector3 prevPosition0;
|
||||||
|
Vector3 prevPosition1;
|
||||||
|
Quaternion orientation;
|
||||||
|
float normalBendRatio;
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bfb6fb60322ae4e7e855e73b08d27331
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
2
Assets/ResourcesData/Etc/Particle/JMO Assets.meta
Normal file
2
Assets/ResourcesData/Etc/Particle/JMO Assets.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 976974e4d3018034e87caeb9f51f20f6
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c865e48369a325f4784ecd8444d1ec51
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f348a2fb2f8a7fe4e82fb08818415884
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 715add6d7a2eff443bf0aee3cf26e7fc
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Electric/CFX_ElectricityBall.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Electric/CFX_ElectricityBall.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,16 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 77ec3c4e07a36814fb3169ecef41b50a
|
||||||
|
labels:
|
||||||
|
- ball
|
||||||
|
- bubble
|
||||||
|
- cartoonfx
|
||||||
|
- electric
|
||||||
|
- particles
|
||||||
|
- toon
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Electric/CFX_ElectricityBall.prefab
|
||||||
|
uploadId: 545941
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c41f95c98750b744bb429ee2fc6a1d70
|
||||||
|
labels:
|
||||||
|
- cartoonfx
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Explosions/CFX_Explosion_B_Smoke+Text.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Explosions/CFX_Explosion_B_Smoke+Text.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,16 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 46876a2780737ec45a19d62f88e5ce56
|
||||||
|
timeCreated: 1505140479
|
||||||
|
licenseType: Store
|
||||||
|
NativeFormatImporter:
|
||||||
|
mainObjectFileID: 100100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Explosions/CFX_Explosion_B_Smoke+Text.prefab
|
||||||
|
uploadId: 545941
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Explosions/CFX_Firework_Trails_Gravity.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Explosions/CFX_Firework_Trails_Gravity.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,16 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4adffb0018aeda44e9263f901167af1f
|
||||||
|
timeCreated: 1505138997
|
||||||
|
licenseType: Store
|
||||||
|
NativeFormatImporter:
|
||||||
|
mainObjectFileID: 100100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Explosions/CFX_Firework_Trails_Gravity.prefab
|
||||||
|
uploadId: 545941
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 45653d11d228e594498b3d9119285e35
|
||||||
|
labels:
|
||||||
|
- cartoonfx
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Hits/CFX_Hit_A Red+RandomText.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Hits/CFX_Hit_A Red+RandomText.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,15 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f95ff734540a0d749be6571b6cb5b37f
|
||||||
|
labels:
|
||||||
|
- cartoonfx
|
||||||
|
- hit
|
||||||
|
- particles
|
||||||
|
- text
|
||||||
|
- toon
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Hits/CFX_Hit_A Red+RandomText.prefab
|
||||||
|
uploadId: 545941
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Hits/CFX_Hit_C White.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Hits/CFX_Hit_C White.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,14 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f06e78284f831ae469c74624ab5d513b
|
||||||
|
labels:
|
||||||
|
- cartoonfx
|
||||||
|
- particles
|
||||||
|
- hit
|
||||||
|
- toon
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Hits/CFX_Hit_C White.prefab
|
||||||
|
uploadId: 545941
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f991151302bbc8440bc158a1be7d008d
|
||||||
|
labels:
|
||||||
|
- cartoonfx
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Misc/CFX_MagicPoof.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Misc/CFX_MagicPoof.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,15 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a40b64bf23366dc42a892af2c6ff6140
|
||||||
|
labels:
|
||||||
|
- cartoonfx
|
||||||
|
- particles
|
||||||
|
- poof
|
||||||
|
- smoke
|
||||||
|
- toon
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Misc/CFX_MagicPoof.prefab
|
||||||
|
uploadId: 545941
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Misc/CFX_Magical_Source.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Misc/CFX_Magical_Source.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,16 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9e4577abe56a95f4a91d29a0473cd30c
|
||||||
|
timeCreated: 1505142609
|
||||||
|
licenseType: Store
|
||||||
|
NativeFormatImporter:
|
||||||
|
mainObjectFileID: 100100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Misc/CFX_Magical_Source.prefab
|
||||||
|
uploadId: 545941
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Misc/CFX_Poof.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Misc/CFX_Poof.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,14 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3156817f64ec68948ad6bb26569b9ef5
|
||||||
|
labels:
|
||||||
|
- cartoonfx
|
||||||
|
- particles
|
||||||
|
- poof
|
||||||
|
- toon
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Misc/CFX_Poof.prefab
|
||||||
|
uploadId: 545941
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Misc/CFX_Tornado.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Misc/CFX_Tornado.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,14 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 352304b7fbe11f445970df6ae36e6227
|
||||||
|
labels:
|
||||||
|
- cartoonfx
|
||||||
|
- particles
|
||||||
|
- tornado
|
||||||
|
- toon
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Misc/CFX_Tornado.prefab
|
||||||
|
uploadId: 545941
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Misc/CFX_Virus.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Misc/CFX_Virus.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,14 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2a474af3f4c27be4e9bdce39cfe4315d
|
||||||
|
labels:
|
||||||
|
- cartoonfx
|
||||||
|
- particles
|
||||||
|
- virus
|
||||||
|
- toon
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX Prefabs/Misc/CFX_Virus.prefab
|
||||||
|
uploadId: 545941
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 84d86077ce20b3d408f08f7cc5cfb4ea
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9ef0e39c32aae7b4480fbdb6d2efb0a1
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Blood/CFX2_Blood.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Blood/CFX2_Blood.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,15 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bc98890f6028f444eaa7789bde5e2eeb
|
||||||
|
labels:
|
||||||
|
- cartoonfx
|
||||||
|
- particles
|
||||||
|
- blood
|
||||||
|
- directional
|
||||||
|
- toon
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Blood/CFX2_Blood.prefab
|
||||||
|
uploadId: 545941
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7e71da46ca428824c9e9e4598154d6d3
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Debris Hits/CFX2_RockHit.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Debris Hits/CFX2_RockHit.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,16 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a97415c6b57076f41a6621a7b51d63a3
|
||||||
|
timeCreated: 1506674220
|
||||||
|
licenseType: Store
|
||||||
|
NativeFormatImporter:
|
||||||
|
mainObjectFileID: 100100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Debris Hits/CFX2_RockHit.prefab
|
||||||
|
uploadId: 545941
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c21f3643835b3b34e897f4b378531f37
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Electric/CFX2_SparksHit_B Sphere.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Electric/CFX2_SparksHit_B Sphere.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,17 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4961a16ba01e09547be3e1c9d16d5ad0
|
||||||
|
timeCreated: 1506673851
|
||||||
|
licenseType: Store
|
||||||
|
NativeFormatImporter:
|
||||||
|
mainObjectFileID: 100100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Electric/CFX2_SparksHit_B
|
||||||
|
Sphere.prefab
|
||||||
|
uploadId: 545941
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: efc53651f7e42d84d86caee3be88073e
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Explosions/CFX2_WWExplosion_C.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Explosions/CFX2_WWExplosion_C.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,16 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: aa8d6482d70a23445b4b2a928ed1b845
|
||||||
|
timeCreated: 1506670975
|
||||||
|
licenseType: Store
|
||||||
|
NativeFormatImporter:
|
||||||
|
mainObjectFileID: 100100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Explosions/CFX2_WWExplosion_C.prefab
|
||||||
|
uploadId: 545941
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 86fef6e72f4589f428dccc24bd05cf0b
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Misc/CFX2_BatsCloud.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Misc/CFX2_BatsCloud.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,14 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d4f5579fb5da2f646a0c2bee91bdf6b5
|
||||||
|
labels:
|
||||||
|
- cartoonfx
|
||||||
|
- particles
|
||||||
|
- symbol
|
||||||
|
- toon
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Misc/CFX2_BatsCloud.prefab
|
||||||
|
uploadId: 545941
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Misc/CFX2_BrokenHeart.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Misc/CFX2_BrokenHeart.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,14 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bcaff8fc36e95584bb27cc3cf7c6cb14
|
||||||
|
labels:
|
||||||
|
- cartoonfx
|
||||||
|
- particles
|
||||||
|
- toon
|
||||||
|
- symbol
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Misc/CFX2_BrokenHeart.prefab
|
||||||
|
uploadId: 545941
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Misc/CFX2_Wandering_Spirits.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Misc/CFX2_Wandering_Spirits.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,16 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: daa6cceb1b087d74aad6916dac2805ea
|
||||||
|
timeCreated: 1505487254
|
||||||
|
licenseType: Store
|
||||||
|
NativeFormatImporter:
|
||||||
|
mainObjectFileID: 100100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Misc/CFX2_Wandering_Spirits.prefab
|
||||||
|
uploadId: 545941
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: fdee0cda8f0d2094fa5ca47abb4ffd95
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Pickup Items/CFX2_PickupDiamond2.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Pickup Items/CFX2_PickupDiamond2.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,15 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: aa3fed151f536ee49b583c6a3ac4a2e1
|
||||||
|
labels:
|
||||||
|
- cartoonfx
|
||||||
|
- particles
|
||||||
|
- pickup
|
||||||
|
- symbol
|
||||||
|
- toon
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Pickup Items/CFX2_PickupDiamond2.prefab
|
||||||
|
uploadId: 545941
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Pickup Items/CFX2_PickupHeart.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Pickup Items/CFX2_PickupHeart.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,15 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3af6f68141914ca43ba39b2403757bd0
|
||||||
|
labels:
|
||||||
|
- cartoonfx
|
||||||
|
- particles
|
||||||
|
- pickup
|
||||||
|
- symbol
|
||||||
|
- toon
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Pickup Items/CFX2_PickupHeart.prefab
|
||||||
|
uploadId: 545941
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Pickup Items/CFX2_PickupSmiley2.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Pickup Items/CFX2_PickupSmiley2.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,15 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1bc4a709f24528b40984e62f32e398a0
|
||||||
|
labels:
|
||||||
|
- cartoonfx
|
||||||
|
- particles
|
||||||
|
- pickup
|
||||||
|
- symbol
|
||||||
|
- toon
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Pickup Items/CFX2_PickupSmiley2.prefab
|
||||||
|
uploadId: 545941
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Pickup Items/CFX2_PickupStar.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Pickup Items/CFX2_PickupStar.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,15 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8fc06027b01064e4f885fd8dd2929310
|
||||||
|
labels:
|
||||||
|
- cartoonfx
|
||||||
|
- particles
|
||||||
|
- pickup
|
||||||
|
- symbol
|
||||||
|
- toon
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Pickup Items/CFX2_PickupStar.prefab
|
||||||
|
uploadId: 545941
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e8472d517d4584f41ac28b96b812564f
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Skull & Ghosts Effects/CFX2_EnemyDeathSkull.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Skull & Ghosts Effects/CFX2_EnemyDeathSkull.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,15 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7867af58a6ec48846ae807eb4022fbaa
|
||||||
|
labels:
|
||||||
|
- cartoonfx
|
||||||
|
- particles
|
||||||
|
- smoke
|
||||||
|
- toon
|
||||||
|
- symbol
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Skull & Ghosts Effects/CFX2_EnemyDeathSkull.prefab
|
||||||
|
uploadId: 545941
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: fda99d3a72bd62d44b37eef4da0ac074
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Water/CFX2_Big_Splash (No Collision).prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Water/CFX2_Big_Splash (No Collision).prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,17 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 77c69ec12208c4c4380d15e30b6f8f68
|
||||||
|
timeCreated: 1507212856
|
||||||
|
licenseType: Store
|
||||||
|
NativeFormatImporter:
|
||||||
|
mainObjectFileID: 100100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX2 Prefabs/Water/CFX2_Big_Splash
|
||||||
|
(No Collision).prefab
|
||||||
|
uploadId: 545941
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9358d72e9ab0589469b7c81a782cb400
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6d8820046d052af4583d35be43c7a959
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX3 Prefabs/Electric/CFX3_Hit_Electric_A_Ground.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX3 Prefabs/Electric/CFX3_Hit_Electric_A_Ground.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,18 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1ca16f2a31fb6a548ad8954bed1d321f
|
||||||
|
labels:
|
||||||
|
- CartoonFX
|
||||||
|
- Toon
|
||||||
|
- Particles
|
||||||
|
- Hit
|
||||||
|
- Electric
|
||||||
|
- Ground
|
||||||
|
NativeFormatImporter:
|
||||||
|
userData:
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX3 Prefabs/Electric/CFX3_Hit_Electric_A_Ground.prefab
|
||||||
|
uploadId: 545941
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX3 Prefabs/Electric/CFX3_Hit_Electric_C_Air.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX3 Prefabs/Electric/CFX3_Hit_Electric_C_Air.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,16 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e243632bb3aff9549abdcfcc2ef0c4f0
|
||||||
|
timeCreated: 1504710934
|
||||||
|
licenseType: Store
|
||||||
|
NativeFormatImporter:
|
||||||
|
mainObjectFileID: 100100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX3 Prefabs/Electric/CFX3_Hit_Electric_C_Air.prefab
|
||||||
|
uploadId: 545941
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d15fe19a363a70749ba9f690ab060547
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX3 Prefabs/Environment/CFX3_Snow_Dense.prefab
(Stored with Git LFS)
Normal file
BIN
Assets/ResourcesData/Etc/Particle/JMO Assets/Cartoon FX (legacy)/CFX3 Prefabs/Environment/CFX3_Snow_Dense.prefab
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,16 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: de07bf378e7247444a0715ad2ff509e3
|
||||||
|
labels:
|
||||||
|
- CartoonFX
|
||||||
|
- Toon
|
||||||
|
- Particles
|
||||||
|
- Snow
|
||||||
|
NativeFormatImporter:
|
||||||
|
userData:
|
||||||
|
AssetOrigin:
|
||||||
|
serializedVersion: 1
|
||||||
|
productId: 109565
|
||||||
|
packageName: Cartoon FX Remaster Free
|
||||||
|
packageVersion: R 1.0.2
|
||||||
|
assetPath: Assets/JMO Assets/Cartoon FX (legacy)/CFX3 Prefabs/Environment/CFX3_Snow_Dense.prefab
|
||||||
|
uploadId: 545941
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5d25cb644a933ed4bad4bc0b015fa1f6
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user