diff --git a/Editor/MeshWindow.cpp b/Editor/MeshWindow.cpp index faebb13b2..bd5d07e60 100644 --- a/Editor/MeshWindow.cpp +++ b/Editor/MeshWindow.cpp @@ -513,6 +513,32 @@ void MeshWindow::Create(EditorComponent* editor) AddWidget(&terrainGenButton); + morphTargetCombo.Create("Morph Target:"); + morphTargetCombo.SetSize(XMFLOAT2(100, hei)); + morphTargetCombo.SetPos(XMFLOAT2(x + 280, y += step)); + morphTargetCombo.OnSelect([&](wiEventArgs args) { + MeshComponent* mesh = wiScene::GetScene().meshes.GetComponent(entity); + if (mesh != nullptr && args.iValue < mesh->targets.size()) + { + morphTargetSlider.SetValue(mesh->targets[args.iValue].weight); + } + }); + morphTargetCombo.SetTooltip("Choose a morph target to edit weight."); + AddWidget(&morphTargetCombo); + + morphTargetSlider.Create(0, 1, 0, 100000, "Weight: "); + morphTargetSlider.SetTooltip("Set the weight for morph target"); + morphTargetSlider.SetSize(XMFLOAT2(100, hei)); + morphTargetSlider.SetPos(XMFLOAT2(x + 280, y += step)); + morphTargetSlider.OnSlide([&](wiEventArgs args) { + MeshComponent* mesh = wiScene::GetScene().meshes.GetComponent(entity); + if (mesh != nullptr && morphTargetCombo.GetSelected() < mesh->targets.size()) + { + mesh->targets[morphTargetCombo.GetSelected()].weight = args.fValue; + mesh->CreateRenderData(); + } + }); + AddWidget(&morphTargetSlider); Translate(XMFLOAT3((float)wiRenderer::GetDevice()->GetScreenWidth() - 1000, 80, 0)); SetVisible(false); @@ -603,6 +629,17 @@ void MeshWindow::SetEntity(Entity entity) massSlider.SetValue(physicscomponent->mass); frictionSlider.SetValue(physicscomponent->friction); } + + uint8_t selected = morphTargetCombo.GetSelected(); + morphTargetCombo.ClearItems(); + for (size_t i = 0; i < mesh->targets.size(); i++) + { + morphTargetCombo.AddItem(std::to_string(i).c_str()); + } + if (selected < mesh->targets.size()) + { + morphTargetCombo.SetSelected(selected); + } SetEnabled(true); } else diff --git a/Editor/MeshWindow.h b/Editor/MeshWindow.h index 3ddc2af12..297eaaa4d 100644 --- a/Editor/MeshWindow.h +++ b/Editor/MeshWindow.h @@ -31,5 +31,8 @@ public: wiComboBox terrainMat2Combo; wiComboBox terrainMat3Combo; wiButton terrainGenButton; + + wiComboBox morphTargetCombo; + wiSlider morphTargetSlider; }; diff --git a/Editor/ModelImporter_GLTF.cpp b/Editor/ModelImporter_GLTF.cpp index 5c161e172..354e3bc58 100644 --- a/Editor/ModelImporter_GLTF.cpp +++ b/Editor/ModelImporter_GLTF.cpp @@ -582,6 +582,12 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene) Entity meshEntity = scene.Entity_CreateMesh(x.name); MeshComponent& mesh = *scene.meshes.GetComponent(meshEntity); + mesh.targets.resize(x.weights.size()); + for (size_t i = 0; i < mesh.targets.size(); i++) + { + mesh.targets[i].weight = static_cast(x.weights[i]); + } + for (auto& prim : x.primitives) { assert(prim.indices >= 0); @@ -781,6 +787,33 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene) } } + for (size_t i = 0; i < mesh.targets.size(); i++) + { + for (auto& attr : prim.targets[i]) + { + const string& attr_name = attr.first; + int attr_data = attr.second; + + const tinygltf::Accessor& accessor = state.gltfModel.accessors[attr_data]; + const tinygltf::BufferView& bufferView = state.gltfModel.bufferViews[accessor.bufferView]; + const tinygltf::Buffer& buffer = state.gltfModel.buffers[bufferView.buffer]; + + int stride = accessor.ByteStride(bufferView); + size_t vertexCount = accessor.count; + + const unsigned char* data = buffer.data.data() + accessor.byteOffset + bufferView.byteOffset; + + if (!attr_name.compare("POSITION")) + { + mesh.targets[i].vertex_positions.resize(vertexOffset + vertexCount); + assert(stride == 12); + for (size_t j = 0; j < vertexCount; ++j) + { + mesh.targets[i].vertex_positions[vertexOffset + j] = ((XMFLOAT3*)data)[j]; + } + } + } + } } } diff --git a/WickedEngine/ArchiveVersionHistory.txt b/WickedEngine/ArchiveVersionHistory.txt index 8b6478527..a9344b3a9 100644 --- a/WickedEngine/ArchiveVersionHistory.txt +++ b/WickedEngine/ArchiveVersionHistory.txt @@ -1,5 +1,6 @@ This file contains changelog of wiArchive versions +53: Support Morph Target 52: Serialized MaterialComponent::subsurfaceProfile 51: Serialized MeshComponent::vertex_tangents 50: Serialized MaterialComponent::SHADERTYPE diff --git a/WickedEngine/wiArchive.cpp b/WickedEngine/wiArchive.cpp index 3c2d51dc9..f3b12aa06 100644 --- a/WickedEngine/wiArchive.cpp +++ b/WickedEngine/wiArchive.cpp @@ -7,7 +7,7 @@ using namespace std; // this should always be only INCREMENTED and only if a new serialization is implemeted somewhere! -uint64_t __archiveVersion = 52; +uint64_t __archiveVersion = 53; // this is the version number of which below the archive is not compatible with the current version uint64_t __archiveVersionBarrier = 22; diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index 075019887..13fb70857 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -429,6 +429,13 @@ namespace wiScene const uint8_t wind = vertex_windweights.empty() ? 0xFF : vertex_windweights[i]; vertices[i].FromFULL(pos, nor, wind); + for (size_t j = 0; j < targets.size(); j++) + { + vertices[i].pos.x += targets[j].weight * targets[j].vertex_positions[i].x; + vertices[i].pos.y += targets[j].weight * targets[j].vertex_positions[i].y; + vertices[i].pos.z += targets[j].weight * targets[j].vertex_positions[i].z; + } + _min = wiMath::Min(_min, pos); _max = wiMath::Max(_max, pos); } diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index 1f6a941b9..6cd124c5e 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -305,6 +305,14 @@ namespace wiScene wiECS::Entity terrain_material2 = wiECS::INVALID_ENTITY; wiECS::Entity terrain_material3 = wiECS::INVALID_ENTITY; + // Morph Targets + struct MeshMorphTarget + { + std::vector vertex_positions; + float_t weight; + }; + std::vector targets; + // Non-serialized attributes: AABB aabb; wiGraphics::GPUBuffer indexBuffer; diff --git a/WickedEngine/wiScene_Serializers.cpp b/WickedEngine/wiScene_Serializers.cpp index 7975ea4bf..e8b035beb 100644 --- a/WickedEngine/wiScene_Serializers.cpp +++ b/WickedEngine/wiScene_Serializers.cpp @@ -336,6 +336,18 @@ namespace wiScene archive >> vertex_tangents; } + if (archive.GetVersion() >= 53) + { + size_t targetCount; + archive >> targetCount; + targets.resize(targetCount); + for (size_t i = 0; i < targetCount; ++i) + { + archive >> targets[i].vertex_positions; + archive >> targets[i].weight; + } + } + wiJobSystem::Execute(seri.ctx, [&](wiJobArgs args) { CreateRenderData(); }); @@ -385,6 +397,16 @@ namespace wiScene archive << vertex_tangents; } + if (archive.GetVersion() >= 53) + { + archive << targets.size(); + for (size_t i = 0; i < targets.size(); ++i) + { + archive << targets[i].vertex_positions; + archive << targets[i].weight; + } + } + } } void ImpostorComponent::Serialize(wiArchive& archive, EntitySerializer& seri)