├── .editorconfig ├── .gitignore ├── LICENSE ├── Live2DCSharpSDK.App ├── LAppAllocator.cs ├── LAppDefine.cs ├── LAppDelegate.cs ├── LAppLive2DManager.cs ├── LAppModel.cs ├── LAppPal.cs ├── LAppTextureManager.cs ├── LAppView.cs ├── Live2DCSharpSDK.App.csproj ├── TextureInfo.cs └── TouchManager.cs ├── Live2DCSharpSDK.Framework ├── Core │ └── CubismCore.cs ├── CubismCdiJson.cs ├── CubismDefaultParameterId.cs ├── CubismFramework.cs ├── CubismLog.cs ├── CubismModelSettingJson.cs ├── CubismOption.cs ├── Effect │ ├── BreathParameterData.cs │ ├── CubismBreath.cs │ ├── CubismEyeBlink.cs │ ├── CubismPose.cs │ ├── EyeState.cs │ └── PartData.cs ├── ICubismAllocator.cs ├── Id │ └── CubismIdManager.cs ├── JsonContext.cs ├── Live2DCSharpSDK.Framework.csproj ├── Math │ ├── CubismMath.cs │ ├── CubismMatrix44.cs │ ├── CubismModelMatrix.cs │ ├── CubismTargetPoint.cs │ └── CubismViewMatrix.cs ├── Model │ ├── CubismMoc.cs │ ├── CubismModel.cs │ ├── CubismModelUserData.cs │ ├── CubismModelUserDataNode.cs │ ├── CubismModelUserDataObj.cs │ ├── CubismUserModel.cs │ ├── DrawableColorData.cs │ ├── DrawableCullingData.cs │ └── PartColorData.cs ├── ModelSettingObj.cs ├── Motion │ ├── ACubismMotion.cs │ ├── CubismExpressionMotion.cs │ ├── CubismExpressionMotionManager.cs │ ├── CubismMotion.cs │ ├── CubismMotionInternal.cs │ ├── CubismMotionManager.cs │ ├── CubismMotionObj.cs │ ├── CubismMotionQueueEntry.cs │ └── CubismMotionQueueManager.cs ├── Physics │ ├── CubismPhysics.cs │ ├── CubismPhysicsInternal.cs │ ├── CubismPhysicsJson.cs │ └── CubismPhysicsObj.cs ├── Rendering │ ├── CubismBlendMode.cs │ ├── CubismClippingContext.cs │ ├── CubismClippingManager.cs │ ├── CubismOffscreenSurface.cs │ ├── CubismRenderer.cs │ ├── CubismTextureColor.cs │ └── RenderType.cs ├── SDKInfo.cs └── Type │ └── RectF.cs ├── Live2DCSharpSDK.OpenGL.Avalonia ├── .gitignore ├── App.axaml ├── App.axaml.cs ├── AvaloniaApi.cs ├── FpsTimer.cs ├── Live2DCSharpSDK.OpenGL.Avalonia.csproj ├── MainWindow.axaml ├── MainWindow.axaml.cs └── Program.cs ├── Live2DCSharpSDK.OpenGL.OpenTK ├── Live2DCSharpSDK.OpenGL.OpenTK.csproj ├── OpenTKApi.cs ├── Program.cs ├── Properties │ └── launchSettings.json └── Window.cs ├── Live2DCSharpSDK.OpenGL.WPF ├── App.xaml ├── App.xaml.cs ├── AssemblyInfo.cs ├── Live2DCSharpSDK.OpenGL.WPF.csproj ├── Live2DCSharpSDK.WPF.user ├── MainWindow.xaml ├── MainWindow.xaml.cs └── OpenTKWPFApi.cs ├── Live2DCSharpSDK.OpenGL ├── CubismClippingContext_OpenGLES2.cs ├── CubismClippingManager_OpenGLES2.cs ├── CubismOffscreenSurface_OpenGLES2.cs ├── CubismRendererProfile_OpenGLES2.cs ├── CubismRenderer_OpenGLES2.cs ├── CubismShaderSet.cs ├── CubismShader_OpenGLES2.cs ├── LAppDelegateOpenGL.cs ├── LAppViewOpenGL.cs ├── Live2DCSharpSDK.OpenGL.csproj ├── OpenGLApi.cs ├── ShaderNames.cs └── TextureInfoOpenGL.cs ├── Live2DCSharpSDK.Vulkan.Silk ├── Live2DCSharpSDK.Vulkan.Silk.csproj └── Program.cs ├── Live2DCSharpSDK.Vulkan ├── .gitignore ├── Blend.cs ├── CubismBufferVulkan.cs ├── CubismClippingContext_Vulkan.cs ├── CubismClippingManager_Vulkan.cs ├── CubismImageVulkan.cs ├── CubismOffscreenSurface_Vulkan.cs ├── CubismPipeline_Vulkan.cs ├── CubismRenderer_Vulkan.cs ├── Descriptor.cs ├── LAppDelegateVulkan.cs ├── LAppViewVulkan.cs ├── Live2DCSharpSDK.Vulkan.csproj ├── ModelUBO.cs ├── ModelVertex.cs ├── PipelineResource.cs ├── QueueFamilyIndices.cs ├── ShaderNames.cs ├── SwapchainManager.cs ├── SwapchainSupportDetails.cs ├── TextureInfoVulkan.cs ├── VulkanApi.cs ├── VulkanManager.cs └── glsl │ ├── FragShaderSrc.frag │ ├── FragShaderSrcMask.frag │ ├── FragShaderSrcMaskInverted.frag │ ├── FragShaderSrcMaskInvertedPremultipliedAlpha.frag │ ├── FragShaderSrcMaskPremultipliedAlpha.frag │ ├── FragShaderSrcPremultipliedAlpha.frag │ ├── FragShaderSrcSetupMask.frag │ ├── VertShaderSrc.vert │ ├── VertShaderSrcMasked.vert │ ├── VertShaderSrcSetupMask.vert │ ├── common.glsl │ ├── glslbuild.ps1 │ └── glslbuild.sh ├── Live2DCSharpSDK.sln └── README.md /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # CS8618: 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。 4 | dotnet_diagnostic.CS8618.severity = none 5 | 6 | [*.cs] 7 | #### 命名样式 #### 8 | 9 | # 命名规则 10 | 11 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion 12 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface 13 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i 14 | 15 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion 16 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types 17 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case 18 | 19 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion 20 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members 21 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case 22 | 23 | # 符号规范 24 | 25 | dotnet_naming_symbols.interface.applicable_kinds = interface 26 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 27 | dotnet_naming_symbols.interface.required_modifiers = 28 | 29 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum 30 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 31 | dotnet_naming_symbols.types.required_modifiers = 32 | 33 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method 34 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 35 | dotnet_naming_symbols.non_field_members.required_modifiers = 36 | 37 | # 命名样式 38 | 39 | dotnet_naming_style.begins_with_i.required_prefix = I 40 | dotnet_naming_style.begins_with_i.required_suffix = 41 | dotnet_naming_style.begins_with_i.word_separator = 42 | dotnet_naming_style.begins_with_i.capitalization = pascal_case 43 | 44 | dotnet_naming_style.pascal_case.required_prefix = 45 | dotnet_naming_style.pascal_case.required_suffix = 46 | dotnet_naming_style.pascal_case.word_separator = 47 | dotnet_naming_style.pascal_case.capitalization = pascal_case 48 | 49 | dotnet_naming_style.pascal_case.required_prefix = 50 | dotnet_naming_style.pascal_case.required_suffix = 51 | dotnet_naming_style.pascal_case.word_separator = 52 | dotnet_naming_style.pascal_case.capitalization = pascal_case 53 | csharp_using_directive_placement = outside_namespace:silent 54 | csharp_style_expression_bodied_methods = false:silent 55 | csharp_style_expression_bodied_constructors = false:silent 56 | csharp_style_expression_bodied_operators = false:silent 57 | csharp_style_expression_bodied_properties = true:silent 58 | csharp_style_expression_bodied_indexers = true:silent 59 | csharp_style_expression_bodied_accessors = true:silent 60 | csharp_style_expression_bodied_lambdas = true:silent 61 | csharp_style_expression_bodied_local_functions = false:silent 62 | csharp_style_conditional_delegate_call = true:suggestion 63 | csharp_style_var_for_built_in_types = false:silent 64 | csharp_style_var_when_type_is_apparent = false:silent 65 | csharp_style_var_elsewhere = false:silent 66 | csharp_prefer_simple_using_statement = true:suggestion 67 | csharp_prefer_braces = true:silent 68 | csharp_style_namespace_declarations = block_scoped:silent 69 | csharp_style_prefer_method_group_conversion = true:silent 70 | csharp_style_prefer_top_level_statements = true:silent 71 | csharp_style_prefer_primary_constructors = true:suggestion 72 | csharp_prefer_static_local_function = true:suggestion 73 | 74 | [*.vb] 75 | #### 命名样式 #### 76 | 77 | # 命名规则 78 | 79 | dotnet_naming_rule.interface_should_be_以_i_开始.severity = suggestion 80 | dotnet_naming_rule.interface_should_be_以_i_开始.symbols = interface 81 | dotnet_naming_rule.interface_should_be_以_i_开始.style = 以_i_开始 82 | 83 | dotnet_naming_rule.类型_should_be_帕斯卡拼写法.severity = suggestion 84 | dotnet_naming_rule.类型_should_be_帕斯卡拼写法.symbols = 类型 85 | dotnet_naming_rule.类型_should_be_帕斯卡拼写法.style = 帕斯卡拼写法 86 | 87 | dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.severity = suggestion 88 | dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.symbols = 非字段成员 89 | dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.style = 帕斯卡拼写法 90 | 91 | # 符号规范 92 | 93 | dotnet_naming_symbols.interface.applicable_kinds = interface 94 | dotnet_naming_symbols.interface.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected 95 | dotnet_naming_symbols.interface.required_modifiers = 96 | 97 | dotnet_naming_symbols.类型.applicable_kinds = class, struct, interface, enum 98 | dotnet_naming_symbols.类型.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected 99 | dotnet_naming_symbols.类型.required_modifiers = 100 | 101 | dotnet_naming_symbols.非字段成员.applicable_kinds = property, event, method 102 | dotnet_naming_symbols.非字段成员.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected 103 | dotnet_naming_symbols.非字段成员.required_modifiers = 104 | 105 | # 命名样式 106 | 107 | dotnet_naming_style.以_i_开始.required_prefix = I 108 | dotnet_naming_style.以_i_开始.required_suffix = 109 | dotnet_naming_style.以_i_开始.word_separator = 110 | dotnet_naming_style.以_i_开始.capitalization = pascal_case 111 | 112 | dotnet_naming_style.帕斯卡拼写法.required_prefix = 113 | dotnet_naming_style.帕斯卡拼写法.required_suffix = 114 | dotnet_naming_style.帕斯卡拼写法.word_separator = 115 | dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case 116 | 117 | dotnet_naming_style.帕斯卡拼写法.required_prefix = 118 | dotnet_naming_style.帕斯卡拼写法.required_suffix = 119 | dotnet_naming_style.帕斯卡拼写法.word_separator = 120 | dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case 121 | 122 | [*.{cs,vb}] 123 | end_of_line = crlf 124 | dotnet_style_qualification_for_field = false:silent 125 | dotnet_style_qualification_for_property = false:silent 126 | dotnet_style_qualification_for_method = false:silent 127 | dotnet_style_qualification_for_event = false:silent 128 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /Resources 2 | obj/ 3 | bin/ 4 | /.vs 5 | Live2DCubismCore.dll 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) .NET Foundation and Contributors 4 | All Rights Reserved 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. -------------------------------------------------------------------------------- /Live2DCSharpSDK.App/LAppAllocator.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using Live2DCSharpSDK.Framework; 3 | 4 | namespace Live2DCSharpSDK.App; 5 | 6 | /// 7 | /// メモリ確保・解放処理のインターフェースの実装。 8 | /// フレームワークから呼び出される。 9 | /// 10 | public class LAppAllocator : ICubismAllocator 11 | { 12 | /// 13 | /// メモリ領域を割り当てる。 14 | /// 15 | /// 割り当てたいサイズ。 16 | /// 指定したメモリ領域 17 | public IntPtr Allocate(int size) 18 | { 19 | return Marshal.AllocHGlobal(size); 20 | } 21 | 22 | /// 23 | /// メモリ領域を解放する 24 | /// 25 | /// 解放するメモリ。 26 | public void Deallocate(IntPtr memory) 27 | { 28 | Marshal.FreeHGlobal(memory); 29 | } 30 | 31 | /// 32 | /// 33 | /// 34 | /// 割り当てたいサイズ。 35 | /// 割り当てたいサイズ。 36 | /// alignedAddress 37 | public unsafe IntPtr AllocateAligned(int size, int alignment) 38 | { 39 | IntPtr offset, shift, alignedAddress; 40 | IntPtr allocation; 41 | void** preamble; 42 | 43 | offset = alignment - 1 + sizeof(void*); 44 | 45 | allocation = Allocate((int)(size + offset)); 46 | 47 | alignedAddress = allocation + sizeof(void*); 48 | 49 | shift = alignedAddress % alignment; 50 | 51 | if (shift != 0) 52 | { 53 | alignedAddress += alignment - shift; 54 | } 55 | 56 | preamble = (void**)alignedAddress; 57 | preamble[-1] = (void*)allocation; 58 | 59 | return alignedAddress; 60 | } 61 | 62 | /// 63 | /// 64 | /// 65 | /// 解放するメモリ。 66 | public unsafe void DeallocateAligned(IntPtr alignedMemory) 67 | { 68 | var preamble = (void**)alignedMemory; 69 | 70 | Deallocate(new IntPtr(preamble[-1])); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.App/LAppDefine.cs: -------------------------------------------------------------------------------- 1 | using Live2DCSharpSDK.Framework; 2 | 3 | namespace Live2DCSharpSDK.App; 4 | 5 | /// 6 | /// アプリケーションクラス。 7 | /// Cubism SDK の管理を行う。 8 | /// 9 | public static class LAppDefine 10 | { 11 | // 画面 12 | public const float ViewScale = 1.0f; 13 | public const float ViewMaxScale = 2.0f; 14 | public const float ViewMinScale = 0.8f; 15 | 16 | public const float ViewLogicalLeft = -1.0f; 17 | public const float ViewLogicalRight = 1.0f; 18 | public const float ViewLogicalBottom = -1.0f; 19 | public const float ViewLogicalTop = -1.0f; 20 | 21 | public const float ViewLogicalMaxLeft = -2.0f; 22 | public const float ViewLogicalMaxRight = 2.0f; 23 | public const float ViewLogicalMaxBottom = -2.0f; 24 | public const float ViewLogicalMaxTop = 2.0f; 25 | 26 | // 外部定義ファイル(json)と合わせる 27 | public const string MotionGroupIdle = "Idle"; // アイドリング 28 | public const string MotionGroupTapBody = "TapBody"; // 体をタップしたとき 29 | 30 | // 外部定義ファイル(json)と合わせる 31 | public const string HitAreaNameHead = "Head"; 32 | public const string HitAreaNameBody = "Body"; 33 | 34 | // MOC3の整合性検証オプション 35 | public const bool MocConsistencyValidationEnable = true; 36 | 37 | // Frameworkから出力するログのレベル設定 38 | public const LogLevel CubismLoggingLevel = LogLevel.Verbose; 39 | } 40 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.App/LAppDelegate.cs: -------------------------------------------------------------------------------- 1 | using Live2DCSharpSDK.Framework.Model; 2 | using Live2DCSharpSDK.Framework.Rendering; 3 | 4 | namespace Live2DCSharpSDK.App; 5 | 6 | /// 7 | /// アプリケーションクラス。 8 | /// Cubism SDK の管理を行う。 9 | /// 10 | public abstract class LAppDelegate : IDisposable 11 | { 12 | /// 13 | /// テクスチャマネージャー 14 | /// 15 | public LAppTextureManager TextureManager { get; private set; } 16 | 17 | public LAppLive2DManager Live2dManager { get; private set; } 18 | 19 | /// 20 | /// View情報 21 | /// 22 | public LAppView View { get; protected set; } 23 | 24 | public CubismTextureColor BGColor { get; set; } = new(0, 0, 0, 0); 25 | 26 | /// 27 | /// クリックしているか 28 | /// 29 | private bool _captured; 30 | /// 31 | /// マウスX座標 32 | /// 33 | private float _mouseX; 34 | /// 35 | /// マウスY座標 36 | /// 37 | private float _mouseY; 38 | 39 | /// 40 | /// Initialize関数で設定したウィンドウ幅 41 | /// 42 | public int WindowWidth { get; protected set; } 43 | /// 44 | /// Initialize関数で設定したウィンドウ高さ 45 | /// 46 | public int WindowHeight { get; protected set; } 47 | 48 | public abstract void OnUpdatePre(); 49 | public abstract void GetWindowSize(out int width, out int height); 50 | public abstract CubismRenderer CreateRenderer(CubismModel model); 51 | public abstract TextureInfo CreateTexture(LAppModel model, int index, int width, int height, IntPtr data); 52 | 53 | public void InitApp() 54 | { 55 | TextureManager = new LAppTextureManager(this); 56 | 57 | // ウィンドウサイズ記憶 58 | GetWindowSize(out int width, out int height); 59 | WindowWidth = width; 60 | WindowHeight = height; 61 | //AppViewの初期化 62 | View.Initialize(); 63 | 64 | //load model 65 | Live2dManager = new LAppLive2DManager(this); 66 | 67 | LAppPal.DeltaTime = 0; 68 | } 69 | 70 | /// 71 | /// 解放する。 72 | /// 73 | public void Dispose() 74 | { 75 | Live2dManager.Dispose(); 76 | } 77 | 78 | public void Resize() 79 | { 80 | GetWindowSize(out int width, out int height); 81 | if ((WindowWidth != width || WindowHeight != height) && width > 0 && height > 0) 82 | { 83 | // サイズを保存しておく 84 | WindowWidth = width; 85 | WindowHeight = height; 86 | //AppViewの初期化 87 | View.Initialize(); 88 | } 89 | } 90 | 91 | /// 92 | /// Need skip 93 | /// 94 | /// 95 | public abstract bool RunPre(); 96 | public abstract void RunPost(); 97 | 98 | /// 99 | /// 実行処理。 100 | /// 101 | public void Run(float tick) 102 | { 103 | Resize(); 104 | 105 | // 時間更新 106 | LAppPal.DeltaTime = tick; 107 | 108 | if (RunPre()) 109 | { 110 | return; 111 | } 112 | 113 | //描画更新 114 | View.Render(); 115 | 116 | RunPost(); 117 | } 118 | 119 | /// 120 | /// OpenGL用 glfwSetMouseButtonCallback用関数。 121 | /// 122 | /// ボタン種類 123 | /// 実行結果 124 | public void OnMouseCallBack(bool press) 125 | { 126 | if (press) 127 | { 128 | _captured = true; 129 | View.OnTouchesBegan(_mouseX, _mouseY); 130 | } 131 | else 132 | { 133 | if (_captured) 134 | { 135 | _captured = false; 136 | View.OnTouchesEnded(_mouseX, _mouseY); 137 | } 138 | } 139 | } 140 | 141 | /// 142 | /// OpenGL用 glfwSetCursorPosCallback用関数。 143 | /// 144 | /// x座標 145 | /// x座標 146 | public void OnMouseCallBack(float x, float y) 147 | { 148 | if (!_captured) 149 | { 150 | return; 151 | } 152 | 153 | _mouseX = x; 154 | _mouseY = y; 155 | 156 | View.OnTouchesMoved(_mouseX, _mouseY); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.App/LAppLive2DManager.cs: -------------------------------------------------------------------------------- 1 | using Live2DCSharpSDK.Framework; 2 | using Live2DCSharpSDK.Framework.Math; 3 | using Live2DCSharpSDK.Framework.Model; 4 | using Live2DCSharpSDK.Framework.Motion; 5 | 6 | namespace Live2DCSharpSDK.App; 7 | 8 | /// 9 | /// サンプルアプリケーションにおいてCubismModelを管理するクラス 10 | /// モデル生成と破棄、タップイベントの処理、モデル切り替えを行う。 11 | /// 12 | /// 13 | /// コンストラクタ 14 | /// 15 | public class LAppLive2DManager(LAppDelegate lapp) : IDisposable 16 | { 17 | public event Action? MotionFinished; 18 | 19 | /// 20 | /// モデル描画に用いるView行列 21 | /// 22 | public CubismMatrix44 ViewMatrix { get; } = new(); 23 | 24 | /// 25 | /// モデルインスタンスのコンテナ 26 | /// 27 | private readonly List _models = []; 28 | 29 | /// 30 | /// 現在のシーンで保持しているモデルを返す 31 | /// 32 | /// モデルリストのインデックス値 33 | /// モデルのインスタンスを返す。インデックス値が範囲外の場合はNULLを返す。 34 | public LAppModel GetModel(int no) 35 | { 36 | return _models[no]; 37 | } 38 | 39 | /// 40 | /// 現在のシーンで保持しているすべてのモデルを解放する 41 | /// 42 | public void ReleaseAllModel() 43 | { 44 | for (int i = 0; i < _models.Count; i++) 45 | { 46 | _models[i].Dispose(); 47 | } 48 | 49 | _models.Clear(); 50 | } 51 | 52 | /// 53 | /// 画面をドラッグしたときの処理 54 | /// 55 | /// 画面のX座標 56 | /// 画面のY座標 57 | public void OnDrag(float x, float y) 58 | { 59 | for (int i = 0; i < _models.Count; i++) 60 | { 61 | LAppModel model = GetModel(i); 62 | 63 | model.SetDragging(x, y); 64 | } 65 | } 66 | 67 | /// 68 | /// 画面をタップしたときの処理 69 | /// 70 | /// 画面のX座標 71 | /// 画面のY座標 72 | public void OnTap(float x, float y) 73 | { 74 | CubismLog.Debug($"[Live2D App]tap point: x:{x:0.00} y:{y:0.00}"); 75 | 76 | for (int i = 0; i < _models.Count; i++) 77 | { 78 | if (_models[i].HitTest(LAppDefine.HitAreaNameHead, x, y)) 79 | { 80 | CubismLog.Debug($"[Live2D App]hit area: [{LAppDefine.HitAreaNameHead}]"); 81 | _models[i].SetRandomExpression(); 82 | } 83 | else if (_models[i].HitTest(LAppDefine.HitAreaNameBody, x, y)) 84 | { 85 | CubismLog.Debug($"[Live2D App]hit area: [{LAppDefine.HitAreaNameBody}]"); 86 | _models[i].StartRandomMotion(LAppDefine.MotionGroupTapBody, MotionPriority.PriorityNormal, OnFinishedMotion); 87 | } 88 | } 89 | } 90 | 91 | private void OnFinishedMotion(CubismModel model, ACubismMotion self) 92 | { 93 | CubismLog.Info($"[Live2D App]Motion Finished: {self}"); 94 | MotionFinished?.Invoke(model, self); 95 | } 96 | 97 | private readonly CubismMatrix44 _projection = new(); 98 | 99 | /// 100 | /// 画面を更新するときの処理 101 | /// モデルの更新処理および描画処理を行う 102 | /// 103 | public void OnUpdate() 104 | { 105 | lapp.OnUpdatePre(); 106 | 107 | int width = lapp.WindowWidth; 108 | int height = lapp.WindowHeight; 109 | foreach (var model in _models) 110 | { 111 | _projection.LoadIdentity(); 112 | 113 | if (model.Model.GetCanvasWidth() > 1.0f && width < height) 114 | { 115 | // 横に長いモデルを縦長ウィンドウに表示する際モデルの横サイズでscaleを算出する 116 | model.ModelMatrix.SetWidth(2.0f); 117 | _projection.Scale(1.0f, (float)width / height); 118 | } 119 | else 120 | { 121 | _projection.Scale((float)height / width, 1.0f); 122 | } 123 | 124 | // 必要があればここで乗算 125 | if (ViewMatrix != null) 126 | { 127 | _projection.MultiplyByMatrix(ViewMatrix); 128 | } 129 | 130 | model.Update(); 131 | model.Draw(_projection); // 参照渡しなのでprojectionは変質する 132 | } 133 | } 134 | 135 | public LAppModel LoadModel(string dir, string name) 136 | { 137 | CubismLog.Debug($"[Live2D App]model load: {name}"); 138 | 139 | // ModelDir[]に保持したディレクトリ名から 140 | // model3.jsonのパスを決定する. 141 | // ディレクトリ名とmodel3.jsonの名前を一致させておくこと. 142 | if (!dir.EndsWith('\\') && !dir.EndsWith('/')) 143 | { 144 | dir = Path.GetFullPath(dir + '/'); 145 | } 146 | var modelJsonName = Path.GetFullPath($"{dir}{name}"); 147 | if (!File.Exists(modelJsonName)) 148 | { 149 | modelJsonName = Path.GetFullPath($"{dir}{name}.model3.json"); 150 | } 151 | if (!File.Exists(modelJsonName)) 152 | { 153 | dir = Path.GetFullPath(dir + name + '/'); 154 | modelJsonName = Path.GetFullPath($"{dir}{name}.model3.json"); 155 | } 156 | if (!File.Exists(modelJsonName)) 157 | { 158 | throw new Exception($"[Live2D]File not found: {modelJsonName}"); 159 | } 160 | 161 | var model = new LAppModel(lapp, dir, modelJsonName); 162 | _models.Add(model); 163 | 164 | return model; 165 | } 166 | 167 | public void RemoveModel(int index) 168 | { 169 | if (_models.Count > index) 170 | { 171 | var model = _models[index]; 172 | _models.RemoveAt(index); 173 | model.Dispose(); 174 | } 175 | } 176 | 177 | public void RemoveModel(LAppModel model) 178 | { 179 | _models.Remove(model); 180 | model.Dispose(); 181 | } 182 | 183 | /// 184 | /// モデル個数を得る 185 | /// 186 | /// 所持モデル個数 187 | public int GetModelNum() 188 | { 189 | return _models.Count; 190 | } 191 | 192 | public void Dispose() 193 | { 194 | ReleaseAllModel(); 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.App/LAppPal.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.App; 2 | 3 | /// 4 | /// プラットフォーム依存機能を抽象化する Cubism Platform Abstraction Layer. 5 | /// ファイル読み込みや時刻取得等のプラットフォームに依存する関数をまとめる 6 | /// 7 | public static class LAppPal 8 | { 9 | /// 10 | /// デルタ時間(前回フレームとの差分)を取得する 11 | /// 12 | /// デルタ時間[ms] 13 | public static float DeltaTime { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.App/LAppTextureManager.cs: -------------------------------------------------------------------------------- 1 | using SkiaSharp; 2 | 3 | namespace Live2DCSharpSDK.App; 4 | 5 | /// 6 | /// 画像読み込み、管理を行うクラス。 7 | /// 8 | public class LAppTextureManager(LAppDelegate lapp) 9 | { 10 | private readonly List _textures = []; 11 | 12 | /// 13 | /// 画像読み込み 14 | /// 15 | /// 読み込む画像ファイルパス名 16 | /// 画像情報。読み込み失敗時はNULLを返す 17 | public unsafe TextureInfo CreateTextureFromPngFile(LAppModel model, int index, string fileName) 18 | { 19 | //search loaded texture already. 20 | var item = _textures.FirstOrDefault(a => a.FileName == fileName); 21 | if (item != null) 22 | { 23 | return item; 24 | } 25 | var info1 = SKBitmap.DecodeBounds(fileName); 26 | info1.ColorType = SKColorType.Rgba8888; 27 | using var image = SKBitmap.Decode(fileName, info1); 28 | 29 | // OpenGL用のテクスチャを生成する 30 | var info = lapp.CreateTexture(model, index, image.Width, image.Height, image.GetPixels()); 31 | info.FileName = fileName; 32 | info.Width = image.Width; 33 | info.Index = index; 34 | info.Height = image.Height; 35 | 36 | _textures.Add(info); 37 | 38 | return info; 39 | } 40 | 41 | /// 42 | /// 指定したテクスチャIDの画像を解放する 43 | /// 44 | /// 解放するテクスチャID 45 | public void ReleaseTexture(TextureInfo info) 46 | { 47 | info.Dispose(); 48 | _textures.Remove(info); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.App/LAppView.cs: -------------------------------------------------------------------------------- 1 | using Live2DCSharpSDK.Framework; 2 | using Live2DCSharpSDK.Framework.Math; 3 | 4 | namespace Live2DCSharpSDK.App; 5 | 6 | /// 7 | /// 描画クラス 8 | /// 9 | /// 10 | /// コンストラクタ 11 | /// 12 | public abstract class LAppView(LAppDelegate lapp) 13 | { 14 | /// 15 | /// タッチマネージャー 16 | /// 17 | private readonly TouchManager _touchManager = new(); 18 | /// 19 | /// デバイスからスクリーンへの行列 20 | /// 21 | private readonly CubismMatrix44 _deviceToScreen = new(); 22 | /// 23 | /// viewMatrix 24 | /// 25 | private readonly CubismViewMatrix _viewMatrix = new(); 26 | 27 | public abstract void RenderPre(); 28 | public abstract void RenderPost(); 29 | 30 | /// 31 | /// 初期化する。 32 | /// 33 | public void Initialize() 34 | { 35 | int width = lapp.WindowWidth; 36 | int height = lapp.WindowHeight; 37 | if (width == 0 || height == 0) 38 | { 39 | return; 40 | } 41 | 42 | // 縦サイズを基準とする 43 | float ratio = (float)width / height; 44 | float left = -ratio; 45 | float right = ratio; 46 | float bottom = LAppDefine.ViewLogicalLeft; 47 | float top = LAppDefine.ViewLogicalRight; 48 | 49 | _viewMatrix.SetScreenRect(left, right, bottom, top); // デバイスに対応する画面の範囲。 Xの左端, Xの右端, Yの下端, Yの上端 50 | _viewMatrix.Scale(LAppDefine.ViewScale, LAppDefine.ViewScale); 51 | 52 | _deviceToScreen.LoadIdentity(); // サイズが変わった際などリセット必須 53 | if (width > height) 54 | { 55 | float screenW = MathF.Abs(right - left); 56 | _deviceToScreen.ScaleRelative(screenW / width, -screenW / width); 57 | } 58 | else 59 | { 60 | float screenH = MathF.Abs(top - bottom); 61 | _deviceToScreen.ScaleRelative(screenH / height, -screenH / height); 62 | } 63 | _deviceToScreen.TranslateRelative(-width * 0.5f, -height * 0.5f); 64 | 65 | // 表示範囲の設定 66 | _viewMatrix.MaxScale = LAppDefine.ViewMaxScale; // 限界拡大率 67 | _viewMatrix.MinScale = LAppDefine.ViewMinScale; // 限界縮小率 68 | 69 | // 表示できる最大範囲 70 | _viewMatrix.SetMaxScreenRect( 71 | LAppDefine.ViewLogicalMaxLeft, 72 | LAppDefine.ViewLogicalMaxRight, 73 | LAppDefine.ViewLogicalMaxBottom, 74 | LAppDefine.ViewLogicalMaxTop 75 | ); 76 | } 77 | 78 | /// 79 | /// 描画する。 80 | /// 81 | internal void Render() 82 | { 83 | RenderPre(); 84 | 85 | var manager = lapp.Live2dManager; 86 | manager.ViewMatrix.SetMatrix(_viewMatrix); 87 | 88 | // Cubism更新・描画 89 | manager.OnUpdate(); 90 | 91 | RenderPost(); 92 | } 93 | 94 | /// 95 | /// タッチされたときに呼ばれる。 96 | /// 97 | /// スクリーンX座標 98 | /// スクリーンY座標 99 | public void OnTouchesBegan(float pointX, float pointY) 100 | { 101 | _touchManager.TouchesBegan(pointX, pointY); 102 | CubismLog.Debug($"[Live2D App]touchesBegan x:{pointX:#.##} y:{pointY:#.##}"); 103 | } 104 | 105 | /// 106 | /// タッチしているときにポインタが動いたら呼ばれる。 107 | /// 108 | /// スクリーンX座標 109 | /// スクリーンY座標 110 | public void OnTouchesMoved(float pointX, float pointY) 111 | { 112 | float viewX = TransformViewX(_touchManager.GetX()); 113 | float viewY = TransformViewY(_touchManager.GetY()); 114 | 115 | _touchManager.TouchesMoved(pointX, pointY); 116 | 117 | lapp.Live2dManager.OnDrag(viewX, viewY); 118 | } 119 | 120 | /// 121 | /// タッチが終了したら呼ばれる。 122 | /// 123 | /// スクリーンX座標 124 | /// スクリーンY座標 125 | public void OnTouchesEnded(float _, float __) 126 | { 127 | // タッチ終了 128 | var live2DManager = lapp.Live2dManager; 129 | live2DManager.OnDrag(0.0f, 0.0f); 130 | // シングルタップ 131 | float x = _deviceToScreen.TransformX(_touchManager.GetX()); // 論理座標変換した座標を取得。 132 | float y = _deviceToScreen.TransformY(_touchManager.GetY()); // 論理座標変換した座標を取得。 133 | CubismLog.Debug($"[Live2D App]touchesEnded x:{x:#.##} y:{y:#.##}"); 134 | live2DManager.OnTap(x, y); 135 | } 136 | 137 | /// 138 | /// X座標をView座標に変換する。 139 | /// 140 | /// デバイスX座標 141 | public float TransformViewX(float deviceX) 142 | { 143 | float screenX = _deviceToScreen.TransformX(deviceX); // 論理座標変換した座標を取得。 144 | return _viewMatrix.InvertTransformX(screenX); // 拡大、縮小、移動後の値。 145 | } 146 | 147 | /// 148 | /// Y座標をView座標に変換する。 149 | /// 150 | /// デバイスY座標 151 | public float TransformViewY(float deviceY) 152 | { 153 | float screenY = _deviceToScreen.TransformY(deviceY); // 論理座標変換した座標を取得。 154 | return _viewMatrix.InvertTransformY(screenY); // 拡大、縮小、移動後の値。 155 | } 156 | 157 | /// 158 | /// X座標をScreen座標に変換する。 159 | /// 160 | /// デバイスX座標 161 | public float TransformScreenX(float deviceX) 162 | { 163 | return _deviceToScreen.TransformX(deviceX); 164 | } 165 | 166 | /// 167 | /// Y座標をScreen座標に変換する。 168 | /// 169 | /// デバイスY座標 170 | public float TransformScreenY(float deviceY) 171 | { 172 | return _deviceToScreen.TransformY(deviceY); 173 | } 174 | 175 | /// 176 | /// 別レンダリングターゲットにモデルを描画するサンプルで 177 | /// 描画時のαを決定する 178 | /// 179 | public static float GetSpriteAlpha(int assign) 180 | { 181 | // assignの数値に応じて適当に決定 182 | float alpha = 0.25f + assign * 0.5f; // サンプルとしてαに適当な差をつける 183 | if (alpha > 1.0f) 184 | { 185 | alpha = 1.0f; 186 | } 187 | if (alpha < 0.1f) 188 | { 189 | alpha = 0.1f; 190 | } 191 | 192 | return alpha; 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.App/Live2DCSharpSDK.App.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | true 8 | 9 | 10 | 11 | portable 12 | 13 | 14 | embedded 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.App/TextureInfo.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.App; 2 | 3 | /// 4 | /// 画像情報構造体 5 | /// 6 | public abstract class TextureInfo 7 | { 8 | public int Index; 9 | /// 10 | /// テクスチャID 11 | /// 12 | public int Id; 13 | /// 14 | /// 横幅 15 | /// 16 | public int Width; 17 | /// 18 | /// 高さ 19 | /// 20 | public int Height; 21 | /// 22 | /// ファイル名 23 | /// 24 | public string FileName; 25 | 26 | /// 27 | /// 画像の解放 28 | /// 29 | public abstract void Dispose(); 30 | }; -------------------------------------------------------------------------------- /Live2DCSharpSDK.App/TouchManager.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.App; 2 | 3 | public class TouchManager 4 | { 5 | /// 6 | /// タッチを開始した時のxの値 7 | /// 8 | private float _startY; 9 | /// 10 | /// タッチを開始した時のyの値 11 | /// 12 | private float _startX; 13 | /// 14 | /// シングルタッチ時のxの値 15 | /// 16 | private float _lastX; 17 | /// 18 | /// シングルタッチ時のyの値 19 | /// 20 | private float _lastY; 21 | /// 22 | /// ダブルタッチ時の一つ目のxの値 23 | /// 24 | private float _lastX1; 25 | /// 26 | /// ダブルタッチ時の一つ目のyの値 27 | /// 28 | private float _lastY1; 29 | /// 30 | /// ダブルタッチ時の二つ目のxの値 31 | /// 32 | private float _lastX2; 33 | /// 34 | /// ダブルタッチ時の二つ目のyの値 35 | /// 36 | private float _lastY2; 37 | /// 38 | /// 2本以上でタッチしたときの指の距離 39 | /// 40 | private float _lastTouchDistance; 41 | /// 42 | /// 前回の値から今回の値へのxの移動距離。 43 | /// 44 | private float _deltaX; 45 | /// 46 | /// 前回の値から今回の値へのyの移動距離。 47 | /// 48 | private float _deltaY; 49 | /// 50 | /// このフレームで掛け合わせる拡大率。拡大操作中以外は1。 51 | /// 52 | private float _scale; 53 | /// 54 | /// シングルタッチ時はtrue 55 | /// 56 | private bool _touchSingle; 57 | /// 58 | /// フリップが有効かどうか 59 | /// 60 | private bool _flipAvailable; 61 | 62 | public TouchManager() 63 | { 64 | _scale = 1.0f; 65 | } 66 | 67 | public float GetCenterX() { return _lastX; } 68 | public float GetCenterY() { return _lastY; } 69 | public float GetDeltaX() { return _deltaX; } 70 | public float GetDeltaY() { return _deltaY; } 71 | public float GetStartX() { return _startX; } 72 | public float GetStartY() { return _startY; } 73 | public float GetScale() { return _scale; } 74 | public float GetX() { return _lastX; } 75 | public float GetY() { return _lastY; } 76 | public float GetX1() { return _lastX1; } 77 | public float GetY1() { return _lastY1; } 78 | public float GetX2() { return _lastX2; } 79 | public float GetY2() { return _lastY2; } 80 | public bool IsSingleTouch() { return _touchSingle; } 81 | public bool IsFlickAvailable() { return _flipAvailable; } 82 | public void DisableFlick() { _flipAvailable = false; } 83 | 84 | /// 85 | /// タッチ開始時イベント 86 | /// 87 | /// タッチした画面のyの値 88 | /// タッチした画面のxの値 89 | public void TouchesBegan(float deviceX, float deviceY) 90 | { 91 | _lastX = deviceX; 92 | _lastY = deviceY; 93 | _startX = deviceX; 94 | _startY = deviceY; 95 | _lastTouchDistance = -1.0f; 96 | _flipAvailable = true; 97 | _touchSingle = true; 98 | } 99 | 100 | /// 101 | /// ドラッグ時のイベント 102 | /// 103 | /// タッチした画面のxの値 104 | /// タッチした画面のyの値 105 | public void TouchesMoved(float deviceX, float deviceY) 106 | { 107 | _lastX = deviceX; 108 | _lastY = deviceY; 109 | _lastTouchDistance = -1.0f; 110 | _touchSingle = true; 111 | } 112 | 113 | /// 114 | /// ドラッグ時のイベント 115 | /// 116 | /// 1つめのタッチした画面のxの値 117 | /// 1つめのタッチした画面のyの値 118 | /// 2つめのタッチした画面のxの値 119 | /// 2つめのタッチした画面のyの値 120 | public void TouchesMoved(float deviceX1, float deviceY1, float deviceX2, float deviceY2) 121 | { 122 | float distance = CalculateDistance(deviceX1, deviceY1, deviceX2, deviceY2); 123 | float centerX = (deviceX1 + deviceX2) * 0.5f; 124 | float centerY = (deviceY1 + deviceY2) * 0.5f; 125 | 126 | if (_lastTouchDistance > 0.0f) 127 | { 128 | _scale = MathF.Pow(distance / _lastTouchDistance, 0.75f); 129 | _deltaX = CalculateMovingAmount(deviceX1 - _lastX1, deviceX2 - _lastX2); 130 | _deltaY = CalculateMovingAmount(deviceY1 - _lastY1, deviceY2 - _lastY2); 131 | } 132 | else 133 | { 134 | _scale = 1.0f; 135 | _deltaX = 0.0f; 136 | _deltaY = 0.0f; 137 | } 138 | 139 | _lastX = centerX; 140 | _lastY = centerY; 141 | _lastX1 = deviceX1; 142 | _lastY1 = deviceY1; 143 | _lastX2 = deviceX2; 144 | _lastY2 = deviceY2; 145 | _lastTouchDistance = distance; 146 | _touchSingle = false; 147 | } 148 | 149 | /// 150 | /// フリックの距離測定 151 | /// 152 | /// フリック距離 153 | public float GetFlickDistance() 154 | { 155 | return CalculateDistance(_startX, _startY, _lastX, _lastY); 156 | } 157 | 158 | /// 159 | /// 点1から点2への距離を求める 160 | /// 161 | /// 1つめのタッチした画面のxの値 162 | /// 1つめのタッチした画面のyの値 163 | /// 2つめのタッチした画面のxの値 164 | /// 2つめのタッチした画面のyの値 165 | /// 2点の距離 166 | public static float CalculateDistance(float x1, float y1, float x2, float y2) 167 | { 168 | return MathF.Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); 169 | } 170 | 171 | /// 172 | /// 二つの値から、移動量を求める。 173 | /// 違う方向の場合は移動量0。同じ方向の場合は、絶対値が小さい方の値を参照する 174 | /// 175 | /// 1つめの移動量 176 | /// 2つめの移動量 177 | /// 小さい方の移動量 178 | public static float CalculateMovingAmount(float v1, float v2) 179 | { 180 | if ((v1 > 0.0f) != (v2 > 0.0f)) 181 | { 182 | return 0.0f; 183 | } 184 | 185 | float sign = v1 > 0.0f ? 1.0f : -1.0f; 186 | float absoluteValue1 = MathF.Abs(v1); 187 | float absoluteValue2 = MathF.Abs(v2); 188 | return sign * ((absoluteValue1 < absoluteValue2) ? absoluteValue1 : absoluteValue2); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/CubismCdiJson.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework; 2 | 3 | public class CubismCdiJson 4 | { 5 | public const string Version = "Version"; 6 | public const string Parameters = "Parameters"; 7 | public const string ParameterGroups = "ParameterGroups"; 8 | public const string Parts = "Parts"; 9 | public const string CombinedParameters = "CombinedParameters"; 10 | public const string Id = "Id"; 11 | public const string GroupId = "GroupId"; 12 | public const string Name = "Name"; 13 | } 14 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/CubismDefaultParameterId.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework; 2 | 3 | public static class CubismDefaultParameterId 4 | { 5 | // パーツID 6 | public const string HitAreaPrefix = "HitArea"; 7 | public const string HitAreaHead = "Head"; 8 | public const string HitAreaBody = "Body"; 9 | public const string PartsIdCore = "Parts01Core"; 10 | public const string PartsArmPrefix = "Parts01Arm_"; 11 | public const string PartsArmLPrefix = "Parts01ArmL_"; 12 | public const string PartsArmRPrefix = "Parts01ArmR_"; 13 | 14 | // パラメータID 15 | public const string ParamAngleX = "ParamAngleX"; 16 | public const string ParamAngleY = "ParamAngleY"; 17 | public const string ParamAngleZ = "ParamAngleZ"; 18 | public const string ParamEyeLOpen = "ParamEyeLOpen"; 19 | public const string ParamEyeLSmile = "ParamEyeLSmile"; 20 | public const string ParamEyeROpen = "ParamEyeROpen"; 21 | public const string ParamEyeRSmile = "ParamEyeRSmile"; 22 | public const string ParamEyeBallX = "ParamEyeBallX"; 23 | public const string ParamEyeBallY = "ParamEyeBallY"; 24 | public const string ParamEyeBallForm = "ParamEyeBallForm"; 25 | public const string ParamBrowLY = "ParamBrowLY"; 26 | public const string ParamBrowRY = "ParamBrowRY"; 27 | public const string ParamBrowLX = "ParamBrowLX"; 28 | public const string ParamBrowRX = "ParamBrowRX"; 29 | public const string ParamBrowLAngle = "ParamBrowLAngle"; 30 | public const string ParamBrowRAngle = "ParamBrowRAngle"; 31 | public const string ParamBrowLForm = "ParamBrowLForm"; 32 | public const string ParamBrowRForm = "ParamBrowRForm"; 33 | public const string ParamMouthForm = "ParamMouthForm"; 34 | public const string ParamMouthOpenY = "ParamMouthOpenY"; 35 | public const string ParamCheek = "ParamCheek"; 36 | public const string ParamBodyAngleX = "ParamBodyAngleX"; 37 | public const string ParamBodyAngleY = "ParamBodyAngleY"; 38 | public const string ParamBodyAngleZ = "ParamBodyAngleZ"; 39 | public const string ParamBreath = "ParamBreath"; 40 | public const string ParamArmLA = "ParamArmLA"; 41 | public const string ParamArmRA = "ParamArmRA"; 42 | public const string ParamArmLB = "ParamArmLB"; 43 | public const string ParamArmRB = "ParamArmRB"; 44 | public const string ParamHandL = "ParamHandL"; 45 | public const string ParamHandR = "ParamHandR"; 46 | public const string ParamHairFront = "ParamHairFront"; 47 | public const string ParamHairSide = "ParamHairSide"; 48 | public const string ParamHairBack = "ParamHairBack"; 49 | public const string ParamHairFluffy = "ParamHairFluffy"; 50 | public const string ParamShoulderY = "ParamShoulderY"; 51 | public const string ParamBustX = "ParamBustX"; 52 | public const string ParamBustY = "ParamBustY"; 53 | public const string ParamBaseX = "ParamBaseX"; 54 | public const string ParamBaseY = "ParamBaseY"; 55 | public const string ParamNONE = "NONE"; 56 | } 57 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/CubismFramework.cs: -------------------------------------------------------------------------------- 1 | using Live2DCSharpSDK.Framework.Core; 2 | using Live2DCSharpSDK.Framework.Id; 3 | 4 | namespace Live2DCSharpSDK.Framework; 5 | 6 | /// 7 | /// Live2D Cubism Original Workflow SDKのエントリポイント 8 | /// 利用開始時はCubismFramework.Initialize()を呼び、CubismFramework.Dispose()で終了する。 9 | /// 10 | public static class CubismFramework 11 | { 12 | /// 13 | /// メッシュ頂点のオフセット値 14 | /// 15 | public const int VertexOffset = 0; 16 | /// 17 | /// メッシュ頂点のステップ値 18 | /// 19 | public const int VertexStep = 2; 20 | 21 | /// 22 | /// IDマネージャのインスタンスを取得する。 23 | /// 24 | public static CubismIdManager CubismIdManager { get; private set; } = new(); 25 | 26 | public static bool IsStarted { get; private set; } 27 | 28 | private static ICubismAllocator? s_allocator; 29 | private static CubismOption? s_option; 30 | 31 | /// 32 | /// Cubism FrameworkのAPIを使用可能にする。 33 | /// APIを実行する前に必ずこの関数を実行すること。 34 | /// 引数に必ずメモリアロケータを渡してください。 35 | /// 一度準備が完了して以降は、再び実行しても内部処理がスキップされます。 36 | /// 37 | /// ICubismAllocatorクラスのインスタンス 38 | /// Optionクラスのインスタンス 39 | /// 準備処理が完了したらtrueが返ります。 40 | public static bool StartUp(ICubismAllocator allocator, CubismOption option) 41 | { 42 | if (IsStarted) 43 | { 44 | CubismLog.Info("[Live2D SDK]CubismFramework.StartUp() is already done."); 45 | return IsStarted; 46 | } 47 | 48 | s_option = option; 49 | if (s_option != null) 50 | { 51 | CubismCore.SetLogFunction(s_option.LogFunction); 52 | } 53 | 54 | if (allocator == null) 55 | { 56 | CubismLog.Warning("[Live2D SDK]CubismFramework.StartUp() failed, need allocator instance."); 57 | IsStarted = false; 58 | } 59 | else 60 | { 61 | s_allocator = allocator; 62 | IsStarted = true; 63 | } 64 | 65 | //Live2D Cubism Coreバージョン情報を表示 66 | if (IsStarted) 67 | { 68 | var version = CubismCore.GetVersion(); 69 | 70 | uint major = (version & 0xFF000000) >> 24; 71 | uint minor = (version & 0x00FF0000) >> 16; 72 | uint patch = version & 0x0000FFFF; 73 | uint versionNumber = version; 74 | 75 | CubismLog.Info($"[Live2D SDK]Cubism Core version: {major:#0}.{minor:0}.{patch:0000} ({versionNumber})"); 76 | } 77 | 78 | CubismLog.Info("[Live2D SDK]CubismFramework.StartUp() is complete."); 79 | 80 | return IsStarted; 81 | } 82 | 83 | /// 84 | /// StartUp()で初期化したCubismFrameworkの各パラメータをクリアします。 85 | /// Dispose()したCubismFrameworkを再利用する際に利用してください。 86 | /// 87 | public static void CleanUp() 88 | { 89 | IsStarted = false; 90 | } 91 | 92 | /// 93 | /// Core APIにバインドしたログ関数を実行する 94 | /// 95 | /// ログメッセージ 96 | public static void CoreLogFunction(string data) 97 | { 98 | CubismCore.GetLogFunction()?.Invoke(data); 99 | } 100 | 101 | /// 102 | /// 現在のログ出力レベル設定の値を返す。 103 | /// 104 | /// 現在のログ出力レベル設定の値 105 | public static LogLevel GetLoggingLevel() 106 | { 107 | if (s_option != null) 108 | return s_option.LoggingLevel; 109 | 110 | return LogLevel.Off; 111 | } 112 | 113 | public static IntPtr Allocate(int size) 114 | => s_allocator!.Allocate(size); 115 | public static IntPtr AllocateAligned(int size, int alignment) 116 | => s_allocator!.AllocateAligned(size, alignment); 117 | public static void Deallocate(IntPtr address) 118 | => s_allocator!.Deallocate(address); 119 | public static void DeallocateAligned(IntPtr address) 120 | => s_allocator!.DeallocateAligned(address); 121 | } 122 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/CubismLog.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework; 2 | 3 | public static class CubismLog 4 | { 5 | private static void CubismLogPrintln(LogLevel level, string head, string fmt, params object?[] args) 6 | { 7 | string data = $"[CSM] {head} {string.Format(fmt, args)}"; 8 | if (level < CubismFramework.GetLoggingLevel()) 9 | return; 10 | 11 | CubismFramework.CoreLogFunction(data); 12 | } 13 | 14 | public static void Verbose(string fmt, params object?[] args) 15 | { 16 | CubismLogPrintln(LogLevel.Verbose, "[V]", fmt, args); 17 | } 18 | 19 | public static void Debug(string fmt, params object?[] args) 20 | { 21 | CubismLogPrintln(LogLevel.Debug, "[D]", fmt, args); 22 | } 23 | 24 | public static void Info(string fmt, params object?[] args) 25 | { 26 | CubismLogPrintln(LogLevel.Info, "[I]", fmt, args); 27 | } 28 | 29 | public static void Warning(string fmt, params object?[] args) 30 | { 31 | CubismLogPrintln(LogLevel.Warning, "[W]", fmt, args); 32 | } 33 | 34 | public static void Error(string fmt, params object?[] args) 35 | { 36 | CubismLogPrintln(LogLevel.Error, "[E]", fmt, args); 37 | throw new Exception(string.Format(fmt, args)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/CubismModelSettingJson.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework; 2 | 3 | public static class CubismModelSettingJson 4 | { 5 | // JSON keys 6 | public const string Version = "Version"; 7 | public const string FileReferences = "FileReferences"; 8 | public const string Groups = "Groups"; 9 | public const string Layout = "Layout"; 10 | public const string HitAreas = "HitAreas"; 11 | 12 | public const string Moc = "Moc"; 13 | public const string Textures = "Textures"; 14 | public const string Physics = "Physics"; 15 | public const string DisplayInfo = "DisplayInfo"; 16 | public const string Pose = "Pose"; 17 | public const string Expressions = "Expressions"; 18 | public const string Motions = "Motions"; 19 | 20 | public const string UserData = "UserData"; 21 | public const string Name = "Name"; 22 | public const string FilePath = "File"; 23 | public const string Id = "Id"; 24 | public const string Ids = "Ids"; 25 | public const string Target = "Target"; 26 | 27 | // Motions 28 | public const string Idle = "Idle"; 29 | public const string TapBody = "TapBody"; 30 | public const string PinchIn = "PinchIn"; 31 | public const string PinchOut = "PinchOut"; 32 | public const string Shake = "Shake"; 33 | public const string FlickHead = "FlickHead"; 34 | public const string Parameter = "Parameter"; 35 | 36 | public const string SoundPath = "Sound"; 37 | public const string FadeInTime = "FadeInTime"; 38 | public const string FadeOutTime = "FadeOutTime"; 39 | 40 | // Layout 41 | public const string CenterX = "CenterX"; 42 | public const string CenterY = "CenterY"; 43 | public const string X = "X"; 44 | public const string Y = "Y"; 45 | public const string Width = "Width"; 46 | public const string Height = "Height"; 47 | 48 | public const string LipSync = "LipSync"; 49 | public const string EyeBlink = "EyeBlink"; 50 | 51 | public const string InitParameter = "init_param"; 52 | public const string InitPartsVisible = "init_parts_visible"; 53 | public const string Val = "val"; 54 | 55 | public static bool GetLayoutMap(this ModelSettingObj obj, Dictionary outLayoutMap) 56 | { 57 | var node = obj.Layout; 58 | if (node == null) 59 | return false; 60 | 61 | var ret = false; 62 | foreach (var item in node) 63 | { 64 | if (outLayoutMap.ContainsKey(item.Key)) 65 | { 66 | outLayoutMap[item.Key] = item.Value; 67 | } 68 | else 69 | { 70 | outLayoutMap.Add(item.Key, item.Value); 71 | } 72 | ret = true; 73 | } 74 | return ret; 75 | } 76 | 77 | public static bool IsExistEyeBlinkParameters(this ModelSettingObj obj) 78 | { 79 | var node = obj.Groups; 80 | if (node == null) 81 | { 82 | return false; 83 | } 84 | 85 | foreach (var item in node) 86 | { 87 | if (item.Name == EyeBlink) 88 | { 89 | return true; 90 | } 91 | } 92 | 93 | return false; 94 | } 95 | 96 | public static bool IsExistLipSyncParameters(this ModelSettingObj obj) 97 | { 98 | var node = obj.Groups; 99 | if (node == null) 100 | { 101 | return false; 102 | } 103 | 104 | foreach (var item in node) 105 | { 106 | if (item.Name == LipSync) 107 | { 108 | return true; 109 | } 110 | } 111 | 112 | return false; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/CubismOption.cs: -------------------------------------------------------------------------------- 1 | using Live2DCSharpSDK.Framework.Core; 2 | 3 | namespace Live2DCSharpSDK.Framework; 4 | 5 | /// 6 | /// ログ出力のレベル 7 | /// 8 | public enum LogLevel 9 | { 10 | /// 11 | /// 詳細ログ 12 | /// 13 | Verbose = 0, 14 | /// 15 | /// デバッグログ 16 | /// 17 | Debug, 18 | /// 19 | /// Infoログ 20 | /// 21 | Info, 22 | /// 23 | /// 警告ログ 24 | /// 25 | Warning, 26 | /// 27 | /// エラーログ 28 | /// 29 | Error, 30 | /// 31 | /// ログ出力無効 32 | /// 33 | Off 34 | }; 35 | 36 | /// 37 | /// CubismFrameworkに設定するオプション要素を定義するクラス 38 | /// 39 | public class CubismOption 40 | { 41 | /// 42 | /// ログ出力の関数ポイ 43 | /// 44 | public required LogFunction LogFunction; 45 | /// 46 | /// ログ出力レベル設定 47 | /// 48 | public LogLevel LoggingLevel; 49 | } 50 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Effect/BreathParameterData.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Effect; 2 | 3 | /// 4 | /// 呼吸のパラメータ情報。 5 | /// 6 | public record BreathParameterData 7 | { 8 | /// 9 | /// 呼吸をひもづけるパラメータIDs 10 | /// 11 | public required string ParameterId { get; set; } 12 | /// 13 | /// 呼吸を正弦波としたときの、波のオフセット 14 | /// 15 | public float Offset { get; set; } 16 | /// 17 | /// 呼吸を正弦波としたときの、波の高さ 18 | /// 19 | public float Peak { get; set; } 20 | /// 21 | /// 呼吸を正弦波としたときの、波の周期 22 | /// 23 | public float Cycle { get; set; } 24 | /// 25 | /// パラメータへの重み 26 | /// 27 | public float Weight { get; set; } 28 | } -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Effect/CubismBreath.cs: -------------------------------------------------------------------------------- 1 | using Live2DCSharpSDK.Framework.Model; 2 | 3 | namespace Live2DCSharpSDK.Framework.Effect; 4 | 5 | /// 6 | /// 呼吸機能を提供する。 7 | /// 8 | public class CubismBreath 9 | { 10 | /// 11 | /// Handles the breathing effect 12 | /// 13 | public required List Parameters { get; init; } 14 | /// 15 | /// 積算時間[秒] 16 | /// 17 | private float _currentTime; 18 | 19 | /// 20 | /// モデルのパラメータを更新する。 21 | /// 22 | /// 対象のモデル 23 | /// デルタ時間[秒] 24 | public void UpdateParameters(CubismModel model, float deltaTimeSeconds) 25 | { 26 | _currentTime += deltaTimeSeconds; 27 | 28 | float t = _currentTime * 2.0f * 3.14159f; 29 | 30 | foreach (var item in Parameters) 31 | { 32 | model.AddParameterValue(item.ParameterId, item.Offset + 33 | (item.Peak * MathF.Sin(t / item.Cycle)), item.Weight); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Effect/CubismEyeBlink.cs: -------------------------------------------------------------------------------- 1 | //IDで指定された目のパラメータが、0のときに閉じるなら true 、1の時に閉じるなら false 。 2 | //#define CloseIfZero 3 | 4 | using Live2DCSharpSDK.Framework.Model; 5 | 6 | namespace Live2DCSharpSDK.Framework.Effect; 7 | 8 | /// 9 | /// 自動まばたき機能を提供する。 10 | /// 11 | public class CubismEyeBlink 12 | { 13 | /// 14 | /// 操作対象のパラメータのIDのリスト 15 | /// 16 | public readonly List ParameterIds = []; 17 | /// 18 | /// 現在の状態 19 | /// 20 | private EyeState _blinkingState; 21 | /// 22 | /// 次のまばたきの時刻[秒] 23 | /// 24 | private float _nextBlinkingTime; 25 | /// 26 | /// 現在の状態が開始した時刻[秒] 27 | /// 28 | private float _stateStartTimeSeconds; 29 | /// 30 | /// まばたきの間隔[秒] 31 | /// 32 | private float _blinkingIntervalSeconds; 33 | /// 34 | /// まぶたを閉じる動作の所要時間[秒] 35 | /// 36 | private float _closingSeconds; 37 | /// 38 | /// まぶたを閉じている動作の所要時間[秒] 39 | /// 40 | private float _closedSeconds; 41 | /// 42 | /// まぶたを開く動作の所要時間[秒] 43 | /// 44 | private float _openingSeconds; 45 | /// 46 | /// デルタ時間の積算値[秒] 47 | /// 48 | private float _userTimeSeconds; 49 | 50 | private readonly Random _random = new(); 51 | 52 | /// 53 | /// インスタンスを作成する。 54 | /// 55 | /// モデルの設定情報 56 | public CubismEyeBlink(ModelSettingObj modelSetting) 57 | { 58 | _blinkingState = EyeState.First; 59 | _blinkingIntervalSeconds = 4.0f; 60 | _closingSeconds = 0.1f; 61 | _closedSeconds = 0.05f; 62 | _openingSeconds = 0.15f; 63 | 64 | foreach (var item in modelSetting.Groups) 65 | { 66 | if (item.Name == CubismModelSettingJson.EyeBlink) 67 | { 68 | foreach (var item1 in item.Ids) 69 | { 70 | if (item1 == null) 71 | continue; 72 | var item2 = CubismFramework.CubismIdManager.GetId(item1); 73 | ParameterIds.Add(item2); 74 | } 75 | break; 76 | } 77 | } 78 | } 79 | 80 | /// 81 | /// まばたきの間隔を設定する。 82 | /// 83 | /// まばたきの間隔の時間[秒] 84 | public void SetBlinkingInterval(float blinkingInterval) 85 | { 86 | _blinkingIntervalSeconds = blinkingInterval; 87 | } 88 | 89 | /// 90 | /// まばたきのモーションの詳細設定を行う。 91 | /// 92 | /// まぶたを閉じる動作の所要時間[秒] 93 | /// まぶたを閉じている動作の所要時間[秒] 94 | /// まぶたを開く動作の所要時間[秒] 95 | public void SetBlinkingSettings(float closing, float closed, float opening) 96 | { 97 | _closingSeconds = closing; 98 | _closedSeconds = closed; 99 | _openingSeconds = opening; 100 | } 101 | 102 | /// 103 | /// モデルのパラメータを更新する。 104 | /// 105 | /// 対象のモデル 106 | /// デルタ時間[秒] 107 | public void UpdateParameters(CubismModel model, float deltaTimeSeconds) 108 | { 109 | _userTimeSeconds += deltaTimeSeconds; 110 | float parameterValue; 111 | float t; 112 | switch (_blinkingState) 113 | { 114 | case EyeState.Closing: 115 | t = ((_userTimeSeconds - _stateStartTimeSeconds) / _closingSeconds); 116 | 117 | if (t >= 1.0f) 118 | { 119 | t = 1.0f; 120 | _blinkingState = EyeState.Closed; 121 | _stateStartTimeSeconds = _userTimeSeconds; 122 | } 123 | 124 | parameterValue = 1.0f - t; 125 | 126 | break; 127 | case EyeState.Closed: 128 | t = ((_userTimeSeconds - _stateStartTimeSeconds) / _closedSeconds); 129 | 130 | if (t >= 1.0f) 131 | { 132 | _blinkingState = EyeState.Opening; 133 | _stateStartTimeSeconds = _userTimeSeconds; 134 | } 135 | 136 | parameterValue = 0.0f; 137 | 138 | break; 139 | case EyeState.Opening: 140 | t = ((_userTimeSeconds - _stateStartTimeSeconds) / _openingSeconds); 141 | 142 | if (t >= 1.0f) 143 | { 144 | t = 1.0f; 145 | _blinkingState = EyeState.Interval; 146 | _nextBlinkingTime = DetermineNextBlinkingTiming(); 147 | } 148 | 149 | parameterValue = t; 150 | 151 | break; 152 | case EyeState.Interval: 153 | if (_nextBlinkingTime < _userTimeSeconds) 154 | { 155 | _blinkingState = EyeState.Closing; 156 | _stateStartTimeSeconds = _userTimeSeconds; 157 | } 158 | 159 | parameterValue = 1.0f; 160 | 161 | break; 162 | case EyeState.First: 163 | default: 164 | _blinkingState = EyeState.Interval; 165 | _nextBlinkingTime = DetermineNextBlinkingTiming(); 166 | 167 | parameterValue = 1.0f; 168 | 169 | break; 170 | } 171 | #if CloseIfZero 172 | parameterValue = -parameterValue; 173 | #endif 174 | 175 | foreach (var item in ParameterIds) 176 | { 177 | model.SetParameterValue(item, parameterValue); 178 | } 179 | } 180 | 181 | /// 182 | /// 次のまばたきのタイミングを決定する。 183 | /// 184 | /// 次のまばたきを行う時刻[秒] 185 | private float DetermineNextBlinkingTiming() 186 | { 187 | float r = _random.Next() / int.MaxValue; 188 | 189 | return _userTimeSeconds + (r * (2.0f * _blinkingIntervalSeconds - 1.0f)); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Effect/EyeState.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Effect; 2 | 3 | public enum EyeState 4 | { 5 | /// 6 | /// 初期状態 7 | /// 8 | First = 0, 9 | /// 10 | /// まばたきしていない状態 11 | /// 12 | Interval, 13 | /// 14 | /// まぶたが閉じていく途中の状態 15 | /// 16 | Closing, 17 | /// 18 | /// まぶたが閉じている状態 19 | /// 20 | Closed, 21 | /// 22 | /// まぶたが開いていく途中の状態 23 | /// 24 | Opening 25 | }; 26 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Effect/PartData.cs: -------------------------------------------------------------------------------- 1 | using Live2DCSharpSDK.Framework.Model; 2 | 3 | namespace Live2DCSharpSDK.Framework.Effect; 4 | 5 | 6 | /// 7 | /// パーツにまつわる諸々のデータを管理する。 8 | /// 9 | public record PartData 10 | { 11 | /// 12 | /// パーツID 13 | /// 14 | public required string PartId { get; set; } 15 | /// 16 | /// パラメータのインデックス 17 | /// 18 | public int ParameterIndex { get; set; } 19 | /// 20 | /// パーツのインデックス 21 | /// 22 | public int PartIndex { get; set; } 23 | /// 24 | /// 連動するパラメータ 25 | /// 26 | public readonly List Link = []; 27 | 28 | /// 29 | /// 初期化する。 30 | /// 31 | /// 初期化に使用するモデル 32 | public void Initialize(CubismModel model) 33 | { 34 | ParameterIndex = model.GetParameterIndex(PartId); 35 | PartIndex = model.GetPartIndex(PartId); 36 | 37 | model.SetParameterValue(ParameterIndex, 1); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/ICubismAllocator.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework; 2 | 3 | /// 4 | /// メモリアロケーションを抽象化したクラス. 5 | /// 6 | /// メモリ確保・解放処理をプラットフォーム側で実装して 7 | /// フレームワークから呼び出すためのインターフェース。 8 | /// 9 | public interface ICubismAllocator 10 | { 11 | /// 12 | /// アラインメント制約なしのヒープ・メモリーを確保します。 13 | /// 14 | /// 確保するバイト数 15 | /// 成功すると割り当てられたメモリのアドレス。 そうでなければ '0'を返す。 16 | IntPtr Allocate(int size); 17 | 18 | /// 19 | /// アラインメント制約なしのヒープ・メモリーを解放します。 20 | /// 21 | /// 解放するメモリのアドレス 22 | void Deallocate(IntPtr memory); 23 | 24 | /// 25 | /// アラインメント制約ありのヒープ・メモリーを確保します。 26 | /// 27 | /// 確保するバイト数 28 | /// メモリーブロックのアラインメント幅 29 | /// 成功すると割り当てられたメモリのアドレス。 そうでなければ '0'を返す。 30 | IntPtr AllocateAligned(int size, int alignment); 31 | 32 | /// 33 | /// アラインメント制約ありのヒープ・メモリーを解放します。 34 | /// 35 | /// 解放するメモリのアドレス 36 | void DeallocateAligned(IntPtr alignedMemory); 37 | } 38 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Id/CubismIdManager.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Id; 2 | 3 | /// 4 | /// ID名を管理する。 5 | /// 6 | public class CubismIdManager 7 | { 8 | /// 9 | /// 登録されているIDのリスト 10 | /// 11 | private readonly List _ids = []; 12 | 13 | /// 14 | /// ID名をリストから登録する。 15 | /// 16 | /// ID名リスト 17 | public void RegisterIds(List list) 18 | { 19 | list.ForEach((item) => 20 | { 21 | GetId(item); 22 | }); 23 | } 24 | 25 | /// 26 | /// ID名からIDを取得する。 27 | /// 未登録のID名の場合、登録も行う。 28 | /// 29 | /// ID名 30 | public string GetId(string item) 31 | { 32 | if (_ids.Contains(item)) 33 | return item; 34 | 35 | _ids.Add(item); 36 | 37 | return item; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/JsonContext.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | using Live2DCSharpSDK.Framework.Model; 3 | using Live2DCSharpSDK.Framework.Motion; 4 | using Live2DCSharpSDK.Framework.Physics; 5 | 6 | namespace Live2DCSharpSDK.Framework; 7 | 8 | [JsonSourceGenerationOptions(WriteIndented = true)] 9 | [JsonSerializable(typeof(ModelSettingObj))] 10 | public partial class ModelSettingObjContext : JsonSerializerContext 11 | { 12 | } 13 | 14 | [JsonSerializable(typeof(CubismMotionObj))] 15 | public partial class CubismMotionObjContext : JsonSerializerContext 16 | { 17 | } 18 | 19 | [JsonSerializable(typeof(CubismModelUserDataObj))] 20 | public partial class CubismModelUserDataObjContext : JsonSerializerContext 21 | { 22 | } 23 | 24 | [JsonSerializable(typeof(CubismPhysicsObj))] 25 | public partial class CubismPhysicsObjContext : JsonSerializerContext 26 | { 27 | } 28 | 29 | 30 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Live2DCSharpSDK.Framework.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | true 8 | 9 | 10 | 11 | portable 12 | 13 | 14 | embedded 15 | 16 | 17 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Math/CubismMatrix44.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Math; 2 | 3 | /// 4 | /// 4x4行列の便利クラス。 5 | /// 6 | public record CubismMatrix44 7 | { 8 | private readonly float[] Ident = 9 | [ 10 | 1.0f, 0.0f, 0.0f, 0.0f, 11 | 0.0f, 1.0f, 0.0f, 0.0f, 12 | 0.0f, 0.0f, 1.0f, 0.0f, 13 | 0.0f, 0.0f, 0.0f, 1.0f 14 | ]; 15 | 16 | private readonly float[] _mpt1 = 17 | [ 18 | 1.0f, 0.0f, 0.0f, 0.0f, 19 | 0.0f, 1.0f, 0.0f, 0.0f, 20 | 0.0f, 0.0f, 1.0f, 0.0f, 21 | 0.0f, 0.0f, 0.0f, 1.0f 22 | ]; 23 | 24 | private readonly float[] _mpt2 = 25 | [ 26 | 1.0f, 0.0f, 0.0f, 0.0f, 27 | 0.0f, 1.0f, 0.0f, 0.0f, 28 | 0.0f, 0.0f, 1.0f, 0.0f, 29 | 0.0f, 0.0f, 0.0f, 1.0f 30 | ]; 31 | 32 | /// 33 | /// 4x4行列データ 34 | /// 35 | protected float[] _tr = new float[16]; 36 | 37 | public float[] Tr => _tr; 38 | 39 | /// 40 | /// コンストラクタ。 41 | /// 42 | public CubismMatrix44() 43 | { 44 | LoadIdentity(); 45 | } 46 | 47 | /// 48 | /// 単位行列に初期化する。 49 | /// 50 | public void LoadIdentity() 51 | { 52 | SetMatrix(Ident); 53 | } 54 | 55 | /// 56 | /// 行列を設定する。 57 | /// 58 | /// 16個の浮動小数点数で表される4x4の行列 59 | public void SetMatrix(float[] tr) 60 | { 61 | Array.Copy(tr, _tr, 16); 62 | } 63 | 64 | public void SetMatrix(CubismMatrix44 tr) 65 | { 66 | SetMatrix(tr.Tr); 67 | } 68 | 69 | /// 70 | /// X軸の拡大率を取得する。 71 | /// 72 | /// X軸の拡大率 73 | public float GetScaleX() 74 | { 75 | return _tr[0]; 76 | } 77 | 78 | /// 79 | /// Y軸の拡大率を取得する。 80 | /// 81 | /// Y軸の拡大率 82 | public float GetScaleY() 83 | { 84 | return _tr[5]; 85 | } 86 | 87 | /// 88 | /// X軸の移動量を取得する。 89 | /// 90 | /// X軸の移動量 91 | public float GetTranslateX() 92 | { 93 | return _tr[12]; 94 | } 95 | 96 | /// 97 | /// Y軸の移動量を取得する。 98 | /// 99 | /// Y軸の移動量 100 | public float GetTranslateY() 101 | { 102 | return _tr[13]; 103 | } 104 | 105 | /// 106 | /// X軸の値を現在の行列で計算する。 107 | /// 108 | /// X軸の値 109 | /// 現在の行列で計算されたX軸の値 110 | public float TransformX(float src) 111 | { 112 | return _tr[0] * src + _tr[12]; 113 | } 114 | 115 | /// 116 | /// Y軸の値を現在の行列で計算する。 117 | /// 118 | /// Y軸の値 119 | /// 現在の行列で計算されたY軸の値 120 | public float TransformY(float src) 121 | { 122 | return _tr[5] * src + _tr[13]; 123 | } 124 | 125 | /// 126 | /// X軸の値を現在の行列で逆計算する。 127 | /// 128 | /// X軸の値 129 | /// 現在の行列で逆計算されたX軸の値 130 | public float InvertTransformX(float src) 131 | { 132 | return (src - _tr[12]) / _tr[0]; 133 | } 134 | 135 | /// 136 | /// Y軸の値を現在の行列で逆計算する。 137 | /// 138 | /// Y軸の値 139 | /// 現在の行列で逆計算されたY軸の値 140 | public float InvertTransformY(float src) 141 | { 142 | return (src - _tr[13]) / _tr[5]; 143 | } 144 | 145 | /// 146 | /// 現在の行列の位置を起点にして相対的に移動する。 147 | /// 148 | /// X軸の移動量 149 | /// Y軸の移動量 150 | public void TranslateRelative(float x, float y) 151 | { 152 | _mpt1[12] = x; 153 | _mpt1[13] = y; 154 | MultiplyByMatrix(_mpt1); 155 | } 156 | 157 | /// 158 | /// 現在の行列の位置を指定した位置へ移動する。 159 | /// 160 | /// X軸の移動量 161 | /// Y軸の移動量 162 | public void Translate(float x, float y) 163 | { 164 | _tr[12] = x; 165 | _tr[13] = y; 166 | } 167 | 168 | /// 169 | /// 現在の行列のX軸の位置を指定した位置へ移動する。 170 | /// 171 | /// X軸の移動量 172 | public void TranslateX(float x) 173 | { 174 | _tr[12] = x; 175 | } 176 | 177 | /// 178 | /// 現在の行列のY軸の位置を指定した位置へ移動する。 179 | /// 180 | /// Y軸の移動量 181 | public void TranslateY(float y) 182 | { 183 | _tr[13] = y; 184 | } 185 | 186 | /// 187 | /// 現在の行列の拡大率を相対的に設定する。 188 | /// 189 | /// X軸の拡大率 190 | /// Y軸の拡大率 191 | public void ScaleRelative(float x, float y) 192 | { 193 | _mpt2[0] = x; 194 | _mpt2[5] = y; 195 | MultiplyByMatrix(_mpt2); 196 | } 197 | 198 | /// 199 | /// 現在の行列の拡大率を指定した倍率に設定する。 200 | /// 201 | /// X軸の拡大率 202 | /// Y軸の拡大率 203 | public void Scale(float x, float y) 204 | { 205 | _tr[0] = x; 206 | _tr[5] = y; 207 | } 208 | 209 | public float[] _mpt = new float[16]; 210 | 211 | public void MultiplyByMatrix(float[] a) 212 | { 213 | Array.Fill(_mpt, 0); 214 | 215 | int n = 4; 216 | 217 | for (int i = 0; i < n; ++i) 218 | { 219 | for (int j = 0; j < n; ++j) 220 | { 221 | for (int k = 0; k < n; ++k) 222 | { 223 | _mpt[j + i * 4] += a[k + i * 4] * _tr[j + k * 4]; 224 | } 225 | } 226 | } 227 | 228 | Array.Copy(_mpt, _tr, 16); 229 | } 230 | 231 | /// 232 | /// 現在の行列に行列を乗算する。 233 | /// 234 | /// 行列 235 | public void MultiplyByMatrix(CubismMatrix44 m) 236 | { 237 | MultiplyByMatrix(m.Tr); 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Math/CubismModelMatrix.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Math; 2 | 3 | /// 4 | /// モデル座標設定用の4x4行列クラス。 5 | /// 6 | public record CubismModelMatrix : CubismMatrix44 7 | { 8 | public const string KeyWidth = "width"; 9 | public const string KeyHeight = "height"; 10 | public const string KeyX = "x"; 11 | public const string KeyY = "y"; 12 | public const string KeyCenterX = "center_x"; 13 | public const string KeyCenterY = "center_y"; 14 | public const string KeyTop = "top"; 15 | public const string KeyBottom = "bottom"; 16 | public const string KeyLeft = "left"; 17 | public const string KeyRight = "right"; 18 | 19 | /// 20 | /// 横幅 21 | /// 22 | private readonly float _width; 23 | /// 24 | /// 縦幅 25 | /// 26 | private readonly float _height; 27 | 28 | public CubismModelMatrix(float w, float h) 29 | { 30 | _width = w; 31 | _height = h; 32 | 33 | SetHeight(2.0f); 34 | } 35 | 36 | /// 37 | /// 横幅を設定する。 38 | /// 39 | /// 横幅 40 | public void SetWidth(float w) 41 | { 42 | float scaleX = w / _width; 43 | float scaleY = scaleX; 44 | Scale(scaleX, scaleY); 45 | } 46 | 47 | /// 48 | /// 縦幅を設定する。 49 | /// 50 | /// 縦幅 51 | public void SetHeight(float h) 52 | { 53 | float scaleX = h / _height; 54 | float scaleY = scaleX; 55 | Scale(scaleX, scaleY); 56 | } 57 | 58 | /// 59 | /// 位置を設定する。 60 | /// 61 | /// X軸の位置 62 | /// Y軸の位置 63 | public void SetPosition(float x, float y) 64 | { 65 | Translate(x, y); 66 | } 67 | 68 | /// 69 | /// 中心位置を設定する。 70 | /// 71 | /// X軸の中心位置 72 | /// Y軸の中心位置 73 | public void SetCenterPosition(float x, float y) 74 | { 75 | CenterX(x); 76 | CenterY(y); 77 | } 78 | 79 | /// 80 | /// 上辺の位置を設定する。 81 | /// 82 | /// 上辺のY軸位置 83 | public void Top(float y) 84 | { 85 | SetY(y); 86 | } 87 | 88 | /// 89 | /// 下辺の位置を設定する。 90 | /// 91 | /// 下辺のY軸位置 92 | public void Bottom(float y) 93 | { 94 | float h = _height * GetScaleY(); 95 | TranslateY(y - h); 96 | } 97 | 98 | /// 99 | /// 左辺の位置を設定する。 100 | /// 101 | /// 左辺のX軸位置 102 | public void Left(float x) 103 | { 104 | SetX(x); 105 | } 106 | 107 | /// 108 | /// 右辺の位置を設定する。 109 | /// 110 | /// 右辺のX軸位置 111 | public void Right(float x) 112 | { 113 | float w = _width * GetScaleX(); 114 | TranslateX(x - w); 115 | } 116 | 117 | /// 118 | /// X軸の中心位置を設定する。 119 | /// 120 | /// X軸の中心位置 121 | public void CenterX(float x) 122 | { 123 | float w = _width * GetScaleX(); 124 | TranslateX(x - (w / 2.0f)); 125 | } 126 | 127 | /// 128 | /// X軸の位置を設定する。 129 | /// 130 | /// X軸の位置 131 | public void SetX(float x) 132 | { 133 | TranslateX(x); 134 | } 135 | 136 | /// 137 | /// Y軸の中心位置を設定する。 138 | /// 139 | /// Y軸の中心位置 140 | public void CenterY(float y) 141 | { 142 | float h = _height * GetScaleY(); 143 | TranslateY(y - (h / 2.0f)); 144 | } 145 | 146 | /// 147 | /// Y軸の位置を設定する。 148 | /// 149 | /// Y軸の位置 150 | public void SetY(float y) 151 | { 152 | TranslateY(y); 153 | } 154 | 155 | /// 156 | /// レイアウト情報から位置を設定する。 157 | /// 158 | /// レイアウト情報 159 | public void SetupFromLayout(Dictionary layout) 160 | { 161 | foreach (var item in layout) 162 | { 163 | if (item.Key == KeyWidth) 164 | { 165 | SetWidth(item.Value); 166 | } 167 | else if (item.Key == KeyHeight) 168 | { 169 | SetHeight(item.Value); 170 | } 171 | } 172 | 173 | foreach (var item in layout) 174 | { 175 | if (item.Key == KeyX) 176 | { 177 | SetX(item.Value); 178 | } 179 | else if (item.Key == KeyY) 180 | { 181 | SetY(item.Value); 182 | } 183 | else if (item.Key == KeyCenterX) 184 | { 185 | CenterX(item.Value); 186 | } 187 | else if (item.Key == KeyCenterY) 188 | { 189 | CenterY(item.Value); 190 | } 191 | else if (item.Key == KeyTop) 192 | { 193 | Top(item.Value); 194 | } 195 | else if (item.Key == KeyBottom) 196 | { 197 | Bottom(item.Value); 198 | } 199 | else if (item.Key == KeyLeft) 200 | { 201 | Left(item.Value); 202 | } 203 | else if (item.Key == KeyRight) 204 | { 205 | Right(item.Value); 206 | } 207 | } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Math/CubismTargetPoint.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Math; 2 | 3 | /// 4 | /// 顔の向きの制御機能を提供するクラス。 5 | /// 6 | public class CubismTargetPoint 7 | { 8 | public const int FrameRate = 30; 9 | public const float Epsilon = 0.01f; 10 | 11 | /// 12 | /// 顔の向きX(-1.0 - 1.0) 13 | /// 14 | public float FaceX { get; private set; } 15 | /// 16 | /// 顔の向きY(-1.0 - 1.0) 17 | /// 18 | public float FaceY { get; private set; } 19 | 20 | /// 21 | /// 顔の向きのX目標値(この値に近づいていく) 22 | /// 23 | private float _faceTargetX; 24 | /// 25 | /// 顔の向きのY目標値(この値に近づいていく) 26 | /// 27 | private float _faceTargetY; 28 | /// 29 | /// 顔の向きの変化速度X 30 | /// 31 | private float _faceVX; 32 | /// 33 | /// 顔の向きの変化速度Y 34 | /// 35 | private float _faceVY; 36 | /// 37 | /// 最後の実行時間[秒] 38 | /// 39 | private float _lastTimeSeconds; 40 | /// 41 | /// デルタ時間の積算値[秒] 42 | /// 43 | private float _userTimeSeconds; 44 | 45 | /// 46 | /// 更新処理を行う。 47 | /// 48 | /// デルタ時間[秒] 49 | public void Update(float deltaTimeSeconds) 50 | { 51 | // デルタ時間を加算する 52 | _userTimeSeconds += deltaTimeSeconds; 53 | 54 | // 首を中央から左右に振るときの平均的な早さは 秒程度。加速・減速を考慮して、その2倍を最高速度とする 55 | // 顔のふり具合を、中央(0.0)から、左右は(+-1.0)とする 56 | float FaceParamMaxV = 40.0f / 10.0f; // 7.5秒間に40分移動(5.3/sc) 57 | float MaxV = FaceParamMaxV * 1.0f / FrameRate; // 1frameあたりに変化できる速度の上限 58 | 59 | if (_lastTimeSeconds == 0.0f) 60 | { 61 | _lastTimeSeconds = _userTimeSeconds; 62 | return; 63 | } 64 | 65 | float deltaTimeWeight = (_userTimeSeconds - _lastTimeSeconds) * FrameRate; 66 | _lastTimeSeconds = _userTimeSeconds; 67 | 68 | // 最高速度になるまでの時間を 69 | float TimeToMaxSpeed = 0.15f; 70 | float FrameToMaxSpeed = TimeToMaxSpeed * FrameRate; // sec * frame/sec 71 | float MaxA = deltaTimeWeight * MaxV / FrameToMaxSpeed; // 1frameあたりの加速度 72 | 73 | // 目指す向きは、(dx, dy)方向のベクトルとなる 74 | float dx = _faceTargetX - FaceX; 75 | float dy = _faceTargetY - FaceY; 76 | 77 | if (MathF.Abs(dx) <= Epsilon && MathF.Abs(dy) <= Epsilon) 78 | { 79 | return; // 変化なし 80 | } 81 | 82 | // 速度の最大よりも大きい場合は、速度を落とす 83 | float d = MathF.Sqrt((dx * dx) + (dy * dy)); 84 | 85 | // 進行方向の最大速度ベクトル 86 | float vx = MaxV * dx / d; 87 | float vy = MaxV * dy / d; 88 | 89 | // 現在の速度から、新規速度への変化(加速度)を求める 90 | float ax = vx - _faceVX; 91 | float ay = vy - _faceVY; 92 | 93 | float a = MathF.Sqrt((ax * ax) + (ay * ay)); 94 | 95 | // 加速のとき 96 | if (a < -MaxA || a > MaxA) 97 | { 98 | ax *= MaxA / a; 99 | ay *= MaxA / a; 100 | } 101 | 102 | // 加速度を元の速度に足して、新速度とする 103 | _faceVX += ax; 104 | _faceVY += ay; 105 | 106 | // 目的の方向に近づいたとき、滑らかに減速するための処理 107 | // 設定された加速度で止まることのできる距離と速度の関係から 108 | // 現在とりうる最高速度を計算し、それ以上のときは速度を落とす 109 | // ※本来、人間は筋力で力(加速度)を調整できるため、より自由度が高いが、簡単な処理ですませている 110 | { 111 | // 加速度、速度、距離の関係式。 112 | // 2 6 2 3 113 | // sqrt(a t + 16 a h t - 8 a h) - a t 114 | // v = -------------------------------------- 115 | // 2 116 | // 4 t - 2 117 | // (t=1) 118 | // 時刻tは、あらかじめ加速度、速度を1/60(フレームレート、単位なし)で 119 | // 考えているので、t=1として消してよい(※未検証) 120 | 121 | float maxV = 0.5f * (MathF.Sqrt((MaxA * MaxA) + 16.0f * MaxA * d - 8.0f * MaxA * d) - MaxA); 122 | float curV = MathF.Sqrt((_faceVX * _faceVX) + (_faceVY * _faceVY)); 123 | 124 | if (curV > maxV) 125 | { 126 | // 現在の速度 > 最高速度のとき、最高速度まで減速 127 | _faceVX *= maxV / curV; 128 | _faceVY *= maxV / curV; 129 | } 130 | } 131 | 132 | FaceX += _faceVX; 133 | FaceY += _faceVY; 134 | } 135 | 136 | /// 137 | /// 顔の向きの目標値を設定する。 138 | /// 139 | /// X軸の顔の向きの値(-1.0 - 1.0) 140 | /// Y軸の顔の向きの値(-1.0 - 1.0) 141 | public void Set(float x, float y) 142 | { 143 | _faceTargetX = x; 144 | _faceTargetY = y; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Math/CubismViewMatrix.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Math; 2 | 3 | /// 4 | /// カメラの位置変更に使うと便利な4x4行列のクラス。 5 | /// 6 | public record CubismViewMatrix : CubismMatrix44 7 | { 8 | /// 9 | /// デバイスに対応する論理座標上の範囲(左辺X軸位置) 10 | /// 11 | public float ScreenLeft { get; private set; } 12 | /// 13 | /// デバイスに対応する論理座標上の範囲(右辺X軸位置) 14 | /// 15 | public float ScreenRight { get; private set; } 16 | /// 17 | /// デバイスに対応する論理座標上の範囲(下辺Y軸位置) 18 | /// 19 | public float ScreenTop { get; private set; } 20 | /// 21 | /// デバイスに対応する論理座標上の範囲(上辺Y軸位置) 22 | /// 23 | public float ScreenBottom { get; private set; } 24 | /// 25 | /// 論理座標上の移動可能範囲(左辺X軸位置) 26 | /// 27 | public float MaxLeft { get; private set; } 28 | /// 29 | /// 論理座標上の移動可能範囲(右辺X軸位置) 30 | /// 31 | public float MaxRight { get; private set; } 32 | /// 33 | /// 論理座標上の移動可能範囲(下辺Y軸位置) 34 | /// 35 | public float MaxTop { get; private set; } 36 | /// 37 | /// 論理座標上の移動可能範囲(上辺Y軸位置) 38 | /// 39 | public float MaxBottom { get; private set; } 40 | /// 41 | /// 拡大率の最大値 42 | /// 43 | public float MaxScale { get; set; } 44 | /// 45 | /// 拡大率の最小値 46 | /// 47 | public float MinScale { get; set; } 48 | 49 | /// 50 | /// 移動を調整する。 51 | /// 52 | /// X軸の移動量 53 | /// Y軸の移動量 54 | public void AdjustTranslate(float x, float y) 55 | { 56 | if (_tr[0] * MaxLeft + (_tr[12] + x) > ScreenLeft) 57 | { 58 | x = ScreenLeft - _tr[0] * MaxLeft - _tr[12]; 59 | } 60 | 61 | if (_tr[0] * MaxRight + (_tr[12] + x) < ScreenRight) 62 | { 63 | x = ScreenRight - _tr[0] * MaxRight - _tr[12]; 64 | } 65 | 66 | 67 | if (_tr[5] * MaxTop + (_tr[13] + y) < ScreenTop) 68 | { 69 | y = ScreenTop - _tr[5] * MaxTop - _tr[13]; 70 | } 71 | 72 | if (_tr[5] * MaxBottom + (_tr[13] + y) > ScreenBottom) 73 | { 74 | y = ScreenBottom - _tr[5] * MaxBottom - _tr[13]; 75 | } 76 | 77 | float[] tr1 = [ 1.0f, 0.0f, 0.0f, 0.0f, 78 | 0.0f, 1.0f, 0.0f, 0.0f, 79 | 0.0f, 0.0f, 1.0f, 0.0f, 80 | x, y, 0.0f, 1.0f ]; 81 | MultiplyByMatrix(tr1); 82 | } 83 | 84 | /// 85 | /// 拡大率を調整する。 86 | /// 87 | /// 拡大を行うX軸の中心位置 88 | /// 拡大を行うY軸の中心位置 89 | /// 拡大率 90 | public void AdjustScale(float cx, float cy, float scale) 91 | { 92 | float maxScale = MaxScale; 93 | float minScale = MinScale; 94 | 95 | float targetScale = scale * _tr[0]; // 96 | 97 | if (targetScale < minScale) 98 | { 99 | if (_tr[0] > 0.0f) 100 | { 101 | scale = minScale / _tr[0]; 102 | } 103 | } 104 | else if (targetScale > maxScale) 105 | { 106 | if (_tr[0] > 0.0f) 107 | { 108 | scale = maxScale / _tr[0]; 109 | } 110 | } 111 | 112 | MultiplyByMatrix([1.0f, 0.0f, 0.0f, 0.0f, 113 | 0.0f, 1.0f, 0.0f, 0.0f, 114 | 0.0f, 0.0f, 1.0f, 0.0f, 115 | -cx, -cy, 0.0f, 1.0f]); 116 | MultiplyByMatrix([scale, 0.0f, 0.0f, 0.0f, 117 | 0.0f, scale, 0.0f, 0.0f, 118 | 0.0f, 0.0f, 1.0f, 0.0f, 119 | 0.0f, 0.0f, 0.0f, 1.0f]); 120 | MultiplyByMatrix([1.0f, 0.0f, 0.0f, 0.0f, 121 | 0.0f, 1.0f, 0.0f, 0.0f, 122 | 0.0f, 0.0f, 1.0f, 0.0f, 123 | cx, cy, 0.0f, 1.0f]); 124 | } 125 | 126 | /// 127 | /// デバイスに対応する論理座標上の範囲の設定を行う。 128 | /// 129 | /// 左辺のX軸の位置 130 | /// 右辺のX軸の位置 131 | /// 下辺のY軸の位置 132 | /// 上辺のY軸の位置 133 | public void SetScreenRect(float left, float right, float bottom, float top) 134 | { 135 | ScreenLeft = left; 136 | ScreenRight = right; 137 | ScreenTop = top; 138 | ScreenBottom = bottom; 139 | } 140 | 141 | /// 142 | /// デバイスに対応する論理座標上の移動可能範囲の設定を行う。 143 | /// 144 | /// 左辺のX軸の位置 145 | /// 右辺のX軸の位置 146 | /// 下辺のY軸の位置 147 | /// 上辺のY軸の位置 148 | public void SetMaxScreenRect(float left, float right, float bottom, float top) 149 | { 150 | MaxLeft = left; 151 | MaxRight = right; 152 | MaxTop = top; 153 | MaxBottom = bottom; 154 | } 155 | 156 | /// 157 | /// 拡大率が最大になっているかどうかを確認する。 158 | /// 159 | /// true 拡大率は最大になっている 160 | /// false 拡大率は最大になっていない 161 | public bool IsMaxScale() 162 | { 163 | return GetScaleX() >= MaxScale; 164 | } 165 | 166 | /// 167 | /// 拡大率が最小になっているかどうかを確認する。 168 | /// 169 | /// true 拡大率は最小になっている 170 | /// false 拡大率は最小になっていない 171 | public bool IsMinScale() 172 | { 173 | return GetScaleX() <= MinScale; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Model/CubismMoc.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using Live2DCSharpSDK.Framework.Core; 3 | 4 | namespace Live2DCSharpSDK.Framework.Model; 5 | 6 | /// 7 | /// Mocデータの管理を行うクラス。 8 | /// 9 | public class CubismMoc : IDisposable 10 | { 11 | /// 12 | /// Mocデータ 13 | /// 14 | private readonly IntPtr _moc; 15 | /// 16 | /// 読み込んだモデルの.moc3 Version 17 | /// 18 | public uint MocVersion { get; } 19 | 20 | public CubismModel Model { get; } 21 | 22 | /// 23 | /// バッファからMocファイルを読み取り、Mocデータを作成する。 24 | /// 25 | /// Mocファイルのバッファ 26 | /// MOCの整合性チェックフラグ(初期値 : false) 27 | /// 28 | public CubismMoc(byte[] mocBytes, bool shouldCheckMocConsistency = false) 29 | { 30 | IntPtr alignedBuffer = CubismFramework.AllocateAligned(mocBytes.Length, CsmEnum.csmAlignofMoc); 31 | Marshal.Copy(mocBytes, 0, alignedBuffer, mocBytes.Length); 32 | 33 | if (shouldCheckMocConsistency) 34 | { 35 | // .moc3の整合性を確認 36 | bool consistency = HasMocConsistency(alignedBuffer, mocBytes.Length); 37 | if (!consistency) 38 | { 39 | CubismFramework.DeallocateAligned(alignedBuffer); 40 | 41 | // 整合性が確認できなければ処理しない 42 | throw new Exception("Inconsistent MOC3."); 43 | } 44 | } 45 | 46 | var moc = CubismCore.ReviveMocInPlace(alignedBuffer, mocBytes.Length); 47 | 48 | if (moc == IntPtr.Zero) 49 | { 50 | throw new Exception("MOC3 is null"); 51 | } 52 | 53 | _moc = moc; 54 | 55 | MocVersion = CubismCore.GetMocVersion(alignedBuffer, mocBytes.Length); 56 | 57 | var modelSize = CubismCore.GetSizeofModel(_moc); 58 | var modelMemory = CubismFramework.AllocateAligned(modelSize, CsmEnum.CsmAlignofModel); 59 | 60 | var model = CubismCore.InitializeModelInPlace(_moc, modelMemory, modelSize); 61 | 62 | if (model == IntPtr.Zero) 63 | { 64 | throw new Exception("MODEL is null"); 65 | } 66 | 67 | Model = new CubismModel(model); 68 | } 69 | 70 | /// 71 | /// 最新の.moc3 Versionを取得する。 72 | /// 73 | /// 74 | public static uint GetLatestMocVersion() 75 | { 76 | return CubismCore.GetLatestMocVersion(); 77 | } 78 | 79 | /// 80 | /// Checks consistency of a moc. 81 | /// 82 | /// Address of unrevived moc. The address must be aligned to 'csmAlignofMoc'. 83 | /// Size of moc (in bytes). 84 | /// '1' if Moc is valid; '0' otherwise. 85 | public static bool HasMocConsistency(IntPtr address, int size) 86 | { 87 | return CubismCore.HasMocConsistency(address, size); 88 | } 89 | 90 | /// 91 | /// Checks consistency of a moc. 92 | /// 93 | /// Mocファイルのバッファ 94 | /// バッファのサイズ 95 | /// 'true' if Moc is valid; 'false' otherwise. 96 | public static bool HasMocConsistencyFromUnrevivedMoc(byte[] data) 97 | { 98 | IntPtr alignedBuffer = CubismFramework.AllocateAligned(data.Length, CsmEnum.csmAlignofMoc); 99 | Marshal.Copy(data, 0, alignedBuffer, data.Length); 100 | 101 | bool consistency = HasMocConsistency(alignedBuffer, data.Length); 102 | 103 | CubismFramework.DeallocateAligned(alignedBuffer); 104 | 105 | return consistency; 106 | } 107 | 108 | /// 109 | /// デストラクタ。 110 | /// 111 | public void Dispose() 112 | { 113 | Model.Dispose(); 114 | CubismFramework.DeallocateAligned(_moc); 115 | GC.SuppressFinalize(this); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Model/CubismModelUserData.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | 3 | namespace Live2DCSharpSDK.Framework.Model; 4 | 5 | /// 6 | /// ユーザデータをロード、管理、検索インターフェイス、解放までを行う。 7 | /// 8 | public class CubismModelUserData 9 | { 10 | public const string ArtMesh = "ArtMesh"; 11 | public const string Meta = "Meta"; 12 | public const string UserDataCount = "UserDataCount"; 13 | public const string TotalUserDataSize = "TotalUserDataSize"; 14 | public const string UserData = "UserData"; 15 | public const string Target = "Target"; 16 | public const string Id = "Id"; 17 | public const string Value = "Value"; 18 | 19 | /// 20 | /// ユーザデータ構造体配列 21 | /// 22 | private readonly List _userDataNodes = []; 23 | /// 24 | /// 閲覧リスト保持 25 | /// 26 | public readonly List ArtMeshUserDataNodes = []; 27 | 28 | /// 29 | /// userdata3.jsonをパースする。 30 | /// 31 | /// userdata3.jsonが読み込まれいるバッファ 32 | public CubismModelUserData(string data) 33 | { 34 | using var stream = File.Open(data, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 35 | var obj = JsonSerializer.Deserialize(stream, CubismModelUserDataObjContext.Default.CubismModelUserDataObj) 36 | ?? throw new Exception("Load UserData error"); 37 | 38 | string typeOfArtMesh = CubismFramework.CubismIdManager.GetId(ArtMesh); 39 | 40 | int nodeCount = obj.Meta.UserDataCount; 41 | 42 | for (int i = 0; i < nodeCount; i++) 43 | { 44 | var node = obj.UserData[i]; 45 | CubismModelUserDataNode addNode = new() 46 | { 47 | TargetId = CubismFramework.CubismIdManager.GetId(node.Id), 48 | TargetType = CubismFramework.CubismIdManager.GetId(node.Target), 49 | Value = CubismFramework.CubismIdManager.GetId(node.Value) 50 | }; 51 | _userDataNodes.Add(addNode); 52 | 53 | if (addNode.TargetType == typeOfArtMesh) 54 | { 55 | ArtMeshUserDataNodes.Add(addNode); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Model/CubismModelUserDataNode.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Model; 2 | 3 | /// 4 | /// Jsonから読み込んだユーザデータを記録しておくための構造体 5 | /// 6 | public record CubismModelUserDataNode 7 | { 8 | /// 9 | /// ユーザデータターゲットタイプ 10 | /// 11 | public required string TargetType { get; set; } 12 | /// 13 | /// ユーザデータターゲットのID 14 | /// 15 | public required string TargetId { get; set; } 16 | /// 17 | /// ユーザデータ 18 | /// 19 | public required string Value { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Model/CubismModelUserDataObj.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Model; 2 | 3 | public record CubismModelUserDataObj 4 | { 5 | public record MetaObj 6 | { 7 | public int UserDataCount { get; set; } 8 | public int TotalUserDataSize { get; set; } 9 | } 10 | 11 | public record UserDataObj 12 | { 13 | public string Target { get; set; } 14 | public string Id { get; set; } 15 | public string Value { get; set; } 16 | } 17 | 18 | public MetaObj Meta { get; set; } 19 | public List UserData { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Model/DrawableColorData.cs: -------------------------------------------------------------------------------- 1 | using Live2DCSharpSDK.Framework.Rendering; 2 | 3 | namespace Live2DCSharpSDK.Framework.Model; 4 | 5 | /// 6 | /// テクスチャの色をRGBAで扱うための構造体 7 | /// 8 | public record DrawableColorData 9 | { 10 | public bool IsOverwritten { get; set; } 11 | public CubismTextureColor Color = new(); 12 | } 13 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Model/DrawableCullingData.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Model; 2 | 3 | /// 4 | /// テクスチャのカリング設定を管理するための構造体 5 | /// 6 | public record DrawableCullingData 7 | { 8 | public bool IsOverwritten { get; set; } 9 | public bool IsCulling { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Model/PartColorData.cs: -------------------------------------------------------------------------------- 1 | using Live2DCSharpSDK.Framework.Rendering; 2 | 3 | namespace Live2DCSharpSDK.Framework.Model; 4 | 5 | /// 6 | /// テクスチャの色をRGBAで扱うための構造体 7 | /// 8 | public record PartColorData 9 | { 10 | public bool IsOverwritten { get; set; } 11 | public CubismTextureColor Color = new(); 12 | } 13 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/ModelSettingObj.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace Live2DCSharpSDK.Framework; 4 | 5 | public record ModelSettingObj 6 | { 7 | public record FileReference 8 | { 9 | public record Expression 10 | { 11 | public string Name { get; set; } 12 | public string File { get; set; } 13 | } 14 | public record Motion 15 | { 16 | public string File { get; set; } 17 | public string Sound { get; set; } 18 | [DefaultValue(-1f)] 19 | public float FadeInTime { get; set; } 20 | [DefaultValue(-1f)] 21 | public float FadeOutTime { get; set; } 22 | } 23 | public string Moc { get; set; } 24 | public List Textures { get; set; } 25 | public string Physics { get; set; } 26 | public string Pose { get; set; } 27 | public string DisplayInfo { get; set; } 28 | public List Expressions { get; set; } 29 | public Dictionary> Motions { get; set; } 30 | public string UserData { get; set; } 31 | } 32 | 33 | public record HitArea 34 | { 35 | public string Id { get; set; } 36 | public string Name { get; set; } 37 | } 38 | 39 | public record Parameter 40 | { 41 | public string Name { get; set; } 42 | public List Ids { get; set; } 43 | } 44 | 45 | public FileReference FileReferences { get; set; } 46 | public List HitAreas { get; set; } 47 | public Dictionary Layout { get; set; } 48 | public List Groups { get; set; } 49 | } 50 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Motion/CubismMotionInternal.cs: -------------------------------------------------------------------------------- 1 | using Live2DCSharpSDK.Framework.Model; 2 | 3 | namespace Live2DCSharpSDK.Framework.Motion; 4 | 5 | /// 6 | /// モーション再生終了コールバック関数定義 7 | /// 8 | public delegate void FinishedMotionCallback(CubismModel model, ACubismMotion self); 9 | 10 | /// 11 | /// イベントのコールバックに登録できる関数の型情報 12 | /// 13 | /// 発火したイベントの文字列データ 14 | /// コールバックに返される登録時に指定されたデータ 15 | public delegate void CubismMotionEventFunction(CubismUserModel? customData, string eventValue); 16 | 17 | /// 18 | /// モーションカーブのセグメントの評価関数。 19 | /// 20 | /// モーションカーブの制御点リスト 21 | /// 評価する時間[秒] 22 | public delegate float csmMotionSegmentEvaluationFunction(CubismMotionPoint[] points, int start, float time); 23 | 24 | /// 25 | /// モーションの優先度定数 26 | /// 27 | public enum MotionPriority : int 28 | { 29 | PriorityNone = 0, 30 | PriorityIdle = 1, 31 | PriorityNormal = 2, 32 | PriorityForce = 3 33 | } 34 | 35 | /// 36 | /// 表情パラメータ値の計算方式 37 | /// 38 | public enum ExpressionBlendType 39 | { 40 | /// 41 | /// 加算 42 | /// 43 | Add = 0, 44 | /// 45 | /// 乗算 46 | /// 47 | Multiply = 1, 48 | /// 49 | /// 上書き 50 | /// 51 | Overwrite = 2 52 | }; 53 | 54 | /// 55 | /// 表情のパラメータ情報の構造体。 56 | /// 57 | public record ExpressionParameter 58 | { 59 | /// 60 | /// パラメータID 61 | /// 62 | public required string ParameterId { get; set; } 63 | /// 64 | /// パラメータの演算種類 65 | /// 66 | public ExpressionBlendType BlendType { get; set; } 67 | /// 68 | /// 値 69 | /// 70 | public float Value { get; set; } 71 | } 72 | 73 | 74 | /// 75 | /// モーションカーブの種類。 76 | /// 77 | public enum CubismMotionCurveTarget 78 | { 79 | /// 80 | /// モデルに対して 81 | /// 82 | Model, 83 | /// 84 | /// パラメータに対して 85 | /// 86 | Parameter, 87 | /// 88 | /// パーツの不透明度に対して 89 | /// 90 | PartOpacity 91 | }; 92 | 93 | /// 94 | /// モーションカーブのセグメントの種類。 95 | /// 96 | public enum CubismMotionSegmentType : int 97 | { 98 | /// 99 | /// リニア 100 | /// 101 | Linear = 0, 102 | /// 103 | /// ベジェ曲線 104 | /// 105 | Bezier = 1, 106 | /// 107 | /// ステップ 108 | /// 109 | Stepped = 2, 110 | /// 111 | /// インバースステップ 112 | /// 113 | InverseStepped = 3 114 | }; 115 | 116 | /// 117 | /// モーションカーブの制御点。 118 | /// 119 | public struct CubismMotionPoint 120 | { 121 | /// 122 | /// 時間[秒] 123 | /// 124 | public float Time; 125 | /// 126 | /// 値 127 | /// 128 | public float Value; 129 | } 130 | 131 | /// 132 | /// モーションカーブのセグメント。 133 | /// 134 | public record CubismMotionSegment 135 | { 136 | /// 137 | /// 使用する評価関数 138 | /// 139 | public csmMotionSegmentEvaluationFunction Evaluate; 140 | /// 141 | /// 最初のセグメントへのインデックス 142 | /// 143 | public int BasePointIndex; 144 | /// 145 | /// セグメントの種類 146 | /// 147 | public CubismMotionSegmentType SegmentType; 148 | } 149 | 150 | /// 151 | /// モーションカーブ。 152 | /// 153 | public record CubismMotionCurve 154 | { 155 | /// 156 | /// カーブの種類 157 | /// 158 | public CubismMotionCurveTarget Type; 159 | /// 160 | /// カーブのID 161 | /// 162 | public string Id; 163 | /// 164 | /// セグメントの個数 165 | /// 166 | public int SegmentCount; 167 | /// 168 | /// 最初のセグメントのインデックス 169 | /// 170 | public int BaseSegmentIndex; 171 | /// 172 | /// フェードインにかかる時間[秒] 173 | /// 174 | public float FadeInTime; 175 | /// 176 | /// フェードアウトにかかる時間[秒] 177 | /// 178 | public float FadeOutTime; 179 | } 180 | 181 | /// 182 | /// イベント。 183 | /// 184 | public record CubismMotionEvent 185 | { 186 | public float FireTime; 187 | public string Value; 188 | } 189 | 190 | /// 191 | /// モーションデータ。 192 | /// 193 | public record CubismMotionData 194 | { 195 | /// 196 | /// モーションの長さ[秒] 197 | /// 198 | public float Duration; 199 | /// 200 | /// ループするかどうか 201 | /// 202 | public bool Loop; 203 | /// 204 | /// カーブの個数 205 | /// 206 | public int CurveCount; 207 | /// 208 | /// UserDataの個数 209 | /// 210 | public int EventCount; 211 | /// 212 | /// フレームレート 213 | /// 214 | public float Fps; 215 | /// 216 | /// カーブのリスト 217 | /// 218 | public CubismMotionCurve[] Curves; 219 | /// 220 | /// セグメントのリスト 221 | /// 222 | public CubismMotionSegment[] Segments; 223 | /// 224 | /// ポイントのリスト 225 | /// 226 | public CubismMotionPoint[] Points; 227 | /// 228 | /// イベントのリスト 229 | /// 230 | public CubismMotionEvent[] Events; 231 | } -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Motion/CubismMotionManager.cs: -------------------------------------------------------------------------------- 1 | using Live2DCSharpSDK.Framework.Model; 2 | 3 | namespace Live2DCSharpSDK.Framework.Motion; 4 | 5 | /// 6 | /// モーションの管理を行うクラス。 7 | /// 8 | public class CubismMotionManager : CubismMotionQueueManager 9 | { 10 | /// 11 | /// 現在再生中のモーションの優先度 12 | /// 13 | public MotionPriority CurrentPriority { get; private set; } 14 | /// 15 | /// 再生予定のモーションの優先度。再生中は0になる。モーションファイルを別スレッドで読み込むときの機能。 16 | /// 17 | public MotionPriority ReservePriority { get; set; } 18 | 19 | /// 20 | /// 優先度を設定してモーションを開始する。 21 | /// 22 | /// モーション 23 | /// 再生が終了したモーションのインスタンスを削除するならtrue 24 | /// 優先度 25 | /// 開始したモーションの識別番号を返す。個別のモーションが終了したか否かを判定するIsFinished()の引数で使用する。開始できない時は「-1」 26 | public CubismMotionQueueEntry StartMotionPriority(ACubismMotion motion, MotionPriority priority) 27 | { 28 | if (priority == ReservePriority) 29 | { 30 | ReservePriority = 0; // 予約を解除 31 | } 32 | 33 | CurrentPriority = priority; // 再生中モーションの優先度を設定 34 | 35 | return StartMotion(motion); 36 | } 37 | 38 | /// 39 | /// モーションを更新して、モデルにパラメータ値を反映する。 40 | /// 41 | /// 対象のモデル 42 | /// デルタ時間[秒] 43 | /// true 更新されている 44 | /// false 更新されていない 45 | public bool UpdateMotion(CubismModel model, float deltaTimeSeconds) 46 | { 47 | UserTimeSeconds += deltaTimeSeconds; 48 | 49 | bool updated = DoUpdateMotion(model, UserTimeSeconds); 50 | 51 | if (IsFinished()) 52 | { 53 | CurrentPriority = 0; // 再生中モーションの優先度を解除 54 | } 55 | 56 | return updated; 57 | } 58 | 59 | /// 60 | /// モーションを予約する。 61 | /// 62 | /// 優先度 63 | /// true 予約できた 64 | /// false 予約できなかった 65 | public bool ReserveMotion(MotionPriority priority) 66 | { 67 | if ((priority <= ReservePriority) || (priority <= CurrentPriority)) 68 | { 69 | return false; 70 | } 71 | 72 | ReservePriority = priority; 73 | 74 | return true; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Motion/CubismMotionObj.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Motion; 2 | 3 | public record CubismMotionObj 4 | { 5 | public record MetaObj 6 | { 7 | public float Duration { get; set; } 8 | public bool Loop { get; set; } 9 | public bool AreBeziersRestricted { get; set; } 10 | public int CurveCount { get; set; } 11 | public float Fps { get; set; } 12 | public int TotalSegmentCount { get; set; } 13 | public int TotalPointCount { get; set; } 14 | public float? FadeInTime { get; set; } 15 | public float? FadeOutTime { get; set; } 16 | public int UserDataCount { get; set; } 17 | public int TotalUserDataSize { get; set; } 18 | } 19 | public record Curve 20 | { 21 | public float? FadeInTime { get; set; } 22 | public float? FadeOutTime { get; set; } 23 | public List Segments { get; set; } 24 | public string Target { get; set; } 25 | public string Id { get; set; } 26 | } 27 | public record UserDataObj 28 | { 29 | public float Time { get; set; } 30 | public string Value { get; set; } 31 | } 32 | public MetaObj Meta { get; set; } 33 | public List Curves { get; set; } 34 | public List UserData { get; set; } 35 | } 36 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Motion/CubismMotionQueueEntry.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Motion; 2 | 3 | /// 4 | /// CubismMotionQueueManagerで再生している各モーションの管理クラス。 5 | /// 6 | public class CubismMotionQueueEntry 7 | { 8 | /// 9 | /// モーション 10 | /// 11 | public required ACubismMotion Motion { get; set; } 12 | 13 | /// 14 | /// 有効化フラグ 15 | /// 16 | public bool Available { get; set; } 17 | /// 18 | /// 終了フラグ 19 | /// 20 | public bool Finished { get; set; } 21 | /// 22 | /// 開始フラグ(0.9.00以降) 23 | /// 24 | public bool Started { get; set; } 25 | /// 26 | /// モーション再生開始時刻[秒] 27 | /// 28 | public float StartTime { get; set; } 29 | /// 30 | /// フェードイン開始時刻(ループの時は初回のみ)[秒] 31 | /// 32 | public float FadeInStartTime { get; set; } 33 | /// 34 | /// 終了予定時刻[秒] 35 | /// 36 | public float EndTime { get; set; } 37 | /// 38 | /// 時刻の状態[秒] 39 | /// 40 | public float StateTime { get; private set; } 41 | /// 42 | /// 重みの状態 43 | /// 44 | public float StateWeight { get; private set; } 45 | /// 46 | /// 最終のMotion側のチェックした時間 47 | /// 48 | public float LastEventCheckSeconds { get; set; } 49 | 50 | public float FadeOutSeconds { get; private set; } 51 | 52 | public bool IsTriggeredFadeOut { get; private set; } 53 | 54 | /// 55 | /// コンストラクタ。 56 | /// 57 | public CubismMotionQueueEntry() 58 | { 59 | Available = true; 60 | StartTime = -1.0f; 61 | EndTime = -1.0f; 62 | } 63 | 64 | /// 65 | /// フェードアウトの開始を設定する。 66 | /// 67 | /// フェードアウトにかかる時間[秒] 68 | public void SetFadeout(float fadeOutSeconds) 69 | { 70 | FadeOutSeconds = fadeOutSeconds; 71 | IsTriggeredFadeOut = true; 72 | } 73 | 74 | /// 75 | /// フェードアウトを開始する。 76 | /// 77 | /// フェードアウトにかかる時間[秒] 78 | /// デルタ時間の積算値[秒] 79 | public void StartFadeout(float fadeOutSeconds, float userTimeSeconds) 80 | { 81 | float newEndTimeSeconds = userTimeSeconds + fadeOutSeconds; 82 | IsTriggeredFadeOut = true; 83 | 84 | if (EndTime < 0.0f || newEndTimeSeconds < EndTime) 85 | { 86 | EndTime = newEndTimeSeconds; 87 | } 88 | } 89 | 90 | /// 91 | /// モーションの状態を設定する。 92 | /// 93 | /// 現在時刻[秒] 94 | /// モーションの重み 95 | public void SetState(float timeSeconds, float weight) 96 | { 97 | StateTime = timeSeconds; 98 | StateWeight = weight; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Physics/CubismPhysicsJson.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Physics; 2 | 3 | /// 4 | /// physics3.jsonのコンテナ。 5 | /// 6 | public record CubismPhysicsJson 7 | { 8 | public const string Position = "Position"; 9 | public const string X = "X"; 10 | public const string Y = "Y"; 11 | public const string Angle = "Angle"; 12 | public const string Type = "Type"; 13 | public const string Id = "Id"; 14 | 15 | // Meta 16 | public const string Meta = "Meta"; 17 | public const string EffectiveForces = "EffectiveForces"; 18 | public const string TotalInputCount = "TotalInputCount"; 19 | public const string TotalOutputCount = "TotalOutputCount"; 20 | public const string PhysicsSettingCount = "PhysicsSettingCount"; 21 | public const string Gravity = "Gravity"; 22 | public const string Wind = "Wind"; 23 | public const string VertexCount = "VertexCount"; 24 | public const string Fps = "Fps"; 25 | 26 | // PhysicsSettings 27 | public const string PhysicsSettings = "PhysicsSettings"; 28 | public const string Normalization = "Normalization"; 29 | public const string Minimum = "Minimum"; 30 | public const string Maximum = "Maximum"; 31 | public const string Default = "Default"; 32 | public const string Reflect = "Reflect"; 33 | public const string Weight = "Weight"; 34 | 35 | // Input 36 | public const string Input = "Input"; 37 | public const string Source = "Source"; 38 | 39 | // Output 40 | public const string Output = "Output"; 41 | public const string Scale = "Scale"; 42 | public const string VertexIndex = "VertexIndex"; 43 | public const string Destination = "Destination"; 44 | 45 | // Particle 46 | public const string Vertices = "Vertices"; 47 | public const string Mobility = "Mobility"; 48 | public const string Delay = "Delay"; 49 | public const string Radius = "Radius"; 50 | public const string Acceleration = "Acceleration"; 51 | } -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Physics/CubismPhysicsObj.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | 3 | namespace Live2DCSharpSDK.Framework.Physics; 4 | 5 | public record CubismPhysicsObj 6 | { 7 | public record MetaObj 8 | { 9 | public record EffectiveForce 10 | { 11 | public Vector2 Gravity { get; set; } 12 | public Vector2 Wind { get; set; } 13 | } 14 | 15 | public EffectiveForce EffectiveForces { get; set; } 16 | public float Fps { get; set; } 17 | public int PhysicsSettingCount { get; set; } 18 | public int TotalInputCount { get; set; } 19 | public int TotalOutputCount { get; set; } 20 | public int VertexCount { get; set; } 21 | } 22 | public record PhysicsSetting 23 | { 24 | public record NormalizationObj 25 | { 26 | public record PositionObj 27 | { 28 | public float Minimum { get; set; } 29 | public float Maximum { get; set; } 30 | public float Default { get; set; } 31 | } 32 | public PositionObj Position { get; set; } 33 | public PositionObj Angle { get; set; } 34 | } 35 | public record InputObj 36 | { 37 | public record SourceObj 38 | { 39 | public string Id { get; set; } 40 | } 41 | public float Weight { get; set; } 42 | public bool Reflect { get; set; } 43 | public string Type { get; set; } 44 | public SourceObj Source { get; set; } 45 | } 46 | public record OutputObj 47 | { 48 | public record DestinationObj 49 | { 50 | public string Id { get; set; } 51 | } 52 | public int VertexIndex { get; set; } 53 | public float Scale { get; set; } 54 | public float Weight { get; set; } 55 | public DestinationObj Destination { get; set; } 56 | public string Type { get; set; } 57 | public bool Reflect { get; set; } 58 | } 59 | public record Vertice 60 | { 61 | public float Mobility { get; set; } 62 | public float Delay { get; set; } 63 | public float Acceleration { get; set; } 64 | public float Radius { get; set; } 65 | public Vector2 Position { get; set; } 66 | } 67 | public NormalizationObj Normalization { get; set; } 68 | public List Input { get; set; } 69 | public List Output { get; set; } 70 | public List Vertices { get; set; } 71 | } 72 | public MetaObj Meta { get; set; } 73 | public List PhysicsSettings { get; set; } 74 | } 75 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Rendering/CubismBlendMode.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Rendering; 2 | 3 | /// 4 | /// カラーブレンディングのモード 5 | /// 6 | public enum CubismBlendMode 7 | { 8 | /// 9 | /// 通常 10 | /// 11 | Normal = 0, 12 | /// 13 | /// 加算 14 | /// 15 | Additive = 1, 16 | /// 17 | /// 乗算 18 | /// 19 | Multiplicative = 2, 20 | /// 21 | /// マスク 22 | /// 23 | Mask = 3, 24 | }; 25 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Rendering/CubismClippingContext.cs: -------------------------------------------------------------------------------- 1 | using Live2DCSharpSDK.Framework.Math; 2 | using Live2DCSharpSDK.Framework.Type; 3 | 4 | namespace Live2DCSharpSDK.Framework.Rendering; 5 | 6 | public unsafe abstract class CubismClippingContext(CubismClippingManager manager, int* clippingDrawableIndices, int clipCount) 7 | { 8 | /// 9 | /// 現在の描画状態でマスクの準備が必要ならtrue 10 | /// 11 | public bool IsUsing; 12 | /// 13 | /// クリッピングマスクのIDリスト 14 | /// 15 | public unsafe int* ClippingIdList = clippingDrawableIndices; 16 | /// 17 | /// クリッピングマスクの数 18 | /// 19 | public int ClippingIdCount = clipCount; 20 | /// 21 | /// RGBAのいずれのチャンネルにこのクリップを配置するか(0:R , 1:G , 2:B , 3:A) 22 | /// 23 | public int LayoutChannelIndex = 0; 24 | /// 25 | /// マスク用チャンネルのどの領域にマスクを入れるか(View座標-1..1, UVは0..1に直す) 26 | /// 27 | public RectF LayoutBounds = new(); 28 | /// 29 | /// このクリッピングで、クリッピングされる全ての描画オブジェクトの囲み矩形(毎回更新) 30 | /// 31 | public RectF AllClippedDrawRect = new(); 32 | /// 33 | /// マスクの位置計算結果を保持する行列 34 | /// 35 | public CubismMatrix44 MatrixForMask = new(); 36 | /// 37 | /// 描画オブジェクトの位置計算結果を保持する行列 38 | /// 39 | public CubismMatrix44 MatrixForDraw = new(); 40 | /// 41 | /// このマスクにクリップされる描画オブジェクトのリスト 42 | /// 43 | public List ClippedDrawableIndexList = []; 44 | /// 45 | /// このマスクが割り当てられるレンダーテクスチャ(フレームバッファ)やカラーバッファのインデックス 46 | /// 47 | public int BufferIndex; 48 | 49 | public CubismClippingManager Manager { get; } = manager; 50 | 51 | /// 52 | /// このマスクにクリップされる描画オブジェクトを追加する 53 | /// 54 | /// クリッピング対象に追加する描画オブジェクトのインデックス 55 | public void AddClippedDrawable(int drawableIndex) 56 | { 57 | ClippedDrawableIndexList.Add(drawableIndex); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Rendering/CubismOffscreenSurface.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Rendering; 2 | 3 | public abstract class CubismOffscreenSurface 4 | { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Rendering/CubismRenderer.cs: -------------------------------------------------------------------------------- 1 | using Live2DCSharpSDK.Framework.Math; 2 | using Live2DCSharpSDK.Framework.Model; 3 | 4 | namespace Live2DCSharpSDK.Framework.Rendering; 5 | 6 | /// 7 | /// モデル描画を処理するレンダラ 8 | /// サブクラスに環境依存の描画命令を記述する 9 | /// 10 | public abstract class CubismRenderer 11 | { 12 | /// 13 | /// テクスチャの異方性フィルタリングのパラメータ 14 | /// 15 | public float Anisotropy { get; set; } 16 | /// 17 | /// レンダリング対象のモデル 18 | /// 19 | public CubismModel Model { get; private set; } 20 | /// 21 | /// 乗算済みαならtrue 22 | /// 23 | public bool IsPremultipliedAlpha { get; set; } 24 | /// 25 | /// カリングが有効ならtrue 26 | /// 27 | public bool IsCulling { get; set; } 28 | /// 29 | /// falseの場合、マスクを纏めて描画する trueの場合、マスクはパーツ描画ごとに書き直す 30 | /// 31 | public bool UseHighPrecisionMask { get; set; } 32 | 33 | /// 34 | /// モデル自体のカラー(RGBA) 35 | /// 36 | public CubismTextureColor ModelColor = new(); 37 | 38 | /// 39 | /// Model-View-Projection 行列 40 | /// 41 | private readonly CubismMatrix44 _mvpMatrix4x4 = new(); 42 | 43 | /// 44 | /// レンダラのインスタンスを生成して取得する 45 | /// 46 | public CubismRenderer(CubismModel model) 47 | { 48 | _mvpMatrix4x4.LoadIdentity(); 49 | Model = model ?? throw new Exception("model is null"); 50 | } 51 | 52 | /// 53 | /// レンダラのインスタンスを解放する 54 | /// 55 | public abstract void Dispose(); 56 | 57 | /// 58 | /// モデルを描画する 59 | /// 60 | public void DrawModel() 61 | { 62 | /** 63 | * DoDrawModelの描画前と描画後に以下の関数を呼んでください。 64 | * ・SaveProfile(); 65 | * ・RestoreProfile(); 66 | * これはレンダラの描画設定を保存・復帰させることで、 67 | * モデル描画直前の状態に戻すための処理です。 68 | */ 69 | 70 | SaveProfile(); 71 | 72 | DoDrawModel(); 73 | 74 | RestoreProfile(); 75 | } 76 | 77 | /// 78 | /// Model-View-Projection 行列をセットする 79 | /// 配列は複製されるので元の配列は外で破棄して良い 80 | /// 81 | /// Model-View-Projection 行列 82 | public void SetMvpMatrix(CubismMatrix44 matrix4x4) 83 | { 84 | _mvpMatrix4x4.SetMatrix(matrix4x4.Tr); 85 | } 86 | 87 | /// 88 | /// Model-View-Projection 行列を取得する 89 | /// 90 | /// Model-View-Projection 行列 91 | public CubismMatrix44 GetMvpMatrix() 92 | { 93 | return _mvpMatrix4x4; 94 | } 95 | 96 | /// 97 | /// 透明度を考慮したモデルの色を計算する。 98 | /// 99 | /// 透明度 100 | /// RGBAのカラー情報 101 | public CubismTextureColor GetModelColorWithOpacity(float opacity) 102 | { 103 | CubismTextureColor modelColorRGBA = new(ModelColor); 104 | modelColorRGBA.A *= opacity; 105 | if (IsPremultipliedAlpha) 106 | { 107 | modelColorRGBA.R *= modelColorRGBA.A; 108 | modelColorRGBA.G *= modelColorRGBA.A; 109 | modelColorRGBA.B *= modelColorRGBA.A; 110 | } 111 | return modelColorRGBA; 112 | } 113 | 114 | /// 115 | /// モデルの色をセットする。 116 | /// 各色0.0f~1.0fの間で指定する(1.0fが標準の状態)。 117 | /// 118 | /// 赤チャンネルの値 119 | /// 緑チャンネルの値 120 | /// 青チャンネルの値 121 | /// αチャンネルの値 122 | public void SetModelColor(float red, float green, float blue, float alpha) 123 | { 124 | if (red < 0.0f) red = 0.0f; 125 | else if (red > 1.0f) red = 1.0f; 126 | 127 | if (green < 0.0f) green = 0.0f; 128 | else if (green > 1.0f) green = 1.0f; 129 | 130 | if (blue < 0.0f) blue = 0.0f; 131 | else if (blue > 1.0f) blue = 1.0f; 132 | 133 | if (alpha < 0.0f) alpha = 0.0f; 134 | else if (alpha > 1.0f) alpha = 1.0f; 135 | 136 | ModelColor.R = red; 137 | ModelColor.G = green; 138 | ModelColor.B = blue; 139 | ModelColor.A = alpha; 140 | } 141 | 142 | /// 143 | /// モデル描画の実装 144 | /// 145 | protected abstract void DoDrawModel(); 146 | 147 | /// 148 | /// モデル描画直前のレンダラのステートを保持する 149 | /// 150 | protected abstract void SaveProfile(); 151 | 152 | /// 153 | /// モデル描画直前のレンダラのステートを復帰させる 154 | /// 155 | protected abstract void RestoreProfile(); 156 | } 157 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Rendering/CubismTextureColor.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Rendering; 2 | 3 | /// 4 | /// テクスチャの色をRGBAで扱うための構造体 5 | /// 6 | public struct CubismTextureColor 7 | { 8 | /// 9 | /// 赤チャンネル 10 | /// 11 | public float R; 12 | /// 13 | /// 緑チャンネル 14 | /// 15 | public float G; 16 | /// 17 | /// 青チャンネル 18 | /// 19 | public float B; 20 | /// 21 | /// αチャンネル 22 | /// 23 | public float A; 24 | 25 | public CubismTextureColor() 26 | { 27 | R = 1.0f; 28 | G = 1.0f; 29 | B = 1.0f; 30 | A = 1.0f; 31 | } 32 | 33 | public CubismTextureColor(CubismTextureColor old) 34 | { 35 | R = old.R; 36 | G = old.G; 37 | B = old.B; 38 | A = old.A; 39 | Check(); 40 | } 41 | 42 | public CubismTextureColor(float r, float g, float b, float a) 43 | { 44 | R = r; 45 | G = g; 46 | B = b; 47 | A = a; 48 | Check(); 49 | } 50 | 51 | private void Check() 52 | { 53 | R = R > 1.0f ? 1f : R; 54 | G = G > 1.0f ? 1f : G; 55 | B = B > 1.0f ? 1f : B; 56 | A = A > 1.0f ? 1f : A; 57 | } 58 | } -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Rendering/RenderType.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Rendering; 2 | 3 | public enum RenderType 4 | { 5 | OpenGL, 6 | Vulkan 7 | } 8 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/SDKInfo.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK; 2 | 3 | public static class SDKInfo 4 | { 5 | public const string Version = "Cubism 5 SDK for Native R1"; 6 | } -------------------------------------------------------------------------------- /Live2DCSharpSDK.Framework/Type/RectF.cs: -------------------------------------------------------------------------------- 1 | namespace Live2DCSharpSDK.Framework.Type; 2 | 3 | /// 4 | /// 矩形形状(座標・長さはfloat値)を定義するクラス 5 | /// 6 | public class RectF 7 | { 8 | /// 9 | /// 左端X座標 10 | /// 11 | public float X; 12 | /// 13 | /// 上端Y座標 14 | /// 15 | public float Y; 16 | /// 17 | /// 幅 18 | /// 19 | public float Width; 20 | /// 21 | /// 高さ 22 | /// 23 | public float Height; 24 | 25 | public RectF() { } 26 | /// 27 | /// 引数付きコンストラクタ 28 | /// 29 | /// 左端X座標 30 | /// 上端Y座標 31 | /// 幅 32 | /// 高さ 33 | public RectF(float x, float y, float w, float h) 34 | { 35 | X = x; 36 | Y = y; 37 | Width = w; 38 | Height = h; 39 | } 40 | 41 | /// 42 | /// 矩形に値をセットする 43 | /// 44 | /// 矩形のインスタンス 45 | public void SetRect(RectF r) 46 | { 47 | X = r.X; 48 | Y = r.Y; 49 | Width = r.Width; 50 | Height = r.Height; 51 | } 52 | 53 | /// 54 | /// 矩形中央を軸にして縦横を拡縮する 55 | /// 56 | /// 幅方向に拡縮する量 57 | /// 高さ方向に拡縮する量 58 | public void Expand(float w, float h) 59 | { 60 | X -= w; 61 | Y -= h; 62 | Width += w * 2.0f; 63 | Height += h * 2.0f; 64 | } 65 | 66 | /// 67 | /// 矩形中央のX座標を取得する 68 | /// 69 | public float GetCenterX() 70 | { 71 | return X + 0.5f * Width; 72 | } 73 | 74 | /// 75 | /// 矩形中央のY座標を取得する 76 | /// 77 | public float GetCenterY() 78 | { 79 | return Y + 0.5f * Height; 80 | } 81 | 82 | /// 83 | /// 右端のX座標を取得する 84 | /// 85 | public float GetRight() 86 | { 87 | return X + Width; 88 | } 89 | 90 | /// 91 | /// 下端のY座標を取得する 92 | /// 93 | public float GetBottom() 94 | { 95 | return Y + Height; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.OpenGL.Avalonia/App.axaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.OpenGL.Avalonia/App.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls.ApplicationLifetimes; 3 | using Avalonia.Markup.Xaml; 4 | 5 | namespace Live2DCSharpSDK.Avalonia; 6 | 7 | public partial class App : Application 8 | { 9 | public override void Initialize() 10 | { 11 | AvaloniaXamlLoader.Load(this); 12 | } 13 | 14 | public override void OnFrameworkInitializationCompleted() 15 | { 16 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) 17 | { 18 | desktop.MainWindow = new MainWindow(); 19 | } 20 | 21 | base.OnFrameworkInitializationCompleted(); 22 | } 23 | } -------------------------------------------------------------------------------- /Live2DCSharpSDK.OpenGL.Avalonia/FpsTimer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using Avalonia.OpenGL.Controls; 4 | using Avalonia.Threading; 5 | 6 | namespace Live2DCSharpSDK.Avalonia; 7 | 8 | public class FpsTimer 9 | { 10 | private readonly OpenGlControlBase _render; 11 | private readonly Timer _timer; 12 | 13 | public int Fps { get; set; } = 60; 14 | public Action? FpsTick { private get; init; } 15 | public bool Pause { get; set; } 16 | public int NowFps { get; private set; } 17 | 18 | private int _time; 19 | private bool _run; 20 | 21 | public FpsTimer(OpenGlControlBase render) 22 | { 23 | _render = render; 24 | _run = true; 25 | _time = (int)((double)1000 / Fps); 26 | _timer = new(Tick); 27 | _timer.Change(0, 1000); 28 | new Thread(() => 29 | { 30 | while (_run) 31 | { 32 | if (Pause) 33 | { 34 | Thread.Sleep(100); 35 | continue; 36 | } 37 | Dispatcher.UIThread.Post(() => 38 | { 39 | _render.RequestNextFrameRendering(); 40 | }); 41 | NowFps++; 42 | Thread.Sleep(_time); 43 | } 44 | }) 45 | { 46 | Name = "ColorMC_Render_Timer" 47 | }.Start(); 48 | } 49 | 50 | private void Tick(object? state) 51 | { 52 | if (!Pause) 53 | { 54 | if (NowFps != Fps && _time > 1) 55 | { 56 | if (NowFps > Fps) 57 | { 58 | _time++; 59 | } 60 | else 61 | { 62 | _time--; 63 | } 64 | } 65 | } 66 | FpsTick?.Invoke(NowFps); 67 | NowFps = 0; 68 | } 69 | 70 | public void Close() 71 | { 72 | _run = false; 73 | _timer.Dispose(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.OpenGL.Avalonia/Live2DCSharpSDK.OpenGL.Avalonia.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | link 6 | enable 7 | true 8 | true 9 | 10 | 11 | 12 | portable 13 | 14 | 15 | embedded 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Live2DCSharpSDK.OpenGL.Avalonia/MainWindow.axaml: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 |