Created
February 27, 2026 10:46
-
-
Save w0wca7a/979ccea6e06a2b12f904262e60670ef1 to your computer and use it in GitHub Desktop.
Silk.NET.Assimp blendshapes handler
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using Silk.NET.Assimp; | |
| using System; | |
| using System.Numerics; | |
| using static MeshHandler.Program.Animation; | |
| namespace MeshHandler; | |
| public class Program | |
| { | |
| Assimp assimp = Assimp.GetApi(); | |
| //List<Material> materials = new List<Material>(); | |
| //List<Mesh> meshes = new List<Mesh>(); | |
| public static void Main(string[] args) | |
| { | |
| var program = new Program(); | |
| program.Run(); | |
| } | |
| private unsafe void Run() | |
| { | |
| // Флаги для импорта (рекомендуемые настройки) | |
| const uint flags = (uint)( | |
| //PostProcessSteps.Triangulate | // Триангуляция mesh'ей | |
| //PostProcessSteps.GenerateSmoothNormals | // Генерация нормалей | |
| //PostProcessSteps.FlipUVs | // Корректировка UV для OpenGL | |
| //PostProcessSteps.CalculateTangentSpace | // Для нормал маппинга | |
| //PostProcessSteps.JoinIdenticalVertices | // Оптимизация вершин | |
| //PostProcessSteps.ImproveCacheLocality | // Улучшение кэша | |
| //PostProcessSteps.OptimizeMeshes // Оптимизация мешей | |
| PostProcessSteps.None | |
| ); | |
| //string path = @"C:\Users\damzi\Desktop\andryuha\andryuha\Resources\Test\headWithMorps.fbx"; | |
| //string path = @"C:\Users\damzi\Desktop\andryuha\andryuha\Resources\Test\headWithMorpsGrouped.fbx"; | |
| string path = @"C:\Users\damzi\Desktop\andryuha\andryuha\Resources\Test\Test.fbx"; | |
| var scene = assimp.ImportFile(path, flags); | |
| if (scene == null || scene->MFlags == Assimp.SceneFlagsIncomplete || scene->MRootNode == null) | |
| { | |
| string error = assimp.GetErrorStringS(); | |
| Console.WriteLine($"Ошибка загрузки: {error}"); | |
| return; | |
| } | |
| // Scene handler | |
| ProcessNode(scene->MRootNode, scene); | |
| } | |
| private unsafe void ProcessNode(Node* node, Scene* scene) | |
| { | |
| // Обрабатываем все меши в текущем узле | |
| for (int i = 0; i < node->MNumMeshes; i++) | |
| { | |
| Mesh* mesh = scene->MMeshes[node->MMeshes[i]]; | |
| var meshData = ProcessMeshes(mesh, scene); | |
| } | |
| // Рекурсивно обрабатываем дочерние узлы | |
| for (int i = 0; i < node->MNumChildren; i++) | |
| { | |
| ProcessNode(node->MChildren[i], scene); | |
| } | |
| } | |
| private unsafe MeshData ProcessMeshes(Mesh* mesh, Scene* scene) | |
| { | |
| MeshData meshData = null; | |
| // Извлечение вершин | |
| for (int i = 0; i < mesh->MNumVertices; i++) | |
| { | |
| Vector3 vertex = mesh->MVertices[i]; | |
| // Используйте координаты: vertex.X, vertex.Y, vertex.Z | |
| // Нормали (если есть) | |
| if (mesh->MNormals != null) | |
| { | |
| Vector3 normal = mesh->MNormals[i]; | |
| } | |
| // Текстурные координаты (обычно до 8 каналов) | |
| if (mesh->MTextureCoords[0] != null) | |
| { | |
| Vector3 texCoord = mesh->MTextureCoords[0][i]; | |
| // Для 2D текстур используйте texCoord.X, texCoord.Y | |
| } | |
| // Цвета вершин (если есть) | |
| if (mesh->MColors[0] != null) | |
| { | |
| Vector4 color = mesh->MColors[0][i]; | |
| } | |
| } | |
| // Извлечение индексов (для индексированного рендеринга) | |
| for (int i = 0; i < mesh->MNumFaces; i++) | |
| { | |
| Face face = mesh->MFaces[i]; | |
| for (int j = 0; j < face.MNumIndices; j++) | |
| { | |
| uint index = face.MIndices[j]; | |
| // Используйте индекс | |
| } | |
| } | |
| // Информация о материале | |
| if (mesh->MMaterialIndex >= 0) | |
| { | |
| Material* material = scene->MMaterials[mesh->MMaterialIndex]; | |
| // Получение пути к текстуре диффузного цвета | |
| AssimpString path; | |
| if (assimp.GetMaterialTexture(material, TextureType.Diffuse, 0, &path, null, null, null, null, null, null) | |
| == Return.Success) | |
| { | |
| string texturePath = path.AsString; | |
| // Загрузите текстуру через Silk.NET.OpenGL | |
| } | |
| } | |
| //Проверяем наличие анимаций Blendshapes | |
| if (mesh->MNumAnimMeshes > 0) | |
| { | |
| for (int i = 0; i < mesh->MNumAnimMeshes; i++) | |
| { | |
| //Animation* anim = scene->MAnimations[i]; | |
| if (mesh->MAnimMeshes[i] == null) continue; | |
| var animMesh = mesh->MAnimMeshes[i]; | |
| string name = animMesh->MName.AsString; | |
| float weight = animMesh->MWeight; | |
| uint numVertices = animMesh->MNumVertices; | |
| Vector3[] vertices = new Vector3[numVertices]; | |
| Vector3[] normals = null; | |
| Vector3[] tangents = null; | |
| Vector3[] bitangents = null; | |
| Vector4[][] colors = new Vector4[8][]; | |
| // Vertices | |
| for (int v = 0; v < numVertices; v++) | |
| { | |
| vertices[v] = animMesh->MVertices[v]; | |
| } | |
| // Normals | |
| if (animMesh->MNormals != null) | |
| { | |
| Vector3[] result = new Vector3[numVertices]; | |
| for (int j = 0; j < numVertices; j++) | |
| { | |
| result[j] = animMesh->MNormals[j]; | |
| } | |
| normals = result; | |
| } | |
| // Tangents | |
| if (animMesh->MTangents != null) | |
| { | |
| Vector3[] result = new Vector3[numVertices]; | |
| for (int t = 0; t < numVertices; t++) | |
| { | |
| result[t] = animMesh->MTangents[t]; | |
| } | |
| tangents = result; | |
| } | |
| // Bitangents | |
| if (animMesh->MBitangents != null) | |
| { | |
| Vector3[] result = new Vector3[numVertices]; | |
| for (int b = 0; b < numVertices; b++) | |
| { | |
| result[b] = animMesh->MTangents[b]; | |
| } | |
| bitangents = result; | |
| } | |
| // Colors | |
| for (int colorSet = 0; colorSet < 8; colorSet++) | |
| { | |
| if (animMesh->MColors[colorSet] != null) | |
| { | |
| Vector4[] result = new Vector4[numVertices]; | |
| for (int c = 0; c < numVertices; c++) | |
| { | |
| result[c] = animMesh->MColors[colorSet][c]; | |
| } | |
| colors[colorSet] = result; | |
| } | |
| } | |
| /* | |
| // Поиск каналов морфинга | |
| for (int j = 0; j < anim->MNumMorphMeshChannels; j++) | |
| { | |
| MorphMeshChannel* morphChannel = anim->MMorphMeshChannels[j]; | |
| // Обработка ключей морфинга | |
| for (int k = 0; k < morphChannel->MNumKeys; k++) | |
| { | |
| MorphMeshKey key = morphChannel->MKeys[k]; | |
| // key.MTime - время ключа | |
| // key.MValue - вес морфинга (0.0 - 1.0) | |
| } | |
| } | |
| */ | |
| meshData = new MeshData | |
| { | |
| Name = name, | |
| Weight = weight, | |
| VertexCount = (int)numVertices, | |
| Vertices = vertices, | |
| Normals = normals, | |
| Tangents = tangents, | |
| Bitangents = bitangents, | |
| Colors = colors | |
| }; | |
| } | |
| } | |
| // Обработка морфинга | |
| var animations = ProcessAnimations(mesh, scene); | |
| return meshData; | |
| } | |
| private unsafe Dictionary<string, Animation> ProcessAnimations(Mesh* mesh, Scene* scene) | |
| { | |
| Dictionary<string, Animation> animations = []; | |
| var ani = scene->MAnimations; | |
| var aniCount = scene->MNumAnimations; | |
| if (ani == null || aniCount == 0) return animations; | |
| for (int i = 0; i < aniCount; i++) | |
| { | |
| var anim = ani[i]; | |
| MeshMorph[] meshMorphs = null; | |
| if (anim-> MNumMorphMeshChannels > 0) | |
| { | |
| meshMorphs = new MeshMorph[anim->MNumMorphMeshChannels]; | |
| for (int mm = 0; mm < anim->MNumMorphMeshChannels; mm++) | |
| { | |
| var _keys = anim->MMorphMeshChannels[mm]->MKeys; | |
| var keysCount = anim->MMorphMeshChannels[mm]->MNumKeys; | |
| MorphMeshKey[] keys = new MorphMeshKey[keysCount]; | |
| if (_keys != null || keysCount > 0) | |
| { | |
| for (int k = 0; k < keysCount; k++) | |
| { | |
| var valuesCount = _keys[k].MNumValuesAndWeights; | |
| uint* valuesPtr = _keys[k].MValues; | |
| double* weightsPtr = _keys[k].MWeights; | |
| var valuesArray = new Span<uint>(valuesPtr, (int)valuesCount).ToArray(); | |
| var weightsArray = new Span<double>(weightsPtr, (int)valuesCount).ToArray(); | |
| var time = _keys[valuesCount].MTime; | |
| var values = valuesArray; | |
| var weights = weightsArray; | |
| var valuesAndWeightsCount = valuesCount; | |
| var morphMeshKey = new MorphMeshKey(); | |
| morphMeshKey.Time = time; | |
| morphMeshKey.Values = values; | |
| morphMeshKey.Weights = weights; | |
| morphMeshKey.ValuesAndWeightsCount = valuesAndWeightsCount; | |
| keys[k] = morphMeshKey; | |
| //{ | |
| // Time = time, | |
| // Values = values, | |
| // Weights = weights, | |
| // ValuesAndWeightsCount = valuesAndWeightsCount | |
| //}; | |
| } | |
| } | |
| MeshMorph meshMorph = new() | |
| { | |
| Name = anim->MMorphMeshChannels[mm]->MName.AsString, | |
| KeysCount = keysCount, | |
| Keys = keys | |
| }; | |
| meshMorphs[mm] = meshMorph; | |
| } | |
| } | |
| var importedAnimation = new Animation() | |
| { | |
| Name = anim->MName.AsString, | |
| Duration = anim->MDuration, | |
| TicksPerSecond = anim->MTicksPerSecond, | |
| ChannelsCount = anim->MNumChannels, | |
| MeshChannelsCount = anim->MNumMeshChannels, | |
| MorphMeshChannelsCount = anim->MNumMorphMeshChannels, | |
| MorphMeshChannels = [.. meshMorphs] | |
| }; | |
| animations.Add(importedAnimation.Name, importedAnimation); | |
| } | |
| return animations; | |
| } | |
| public class MeshData | |
| { | |
| public string Name { get; set; } | |
| public float Weight { get; set; } | |
| public int VertexCount { get; set; } | |
| public Vector3[] Vertices { get; set; } | |
| public Vector3[] Normals { get; set; } | |
| public Vector3[] Tangents { get; set; } | |
| public Vector3[] Bitangents { get; set; } | |
| public Vector4[][] Colors { get; set; } = new Vector4[8][]; | |
| } | |
| public class Animation | |
| { | |
| public string Name { get; set; } | |
| public double Duration { get; set; } | |
| public double TicksPerSecond { get; set; } | |
| public uint ChannelsCount { get; set; } | |
| public Dictionary<string, float[]> Channels; | |
| //public NodeAnim** mChannels = null, | |
| public uint MeshChannelsCount { get; set; } | |
| public Dictionary<string, float[]> MeshChannels; | |
| //MeshAnim** mMeshChannels = null, | |
| public uint MorphMeshChannelsCount { get; set; } | |
| public List<MeshMorph> MorphMeshChannels = []; | |
| //public MeshMorphAnim** mMorphMeshChannels = null | |
| public class MeshMorph | |
| { | |
| public string Name { get; set; } | |
| public uint KeysCount { get; set; } | |
| public MorphMeshKey[] Keys { get; set; } | |
| } | |
| public class MorphMeshKey | |
| { | |
| public double Time { get; set; } | |
| public uint[] Values { get; set; } | |
| public double[] Weights { get; set; } | |
| public uint ValuesAndWeightsCount { get; set; } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment