├── .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 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL.Avalonia/MainWindow.axaml.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Coloryr/Live2DCSharpSDK/a016c99aa6495b3dc872a449153d9c53ce476406/Live2DCSharpSDK.OpenGL.Avalonia/MainWindow.axaml.cs
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL.Avalonia/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Avalonia;
3 |
4 | namespace Live2DCSharpSDK.Avalonia;
5 |
6 | internal class Program
7 | {
8 | // Initialization code. Don't use any Avalonia, third-party APIs or any
9 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
10 | // yet and stuff might break.
11 | [STAThread]
12 | public static void Main(string[] args) => BuildAvaloniaApp()
13 | .StartWithClassicDesktopLifetime(args);
14 |
15 | // Avalonia configuration, don't remove; also used by visual designer.
16 | public static AppBuilder BuildAvaloniaApp()
17 | => AppBuilder.Configure()
18 | .UsePlatformDetect()
19 | .LogToTrace();
20 | }
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL.OpenTK/Live2DCSharpSDK.OpenGL.OpenTK.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | enable
7 | enable
8 | true
9 |
10 |
11 |
12 | portable
13 |
14 |
15 | embedded
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL.OpenTK/Program.cs:
--------------------------------------------------------------------------------
1 | using OpenTK.Mathematics;
2 | using OpenTK.Windowing.Common;
3 | using OpenTK.Windowing.Desktop;
4 |
5 | namespace Live2DCSharpSDK.OpenTK;
6 |
7 | public static class Program
8 | {
9 | private static void Main()
10 | {
11 | var nativeWindowSettings = new NativeWindowSettings()
12 | {
13 | ClientSize = new Vector2i(600, 600),
14 | Title = "Live2D",
15 | // This is needed to run on macos
16 | Flags = ContextFlags.ForwardCompatible,
17 | Vsync = VSyncMode.Adaptive
18 | };
19 |
20 | using var window = new Window(GameWindowSettings.Default, nativeWindowSettings);
21 | window.Run();
22 | }
23 | }
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL.OpenTK/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "Live2DCSharpSDK.OpenTK": {
4 | "commandName": "Project",
5 | "nativeDebugging": true
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL.OpenTK/Window.cs:
--------------------------------------------------------------------------------
1 | using Live2DCSharpSDK.App;
2 | using Live2DCSharpSDK.Framework;
3 | using Live2DCSharpSDK.OpenGL;
4 | using OpenTK.Graphics.OpenGL4;
5 | using OpenTK.Windowing.Common;
6 | using OpenTK.Windowing.Desktop;
7 | using OpenTK.Windowing.GraphicsLibraryFramework;
8 | using ErrorCode = OpenTK.Graphics.OpenGL4.ErrorCode;
9 |
10 | namespace Live2DCSharpSDK.OpenTK;
11 |
12 | public class Window : GameWindow
13 | {
14 | private LAppDelegate lapp;
15 | public Window(GameWindowSettings gameWindowSettings, NativeWindowSettings nativeWindowSettings)
16 | : base(gameWindowSettings, nativeWindowSettings)
17 | {
18 | var version = GL.GetString(StringName.Version);
19 |
20 | var cubismAllocator = new LAppAllocator();
21 | var cubismOption = new CubismOption()
22 | {
23 | LogFunction = Console.WriteLine,
24 | LoggingLevel = LAppDefine.CubismLoggingLevel
25 | };
26 | CubismFramework.StartUp(cubismAllocator, cubismOption);
27 | }
28 |
29 | protected unsafe override void OnLoad()
30 | {
31 | base.OnLoad();
32 | lapp = new LAppDelegateOpenGL(new OpenTKApi(this))
33 | {
34 | BGColor = new(0, 1, 0, 1)
35 | };
36 |
37 | //var model = lapp.Live2dManager.LoadModel("F:\\live2d\\Resources\\Mao", "Mao");
38 | //model.ModelMatrix.TranslateX(0.9f);
39 |
40 | var model = lapp.Live2dManager.LoadModel("F:\\live2d\\Resources\\Haru\\", "Haru");
41 | //model.ModelMatrix.TranslateX(0.8f);
42 |
43 | //model = lapp.Live2dManager.LoadModel("E:\\code\\Live2DCSharpSDK\\Resources\\Haru\\", "Haru");
44 | //model.ModelMatrix.TranslateX(0.7f);
45 |
46 | //model = lapp.Live2dManager.LoadModel("E:\\code\\Live2DCSharpSDK\\Resources\\Haru\\", "Haru");
47 | //model.ModelMatrix.TranslateX(0.6f);
48 |
49 | //model = lapp.Live2dManager.LoadModel("E:\\code\\Live2DCSharpSDK\\Resources\\Haru\\", "Haru");
50 | //model.ModelMatrix.TranslateX(0.5f);
51 |
52 | //model = lapp.Live2dManager.LoadModel("E:\\code\\Live2DCSharpSDK\\Resources\\Haru\\", "Haru");
53 | //model.ModelMatrix.TranslateX(0.4f);
54 |
55 | //model = lapp.Live2dManager.LoadModel("E:\\code\\Live2DCSharpSDK\\Resources\\Haru\\", "Haru");
56 | //model.ModelMatrix.TranslateX(0.3f);
57 |
58 | //model = lapp.Live2dManager.LoadModel("E:\\code\\Live2DCSharpSDK\\Resources\\Haru\\", "Haru");
59 | //model.ModelMatrix.TranslateX(0.1f);
60 |
61 | //model = lapp.Live2dManager.LoadModel("E:\\code\\Live2DCSharpSDK\\Resources\\Haru\\", "Haru");
62 | //model.ModelMatrix.TranslateX(0.0f);
63 |
64 | //model = lapp.Live2dManager.LoadModel("E:\\code\\Live2DCSharpSDK\\Resources\\Hiyori\\", "Hiyori");
65 | //model.ModelMatrix.TranslateX(-0.0f);
66 |
67 | //model = lapp.Live2dManager.LoadModel("E:\\code\\Live2DCSharpSDK\\Resources\\Hiyori\\", "Hiyori");
68 | //model.ModelMatrix.TranslateX(-0.1f);
69 |
70 | //model = lapp.Live2dManager.LoadModel("E:\\code\\Live2DCSharpSDK\\Resources\\Hiyori\\", "Hiyori");
71 | //model.ModelMatrix.TranslateX(-0.2f);
72 |
73 | //model = lapp.Live2dManager.LoadModel("E:\\code\\Live2DCSharpSDK\\Resources\\Hiyori\\", "Hiyori");
74 | //model.ModelMatrix.TranslateX(-0.3f);
75 |
76 | //model = lapp.Live2dManager.LoadModel("E:\\code\\Live2DCSharpSDK\\Resources\\Hiyori\\", "Hiyori");
77 | //model.ModelMatrix.TranslateX(-0.4f);
78 |
79 | //model = lapp.Live2dManager.LoadModel("E:\\code\\Live2DCSharpSDK\\Resources\\Hiyori\\", "Hiyori");
80 | //model.ModelMatrix.TranslateX(-0.5f);
81 |
82 | //model = lapp.Live2dManager.LoadModel("E:\\code\\Live2DCSharpSDK\\Resources\\Hiyori\\", "Hiyori");
83 | //model.ModelMatrix.TranslateX(-0.6f);
84 |
85 | //model = lapp.Live2dManager.LoadModel("E:\\code\\Live2DCSharpSDK\\Resources\\Hiyori\\", "Hiyori");
86 | //model.ModelMatrix.TranslateX(-0.7f);
87 |
88 | //model = lapp.Live2dManager.LoadModel("E:\\code\\Live2DCSharpSDK\\Resources\\Hiyori\\", "Hiyori");
89 | //model.ModelMatrix.TranslateX(-0.8f);
90 |
91 | //model = lapp.Live2dManager.LoadModel("E:\\code\\Live2DCSharpSDK\\Resources\\Hiyori\\", "Hiyori");
92 | //model.ModelMatrix.TranslateX(-0.9f);
93 |
94 | //WindowT.SetFather(GLFW.GetWin32Window(WindowPtr));
95 | }
96 |
97 | protected override void OnRenderFrame(FrameEventArgs e)
98 | {
99 | base.OnRenderFrame(e);
100 |
101 | lapp.Run((float)UpdateTime);
102 |
103 | var code = GL.GetError();
104 | if (code != ErrorCode.NoError)
105 | {
106 | throw new Exception();
107 | }
108 |
109 | SwapBuffers();
110 | }
111 |
112 | protected override void OnResize(ResizeEventArgs e)
113 | {
114 | base.OnResize(e);
115 |
116 | lapp.Resize();
117 |
118 | GL.Viewport(0, 0, e.Width, e.Height);
119 | }
120 |
121 | protected override void OnUpdateFrame(FrameEventArgs e)
122 | {
123 | base.OnUpdateFrame(e);
124 |
125 | KeyboardState input = KeyboardState;
126 |
127 | if (input.IsKeyDown(Keys.Escape))
128 | {
129 | Close();
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL.WPF/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL.WPF/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace Live2DCSharpSDK.WPF
4 | {
5 | ///
6 | /// Interaction logic for App.xaml
7 | ///
8 | public partial class App : Application
9 | {
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL.WPF/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
11 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL.WPF/Live2DCSharpSDK.OpenGL.WPF.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | net8.0-windows
6 | enable
7 | enable
8 | true
9 | true
10 |
11 |
12 |
13 | portable
14 |
15 |
16 | embedded
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | PreserveNewest
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL.WPF/Live2DCSharpSDK.WPF.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Designer
7 |
8 |
9 |
10 |
11 | Designer
12 |
13 |
14 |
15 |
16 | PreserveNewest
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL.WPF/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL.WPF/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using Live2DCSharpSDK.App;
3 | using Live2DCSharpSDK.Framework;
4 | using Live2DCSharpSDK.OpenGL;
5 | using OpenTK.Graphics.OpenGL4;
6 | using OpenTK.Mathematics;
7 | using OpenTK.Wpf;
8 |
9 | namespace Live2DCSharpSDK.WPF;
10 |
11 | ///
12 | /// Interaction logic for MainWindow.xaml
13 | ///
14 | public partial class MainWindow : Window
15 | {
16 | GLWpfControl GLControl;
17 | private LAppDelegate lapp;
18 |
19 | public MainWindow()
20 | {
21 | InitializeComponent();
22 | GLControl = new();
23 |
24 | GLControl.SizeChanged += GLControl_Resized;
25 | GLControl.Render += GLControl_Render;
26 | BorderOpenTK.Child = GLControl;
27 | //CompositionTarget.Rendering += CompositionTarget_Rendering;
28 |
29 | var cubismAllocator = new LAppAllocator();
30 | var cubismOption = new CubismOption()
31 | {
32 | LogFunction = Console.WriteLine,
33 | LoggingLevel = LAppDefine.CubismLoggingLevel
34 | };
35 | CubismFramework.StartUp(cubismAllocator, cubismOption);
36 |
37 | var settings = new GLWpfControlSettings
38 | {
39 | MajorVersion = 3,
40 | MinorVersion = 3
41 | };
42 | GLControl.Start(settings);
43 | lapp = new LAppDelegateOpenGL(new OpenTKWPFApi(GLControl))
44 | {
45 | BGColor = new(0, 1, 0, 1)
46 | };
47 | var model = lapp.Live2dManager.LoadModel("F:\\live2d\\Resources\\Mao", "Mao");
48 | //model = lapp.Live2dManager.LoadModel("F:\\Downloads\\haru_greeter_pro_jp\\haru_greeter_pro_jp\\runtime", "haru_greeter_t05");
49 | }
50 |
51 | private void GLControl_Render(TimeSpan obj)
52 | {
53 | GL.ClearColor(Color4.Blue);
54 | GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
55 | lapp.Run((float)obj.TotalSeconds);
56 | }
57 |
58 | private void GLControl_Resized(object sender, SizeChangedEventArgs e)
59 | {
60 | if (lapp == null)
61 | return;
62 | lapp.Resize();
63 | GL.Viewport(0, 0, (int)GLControl.ActualWidth, (int)GLControl.ActualHeight);
64 | }
65 | }
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL/CubismClippingContext_OpenGLES2.cs:
--------------------------------------------------------------------------------
1 | using Live2DCSharpSDK.Framework.Model;
2 | using Live2DCSharpSDK.Framework.Rendering;
3 |
4 | namespace Live2DCSharpSDK.OpenGL;
5 |
6 | public unsafe class CubismClippingContext_OpenGLES2(CubismClippingManager manager, CubismModel model,
7 | int* clippingDrawableIndices, int clipCount) : CubismClippingContext(manager, clippingDrawableIndices, clipCount)
8 | {
9 |
10 | }
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL/CubismClippingManager_OpenGLES2.cs:
--------------------------------------------------------------------------------
1 | using Live2DCSharpSDK.Framework.Model;
2 | using Live2DCSharpSDK.Framework.Rendering;
3 | using Live2DCSharpSDK.Framework.Type;
4 |
5 | namespace Live2DCSharpSDK.OpenGL;
6 |
7 | public class CubismClippingManager_OpenGLES2(OpenGLApi gl) : CubismClippingManager
8 | {
9 | public override RenderType RenderType => RenderType.OpenGL;
10 |
11 | public override unsafe CubismClippingContext CreateClippingContext(CubismClippingManager manager, CubismModel model,
12 | int* clippingDrawableIndices, int clipCount)
13 | {
14 | return new CubismClippingContext_OpenGLES2(manager, model, clippingDrawableIndices, clipCount);
15 | }
16 |
17 | ///
18 | /// クリッピングコンテキストを作成する。モデル描画時に実行する。
19 | ///
20 | /// モデルのインスタンス
21 | /// レンダラのインスタンス
22 | /// フレームバッファ
23 | /// ビューポート
24 | internal unsafe void SetupClippingContext(CubismModel model, CubismRenderer_OpenGLES2 renderer, int lastFBO, int[] lastViewport)
25 | {
26 | // 全てのクリッピングを用意する
27 | // 同じクリップ(複数の場合はまとめて1つのクリップ)を使う場合は1度だけ設定する
28 | int usingClipCount = 0;
29 | for (int clipIndex = 0; clipIndex < ClippingContextListForMask.Count; clipIndex++)
30 | {
31 | // 1つのクリッピングマスクに関して
32 | var cc = ClippingContextListForMask[clipIndex];
33 |
34 | // このクリップを利用する描画オブジェクト群全体を囲む矩形を計算
35 | CalcClippedDrawTotalBounds(model, cc!);
36 |
37 | if (cc!.IsUsing)
38 | {
39 | usingClipCount++; //使用中としてカウント
40 | }
41 | }
42 |
43 | if (usingClipCount <= 0)
44 | {
45 | return;
46 | }
47 |
48 | // マスク作成処理
49 | // 生成したOffscreenSurfaceと同じサイズでビューポートを設定
50 | gl.Viewport(0, 0, (int)ClippingMaskBufferSize.X, (int)ClippingMaskBufferSize.Y);
51 |
52 | // 後の計算のためにインデックスの最初をセット
53 | CurrentMaskBuffer = renderer.GetMaskBuffer(0);
54 | var buffer = (CurrentMaskBuffer as CubismOffscreenSurface_OpenGLES2)!;
55 | // ----- マスク描画処理 -----
56 | buffer.BeginDraw(lastFBO);
57 |
58 | renderer.PreDraw(); // バッファをクリアする
59 |
60 | // 各マスクのレイアウトを決定していく
61 | SetupLayoutBounds(usingClipCount);
62 |
63 | // サイズがレンダーテクスチャの枚数と合わない場合は合わせる
64 | if (ClearedMaskBufferFlags.Count != RenderTextureCount)
65 | {
66 | ClearedMaskBufferFlags.Clear();
67 |
68 | for (int i = 0; i < RenderTextureCount; ++i)
69 | {
70 | ClearedMaskBufferFlags.Add(false);
71 | }
72 | }
73 | else
74 | {
75 | // マスクのクリアフラグを毎フレーム開始時に初期化
76 | for (int i = 0; i < RenderTextureCount; ++i)
77 | {
78 | ClearedMaskBufferFlags[i] = false;
79 | }
80 | }
81 |
82 | // 実際にマスクを生成する
83 | // 全てのマスクをどの様にレイアウトして描くかを決定し、ClipContext , ClippedDrawContext に記憶する
84 | for (int clipIndex = 0; clipIndex < ClippingContextListForMask.Count; clipIndex++)
85 | {
86 | // --- 実際に1つのマスクを描く ---
87 | var clipContext = ClippingContextListForMask[clipIndex];
88 | RectF allClippedDrawRect = clipContext!.AllClippedDrawRect; //このマスクを使う、全ての描画オブジェクトの論理座標上の囲み矩形
89 | RectF layoutBoundsOnTex01 = clipContext.LayoutBounds; //この中にマスクを収める
90 | float MARGIN = 0.05f;
91 |
92 | // clipContextに設定したオフスクリーンサーフェイスをインデックスで取得
93 | var clipContextOffscreenSurface = renderer.GetMaskBuffer(clipContext.BufferIndex);
94 |
95 | // 現在のオフスクリーンサーフェイスがclipContextのものと異なる場合
96 | if (CurrentMaskBuffer != clipContextOffscreenSurface)
97 | {
98 | buffer.EndDraw();
99 | CurrentMaskBuffer = clipContextOffscreenSurface;
100 | buffer = (CurrentMaskBuffer as CubismOffscreenSurface_OpenGLES2)!;
101 | // マスク用RenderTextureをactiveにセット
102 | buffer.BeginDraw(lastFBO);
103 |
104 | // バッファをクリアする。
105 | renderer.PreDraw();
106 | }
107 |
108 | // モデル座標上の矩形を、適宜マージンを付けて使う
109 | TmpBoundsOnModel.SetRect(allClippedDrawRect);
110 | TmpBoundsOnModel.Expand(allClippedDrawRect.Width * MARGIN, allClippedDrawRect.Height * MARGIN);
111 | //########## 本来は割り当てられた領域の全体を使わず必要最低限のサイズがよい
112 | // シェーダ用の計算式を求める。回転を考慮しない場合は以下のとおり
113 | // movePeriod' = movePeriod * scaleX + offX [[ movePeriod' = (movePeriod - tmpBoundsOnModel.movePeriod)*scale + layoutBoundsOnTex01.movePeriod ]]
114 | float scaleX = layoutBoundsOnTex01.Width / TmpBoundsOnModel.Width;
115 | float scaleY = layoutBoundsOnTex01.Height / TmpBoundsOnModel.Height;
116 |
117 | // マスク生成時に使う行列を求める
118 | CreateMatrixForMask(false, layoutBoundsOnTex01, scaleX, scaleY);
119 |
120 | clipContext.MatrixForMask.SetMatrix(TmpMatrixForMask.Tr);
121 | clipContext.MatrixForDraw.SetMatrix(TmpMatrixForDraw.Tr);
122 |
123 | // 実際の描画を行う
124 | int clipDrawCount = clipContext.ClippingIdCount;
125 | for (int i = 0; i < clipDrawCount; i++)
126 | {
127 | int clipDrawIndex = clipContext.ClippingIdList[i];
128 |
129 | // 頂点情報が更新されておらず、信頼性がない場合は描画をパスする
130 | if (!model.GetDrawableDynamicFlagVertexPositionsDidChange(clipDrawIndex))
131 | {
132 | continue;
133 | }
134 |
135 | renderer.IsCulling = model.GetDrawableCulling(clipDrawIndex);
136 |
137 | // マスクがクリアされていないなら処理する
138 | if (!ClearedMaskBufferFlags[clipContext.BufferIndex])
139 | {
140 | // マスクをクリアする
141 | // 1が無効(描かれない)領域、0が有効(描かれる)領域。(シェーダーCd*Csで0に近い値をかけてマスクを作る。1をかけると何も起こらない)
142 | gl.ClearColor(1.0f, 1.0f, 1.0f, 1.0f);
143 | gl.Clear(gl.GL_COLOR_BUFFER_BIT);
144 | ClearedMaskBufferFlags[clipContext.BufferIndex] = true;
145 | }
146 |
147 | // 今回専用の変換を適用して描く
148 | // チャンネルも切り替える必要がある(A,R,G,B)
149 | renderer.ClippingContextBufferForMask = clipContext;
150 |
151 | renderer.DrawMeshOpenGL(model, clipDrawIndex);
152 | }
153 | }
154 |
155 | // --- 後処理 ---
156 | buffer.EndDraw();
157 | renderer.ClippingContextBufferForMask = null;
158 | gl.Viewport(lastViewport[0], lastViewport[1], lastViewport[2], lastViewport[3]);
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL/CubismOffscreenSurface_OpenGLES2.cs:
--------------------------------------------------------------------------------
1 | using Live2DCSharpSDK.Framework.Rendering;
2 |
3 | namespace Live2DCSharpSDK.OpenGL;
4 |
5 | ///
6 | /// オフスクリーン描画用構造体
7 | ///
8 | public class CubismOffscreenSurface_OpenGLES2(OpenGLApi gl) : CubismOffscreenSurface
9 | {
10 | ///
11 | /// レンダリングターゲットとしてのアドレス
12 | ///
13 | public int RenderTexture { get; private set; }
14 | ///
15 | /// 描画の際使用するテクスチャとしてのアドレス
16 | ///
17 | public int ColorBuffer { get; private set; }
18 |
19 | ///
20 | /// 旧フレームバッファ
21 | ///
22 | private int _oldFBO;
23 |
24 | ///
25 | /// Create時に指定された幅
26 | ///
27 | public int BufferWidth { get; private set; }
28 | ///
29 | /// Create時に指定された高さ
30 | ///
31 | public int BufferHeight { get; private set; }
32 | ///
33 | /// 引数によって設定されたカラーバッファか?
34 | ///
35 | private bool _isColorBufferInherited;
36 |
37 | ///
38 | /// 指定の描画ターゲットに向けて描画開始
39 | ///
40 | /// 0以上の場合、EndDrawでこの値をglBindFramebufferする
41 | public void BeginDraw(int restoreFBO = -1)
42 | {
43 | if (RenderTexture == 0)
44 | {
45 | return;
46 | }
47 |
48 | // バックバッファのサーフェイスを記憶しておく
49 | if (restoreFBO < 0)
50 | {
51 | gl.GetIntegerv(gl.GL_FRAMEBUFFER_BINDING, out _oldFBO);
52 | }
53 | else
54 | {
55 | _oldFBO = restoreFBO;
56 | }
57 |
58 | //マスク用RenderTextureをactiveにセット
59 | gl.BindFramebuffer(gl.GL_FRAMEBUFFER, RenderTexture);
60 | }
61 |
62 | ///
63 | /// 描画終了
64 | ///
65 | public void EndDraw()
66 | {
67 | if (RenderTexture == 0)
68 | {
69 | return;
70 | }
71 |
72 | // 描画対象を戻す
73 | gl.BindFramebuffer(gl.GL_FRAMEBUFFER, _oldFBO);
74 | }
75 |
76 | ///
77 | /// レンダリングターゲットのクリア
78 | /// 呼ぶ場合はBeginDrawの後で呼ぶこと
79 | ///
80 | /// 赤(0.0~1.0)
81 | /// 緑(0.0~1.0)
82 | /// 青(0.0~1.0)
83 | /// α(0.0~1.0)
84 | public void Clear(float r, float g, float b, float a)
85 | {
86 | // マスクをクリアする
87 | gl.ClearColor(r, g, b, a);
88 | gl.Clear(gl.GL_COLOR_BUFFER_BIT);
89 | }
90 |
91 | ///
92 | /// CubismOffscreenFrame作成
93 | ///
94 | /// 作成するバッファ幅
95 | /// 作成するバッファ高さ
96 | /// 0以外の場合、ピクセル格納領域としてcolorBufferを使用する
97 | public unsafe bool CreateOffscreenSurface(int displayBufferWidth, int displayBufferHeight, int colorBuffer = 0)
98 | {
99 | // 一旦削除
100 | DestroyOffscreenSurface();
101 |
102 | // 新しく生成する
103 | if (colorBuffer == 0)
104 | {
105 | ColorBuffer = gl.GenTexture();
106 |
107 | gl.BindTexture(gl.GL_TEXTURE_2D, ColorBuffer);
108 | gl.TexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, displayBufferWidth, displayBufferHeight, 0, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, 0);
109 | gl.TexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE);
110 | gl.TexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP_TO_EDGE);
111 | gl.TexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR);
112 | gl.TexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR);
113 | gl.BindTexture(gl.GL_TEXTURE_2D, 0);
114 |
115 | _isColorBufferInherited = false;
116 | }
117 | else
118 | {
119 | // 指定されたものを使用
120 | ColorBuffer = colorBuffer;
121 |
122 | _isColorBufferInherited = true;
123 | }
124 |
125 | gl.GetIntegerv(gl.GL_FRAMEBUFFER_BINDING, out int tmpFramebufferObject);
126 |
127 | int ret = gl.GenFramebuffer();
128 | gl.BindFramebuffer(gl.GL_FRAMEBUFFER, ret);
129 | gl.FramebufferTexture2D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D, ColorBuffer, 0);
130 | gl.BindFramebuffer(gl.GL_FRAMEBUFFER, tmpFramebufferObject);
131 |
132 | RenderTexture = ret;
133 |
134 | BufferWidth = displayBufferWidth;
135 | BufferHeight = displayBufferHeight;
136 |
137 | // 成功
138 | return true;
139 | }
140 |
141 | ///
142 | /// CubismOffscreenFrameの削除
143 | ///
144 | public void DestroyOffscreenSurface()
145 | {
146 | if (!_isColorBufferInherited && (ColorBuffer != 0))
147 | {
148 | gl.DeleteTexture(ColorBuffer);
149 | ColorBuffer = 0;
150 | }
151 |
152 | if (RenderTexture != 0)
153 | {
154 | gl.DeleteFramebuffer(RenderTexture);
155 | RenderTexture = 0;
156 | }
157 | }
158 |
159 | ///
160 | /// 現在有効かどうか
161 | ///
162 | public bool IsValid()
163 | {
164 | return RenderTexture != 0;
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL/CubismShaderSet.cs:
--------------------------------------------------------------------------------
1 | namespace Live2DCSharpSDK.OpenGL;
2 |
3 | internal record CubismShaderSet
4 | {
5 | ///
6 | /// シェーダプログラムのアドレス
7 | ///
8 | internal int ShaderProgram;
9 | ///
10 | /// シェーダプログラムに渡す変数のアドレス(Position)
11 | ///
12 | internal int AttributePositionLocation;
13 | ///
14 | /// シェーダプログラムに渡す変数のアドレス(TexCoord)
15 | ///
16 | internal int AttributeTexCoordLocation;
17 | ///
18 | /// シェーダプログラムに渡す変数のアドレス(Matrix)
19 | ///
20 | internal int UniformMatrixLocation;
21 | ///
22 | /// シェーダプログラムに渡す変数のアドレス(ClipMatrix)
23 | ///
24 | internal int UniformClipMatrixLocation;
25 | ///
26 | /// シェーダプログラムに渡す変数のアドレス(Texture0)
27 | ///
28 | internal int SamplerTexture0Location;
29 | ///
30 | /// シェーダプログラムに渡す変数のアドレス(Texture1)
31 | ///
32 | internal int SamplerTexture1Location;
33 | ///
34 | /// シェーダプログラムに渡す変数のアドレス(BaseColor)
35 | ///
36 | internal int UniformBaseColorLocation;
37 | ///
38 | /// シェーダプログラムに渡す変数のアドレス(MultiplyColor)
39 | ///
40 | internal int UniformMultiplyColorLocation;
41 | ///
42 | /// シェーダプログラムに渡す変数のアドレス(ScreenColor)
43 | ///
44 | internal int UniformScreenColorLocation;
45 | ///
46 | /// シェーダプログラムに渡す変数のアドレス(ChannelFlag)
47 | ///
48 | internal int UnifromChannelFlagLocation;
49 | };
50 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL/LAppDelegateOpenGL.cs:
--------------------------------------------------------------------------------
1 | using Live2DCSharpSDK.App;
2 | using Live2DCSharpSDK.Framework.Model;
3 | using Live2DCSharpSDK.Framework.Rendering;
4 |
5 | namespace Live2DCSharpSDK.OpenGL;
6 |
7 | public class LAppDelegateOpenGL : LAppDelegate
8 | {
9 | public OpenGLApi GL { get; }
10 |
11 | public LAppDelegateOpenGL(OpenGLApi gl)
12 | {
13 | GL = gl;
14 |
15 | //テクスチャサンプリング設定
16 | GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
17 | GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
18 |
19 | //透過設定
20 | GL.Enable(GL.GL_BLEND);
21 | GL.BlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
22 |
23 | View = new LAppViewOpenGL(this);
24 |
25 | InitApp();
26 | }
27 |
28 | public override void GetWindowSize(out int width, out int height)
29 | {
30 | GL.GetWindowSize(out width, out height);
31 | }
32 |
33 | public override bool RunPre()
34 | {
35 | // 画面の初期化
36 | GL.ClearColor(BGColor.R, BGColor.G, BGColor.B, BGColor.A);
37 | GL.Clear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
38 | GL.ClearDepthf(1.0f);
39 |
40 | return false;
41 | }
42 |
43 | public override CubismRenderer CreateRenderer(CubismModel model)
44 | {
45 | return new CubismRenderer_OpenGLES2(GL, this, model);
46 | }
47 |
48 | public override TextureInfo CreateTexture(LAppModel model, int index, int width, int height, nint data)
49 | {
50 | int textureId = GL.GenTexture();
51 | GL.BindTexture(GL.GL_TEXTURE_2D, textureId);
52 | GL.TexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, width, height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, data);
53 | GL.GenerateMipmap(GL.GL_TEXTURE_2D);
54 | GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_LINEAR);
55 | GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
56 | GL.BindTexture(GL.GL_TEXTURE_2D, 0);
57 |
58 | (model.Renderer as CubismRenderer_OpenGLES2)?.BindTexture(index, textureId);
59 |
60 | return new TextureInfoOpenGL(GL)
61 | {
62 | Id = textureId
63 | };
64 | }
65 |
66 | public override void RunPost()
67 | {
68 |
69 | }
70 |
71 | public override void OnUpdatePre()
72 | {
73 |
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL/LAppViewOpenGL.cs:
--------------------------------------------------------------------------------
1 | using Live2DCSharpSDK.App;
2 |
3 | namespace Live2DCSharpSDK.OpenGL;
4 |
5 | public class LAppViewOpenGL(LAppDelegate lapp) : LAppView(lapp)
6 | {
7 | public override void RenderPost()
8 | {
9 |
10 | }
11 |
12 | public override void RenderPre()
13 | {
14 |
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL/Live2DCSharpSDK.OpenGL.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 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL/ShaderNames.cs:
--------------------------------------------------------------------------------
1 | namespace Live2DCSharpSDK.OpenGL;
2 |
3 | public enum ShaderNames : int
4 | {
5 | // SetupMask
6 | SetupMask,
7 |
8 | //Normal
9 | Normal,
10 | NormalMasked,
11 | NormalMaskedInverted,
12 | NormalPremultipliedAlpha,
13 | NormalMaskedPremultipliedAlpha,
14 | NormalMaskedInvertedPremultipliedAlpha,
15 |
16 | //Add
17 | Add,
18 | AddMasked,
19 | AddMaskedInverted,
20 | AddPremultipliedAlpha,
21 | AddMaskedPremultipliedAlpha,
22 | AddMaskedPremultipliedAlphaInverted,
23 |
24 | //Mult
25 | Mult,
26 | MultMasked,
27 | MultMaskedInverted,
28 | MultPremultipliedAlpha,
29 | MultMaskedPremultipliedAlpha,
30 | MultMaskedPremultipliedAlphaInverted,
31 | };
--------------------------------------------------------------------------------
/Live2DCSharpSDK.OpenGL/TextureInfoOpenGL.cs:
--------------------------------------------------------------------------------
1 | using Live2DCSharpSDK.App;
2 |
3 | namespace Live2DCSharpSDK.OpenGL;
4 |
5 | public class TextureInfoOpenGL(OpenGLApi api) : TextureInfo
6 | {
7 | public override void Dispose()
8 | {
9 | api.DeleteTexture(Id);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan.Silk/Live2DCSharpSDK.Vulkan.Silk.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | enable
7 | enable
8 | true
9 |
10 |
11 |
12 | portable
13 |
14 |
15 | embedded
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan.Silk/Program.cs:
--------------------------------------------------------------------------------
1 | using Live2DCSharpSDK.App;
2 | using Live2DCSharpSDK.Framework;
3 | using Live2DCSharpSDK.Vulkan;
4 | using Silk.NET.Core.Native;
5 | using Silk.NET.Maths;
6 | using Silk.NET.Vulkan;
7 | using Silk.NET.Windowing;
8 |
9 | namespace Live2DCSharpSDK.Silk.Vulkan;
10 |
11 | internal class Program : VulkanApi
12 | {
13 | private IWindow window;
14 | private Vk vk;
15 |
16 | static void Main(string[] args)
17 | {
18 | var cubismAllocator = new LAppAllocator();
19 | var cubismOption = new CubismOption()
20 | {
21 | LogFunction = Console.WriteLine,
22 | LoggingLevel = LAppDefine.CubismLoggingLevel
23 | };
24 | CubismFramework.StartUp(cubismAllocator, cubismOption);
25 |
26 | new Program().InitWindow();
27 | }
28 |
29 | public override unsafe VkNonDispatchableHandle CreateSurface(VkHandle handle, T* handel1)
30 | {
31 | return window.VkSurface!.Create(handle, handel1);
32 | }
33 |
34 | public override unsafe byte** GetRequiredExtensions(out uint count)
35 | {
36 | return window.VkSurface!.GetRequiredExtensions(out count);
37 | }
38 |
39 | public override void GetWindowSize(out int width, out int height)
40 | {
41 | width = window.FramebufferSize.X;
42 | height = window.FramebufferSize.Y;
43 | }
44 |
45 | private void InitWindow()
46 | {
47 | //Create a window.
48 | var options = WindowOptions.DefaultVulkan with
49 | {
50 | Size = new Vector2D(400, 400),
51 | Title = "Vulkan",
52 | };
53 |
54 | window = Window.Create(options);
55 | window.Initialize();
56 |
57 | if (window.VkSurface is null)
58 | {
59 | throw new Exception("Windowing platform doesn't support Vulkan.");
60 | }
61 | vk = Vk.GetApi();
62 | var live2d = new LAppDelegateVulkan(this)
63 | {
64 | BGColor = new(0, 1, 0, 1)
65 | };
66 |
67 | var model = live2d.Live2dManager.LoadModel("F:\\live2d\\Resources\\Haru\\", "Haru");
68 |
69 | window.Resize += (size) =>
70 | {
71 | live2d.Resize();
72 | };
73 | window.Render += (time) =>
74 | {
75 | live2d.Run((float)time);
76 | };
77 | window.Run();
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/.gitignore:
--------------------------------------------------------------------------------
1 | /spv
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/Blend.cs:
--------------------------------------------------------------------------------
1 | namespace Live2DCSharpSDK.Vulkan;
2 |
3 | public static class Blend
4 | {
5 | public const int Normal = 0;
6 | public const int Add = 1;
7 | public const int Mult = 2;
8 | public const int Mask = 3;
9 | };
10 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/CubismBufferVulkan.cs:
--------------------------------------------------------------------------------
1 | using Live2DCSharpSDK.Framework;
2 | using Silk.NET.Vulkan;
3 |
4 | using Buffer = Silk.NET.Vulkan.Buffer;
5 |
6 | namespace Live2DCSharpSDK.Vulkan;
7 |
8 | ///
9 | /// バッファを扱うクラス
10 | ///
11 | ///
12 | public class CubismBufferVulkan(Vk vk)
13 | {
14 | //VkDeviceSize ulong
15 |
16 | ///
17 | /// バッファ
18 | ///
19 | public Buffer Buffer => _buffer;
20 |
21 | private Buffer _buffer;
22 |
23 | ///
24 | /// メモリ
25 | ///
26 | private DeviceMemory _memory;
27 | ///
28 | /// マップ領域へのアドレス
29 | ///
30 | private unsafe void* _mapped;
31 |
32 | ///
33 | /// 物理デバイスのメモリタイプのインデックスを探す
34 | ///
35 | /// 物理デバイス
36 | /// メモリタイプが存在していたら設定されるビットマスク
37 | /// メモリがデバイスにアクセスするときのタイプ
38 | ///
39 | public unsafe int FindMemoryType(PhysicalDevice physicalDevice, uint typeFilter, MemoryPropertyFlags properties)
40 | {
41 | vk.GetPhysicalDeviceMemoryProperties(physicalDevice, out var memProperties);
42 |
43 | for (int i = 0; i < memProperties.MemoryTypeCount; i++)
44 | {
45 | if ((typeFilter & (1 << i)) != 0
46 | && (memProperties.MemoryTypes[i].PropertyFlags & properties) == properties)
47 | {
48 | return i;
49 | }
50 | }
51 | CubismLog.Error("[Live2D Vulkan]failed to find suitable memory type!");
52 | return 0;
53 | }
54 |
55 | ///
56 | /// バッファを作成する
57 | ///
58 | /// デバイス
59 | /// 物理デバイス
60 | /// バッファサイズ
61 | /// バッファの使用法を指定するビットマスク
62 | /// メモリがデバイスにアクセスする際のタイプ
63 | public unsafe void CreateBuffer(Device device, PhysicalDevice physicalDevice, ulong size, BufferUsageFlags usage,
64 | MemoryPropertyFlags properties)
65 | {
66 | var bufferInfo = new BufferCreateInfo()
67 | {
68 | SType = StructureType.BufferCreateInfo,
69 | Size = size,
70 | Usage = usage,
71 | SharingMode = SharingMode.Exclusive
72 | };
73 |
74 | if (vk.CreateBuffer(device, ref bufferInfo, null, out _buffer) != Result.Success)
75 | {
76 | CubismLog.Error("[Live2D Vulkan]failed to create buffer!");
77 | }
78 |
79 | vk.GetBufferMemoryRequirements(device, _buffer, out var memRequirements);
80 |
81 | var allocInfo = new MemoryAllocateInfo()
82 | {
83 | SType = StructureType.MemoryAllocateInfo,
84 | AllocationSize = memRequirements.Size,
85 | MemoryTypeIndex = (uint)FindMemoryType(physicalDevice, memRequirements.MemoryTypeBits, properties)
86 | };
87 | if (vk.AllocateMemory(device, ref allocInfo, null, out _memory) != Result.Success)
88 | {
89 | CubismLog.Error("[Live2D Vulkan]failed to allocate buffer memory!");
90 | }
91 | vk.BindBufferMemory(device, _buffer, _memory, 0);
92 | }
93 |
94 | ///
95 | /// メモリをアドレス空間にマップし、そのアドレスポインタを取得する
96 | ///
97 | /// デバイス
98 | /// マップするサイズ
99 | public unsafe void Map(Device device, ulong size)
100 | {
101 | vk.MapMemory(device, _memory, 0, size, 0, ref _mapped);
102 | }
103 |
104 | ///
105 | /// メモリブロックをコピーする
106 | ///
107 | /// コピーするデータ
108 | /// コピーするサイズ
109 | public unsafe void MemCpy(void* src, ulong size)
110 | {
111 | System.Buffer.MemoryCopy(src, _mapped, size, size);
112 | }
113 |
114 | ///
115 | /// リソースを破棄する
116 | ///
117 | /// デバイス
118 | public void UnMap(Device device)
119 | {
120 | vk.UnmapMemory(device, _memory);
121 | }
122 |
123 | public unsafe void Destroy(Device device)
124 | {
125 | vk.DestroyBuffer(device, Buffer, null);
126 | vk.FreeMemory(device, _memory, null);
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/CubismClippingContext_Vulkan.cs:
--------------------------------------------------------------------------------
1 | using Live2DCSharpSDK.Framework.Rendering;
2 |
3 | namespace Live2DCSharpSDK.Vulkan;
4 |
5 | public unsafe class CubismClippingContext_Vulkan(CubismClippingManager manager, int* clippingDrawableIndices, int clipCount)
6 | : CubismClippingContext(manager, clippingDrawableIndices, clipCount)
7 | {
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/CubismClippingManager_Vulkan.cs:
--------------------------------------------------------------------------------
1 | using Live2DCSharpSDK.Framework.Model;
2 | using Live2DCSharpSDK.Framework.Rendering;
3 | using Silk.NET.Vulkan;
4 |
5 | namespace Live2DCSharpSDK.Vulkan;
6 |
7 | public class CubismClippingManager_Vulkan(Vk vk) : CubismClippingManager
8 | {
9 | public override RenderType RenderType => RenderType.Vulkan;
10 |
11 | public override unsafe CubismClippingContext CreateClippingContext(CubismClippingManager manager,
12 | CubismModel model, int* clippingDrawableIndices, int clipCount)
13 | {
14 | return new CubismClippingContext_Vulkan(manager, clippingDrawableIndices, clipCount);
15 | }
16 |
17 | ///
18 | /// クリッピングコンテキストを作成する。モデル描画時に実行する。
19 | ///
20 | /// モデルのインスタンス
21 | /// コマンドバッファ
22 | /// 更新用コマンドバッファ
23 | /// レンダラのインスタンス
24 | public unsafe void SetupClippingContext(CubismModel model, CommandBuffer commandBuffer, CommandBuffer updateCommandBuffer,
25 | CubismRenderer_Vulkan renderer)
26 | {
27 | // 全てのクリッピングを用意する
28 | // 同じクリップ(複数の場合はまとめて1つのクリップ)を使う場合は1度だけ設定する
29 | int usingClipCount = 0;
30 |
31 | for (int clipIndex = 0; clipIndex < ClippingContextListForMask.Count; clipIndex++)
32 | {
33 | // 1つのクリッピングマスクに関して
34 | var cc = ClippingContextListForMask[clipIndex];
35 |
36 | // このクリップを利用する描画オブジェクト群全体を囲む矩形を計算
37 | CalcClippedDrawTotalBounds(model, cc);
38 |
39 | if (cc.IsUsing)
40 | {
41 | usingClipCount++; //使用中としてカウント
42 | }
43 | }
44 |
45 | if (usingClipCount <= 0)
46 | {
47 | return;
48 | }
49 |
50 | // マスク作成処理
51 | // 後の計算のためにインデックスの最初をセット
52 | CurrentMaskBuffer = renderer.GetMaskBuffer(0);
53 |
54 | var buffer = (CurrentMaskBuffer as CubismOffscreenSurface_Vulkan)!;
55 |
56 | // 1が無効(描かれない)領域、0が有効(描かれる)領域。(シェーダで Cd*Csで0に近い値をかけてマスクを作る。1をかけると何も起こらない)
57 | buffer.BeginDraw(commandBuffer, 1.0f, 1.0f, 1.0f, 1.0f);
58 |
59 | // 生成したFrameBufferと同じサイズでビューポートを設定
60 | var viewport = CubismRenderer_Vulkan.GetViewport(ClippingMaskBufferSize.X, ClippingMaskBufferSize.Y, 0.0f, 1.0f);
61 | vk.CmdSetViewport(commandBuffer, 0, 1, &viewport);
62 | var rect = CubismRenderer_Vulkan.GetScissor(0.0f, 0.0f, ClippingMaskBufferSize.X, ClippingMaskBufferSize.Y);
63 | vk.CmdSetScissor(commandBuffer, 0, 1, &rect);
64 |
65 | // 各マスクのレイアウトを決定していく
66 | SetupLayoutBounds(usingClipCount);
67 |
68 | // サイズがレンダーテクスチャの枚数と合わない場合は合わせる
69 | if (ClearedMaskBufferFlags.Count != RenderTextureCount)
70 | {
71 | ClearedMaskBufferFlags.Clear();
72 |
73 | for (int i = 0; i < RenderTextureCount; ++i)
74 | {
75 | ClearedMaskBufferFlags.Add(false);
76 | }
77 | }
78 | else
79 | {
80 | // マスクのクリアフラグを毎フレーム開始時に初期化
81 | for (int i = 0; i < RenderTextureCount; ++i)
82 | {
83 | ClearedMaskBufferFlags[i] = false;
84 | }
85 | }
86 |
87 | // 実際にマスクを生成する
88 | // 全てのマスクをどの様にレイアウトして描くかを決定し、ClipContext , ClippedDrawContext に記憶する
89 | for (int clipIndex = 0; clipIndex < ClippingContextListForMask.Count; clipIndex++)
90 | {
91 | // --- 実際に1つのマスクを描く ---
92 | var clipContext = (ClippingContextListForMask[clipIndex] as CubismClippingContext_Vulkan)!;
93 | var allClippedDrawRect = clipContext.AllClippedDrawRect; //このマスクを使う、全ての描画オブジェクトの論理座標上の囲み矩形
94 | var layoutBoundsOnTex01 = clipContext.LayoutBounds; //この中にマスクを収める
95 | var MARGIN = 0.05f;
96 |
97 | // clipContextに設定したオフスクリーンサーフェイスをインデックスで取得
98 | var clipContextOffscreenSurface = renderer.GetMaskBuffer(clipContext.BufferIndex)!;
99 |
100 | // 現在のオフスクリーンサーフェイスがclipContextのものと異なる場合
101 | if (CurrentMaskBuffer != clipContextOffscreenSurface)
102 | {
103 | buffer.EndDraw(commandBuffer);
104 | CurrentMaskBuffer = clipContextOffscreenSurface;
105 | buffer = (CurrentMaskBuffer as CubismOffscreenSurface_Vulkan)!;
106 | // マスク用RenderTextureをactiveにセット
107 | buffer.BeginDraw(commandBuffer, 1.0f, 1.0f, 1.0f, 1.0f);
108 | }
109 |
110 | // モデル座標上の矩形を、適宜マージンを付けて使う
111 | TmpBoundsOnModel.SetRect(allClippedDrawRect);
112 | TmpBoundsOnModel.Expand(allClippedDrawRect.Width * MARGIN, allClippedDrawRect.Height * MARGIN);
113 | //########## 本来は割り当てられた領域の全体を使わず必要最低限のサイズがよい
114 | // シェーダ用の計算式を求める。回転を考慮しない場合は以下のとおり
115 | // movePeriod' = movePeriod * scaleX + offX [[ movePeriod' = (movePeriod - tmpBoundsOnModel.movePeriod)*scale + layoutBoundsOnTex01.movePeriod ]]
116 | var scaleX = layoutBoundsOnTex01.Width / TmpBoundsOnModel.Width;
117 | var scaleY = layoutBoundsOnTex01.Height / TmpBoundsOnModel.Height;
118 |
119 | // マスク生成時に使う行列を求める
120 | CreateMatrixForMask(false, layoutBoundsOnTex01, scaleX, scaleY);
121 |
122 | clipContext.MatrixForMask.SetMatrix(TmpMatrixForMask);
123 | clipContext.MatrixForDraw.SetMatrix(TmpMatrixForDraw);
124 |
125 | // 実際の描画を行う
126 | int clipDrawCount = clipContext.ClippingIdCount;
127 | for (int i = 0; i < clipDrawCount; i++)
128 | {
129 | int clipDrawIndex = clipContext.ClippingIdList[i];
130 |
131 | // 頂点情報が更新されておらず、信頼性がない場合は描画をパスする
132 | if (!model.GetDrawableDynamicFlagVertexPositionsDidChange(clipDrawIndex))
133 | {
134 | continue;
135 | }
136 |
137 | renderer.IsCulling = model.GetDrawableCulling(clipDrawIndex);
138 |
139 | // レンダーパス開始時にマスクはクリアされているのでクリアする必要なし
140 | // 今回専用の変換を適用して描く
141 | // チャンネルも切り替える必要がある(A,R,G,B)
142 | renderer.ClippingContextBufferForMask = clipContext;
143 | renderer.DrawMeshVulkan(model, clipDrawIndex, commandBuffer, updateCommandBuffer);
144 | }
145 | }
146 | // --- 後処理 ---
147 | buffer.EndDraw(commandBuffer);
148 | renderer.ClippingContextBufferForMask = null;
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/CubismPipeline_Vulkan.cs:
--------------------------------------------------------------------------------
1 | using Silk.NET.Vulkan;
2 |
3 | namespace Live2DCSharpSDK.Vulkan;
4 |
5 | public class CubismPipeline_Vulkan(Vk vk, Device device)
6 | {
7 | private const int ShaderCount = 19;
8 | private PipelineResource[] _pipelineResource;
9 | ///
10 | /// シェーダーごとにPipelineResourceのインスタンスを作成する
11 | ///
12 | /// ディスクリプタセットレイアウト
13 | public void CreatePipelines(DescriptorSetLayout descriptorSetLayout)
14 | {
15 | //パイプラインを作成済みの場合は生成する必要なし
16 | if (_pipelineResource != null)
17 | {
18 | return;
19 | }
20 |
21 | _pipelineResource = new PipelineResource[ShaderCount];
22 |
23 | for (int a = 0; a < 7; a++)
24 | {
25 | _pipelineResource[a] = new(vk, device);
26 | }
27 |
28 | _pipelineResource[0].CreateGraphicsPipeline("VertShaderSrcSetupMask.spv", "FragShaderSrcSetupMask.spv", descriptorSetLayout);
29 | _pipelineResource[1].CreateGraphicsPipeline("VertShaderSrc.spv", "FragShaderSrc.spv", descriptorSetLayout);
30 | _pipelineResource[2].CreateGraphicsPipeline("VertShaderSrcMasked.spv", "FragShaderSrcMask.spv", descriptorSetLayout);
31 | _pipelineResource[3].CreateGraphicsPipeline("VertShaderSrcMasked.spv", "FragShaderSrcMaskInverted.spv", descriptorSetLayout);
32 | _pipelineResource[4].CreateGraphicsPipeline("VertShaderSrc.spv", "FragShaderSrcPremultipliedAlpha.spv", descriptorSetLayout);
33 | _pipelineResource[5].CreateGraphicsPipeline("VertShaderSrcMasked.spv", "FragShaderSrcMaskPremultipliedAlpha.spv", descriptorSetLayout);
34 | _pipelineResource[6].CreateGraphicsPipeline("VertShaderSrcMasked.spv", "FragShaderSrcMaskInvertedPremultipliedAlpha.spv", descriptorSetLayout);
35 |
36 | _pipelineResource[7] = _pipelineResource[1];
37 | _pipelineResource[8] = _pipelineResource[2];
38 | _pipelineResource[9] = _pipelineResource[3];
39 | _pipelineResource[10] = _pipelineResource[4];
40 | _pipelineResource[11] = _pipelineResource[5];
41 | _pipelineResource[12] = _pipelineResource[6];
42 |
43 | _pipelineResource[13] = _pipelineResource[1];
44 | _pipelineResource[14] = _pipelineResource[2];
45 | _pipelineResource[15] = _pipelineResource[3];
46 | _pipelineResource[16] = _pipelineResource[4];
47 | _pipelineResource[17] = _pipelineResource[5];
48 | _pipelineResource[18] = _pipelineResource[6];
49 | }
50 |
51 | ///
52 | /// 指定したシェーダーのグラフィックスパイプラインを取得する
53 | ///
54 | /// シェーダインデックス
55 | /// ブレンドモードのインデックス
56 | /// 指定したシェーダーのグラフィックスパイプライン
57 | public Pipeline GetPipeline(int shaderIndex, int blendIndex)
58 | {
59 | return _pipelineResource[shaderIndex].GetPipeline(blendIndex);
60 | }
61 |
62 | ///
63 | /// 指定したブレンド方法のパイプラインレイアウトを取得する
64 | ///
65 | /// シェーダインデックス
66 | /// ブレンドモードのインデックス
67 | /// 指定したブレンド方法のパイプラインレイアウト
68 | public PipelineLayout GetPipelineLayout(int shaderIndex, int blendIndex)
69 | {
70 | return _pipelineResource[shaderIndex].GetPipelineLayout(blendIndex);
71 | }
72 |
73 | ///
74 | /// リソースを開放する
75 | ///
76 | public void ReleaseShaderProgram()
77 | {
78 | for (int i = 0; i < 7; i++)
79 | {
80 | _pipelineResource[i].Release();
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/Descriptor.cs:
--------------------------------------------------------------------------------
1 | using Silk.NET.Vulkan;
2 |
3 | namespace Live2DCSharpSDK.Vulkan;
4 |
5 | ///
6 | /// ディスクリプタセットとUBOを保持する構造体コマンドバッファでまとめて描画する場合、ディスクリプタセットをバインド後に更新してはならない。
7 | ///
8 | /// マスクされる描画対象のみ、フレームバッファをディスクリプタセットに設定する必要があるが、その際バインド済みのディスクリプタセットを更新しないよう、別でマスクされる用のディスクリプタセットを用意する。
9 | ///
10 | public class Descriptor
11 | {
12 | ///
13 | /// ユニフォームバッファ
14 | ///
15 | public CubismBufferVulkan UniformBuffer;
16 | ///
17 | /// ディスクリプタセット
18 | ///
19 | public DescriptorSet DescriptorSet;
20 | ///
21 | /// ディスクリプタセットが更新されたか
22 | ///
23 | public bool IsDescriptorSetUpdated;
24 | ///
25 | /// マスクされる描画対象用のディスクリプタセット
26 | ///
27 | public DescriptorSet DescriptorSetMasked;
28 | ///
29 | /// マスクされる描画対象用のディスクリプタセットが更新されたか
30 | ///
31 | public bool IsDescriptorSetMaskedUpdated;
32 | }
33 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/LAppDelegateVulkan.cs:
--------------------------------------------------------------------------------
1 | using Live2DCSharpSDK.App;
2 | using Live2DCSharpSDK.Framework.Model;
3 | using Live2DCSharpSDK.Framework.Rendering;
4 | using Silk.NET.Vulkan;
5 |
6 | namespace Live2DCSharpSDK.Vulkan;
7 |
8 | public class LAppDelegateVulkan : LAppDelegate
9 | {
10 | public readonly VulkanApi _api;
11 | public readonly Vk _vk;
12 | public readonly VulkanManager VulkanManager;
13 |
14 | public LAppDelegateVulkan(VulkanApi api)
15 | {
16 | _api = api;
17 | _vk = Vk.GetApi();
18 |
19 | VulkanManager = new VulkanManager(this, _vk, _api);
20 | VulkanManager.Initialize();
21 |
22 | var swapchainManager = VulkanManager.SwapchainManager;
23 | // レンダラにvulkanManagerの変数を渡す
24 | CubismRenderer_Vulkan.InitializeConstantSettings(
25 | VulkanManager.Device, VulkanManager.PhysicalDevice,
26 | VulkanManager.CommandPool, VulkanManager.GraphicQueue,
27 | swapchainManager.Extent, swapchainManager.SwapchainFormat,
28 | VulkanManager.SurfaceFormat,
29 | VulkanManager.GetSwapchainImage(), VulkanManager.GetSwapchainImageView(),
30 | VulkanManager.DepthFormat
31 | );
32 |
33 | View = new LAppViewVulkan(this);
34 | InitApp();
35 | }
36 |
37 | public new void Resize()
38 | {
39 | VulkanManager.FramebufferResized = true;
40 | base.Resize();
41 | }
42 |
43 | public override CubismRenderer CreateRenderer(CubismModel model)
44 | {
45 | return new CubismRenderer_Vulkan(_vk, VulkanManager, model);
46 | }
47 |
48 | public override TextureInfo CreateTexture(LAppModel model, int index, int width, int height, nint data)
49 | {
50 | _vk.DeviceWaitIdle(VulkanManager.Device);
51 |
52 | return new TextureInfoVulkan(_vk, this, model, VulkanManager.SurfaceFormat, ImageTiling.Optimal,
53 | ImageUsageFlags.TransferSrcBit | ImageUsageFlags.TransferDstBit | ImageUsageFlags.SampledBit,
54 | (uint)width, (uint)height, data);
55 | }
56 |
57 | public override void GetWindowSize(out int width, out int height)
58 | {
59 | _api.GetWindowSize(out width, out height);
60 | }
61 |
62 | public override void OnUpdatePre()
63 | {
64 | CubismRenderer_Vulkan.UpdateRendererSettings(VulkanManager.GetSwapchainImage(), VulkanManager.GetSwapchainImageView());
65 | }
66 |
67 | public override void RunPost()
68 | {
69 | VulkanManager.PostDraw();
70 | RecreateSwapchain();
71 | }
72 |
73 | public override bool RunPre()
74 | {
75 | VulkanManager.UpdateDrawFrame();
76 |
77 | return RecreateSwapchain();
78 | }
79 |
80 | private bool RecreateSwapchain()
81 | {
82 | if (VulkanManager.IsSwapchainInvalid)
83 | {
84 | GetWindowSize(out var width, out var height);
85 | if (width == 0 || height == 0)
86 | {
87 | return true;
88 | }
89 |
90 | VulkanManager.RecreateSwapchain();
91 | CubismRenderer_Vulkan.UpdateSwapchainVariable(
92 | VulkanManager.SwapchainManager.Extent,
93 | VulkanManager.GetSwapchainImage(),
94 | VulkanManager.GetSwapchainImageView()
95 | );
96 |
97 | // AppViewの初期化
98 | View.Initialize();
99 | // サイズを保存しておく
100 | WindowWidth = width;
101 | WindowHeight = height;
102 | VulkanManager.IsSwapchainInvalid = false;
103 | return true;
104 | }
105 | return false;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/LAppViewVulkan.cs:
--------------------------------------------------------------------------------
1 | using Live2DCSharpSDK.App;
2 | using Silk.NET.Vulkan;
3 |
4 | namespace Live2DCSharpSDK.Vulkan;
5 |
6 | public class LAppViewVulkan(LAppDelegateVulkan lapp) : LAppView(lapp)
7 | {
8 | public override void RenderPost()
9 | {
10 |
11 | }
12 |
13 | public override unsafe void RenderPre()
14 | {
15 | var vkManager = lapp.VulkanManager;
16 | var commandBuffer = vkManager.BeginSingleTimeCommands();
17 |
18 | var color = lapp.BGColor;
19 |
20 | var colorAttachment = new RenderingAttachmentInfo
21 | {
22 | SType = StructureType.RenderingAttachmentInfoKhr,
23 | ImageView = vkManager.GetSwapchainImageView(),
24 | ImageLayout = ImageLayout.AttachmentOptimal,
25 | LoadOp = AttachmentLoadOp.Clear,
26 | StoreOp = AttachmentStoreOp.Store,
27 | ClearValue = new()
28 | {
29 | Color = new(color.R, color.G, color.B, color.A)
30 | }
31 | };
32 |
33 | var renderingInfo = new RenderingInfo
34 | {
35 | SType = StructureType.RenderingInfo,
36 | RenderArea = new(new(0, 0), vkManager.SwapchainManager.Extent),
37 | LayerCount = 1,
38 | ColorAttachmentCount = 1,
39 | PColorAttachments = &colorAttachment
40 | };
41 |
42 | lapp._vk.CmdBeginRendering(commandBuffer, &renderingInfo);
43 | lapp._vk.CmdEndRendering(commandBuffer);
44 | vkManager.SubmitCommand(commandBuffer, true);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/Live2DCSharpSDK.Vulkan.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 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/ModelUBO.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Live2DCSharpSDK.Vulkan;
4 |
5 | ///
6 | /// モデル用ユニフォームバッファオブジェクトの中身を保持する構造体
7 | ///
8 | [StructLayout(LayoutKind.Sequential)]
9 | public unsafe struct ModelUBO
10 | {
11 | ///
12 | /// シェーダープログラムに渡すデータ(ProjectionMatrix)
13 | ///
14 | public fixed float ProjectionMatrix[16];
15 | ///
16 | /// シェーダープログラムに渡すデータ(ClipMatrix)
17 | ///
18 | public fixed float ClipMatrix[16];
19 | ///
20 | /// シェーダープログラムに渡すデータ(BaseColor)
21 | ///
22 | public fixed float BaseColor[4];
23 | ///
24 | /// シェーダープログラムに渡すデータ(MultiplyColor)
25 | ///
26 | public fixed float MultiplyColor[4];
27 | ///
28 | /// シェーダープログラムに渡すデータ(ScreenColor)
29 | ///
30 | public fixed float ScreenColor[4];
31 | ///
32 | /// シェーダープログラムに渡すデータ(ChannelFlag)
33 | ///
34 | public fixed float ChannelFlag[4];
35 | }
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/ModelVertex.cs:
--------------------------------------------------------------------------------
1 | using System.Numerics;
2 | using System.Runtime.InteropServices;
3 | using Silk.NET.Vulkan;
4 |
5 | namespace Live2DCSharpSDK.Vulkan;
6 |
7 | [StructLayout(LayoutKind.Sequential)]
8 | public struct ModelVertex
9 | {
10 | ///
11 | /// Position
12 | ///
13 | public Vector2 Pos;
14 | ///
15 | /// UVs
16 | ///
17 | public Vector2 TexCoord;
18 |
19 | public static VertexInputBindingDescription GetBindingDescription()
20 | {
21 | return new()
22 | {
23 | Binding = 0,
24 | Stride = (uint)Marshal.SizeOf(),
25 | InputRate = VertexInputRate.Vertex
26 | };
27 | }
28 |
29 | public static unsafe void GetAttributeDescriptions(VertexInputAttributeDescription* attributeDescriptions)
30 | {
31 | attributeDescriptions[0].Binding = 0;
32 | attributeDescriptions[0].Location = 0;
33 | attributeDescriptions[0].Format = Format.R32G32Sfloat;
34 | attributeDescriptions[0].Offset = 0;
35 |
36 | attributeDescriptions[1].Binding = 0;
37 | attributeDescriptions[1].Location = 1;
38 | attributeDescriptions[1].Format = Format.R32G32Sfloat;
39 | attributeDescriptions[1].Offset = (uint)Marshal.SizeOf();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/QueueFamilyIndices.cs:
--------------------------------------------------------------------------------
1 | namespace Live2DCSharpSDK.Vulkan;
2 |
3 | public class QueueFamilyIndices
4 | {
5 | // 描画用と表示用のキューファミリは必ずしも一致するとは限らないので分ける
6 |
7 | ///
8 | /// 描画コマンドに使用するキューファミリ
9 | ///
10 | public int GraphicsFamily = -1;
11 | ///
12 | /// 表示に使用するキューファミリ
13 | ///
14 | public int PresentFamily = -1;
15 |
16 | ///
17 | /// 対応するキューファミリがあるか
18 | ///
19 | ///
20 | public bool IsComplete()
21 | {
22 | return GraphicsFamily != -1 && PresentFamily != -1;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/ShaderNames.cs:
--------------------------------------------------------------------------------
1 | namespace Live2DCSharpSDK.Vulkan;
2 |
3 | public class ShaderNames
4 | {
5 | // SetupMask
6 | public const int SetupMask = 0;
7 |
8 | //Normal
9 | public const int Normal = 1;
10 | public const int ShaderNames_NormalMasked = 2;
11 | public const int ShaderNames_NormalMaskedInverted = 3;
12 | public const int ShaderNames_NormalPremultipliedAlpha = 4;
13 | public const int ShaderNames_NormalMaskedPremultipliedAlpha = 5;
14 | public const int ShaderNames_NormalMaskedInvertedPremultipliedAlpha = 7;
15 |
16 | //Add
17 | public const int Add = 8;
18 | public const int ShaderNames_AddMasked = 9;
19 | public const int ShaderNames_AddMaskedInverted = 10;
20 | public const int ShaderNames_AddPremultipliedAlpha = 11;
21 | public const int ShaderNames_AddMaskedPremultipliedAlpha = 12;
22 | public const int ShaderNames_AddMaskedPremultipliedAlphaInverted = 13;
23 |
24 | //Mult
25 | public const int Mult = 14;
26 | public const int ShaderNames_MultMasked = 15;
27 | public const int ShaderNames_MultMaskedInverted = 16;
28 | public const int ShaderNames_MultPremultipliedAlpha = 17;
29 | public const int ShaderNames_MultMaskedPremultipliedAlpha = 18;
30 | public const int ShaderNames_MultMaskedPremultipliedAlphaInverted = 19;
31 | }
32 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/SwapchainSupportDetails.cs:
--------------------------------------------------------------------------------
1 | using Silk.NET.Vulkan;
2 |
3 | namespace Live2DCSharpSDK.Vulkan;
4 |
5 | public class SwapchainSupportDetails
6 | {
7 | ///
8 | /// 基本的な機能
9 | ///
10 | public SurfaceCapabilitiesKHR Capabilities;
11 | ///
12 | /// 利用可能なフォーマット
13 | ///
14 | public SurfaceFormatKHR[] Formats;
15 | ///
16 | /// 利用可能な表示モード
17 | ///
18 | public PresentModeKHR[] PresentModes;
19 | }
20 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/VulkanApi.cs:
--------------------------------------------------------------------------------
1 | using Silk.NET.Core.Native;
2 |
3 | namespace Live2DCSharpSDK.Vulkan;
4 |
5 | public abstract class VulkanApi
6 | {
7 | public abstract void GetWindowSize(out int width, out int height);
8 | public abstract unsafe byte** GetRequiredExtensions(out uint count);
9 | public abstract unsafe VkNonDispatchableHandle CreateSurface(VkHandle handle, T* handel1) where T : unmanaged;
10 | }
11 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/glsl/FragShaderSrc.frag:
--------------------------------------------------------------------------------
1 | #version 460
2 | #extension GL_GOOGLE_include_directive : enable
3 | #include "common.glsl"
4 |
5 | layout(location = 0) in vec2 v_texCoord;
6 |
7 | layout(location = 0) out vec4 outColor;
8 |
9 | void main()
10 | {
11 | vec4 texColor = texture(s_texture0, v_texCoord);
12 | texColor.rgb = texColor.rgb * ubo.u_multiplyColor.rgb;
13 | texColor.rgb = texColor.rgb + ubo.u_screenColor.rgb - (texColor.rgb * ubo.u_screenColor.rgb);
14 | vec4 color = texColor * ubo.u_baseColor;
15 | outColor = vec4(color.rgb * color.a, color.a);
16 | }
17 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/glsl/FragShaderSrcMask.frag:
--------------------------------------------------------------------------------
1 | #version 460
2 | #extension GL_GOOGLE_include_directive : enable
3 | #include "common.glsl"
4 |
5 | layout(location = 0) in vec2 v_texCoord;
6 | layout(location = 1) in vec4 v_clipPos;
7 |
8 | layout(location = 0) out vec4 outColor;
9 |
10 | void main()
11 | {
12 | vec4 texColor = texture(s_texture0, v_texCoord);
13 | texColor.rgb = texColor.rgb * ubo.u_multiplyColor.rgb;
14 | texColor.rgb = texColor.rgb + ubo.u_screenColor.rgb - (texColor.rgb * ubo.u_screenColor.rgb);
15 | vec4 col_formask = texColor * ubo.u_baseColor;
16 | col_formask.rgb = col_formask.rgb * col_formask.a;
17 | vec4 clipMask = (1.0 - texture(s_texture1, v_clipPos.xy / v_clipPos.w)) * ubo.u_channelFlag;
18 | float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;
19 | col_formask = col_formask * maskVal;
20 | outColor = col_formask;
21 | }
22 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/glsl/FragShaderSrcMaskInverted.frag:
--------------------------------------------------------------------------------
1 | #version 460
2 | #extension GL_GOOGLE_include_directive : enable
3 | #include "common.glsl"
4 |
5 | layout(location = 0) in vec2 v_texCoord;
6 | layout(location = 1) in vec4 v_clipPos;
7 |
8 | layout(location = 0) out vec4 outColor;
9 |
10 | void main()
11 | {
12 | vec4 texColor = texture(s_texture0, v_texCoord);
13 | texColor.rgb = texColor.rgb * ubo.u_multiplyColor.rgb;
14 | texColor.rgb = texColor.rgb + ubo.u_screenColor.rgb - (texColor.rgb * ubo.u_screenColor.rgb);
15 | vec4 col_formask = texColor * ubo.u_baseColor;
16 | col_formask.rgb = col_formask.rgb * col_formask.a ;
17 | vec4 clipMask = (1.0 - texture(s_texture1, v_clipPos.xy / v_clipPos.w)) * ubo.u_channelFlag;
18 | float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;
19 | col_formask = col_formask * (1.0 - maskVal);
20 | outColor = col_formask;
21 | }
22 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/glsl/FragShaderSrcMaskInvertedPremultipliedAlpha.frag:
--------------------------------------------------------------------------------
1 | #version 460
2 | #extension GL_GOOGLE_include_directive : enable
3 | #include "common.glsl"
4 |
5 | layout(location = 0) in vec2 v_texCoord;
6 | layout(location = 1) in vec4 v_clipPos;
7 |
8 | layout(location = 0) out vec4 outColor;
9 |
10 | void main()
11 | {
12 | vec4 texColor = texture(s_texture0, v_texCoord);
13 | texColor.rgb = texColor.rgb * ubo.u_multiplyColor.rgb;
14 | texColor.rgb = (texColor.rgb + ubo.u_screenColor.rgb * texColor.a) - (texColor.rgb * ubo.u_screenColor.rgb);
15 | vec4 col_formask = texColor * ubo.u_baseColor;
16 | vec4 clipMask = (1.0 - texture(s_texture1, v_clipPos.xy / v_clipPos.w)) * ubo.u_channelFlag;
17 | float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;
18 | col_formask = col_formask * (1.0 - maskVal);
19 | outColor = col_formask;
20 | }
21 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/glsl/FragShaderSrcMaskPremultipliedAlpha.frag:
--------------------------------------------------------------------------------
1 | #version 460
2 | #extension GL_GOOGLE_include_directive : enable
3 | #include "common.glsl"
4 |
5 | layout(location = 0) in vec2 v_texCoord;
6 | layout(location = 1) in vec4 v_clipPos;
7 |
8 | layout(location = 0) out vec4 outColor;
9 |
10 | void main()
11 | {
12 | vec4 texColor = texture(s_texture0, v_texCoord);
13 | texColor.rgb = texColor.rgb * ubo.u_multiplyColor.rgb;
14 | texColor.rgb = (texColor.rgb + ubo.u_screenColor.rgb * texColor.a) - (texColor.rgb * ubo.u_screenColor.rgb);
15 | vec4 col_formask = texColor * ubo.u_baseColor;
16 | vec4 clipMask = (1.0 - texture(s_texture1, v_clipPos.xy / v_clipPos.w)) * ubo.u_channelFlag;
17 | float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;
18 | col_formask = col_formask * maskVal;
19 | outColor = col_formask;
20 | }
21 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/glsl/FragShaderSrcPremultipliedAlpha.frag:
--------------------------------------------------------------------------------
1 | #version 460
2 | #extension GL_GOOGLE_include_directive : enable
3 | #include "common.glsl"
4 |
5 | layout(location = 0) in vec2 v_texCoord;
6 | layout(location = 0) out vec4 outColor;
7 |
8 | void main()
9 | {
10 | vec4 texColor = texture(s_texture0 , v_texCoord);
11 | texColor.rgb = texColor.rgb * ubo.u_multiplyColor.rgb;
12 | texColor.rgb = (texColor.rgb + ubo.u_screenColor.rgb * texColor.a) - (texColor.rgb * ubo.u_screenColor.rgb);
13 | outColor = texColor * ubo.u_baseColor;
14 | }
15 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/glsl/FragShaderSrcSetupMask.frag:
--------------------------------------------------------------------------------
1 | #version 460
2 | #extension GL_GOOGLE_include_directive : enable
3 | #include "common.glsl"
4 |
5 | layout(location = 0) in vec2 v_texCoord;
6 | layout(location = 1) in vec4 v_myPos;
7 | layout(location = 0) out vec4 outColor;
8 |
9 | void main()
10 | {
11 | float isInside = step(ubo.u_baseColor.x, v_myPos.x/v_myPos.w)*
12 | step(ubo.u_baseColor.y, v_myPos.y/v_myPos.w)*
13 | step(v_myPos.x/v_myPos.w, ubo.u_baseColor.z)*
14 | step(v_myPos.y/v_myPos.w, ubo.u_baseColor.w);
15 |
16 | outColor = ubo.u_channelFlag * texture(s_texture0 , v_texCoord).a * isInside;
17 | }
18 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/glsl/VertShaderSrc.vert:
--------------------------------------------------------------------------------
1 | #version 460
2 | #extension GL_GOOGLE_include_directive : enable
3 | #include "common.glsl"
4 |
5 | layout(location = 0) in vec4 a_position;
6 | layout(location = 1) in vec2 a_texCoord;
7 |
8 | layout(location = 0) out vec2 v_texCoord;
9 |
10 | void main()
11 | {
12 | vec4 pos = ubo.u_matrix * a_position;
13 | pos.y = -pos.y;
14 | gl_Position = pos;
15 | v_texCoord = a_texCoord;
16 | v_texCoord.y = 1.0 - v_texCoord.y;
17 | }
18 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/glsl/VertShaderSrcMasked.vert:
--------------------------------------------------------------------------------
1 | #version 460
2 | #extension GL_GOOGLE_include_directive : enable
3 | #include "common.glsl"
4 |
5 | layout(location = 0) in vec4 a_position;
6 | layout(location = 1) in vec2 a_texCoord;
7 |
8 | layout(location = 0) out vec2 v_texCoord;
9 | layout(location = 1) out vec4 v_clipPos;
10 |
11 | void main()
12 | {
13 | vec4 pos = ubo.u_matrix * a_position;
14 | pos.y = -pos.y;
15 | gl_Position = pos;
16 | v_clipPos = ubo.u_clipMatrix * a_position;
17 | v_clipPos.y = 1.0 - v_clipPos.y;
18 | v_texCoord = a_texCoord;
19 | v_texCoord.y = 1.0 - v_texCoord.y;
20 | }
21 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/glsl/VertShaderSrcSetupMask.vert:
--------------------------------------------------------------------------------
1 | #version 460
2 | #extension GL_GOOGLE_include_directive : enable
3 | #include "common.glsl"
4 |
5 | layout(location = 0) in vec4 a_position;
6 | layout(location = 1) in vec2 a_texCoord;
7 |
8 | layout(location = 0) out vec2 v_texCoord;
9 | layout(location = 1) out vec4 v_myPos;
10 |
11 | void main()
12 | {
13 | vec4 pos = ubo.u_clipMatrix * a_position;
14 | pos.y = -pos.y;
15 | gl_Position = pos;
16 | v_myPos = ubo.u_clipMatrix * a_position;
17 | v_texCoord = a_texCoord;
18 | v_texCoord.y = 1.0 - v_texCoord.y;
19 | }
20 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/glsl/common.glsl:
--------------------------------------------------------------------------------
1 | layout(binding = 0) uniform UBO
2 | {
3 | mat4 u_matrix;
4 | mat4 u_clipMatrix;
5 | vec4 u_baseColor;
6 | vec4 u_multiplyColor;
7 | vec4 u_screenColor;
8 | vec4 u_channelFlag;
9 | }ubo;
10 |
11 | layout(binding = 1) uniform sampler2D s_texture0;
12 | layout(binding = 2) uniform sampler2D s_texture1;
13 |
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/glsl/glslbuild.ps1:
--------------------------------------------------------------------------------
1 | # 设置输入和输出目录
2 | $inputDirectory = ".\" # 输入目录
3 | $outputDirectory = ".\spv\" # 输出目录
4 |
5 | # 确保输出目录存在
6 | if (-Not (Test-Path -Path $outputDirectory)) {
7 | New-Item -ItemType Directory -Path $outputDirectory
8 | }
9 |
10 | # 获取所有的 .frag 和 .vert 文件
11 | $shaderFiles = Get-ChildItem -Path $inputDirectory -Recurse -Include *.frag, *.vert
12 |
13 | if (-not (Test-Path -Path $outputDirectory)) {
14 | New-Item -ItemType Directory -Path $outputDirectory | Out-Null
15 | }
16 |
17 | # 初始化编译后的着色器文件列表
18 | $compiledShadersFramework = @()
19 |
20 | foreach ($shader in $shaderFiles) {
21 | $fileName = $shader.Name
22 |
23 | # 跳过common.glsl文件
24 | if ($fileName -eq "common.glsl") {
25 | continue
26 | }
27 |
28 | $fullPath = $shader.FullName
29 | $outputFileName = [System.IO.Path]::GetFileNameWithoutExtension($fileName) + ".spv"
30 | $outputFile = Join-Path -Path $outputDirectory -ChildPath $outputFileName
31 |
32 | # 添加到编译后的着色器列表
33 | $compiledShadersFramework += $outputFile
34 |
35 | # 创建自定义命令以编译着色器
36 | $command = "$env:VK_SDK_PATH\Bin\glslc.exe `"$fullPath`" -o `"$outputFile`""
37 |
38 | # 执行命令
39 | Invoke-Expression $command
40 | }
41 |
42 | # 输出结果
43 | Write-Host "Compiled Shaders:"
44 | $compiledShadersFramework
--------------------------------------------------------------------------------
/Live2DCSharpSDK.Vulkan/glsl/glslbuild.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # 设置输入和输出目录
4 | inputDirectory="." # 输入目录
5 | outputDirectory="./spv" # 输出目录
6 |
7 | # 确保输出目录存在
8 | if [ ! -d "$outputDirectory" ]; then
9 | mkdir -p "$outputDirectory"
10 | fi
11 |
12 | # 获取所有的 .frag 和 .vert 文件
13 | shaderFiles=$(find "$inputDirectory" -type f \( -name "*.frag" -o -name "*.vert" \))
14 |
15 | # 初始化编译后的着色器文件列表
16 | compiledShadersFramework=()
17 |
18 | # 遍历每个着色器文件
19 | for shader in $shaderFiles; do
20 | fileName=$(basename "$shader")
21 |
22 | # 跳过common.glsl文件
23 | if [ "$fileName" == "common.glsl" ]; then
24 | continue
25 | fi
26 |
27 | outputFileName="${fileName%.*}.spv" # 获取不带扩展名的文件名并添加.spv扩展名
28 | outputFile="$outputDirectory/$outputFileName"
29 |
30 | # 添加到编译后的着色器列表
31 | compiledShadersFramework+=("$outputFile")
32 |
33 | # 创建自定义命令以编译着色器
34 | command="glslc \"$shader\" -o \"$outputFile\""
35 |
36 | # 执行命令
37 | eval $command
38 | done
39 |
40 | # 输出结果
41 | echo "Compiled Shaders:"
42 | for compiledShader in "${compiledShadersFramework[@]}"; do
43 | echo "$compiledShader"
44 | done
--------------------------------------------------------------------------------
/Live2DCSharpSDK.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.7.33711.374
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Live2DCSharpSDK.Framework", "Live2DCSharpSDK.Framework\Live2DCSharpSDK.Framework.csproj", "{43B975EE-EC7E-4667-945A-245ECC4F5AF5}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Live2DCSharpSDK.App", "Live2DCSharpSDK.App\Live2DCSharpSDK.App.csproj", "{1D854B32-EC36-46A1-A9A2-2B06E9421338}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Live2DCSharpSDK.OpenGL.OpenTK", "Live2DCSharpSDK.OpenGL.OpenTK\Live2DCSharpSDK.OpenGL.OpenTK.csproj", "{8107A4BA-F80E-47F7-AF7B-4F9467101E93}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Live2DCSharpSDK.OpenGL.Avalonia", "Live2DCSharpSDK.OpenGL.Avalonia\Live2DCSharpSDK.OpenGL.Avalonia.csproj", "{7A072212-FDAC-46D1-9B78-6D37BB5F57D1}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OpenGL", "OpenGL", "{C1A91469-B605-4DDC-964A-137C82ABEF7B}"
15 | EndProject
16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{48E55F3F-9D1F-4D46-A2B6-58608590A8F6}"
17 | ProjectSection(SolutionItems) = preProject
18 | .editorconfig = .editorconfig
19 | EndProjectSection
20 | EndProject
21 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Live2DCSharpSDK.OpenGL.WPF", "Live2DCSharpSDK.OpenGL.WPF\Live2DCSharpSDK.OpenGL.WPF.csproj", "{31F12B93-E865-43F0-9967-00733D967F76}"
22 | EndProject
23 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Live2DCSharpSDK.Vulkan", "Live2DCSharpSDK.Vulkan\Live2DCSharpSDK.Vulkan.csproj", "{9B1C3543-86E2-4D30-8C24-7EA5DA96E1A5}"
24 | EndProject
25 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Live2DCSharpSDK.OpenGL", "Live2DCSharpSDK.OpenGL\Live2DCSharpSDK.OpenGL.csproj", "{803D5E9A-7C78-4218-A521-7C6C195FFB22}"
26 | EndProject
27 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Vulkan", "Vulkan", "{61A9217C-96D2-4897-BAA3-3FFA2259E97D}"
28 | EndProject
29 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Live2DCSharpSDK.Vulkan.Silk", "Live2DCSharpSDK.Vulkan.Silk\Live2DCSharpSDK.Vulkan.Silk.csproj", "{39FF395F-C87A-4E3D-8F72-85B6A5A8FC03}"
30 | EndProject
31 | Global
32 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
33 | Debug|Any CPU = Debug|Any CPU
34 | Release|Any CPU = Release|Any CPU
35 | EndGlobalSection
36 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
37 | {43B975EE-EC7E-4667-945A-245ECC4F5AF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38 | {43B975EE-EC7E-4667-945A-245ECC4F5AF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
39 | {43B975EE-EC7E-4667-945A-245ECC4F5AF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
40 | {43B975EE-EC7E-4667-945A-245ECC4F5AF5}.Release|Any CPU.Build.0 = Release|Any CPU
41 | {1D854B32-EC36-46A1-A9A2-2B06E9421338}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
42 | {1D854B32-EC36-46A1-A9A2-2B06E9421338}.Debug|Any CPU.Build.0 = Debug|Any CPU
43 | {1D854B32-EC36-46A1-A9A2-2B06E9421338}.Release|Any CPU.ActiveCfg = Release|Any CPU
44 | {1D854B32-EC36-46A1-A9A2-2B06E9421338}.Release|Any CPU.Build.0 = Release|Any CPU
45 | {8107A4BA-F80E-47F7-AF7B-4F9467101E93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
46 | {8107A4BA-F80E-47F7-AF7B-4F9467101E93}.Debug|Any CPU.Build.0 = Debug|Any CPU
47 | {8107A4BA-F80E-47F7-AF7B-4F9467101E93}.Release|Any CPU.ActiveCfg = Release|Any CPU
48 | {8107A4BA-F80E-47F7-AF7B-4F9467101E93}.Release|Any CPU.Build.0 = Release|Any CPU
49 | {7A072212-FDAC-46D1-9B78-6D37BB5F57D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
50 | {7A072212-FDAC-46D1-9B78-6D37BB5F57D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
51 | {7A072212-FDAC-46D1-9B78-6D37BB5F57D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
52 | {7A072212-FDAC-46D1-9B78-6D37BB5F57D1}.Release|Any CPU.Build.0 = Release|Any CPU
53 | {31F12B93-E865-43F0-9967-00733D967F76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
54 | {31F12B93-E865-43F0-9967-00733D967F76}.Debug|Any CPU.Build.0 = Debug|Any CPU
55 | {31F12B93-E865-43F0-9967-00733D967F76}.Release|Any CPU.ActiveCfg = Release|Any CPU
56 | {31F12B93-E865-43F0-9967-00733D967F76}.Release|Any CPU.Build.0 = Release|Any CPU
57 | {9B1C3543-86E2-4D30-8C24-7EA5DA96E1A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
58 | {9B1C3543-86E2-4D30-8C24-7EA5DA96E1A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
59 | {9B1C3543-86E2-4D30-8C24-7EA5DA96E1A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
60 | {9B1C3543-86E2-4D30-8C24-7EA5DA96E1A5}.Release|Any CPU.Build.0 = Release|Any CPU
61 | {803D5E9A-7C78-4218-A521-7C6C195FFB22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
62 | {803D5E9A-7C78-4218-A521-7C6C195FFB22}.Debug|Any CPU.Build.0 = Debug|Any CPU
63 | {803D5E9A-7C78-4218-A521-7C6C195FFB22}.Release|Any CPU.ActiveCfg = Release|Any CPU
64 | {803D5E9A-7C78-4218-A521-7C6C195FFB22}.Release|Any CPU.Build.0 = Release|Any CPU
65 | {39FF395F-C87A-4E3D-8F72-85B6A5A8FC03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
66 | {39FF395F-C87A-4E3D-8F72-85B6A5A8FC03}.Debug|Any CPU.Build.0 = Debug|Any CPU
67 | {39FF395F-C87A-4E3D-8F72-85B6A5A8FC03}.Release|Any CPU.ActiveCfg = Release|Any CPU
68 | {39FF395F-C87A-4E3D-8F72-85B6A5A8FC03}.Release|Any CPU.Build.0 = Release|Any CPU
69 | EndGlobalSection
70 | GlobalSection(SolutionProperties) = preSolution
71 | HideSolutionNode = FALSE
72 | EndGlobalSection
73 | GlobalSection(NestedProjects) = preSolution
74 | {8107A4BA-F80E-47F7-AF7B-4F9467101E93} = {C1A91469-B605-4DDC-964A-137C82ABEF7B}
75 | {7A072212-FDAC-46D1-9B78-6D37BB5F57D1} = {C1A91469-B605-4DDC-964A-137C82ABEF7B}
76 | {31F12B93-E865-43F0-9967-00733D967F76} = {C1A91469-B605-4DDC-964A-137C82ABEF7B}
77 | {9B1C3543-86E2-4D30-8C24-7EA5DA96E1A5} = {61A9217C-96D2-4897-BAA3-3FFA2259E97D}
78 | {803D5E9A-7C78-4218-A521-7C6C195FFB22} = {C1A91469-B605-4DDC-964A-137C82ABEF7B}
79 | {39FF395F-C87A-4E3D-8F72-85B6A5A8FC03} = {61A9217C-96D2-4897-BAA3-3FFA2259E97D}
80 | EndGlobalSection
81 | GlobalSection(ExtensibilityGlobals) = postSolution
82 | SolutionGuid = {53197E4D-3AAB-4AC2-91AF-DDBB326E65FD}
83 | EndGlobalSection
84 | EndGlobal
85 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Live2DCSharpSDK
2 |
3 | 交流QQ群:571239090
4 |
5 | 用于[Live2D](https://www.live2d.com/)的OpenGL渲染器,基于[官方](https://github.com/Live2D/CubismNativeSamples)渲染器改写。
6 | 只需要添加[Core](https://www.live2d.com/download/cubism-sdk/download-native/)的动态链接库即可运行
7 |
--------------------------------------------------------------------------------