mirror of
https://github.com/maker-community/ElectronBot.DotNet.git
synced 2026-10-24 18:19:48 +08:00
631 lines
20 KiB
C#
631 lines
20 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Text;
|
|
using Windows.ApplicationModel;
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
using CommunityToolkit.Mvvm.Input;
|
|
using Controls.CompactOverlay;
|
|
using ElectronBot.Braincase;
|
|
using ElectronBot.Braincase.Helpers;
|
|
using HelixToolkit.SharpDX.Core;
|
|
using HelixToolkit.WinUI;
|
|
using Microsoft.UI.Windowing;
|
|
using Microsoft.UI.Xaml;
|
|
using Models;
|
|
using SharpDX;
|
|
using Assimp;
|
|
using HelixToolkit.SharpDX.Core.Assimp;
|
|
using HelixToolkit.SharpDX.Core.Model.Scene;
|
|
using BoundingBox = SharpDX.BoundingBox;
|
|
using Camera = HelixToolkit.WinUI.Camera;
|
|
using Verdure.ElectronBot.Core.Models;
|
|
|
|
namespace ViewModels;
|
|
public partial class ModelLoadCompactOverlayViewModel : ObservableRecipient
|
|
{
|
|
public IEffectsManager EffectsManager
|
|
{
|
|
get;
|
|
}
|
|
|
|
public SceneNodeGroupModel3D BodyModel
|
|
{
|
|
get;
|
|
} = new SceneNodeGroupModel3D();
|
|
|
|
public SceneNodeGroupModel3D LeftArmModel
|
|
{
|
|
get;
|
|
} = new SceneNodeGroupModel3D();
|
|
|
|
public SceneNodeGroupModel3D RightArmModel
|
|
{
|
|
get;
|
|
} = new SceneNodeGroupModel3D();
|
|
|
|
public SceneNodeGroupModel3D HeadModel
|
|
{
|
|
get;
|
|
} = new SceneNodeGroupModel3D();
|
|
|
|
public SceneNodeGroupModel3D BaseModel
|
|
{
|
|
get;
|
|
} = new SceneNodeGroupModel3D();
|
|
|
|
public DiffuseMaterial Material
|
|
{
|
|
private set;
|
|
get;
|
|
}
|
|
|
|
[ObservableProperty] bool _showAxis = true;
|
|
|
|
[ObservableProperty]
|
|
private Vector3 _modelCentroidPoint = default;
|
|
|
|
[ObservableProperty]
|
|
private Vector3 _headModelCentroidPoint = default;
|
|
|
|
[ObservableProperty]
|
|
private bool _showWireframe = false;
|
|
[ObservableProperty]
|
|
private BoundingBox _rightShoulderBoundingBox = default;
|
|
|
|
[ObservableProperty]
|
|
private BoundingBox _leftShoulderBoundingBox = default;
|
|
|
|
[ObservableProperty]
|
|
private BoundingBox _bodyBoundingBox = default;
|
|
|
|
[ObservableProperty]
|
|
private BoundingBox _headBoundingBox = default;
|
|
|
|
[ObservableProperty]
|
|
private BoundingBox _baseBoundingBox = default;
|
|
|
|
private Matrix _bodyMt = default;
|
|
|
|
private Matrix _leftArmMt = default;
|
|
|
|
private Matrix _rightArmMt = default;
|
|
|
|
private Matrix _headMt = default;
|
|
|
|
private Matrix _baseMt = default;
|
|
|
|
[ObservableProperty] private TextureModel _environmentMap;
|
|
|
|
private readonly Importer _importer = new();
|
|
|
|
private readonly DiffuseMaterial _pinkModelMaterial = new()
|
|
{
|
|
Name = "Pink",
|
|
DiffuseColor = Color.LightPink// DiffuseMaterials.ToColor(255, 192, 203, 1.0),
|
|
};
|
|
|
|
|
|
public Camera Camera
|
|
{
|
|
get;
|
|
} = new OrthographicCamera() { NearPlaneDistance = 1e-2, FarPlaneDistance = 1e4 };
|
|
|
|
private readonly DispatcherTimer _timer = new()
|
|
{
|
|
Interval = TimeSpan.FromMilliseconds(200)
|
|
};
|
|
|
|
[ObservableProperty] private string _voiceResult = string.Empty;
|
|
|
|
public ModelLoadCompactOverlayViewModel(IEffectsManager effectsManager)
|
|
{
|
|
EffectsManager = effectsManager;
|
|
|
|
Material = new DiffuseMaterial()
|
|
{
|
|
EnableUnLit = false,
|
|
DiffuseMap = LoadTexture("eyes-closed.png")
|
|
};
|
|
|
|
var filePath = Package.Current.InstalledLocation.Path + "\\Assets\\Cubemap_Grandcanyon.dds";
|
|
|
|
EnvironmentMap = LoadTextureByFullPath(filePath);
|
|
|
|
_timer.Tick += Timer_Tick;
|
|
}
|
|
|
|
private async void Timer_Tick(object? sender, object e)
|
|
{
|
|
var resultState = EbHelper.IsVoiceEnabled();
|
|
|
|
if (resultState)
|
|
{
|
|
VoiceResult = "快捷键按下";
|
|
var voiceLock = ElectronBotHelper.Instance.VoiceLock;
|
|
|
|
if (resultState && !voiceLock)
|
|
{
|
|
await ElectronBotHelper.Instance.MediaPlayerPlaySoundByTtsAsync("主人需要帮忙吗", true);
|
|
}
|
|
|
|
ElectronBotHelper.Instance.VoiceLock = true;
|
|
}
|
|
else
|
|
{
|
|
VoiceResult = "快捷键松开";
|
|
}
|
|
}
|
|
|
|
[RelayCommand]
|
|
public void PlayAction()
|
|
{
|
|
var playEmojisLock = ElectronBotHelper.Instance.PlayEmojisLock;
|
|
|
|
if (!playEmojisLock)
|
|
{
|
|
//随机播放表情
|
|
ElectronBotHelper.Instance.ToPlayEmojisRandom();
|
|
}
|
|
|
|
ElectronBotHelper.Instance.PlayEmojisLock = true;
|
|
}
|
|
|
|
|
|
[RelayCommand]
|
|
public void Loaded()
|
|
{
|
|
App.MainWindow.DispatcherQueue.TryEnqueue(() =>
|
|
{
|
|
try
|
|
{
|
|
var body = new List<string>()
|
|
{
|
|
"Body1.obj",
|
|
"Body2.obj",
|
|
};
|
|
|
|
var head = new List<string>()
|
|
{
|
|
"Head1.obj",
|
|
"Head2.obj",
|
|
"Head3.obj",
|
|
};
|
|
|
|
var leftArm = new List<string>()
|
|
{
|
|
"LeftArm1.obj",
|
|
"LeftArm2.obj",
|
|
"LeftShoulder.obj",
|
|
};
|
|
|
|
var rightArm = new List<string>()
|
|
{
|
|
"RightArm1.obj",
|
|
"RightArm2.obj",
|
|
"RightShoulder.obj"
|
|
};
|
|
|
|
|
|
var baseBody = new List<string>()
|
|
{
|
|
"Base.obj",
|
|
};
|
|
|
|
foreach (var modelName in head)
|
|
{
|
|
var modelPath = Package.Current.InstalledLocation.Path + $"\\Assets\\ElectronBotModel\\{modelName}";
|
|
|
|
var newScene = _importer.Load(modelPath);
|
|
|
|
if (newScene != null && newScene.Root != null)
|
|
{
|
|
// Pre-attach and calculate all scene info in a separate task.
|
|
newScene.Root.Attach(EffectsManager);
|
|
|
|
newScene.Root.UpdateAllTransformMatrix();
|
|
|
|
HeadModel.AddNode(newScene.Root);
|
|
|
|
_headMt = HeadModel.HxTransform3D;
|
|
|
|
if (modelName == "Head3.obj")
|
|
{
|
|
foreach (var node in newScene.Root.Traverse())
|
|
{
|
|
if (node is MeshNode meshNode)
|
|
{
|
|
// this is face
|
|
meshNode.Material = Material;
|
|
}
|
|
}
|
|
}
|
|
else if (modelName == "Head1.obj")
|
|
{
|
|
if (newScene.Root.TryGetCentroid(out var centroid))
|
|
{
|
|
// Must use UI thread to set value back.
|
|
HeadModelCentroidPoint = centroid;
|
|
}
|
|
foreach (var node in newScene.Root.Traverse())
|
|
{
|
|
if (node is MeshNode meshNode)
|
|
{
|
|
meshNode.Material = _pinkModelMaterial;
|
|
}
|
|
}
|
|
}
|
|
else if (modelName == "Head2.obj")
|
|
{
|
|
foreach (var node in newScene.Root.Traverse())
|
|
{
|
|
if (node is MeshNode meshNode)
|
|
{
|
|
meshNode.Material = DiffuseMaterials.PureWhite;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
foreach (var modelName in body)
|
|
{
|
|
var modelPath = Package.Current.InstalledLocation.Path + $"\\Assets\\ElectronBotModel\\{modelName}";
|
|
|
|
var newScene = _importer.Load(modelPath);
|
|
|
|
if (newScene != null && newScene.Root != null)
|
|
{
|
|
// Pre-attach and calculate all scene info in a separate task.
|
|
newScene.Root.Attach(EffectsManager);
|
|
newScene.Root.UpdateAllTransformMatrix();
|
|
|
|
BodyModel.AddNode(newScene.Root);
|
|
|
|
_bodyMt = BodyModel.HxTransform3D;
|
|
|
|
if (modelName == "Body2.obj")
|
|
{
|
|
if (newScene.Root.TryGetCentroid(out var centroid))
|
|
{
|
|
// Must use UI thread to set value back.
|
|
ModelCentroidPoint = centroid;
|
|
}
|
|
|
|
foreach (var node in newScene.Root.Traverse())
|
|
{
|
|
if (node is MeshNode meshNode)
|
|
{
|
|
meshNode.Material = DiffuseMaterials.PureWhite;
|
|
}
|
|
}
|
|
}
|
|
else if (modelName == "Body1.obj")
|
|
{
|
|
foreach (var node in newScene.Root.Traverse())
|
|
{
|
|
if (node is MeshNode meshNode)
|
|
{
|
|
meshNode.Material = _pinkModelMaterial;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var modelName in rightArm)
|
|
{
|
|
var modelPath = Package.Current.InstalledLocation.Path + $"\\Assets\\ElectronBotModel\\{modelName}";
|
|
var newScene = _importer.Load(modelPath);
|
|
if (newScene != null && newScene.Root != null)
|
|
{
|
|
// Pre-attach and calculate all scene info in a separate task.
|
|
newScene.Root.Attach(EffectsManager);
|
|
newScene.Root.UpdateAllTransformMatrix();
|
|
|
|
RightArmModel.AddNode(newScene.Root);
|
|
|
|
_rightArmMt = RightArmModel.HxTransform3D;
|
|
|
|
if (newScene.Root.TryGetBound(out var bound))
|
|
{
|
|
// Must use UI thread to set value back.
|
|
if (modelName == "RightShoulder.obj")
|
|
{
|
|
RightShoulderBoundingBox = bound;
|
|
}
|
|
|
|
}
|
|
|
|
if (modelName == "RightArm1.obj")
|
|
{
|
|
foreach (var node in newScene.Root.Traverse())
|
|
{
|
|
if (node is MeshNode meshNode)
|
|
{
|
|
meshNode.Material = DiffuseMaterials.PureWhite;
|
|
}
|
|
}
|
|
}
|
|
else if (modelName == "RightArm2.obj")
|
|
{
|
|
foreach (var node in newScene.Root.Traverse())
|
|
{
|
|
if (node is MeshNode meshNode)
|
|
{
|
|
meshNode.Material = _pinkModelMaterial;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
foreach (var modelName in leftArm)
|
|
{
|
|
var modelPath = Package.Current.InstalledLocation.Path + $"\\Assets\\ElectronBotModel\\{modelName}";
|
|
var newScene = _importer.Load(modelPath);
|
|
if (newScene != null && newScene.Root != null)
|
|
{
|
|
// Pre-attach and calculate all scene info in a separate task.
|
|
newScene.Root.Attach(EffectsManager);
|
|
newScene.Root.UpdateAllTransformMatrix();
|
|
|
|
LeftArmModel.AddNode(newScene.Root);
|
|
|
|
_leftArmMt = LeftArmModel.HxTransform3D;
|
|
|
|
if (newScene.Root.TryGetBound(out var bound))
|
|
{
|
|
// Must use UI thread to set value back.
|
|
if (modelName == "LeftShoulder.obj")
|
|
{
|
|
LeftShoulderBoundingBox = bound;
|
|
}
|
|
|
|
}
|
|
|
|
if (modelName == "LeftArm1.obj")
|
|
{
|
|
foreach (var node in newScene.Root.Traverse())
|
|
{
|
|
if (node is MeshNode meshNode)
|
|
{
|
|
meshNode.Material = DiffuseMaterials.PureWhite;
|
|
}
|
|
}
|
|
}
|
|
else if (modelName == "LeftArm2.obj")
|
|
{
|
|
foreach (var node in newScene.Root.Traverse())
|
|
{
|
|
if (node is MeshNode meshNode)
|
|
{
|
|
meshNode.Material = _pinkModelMaterial;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var modelName in baseBody)
|
|
{
|
|
var modelPath = Package.Current.InstalledLocation.Path + $"\\Assets\\ElectronBotModel\\{modelName}";
|
|
var newScene = _importer.Load(modelPath);
|
|
if (newScene != null && newScene.Root != null)
|
|
{
|
|
// Pre-attach and calculate all scene info in a separate task.
|
|
newScene.Root.Attach(EffectsManager);
|
|
newScene.Root.UpdateAllTransformMatrix();
|
|
|
|
BaseModel.AddNode(newScene.Root);
|
|
|
|
_baseMt = BaseModel.HxTransform3D;
|
|
|
|
if (newScene.Root.TryGetBound(out var bound))
|
|
{
|
|
// Must use UI thread to set value back.
|
|
if (modelName == "Base.obj")
|
|
{
|
|
BaseBoundingBox = bound;
|
|
}
|
|
|
|
}
|
|
|
|
if (modelName == "Base.obj")
|
|
{
|
|
foreach (var node in newScene.Root.Traverse())
|
|
{
|
|
if (node is MeshNode meshNode)
|
|
{
|
|
meshNode.Material = DiffuseMaterials.PureWhite;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FocusCameraToScene();
|
|
|
|
ElectronBotHelper.Instance.ModelActionFrame += Instance_ModelActionFrame;
|
|
|
|
|
|
_timer.Start();
|
|
ElectronBotHelper.Instance.LoadAppList();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
ToastHelper.SendToast("模型加载失败", TimeSpan.FromSeconds(3));
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
public void UnLoaded()
|
|
{
|
|
ElectronBotHelper.Instance.ModelActionFrame -= Instance_ModelActionFrame;
|
|
HeadModel.Dispose();
|
|
BodyModel.Dispose();
|
|
RightArmModel.Dispose();
|
|
LeftArmModel.Dispose();
|
|
BaseModel.Dispose();
|
|
EffectsManager.Dispose();
|
|
_importer.Dispose();
|
|
ElectronBotHelper.Instance.PlayEmojisLock = false;
|
|
|
|
_timer.Stop();
|
|
}
|
|
|
|
private void Instance_ModelActionFrame(object? sender, Verdure.ElectronBot.Core.Models.ModelActionFrame ex)
|
|
{
|
|
var e = new OnlyAction();
|
|
|
|
if (ElectronBotHelper.Instance.IsEntityFirstEnabled)
|
|
{
|
|
e = ex.Actions;
|
|
}
|
|
else
|
|
{
|
|
e = new OnlyAction()
|
|
{
|
|
J1 = ex.J1,
|
|
J2 = ex.J2,
|
|
J3 = ex.J3,
|
|
J4 = ex.J4,
|
|
J5 = ex.J5,
|
|
J6 = ex.J6
|
|
};
|
|
}
|
|
|
|
App.MainWindow.DispatcherQueue.TryEnqueue(() =>
|
|
{
|
|
BodyModel.HxTransform3D = _bodyMt * Matrix.RotationY(MathUtil.DegreesToRadians(-(e.J6)));
|
|
|
|
Material = new DiffuseMaterial()
|
|
{
|
|
EnableUnLit = false,
|
|
DiffuseMap = LoadTextureByStream(ex.FrameStream)
|
|
};
|
|
|
|
|
|
var nodeList = HeadModel.GroupNode;
|
|
|
|
foreach (var itemMode in nodeList.Items)
|
|
{
|
|
if (itemMode.Name == "Head3.obj")
|
|
{
|
|
foreach (var node in itemMode.Traverse())
|
|
{
|
|
try
|
|
{
|
|
if (node is MeshNode meshNode)
|
|
{
|
|
meshNode.Material = Material;
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
var rightList = RightShoulderBoundingBox.GetCorners();
|
|
|
|
var rightAverage = new SharpDX.Vector3(
|
|
(rightList[1].X + rightList[5].X) / 2f,
|
|
((rightList[1].Y + rightList[5].Y) / 2f) - 8f,
|
|
(rightList[1].Z + rightList[5].Z) / 2f);
|
|
|
|
var leftList = LeftShoulderBoundingBox.GetCorners();
|
|
|
|
var leftAverage = new SharpDX.Vector3(
|
|
(leftList[0].X + leftList[4].X) / 2f,
|
|
((leftList[0].Y + leftList[4].Y) / 2f) - 8f,
|
|
(leftList[0].Z + leftList[4].Z) / 2f);
|
|
|
|
var translationMatrix = Matrix.Translation(-rightAverage.X, -rightAverage.Y, -rightAverage.Z);
|
|
|
|
var tr2 = _rightArmMt * translationMatrix;
|
|
|
|
var tr3 = tr2 * Matrix.RotationZ(MathUtil.DegreesToRadians(-(e.J4)));
|
|
var tr4 = tr3 * Matrix.RotationX(MathUtil.DegreesToRadians(-(e.J5)));
|
|
|
|
var tr5 = tr4 * Matrix.Translation(rightAverage.X, rightAverage.Y, rightAverage.Z);
|
|
|
|
|
|
var tr6 = tr5 * Matrix.RotationY(MathUtil.DegreesToRadians(-(e.J6)));
|
|
|
|
RightArmModel.HxTransform3D = tr6;
|
|
|
|
|
|
var leftMatrix = Matrix.Translation(-leftAverage.X, -leftAverage.Y, -leftAverage.Z);
|
|
|
|
var leftTr2 = _leftArmMt * leftMatrix;
|
|
|
|
var leftTr3 = leftTr2 * Matrix.RotationZ(MathUtil.DegreesToRadians((e.J2)));
|
|
var leftTr4 = leftTr3 * Matrix.RotationX(MathUtil.DegreesToRadians(-(e.J3)));
|
|
|
|
var leftTr5 = leftTr4 * Matrix.Translation(leftAverage.X, leftAverage.Y, leftAverage.Z);
|
|
|
|
|
|
var leftTr6 = leftTr5 * Matrix.RotationY(MathUtil.DegreesToRadians(-(e.J6)));
|
|
|
|
LeftArmModel.HxTransform3D = leftTr6;
|
|
|
|
var headMatrix = Matrix.Translation(-HeadModelCentroidPoint.X, -HeadModelCentroidPoint.Y, -HeadModelCentroidPoint.Z);
|
|
|
|
var headTr2 = _headMt * headMatrix;
|
|
|
|
var headTr3 = headTr2 * Matrix.RotationX(MathUtil.DegreesToRadians(-(e.J1)));
|
|
|
|
var headTr4 = headTr3 * Matrix.Translation(HeadModelCentroidPoint.X, HeadModelCentroidPoint.Y, HeadModelCentroidPoint.Z);
|
|
|
|
|
|
var headTr5 = headTr4 * Matrix.RotationY(MathUtil.DegreesToRadians(-(e.J6)));
|
|
|
|
HeadModel.HxTransform3D = headTr5;
|
|
});
|
|
}
|
|
|
|
private void FocusCameraToScene()
|
|
{
|
|
var maxWidth = Math.Max(Math.Max(RightShoulderBoundingBox.Width, RightShoulderBoundingBox.Height), BodyBoundingBox.Depth) + 240;
|
|
var pos = RightShoulderBoundingBox.Center + new Vector3(0, 0, maxWidth);
|
|
Camera.Position = pos;
|
|
Camera.LookDirection = RightShoulderBoundingBox.Center - pos;
|
|
Camera.UpDirection = Vector3.UnitY;
|
|
if (Camera is OrthographicCamera orthCam)
|
|
{
|
|
orthCam.Width = maxWidth;
|
|
}
|
|
}
|
|
|
|
[RelayCommand]
|
|
public void CompactOverlay()
|
|
{
|
|
App.MainWindow.Show();
|
|
}
|
|
|
|
private TextureModel LoadTextureByFullPath(string filePath)
|
|
{
|
|
return TextureModel.Create(filePath);
|
|
}
|
|
|
|
private TextureModel LoadTexture(string file)
|
|
{
|
|
var filePath = Package.Current.InstalledLocation.Path + $"\\Assets\\Emoji\\Pic\\{file}";
|
|
|
|
return TextureModel.Create(filePath);
|
|
}
|
|
|
|
private TextureModel LoadTextureByStream(Stream data)
|
|
{
|
|
|
|
return TextureModel.Create(data);
|
|
}
|
|
}
|