// // Created by martin on 12.11.21. // #include "AnimationController.h" #include #include #include #include #include #include "AnimNodes/AnimSamplerNode.h" #include "AnimNodes/BlendNode.h" #include "AnimNodes/SpeedScaleNode.h" #include "SkinnedMesh.h" AnimationController::AnimationController(SkinnedMesh* skinned_mesh) : m_current_time(0.f), m_skinned_mesh(skinned_mesh) { const int num_soa_joints = skinned_mesh->m_skeleton.num_soa_joints(); const int num_joints = skinned_mesh->m_skeleton.num_joints(); skinned_mesh->m_local_matrices.resize(num_soa_joints); skinned_mesh->m_model_matrices.resize(num_joints); m_local_matrices.resize(num_soa_joints); ResetAnims(); AnimSamplerNode* sampler_node0 = new AnimSamplerNode(this); sampler_node0->m_name = "AnimSampler0"; sampler_node0->SetAnimation(skinned_mesh->m_animations[1]); m_anim_nodes.push_back(sampler_node0); AnimSamplerNode* sampler_node1 = new AnimSamplerNode(this); sampler_node1->m_name = "AnimSampler1"; sampler_node1->SetAnimation(skinned_mesh->m_animations[2]); m_anim_nodes.push_back(sampler_node1); SpeedScaleNode* speed_node = new SpeedScaleNode(this); speed_node->m_name = "SpeedNode0"; speed_node->m_input_node = sampler_node0; m_anim_nodes.push_back(speed_node); BlendNode* blend_node = new BlendNode(this); blend_node->m_name = "Blend0"; blend_node->m_input_A = speed_node; blend_node->m_input_B = sampler_node1; blend_node->m_sync_inputs = false; m_anim_nodes.push_back(blend_node); SpeedScaleNode* speed_node1 = new SpeedScaleNode(this); speed_node1->m_name = "SpeedNode1"; speed_node1->m_input_node = blend_node; m_anim_nodes.push_back(speed_node1); m_output_node = speed_node1; UpdateOrderedNodes(); m_output_node->Reset(); } AnimationController::~AnimationController() { while (m_anim_nodes.size() > 0) { delete m_anim_nodes[m_anim_nodes.size() - 1]; m_anim_nodes.pop_back(); } m_output_node = nullptr; } void AnimationController::ResetAnims() { for (int i = 0; i < m_ordered_nodes.size(); i++) { m_ordered_nodes[i]->Reset(); } } void AnimationController::UpdateOrderedNodes() { std::vector node_stack; node_stack.push_back(m_output_node); m_ordered_nodes.clear(); while (node_stack.size() > 0) { AnimNode* node = node_stack.back(); m_ordered_nodes.push_back(node); node_stack.pop_back(); std::vector node_inputs; node->GetInputNodes(node_inputs); for (int i = node_inputs.size() - 1; i >= 0; i--) { node_stack.push_back(node_inputs[i]); } } } void AnimationController::UpdateBlendLogic() { } void AnimationController::UpdateTime(float dt) { if (m_output_node == nullptr) { return; } // Mark all nodes that evaluate time using sync tracks. m_output_node->UpdateIsSynced(false); // For all synced nodes calculate their current sync track durations for (int i = m_ordered_nodes.size() - 1; i >= 0; i--) { AnimNode* node = m_ordered_nodes[i]; if (node->m_is_time_synced) { node->EvalAnimDuration(); } } // Update the time of all nodes. m_output_node->UpdateTime(dt); } void AnimationController::Evaluate() { if (m_output_node == nullptr) { return; } m_output_node->Evaluate(&m_local_matrices); // convert joint matrices from local to model space ozz::animation::LocalToModelJob ltm_job; ltm_job.skeleton = &m_skinned_mesh->m_skeleton; ltm_job.input = make_span(m_local_matrices); ltm_job.output = make_span(m_skinned_mesh->m_model_matrices); ltm_job.Run(); }; void AnimationController::DrawDebugUi() { ImGui::SetNextWindowSize(ImVec2(500, 300), ImGuiCond_FirstUseEver); ImGui::Begin("AnimationController"); if (ImGui::Button("Reset")) { ResetAnims(); } if (m_output_node && ImGui::TreeNode("Output")) { m_output_node->DrawDebugUi(); ImGui::TreePop(); } if (m_output_node && ImGui::TreeNode("Nodes")) { ImGui::Columns(4, "NodeOverview"); // 4-ways, with border ImGui::Separator(); ImGui::Text("Name"); ImGui::NextColumn(); ImGui::Text("Synced"); ImGui::NextColumn(); ImGui::Text("Duration"); ImGui::NextColumn(); ImGui::Text("Time"); ImGui::NextColumn(); ImGui::Separator(); static int selected = -1; for (int i = 0; i < m_ordered_nodes.size(); i++) { AnimNode* node = m_ordered_nodes[i]; if (ImGui::Selectable(node->m_name.c_str(), selected == i, ImGuiSelectableFlags_SpanAllColumns)) selected = i; bool hovered = ImGui::IsItemHovered(); ImGui::NextColumn(); ImGui::Text(node->m_is_time_synced ? "X" : "-"); ImGui::NextColumn(); ImGui::PushID((void*)&node->m_anim_duration); ImGui::Text("%2.3f", node->m_anim_duration); ImGui::NextColumn(); ImGui::PopID(); ImGui::PushID((void*)&node->m_current_time); ImGui::Text("%2.3f", node->m_current_time); ImGui::NextColumn(); ImGui::PopID(); } ImGui::Columns(1); ImGui::Separator(); ImGui::TreePop(); } ImGui::End(); }