/* * Copyright (c) Contributors to the Open 3D Engine Project. * For complete copyright and license terms please see the LICENSE at the root of this distribution. * * SPDX-License-Identifier: Apache-2.0 OR MIT * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace AtomSampleViewer { void SkinnedMeshExampleComponent::Reflect(AZ::ReflectContext* context) { if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) { serializeContext->Class < SkinnedMeshExampleComponent, AZ::Component>() ->Version(0) ; } } void SkinnedMeshExampleComponent::Activate() { CreateSkinnedMeshContainer(); m_skinnedMeshContainer->SetActiveSkinnedMeshCount(1); AZ::TickBus::Handler::BusConnect(); m_imguiSidebar.Activate(); ConfigureCamera(); AddImageBasedLight(); } void SkinnedMeshExampleComponent::CreatePlaneObject() { auto meshAsset = AZ::RPI::AssetUtils::GetAssetByProductPath("objects/plane.fbx.azmodel"); m_planeMeshHandle = GetMeshFeatureProcessor()->AcquireMesh(AZ::Render::MeshHandleDescriptor(meshAsset)); GetMeshFeatureProcessor()->SetTransform(m_planeMeshHandle, AZ::Transform::CreateIdentity()); } void SkinnedMeshExampleComponent::Deactivate() { m_skinnedMeshContainer = nullptr; AZ::TickBus::Handler::BusDisconnect(); m_imguiSidebar.Deactivate(); GetMeshFeatureProcessor()->ReleaseMesh(m_planeMeshHandle); m_defaultIbl.Reset(); } void SkinnedMeshExampleComponent::AddImageBasedLight() { m_defaultIbl.Init(m_scene); } void SkinnedMeshExampleComponent::ConfigureCamera() { AZ::Debug::CameraControllerRequestBus::Event(GetCameraEntityId(), &AZ::Debug::CameraControllerRequestBus::Events::Enable, azrtti_typeid()); AZ::Debug::NoClipControllerRequestBus::Event(GetCameraEntityId(), &AZ::Debug::NoClipControllerRequestBus::Events::SetPosition, AZ::Vector3(0.0f, -1.0f, 1.0f)); AZ::Debug::NoClipControllerRequestBus::Event(GetCameraEntityId(), &AZ::Debug::NoClipControllerRequestBus::Events::SetPitch, -0.8f); } void SkinnedMeshExampleComponent::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint timePoint) { m_runTime += deltaTime; DrawSidebar(); if (!m_useFixedTime) { m_skinnedMeshContainer->UpdateAnimation(m_runTime, m_useOutOfSyncBoneAnimation); } if (m_drawBones) { m_skinnedMeshContainer->DrawBones(); } } void SkinnedMeshExampleComponent::DrawSidebar() { if (!m_imguiSidebar.Begin()) { return; } SkinnedMeshConfig config = m_skinnedMeshContainer->GetSkinnedMeshConfig(); bool configWasModified = false; // Imgui limits slider range to half the natural range of the type float segmentCountFloat = static_cast(config.m_segmentCount); configWasModified |= ScriptableImGui::SliderFloat("Segments Per-Mesh", &segmentCountFloat, 2.0f, 2048.0f, "%.0f", ImGuiSliderFlags_Logarithmic); configWasModified |= ScriptableImGui::SliderInt("Vertices Per-Segment", &config.m_verticesPerSegment, 4, 2048); configWasModified |= ScriptableImGui::SliderInt("Bones Per-Mesh", &config.m_boneCount, 4, 256); configWasModified |= ScriptableImGui::SliderInt("Influences Per-Vertex", &config.m_influencesPerVertex, 4, 4); configWasModified |= ScriptableImGui::SliderInt("Sub-mesh count", &config.m_subMeshCount, 1, 128); if (configWasModified) { config.m_segmentCount = static_cast(segmentCountFloat); m_skinnedMeshContainer->SetSkinnedMeshConfig(config); } bool animationWasModified = configWasModified; animationWasModified |= ScriptableImGui::Checkbox("Use Fixed Animation Time", &m_useFixedTime); animationWasModified |= ScriptableImGui::SliderFloat("Fixed Animation Time", &m_fixedAnimationTime, 0.0f, 20.0f); animationWasModified |= ScriptableImGui::Checkbox("Use Out of Sync Bone Animation", &m_useOutOfSyncBoneAnimation); if (m_useFixedTime && animationWasModified) { m_skinnedMeshContainer->UpdateAnimation(m_fixedAnimationTime, m_useOutOfSyncBoneAnimation); } ScriptableImGui::Checkbox("Draw bones", &m_drawBones); if (ScriptableImGui::Button("Reset Clock")) { m_runTime = 0; } m_imguiSidebar.End(); } void SkinnedMeshExampleComponent::CreateSkinnedMeshContainer() { const auto skinnedMeshFeatureProcessor = m_scene->GetFeatureProcessor(); const auto meshFeatureProcessor = m_scene->GetFeatureProcessor(); // Default settings for the sample SkinnedMeshConfig config; config.m_segmentCount = 10; config.m_verticesPerSegment = 7; config.m_boneCount = 4; config.m_influencesPerVertex = 4; m_skinnedMeshContainer = AZStd::make_unique(skinnedMeshFeatureProcessor, meshFeatureProcessor, config); } }