├── .gitignore ├── Content ├── Demo │ ├── Blade_Chainsaw │ │ ├── M_Blade_Chainsaw.uasset │ │ ├── SK_Blade_Chainsaw.uasset │ │ ├── SK_Blade_Chainsaw_Skeleton.uasset │ │ ├── T_Blade_Chainsaw1_D.uasset │ │ ├── T_Blade_Chainsaw1_M.uasset │ │ ├── T_Blade_Chainsaw1_N.uasset │ │ ├── T_Blade_Chainsaw2_D.uasset │ │ ├── T_Blade_Chainsaw2_M.uasset │ │ └── T_Blade_Chainsaw2_N.uasset │ ├── Geometry │ │ └── Meshes │ │ │ ├── 1M_Cube.uasset │ │ │ ├── 1M_Cube_Chamfer.uasset │ │ │ ├── Bump_StaticMesh.uasset │ │ │ ├── CubeMaterial.uasset │ │ │ ├── LeftArm_StaticMesh.uasset │ │ │ ├── Linear_Stair_StaticMesh.uasset │ │ │ ├── RampMaterial.uasset │ │ │ ├── Ramp_StaticMesh.uasset │ │ │ ├── RightArm_StaticMesh.uasset │ │ │ └── TemplateFloor.uasset │ ├── Materials │ │ ├── MI_Head.uasset │ │ ├── MI_Left.uasset │ │ ├── MI_Right.uasset │ │ ├── M_Basic.uasset │ │ ├── M_Mirror.uasset │ │ └── MirrorTexture.uasset │ ├── Modular_Mannequin │ │ ├── Character │ │ │ ├── Animations │ │ │ │ └── UE4_Mannequin_A-Pose.uasset │ │ │ ├── Materials │ │ │ │ ├── M_UE4Man_Body.uasset │ │ │ │ ├── M_UE4Man_ChestLogo.uasset │ │ │ │ └── MaterialLayers │ │ │ │ │ ├── ML_GlossyBlack_Latex_UE4.uasset │ │ │ │ │ ├── ML_Plastic_Shiny_Beige.uasset │ │ │ │ │ ├── ML_Plastic_Shiny_Beige_LOGO.uasset │ │ │ │ │ ├── ML_SoftMetal_UE4.uasset │ │ │ │ │ ├── T_ML_Aluminum01.uasset │ │ │ │ │ ├── T_ML_Aluminum01_N.uasset │ │ │ │ │ ├── T_ML_Rubber_Blue_01_D.uasset │ │ │ │ │ └── T_ML_Rubber_Blue_01_N.uasset │ │ │ ├── Mesh │ │ │ │ ├── SK_Mannequin.uasset │ │ │ │ ├── SK_Mannequin_Arms_Only.uasset │ │ │ │ ├── SK_Mannequin_Chest_Only.uasset │ │ │ │ ├── SK_Mannequin_Guts_Only.uasset │ │ │ │ ├── SK_Mannequin_Head.uasset │ │ │ │ ├── SK_Mannequin_Legs_Only.uasset │ │ │ │ ├── SK_Mannequin_LowerHalf.uasset │ │ │ │ ├── SK_Mannequin_Pelvis_Only.uasset │ │ │ │ ├── SK_Mannequin_Ribs_Only.uasset │ │ │ │ ├── SK_Mannequin_Torso_Only.uasset │ │ │ │ ├── SK_Mannequin_UpperBody.uasset │ │ │ │ └── UE4_Mannequin_Skeleton.uasset │ │ │ ├── PhysicalAssets │ │ │ │ ├── SK_Mannequin_Arms_Only_PhysicsAsset.uasset │ │ │ │ ├── SK_Mannequin_Chest_Only_PhysicsAsset.uasset │ │ │ │ ├── SK_Mannequin_Guts_Only_PhysicsAsset.uasset │ │ │ │ ├── SK_Mannequin_Head_PhysicsAsset.uasset │ │ │ │ ├── SK_Mannequin_Legs_Only_PhysicsAsset.uasset │ │ │ │ ├── SK_Mannequin_LowerHalf_PhysicsAsset.uasset │ │ │ │ ├── SK_Mannequin_Pelvis_Only_PhysicsAsset.uasset │ │ │ │ ├── SK_Mannequin_PhysicsAsset.uasset │ │ │ │ ├── SK_Mannequin_Ribs_Only_PhysicsAsset.uasset │ │ │ │ ├── SK_Mannequin_Torso_Only_PhysicsAsset.uasset │ │ │ │ └── SK_Mannequin_UpperBody_PhysicsAsset.uasset │ │ │ └── Textures │ │ │ │ ├── UE4Man_Logo_N.uasset │ │ │ │ ├── UE4_LOGO_CARD.uasset │ │ │ │ ├── UE4_Mannequin_MAT_MASKA.uasset │ │ │ │ └── UE4_Mannequin__normals.uasset │ │ └── UE4_Mannequin_A-Pose.uasset │ └── ParagonAnimations │ │ ├── Greystone_AO_Blendspace.uasset │ │ ├── Greystone_Locomotion_BS.uasset │ │ ├── Idle.uasset │ │ ├── Idle1.uasset │ │ ├── Idle_AO_CC.uasset │ │ ├── Idle_AO_CD.uasset │ │ ├── Idle_AO_CU.uasset │ │ ├── Idle_AO_LC.uasset │ │ ├── Idle_AO_LD.uasset │ │ ├── Idle_AO_LU.uasset │ │ ├── Idle_AO_RC.uasset │ │ ├── Idle_AO_RD.uasset │ │ ├── Idle_AO_RU.uasset │ │ ├── JogBwdSlopeLean.uasset │ │ ├── JogFwdSlopeLean.uasset │ │ ├── JogLeftSlopeLean.uasset │ │ ├── JogRightSlopeLean.uasset │ │ ├── Jog_Bwd.uasset │ │ ├── Jog_Bwd_Circle_Left.uasset │ │ ├── Jog_Bwd_Circle_Right.uasset │ │ ├── Jog_Downhill_Bwd.uasset │ │ ├── Jog_Downhill_Fwd.uasset │ │ ├── Jog_Downhill_Left.uasset │ │ ├── Jog_Downhill_Right.uasset │ │ ├── Jog_Fwd.uasset │ │ ├── Jog_Fwd_Circle_Left.uasset │ │ ├── Jog_Fwd_Circle_Right.uasset │ │ ├── Jog_Left.uasset │ │ ├── Jog_Left_Circle_Left.uasset │ │ ├── Jog_Left_Circle_Right.uasset │ │ ├── Jog_Right.uasset │ │ ├── Jog_Right_Circle_Left.uasset │ │ ├── Jog_Right_Circle_Right.uasset │ │ ├── Jog_Uphill_Bwd.uasset │ │ ├── Jog_Uphill_Fwd.uasset │ │ ├── Jog_Uphill_Left.uasset │ │ ├── Jog_Uphill_Right.uasset │ │ ├── Locomotion_BS.uasset │ │ ├── Locomotion_TravelMode_BS1D.uasset │ │ ├── SprintBwdSlopeLean.uasset │ │ ├── SprintFwdSlopeLean.uasset │ │ ├── TravelMode_Bwd.uasset │ │ ├── TravelMode_Bwd_Circle_Left.uasset │ │ ├── TravelMode_Bwd_Circle_Right.uasset │ │ ├── TravelMode_Downhill_Bwd.uasset │ │ ├── TravelMode_Downhill_Fwd.uasset │ │ ├── TravelMode_Fwd.uasset │ │ ├── TravelMode_Fwd_Circle_Left.uasset │ │ ├── TravelMode_Fwd_Circle_Right.uasset │ │ ├── TravelMode_Left.uasset │ │ ├── TravelMode_Right.uasset │ │ ├── TravelMode_Uphill_Bwd.uasset │ │ └── TravelMode_Uphill_Fwd.uasset ├── OpenMotion │ ├── OpenMotion_AnimBP.uasset │ └── OpenMotion_Character.uasset ├── OpenMotionDemo.umap ├── UBIK │ ├── Core │ │ ├── I_VRChar.uasset │ │ ├── UBIKComponent.uasset │ │ └── UBIKHelpers.uasset │ ├── VRChar.uasset │ └── VRChar_AnimBP.uasset ├── UE4_Caliko │ └── DemoIK.uasset └── UE4_CalikoDemo.umap ├── LICENSE ├── OpenMotion.uplugin ├── README.md ├── Resources └── Icon128.png └── Source └── OpenMotion ├── OpenMotion.Build.cs ├── Private ├── EBoneConnectionPoint.cpp ├── EBoneConstraintType.cpp ├── EJointType.cpp ├── FabrikBone.cpp ├── FabrikChain.cpp ├── FabrikDebugComponent.cpp ├── FabrikDemoActor.cpp ├── FabrikJoint.cpp ├── FabrikMat3f.cpp ├── FabrikStructure.cpp ├── FabrikUtil.cpp ├── OpenMotion.cpp ├── OpenMotionComponent.cpp └── OpenMotionLibrary.cpp └── Public ├── EBoneConnectionPoint.h ├── EBoneConstraintType.h ├── EJointType.h ├── FabrikBone.h ├── FabrikChain.h ├── FabrikDebugComponent.h ├── FabrikDemoActor.h ├── FabrikJoint.h ├── FabrikMat3f.h ├── FabrikStructure.h ├── FabrikUtil.h ├── OpenMotion.h ├── OpenMotionComponent.h └── OpenMotionLibrary.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Visual Studio 2015 user specific files 2 | .vs/ 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | 22 | # Compiled Static libraries 23 | *.lai 24 | *.la 25 | *.a 26 | *.lib 27 | 28 | # Executables 29 | *.exe 30 | *.out 31 | *.app 32 | *.ipa 33 | 34 | # These project files can be generated by the engine 35 | *.xcodeproj 36 | *.xcworkspace 37 | *.sln 38 | *.suo 39 | *.opensdf 40 | *.sdf 41 | *.VC.db 42 | *.VC.opendb 43 | 44 | # Precompiled Assets 45 | SourceArt/**/*.png 46 | SourceArt/**/*.tga 47 | 48 | # Binary Files 49 | Binaries/* 50 | Plugins/*/Binaries/* 51 | 52 | # Builds 53 | Build/* 54 | 55 | # Whitelist PakBlacklist-.txt files 56 | !Build/*/ 57 | Build/*/** 58 | !Build/*/PakBlacklist*.txt 59 | 60 | # Don't ignore icon files in Build 61 | !Build/**/*.ico 62 | 63 | # Built data for maps 64 | *_BuiltData.uasset 65 | 66 | # Configuration files generated by the Editor 67 | Saved/* 68 | 69 | # Compiled source files for the engine to use 70 | Intermediate/* 71 | Plugins/*/Intermediate/* 72 | 73 | # Cache files for the editor to use 74 | DerivedDataCache/* 75 | -------------------------------------------------------------------------------- /Content/Demo/Blade_Chainsaw/M_Blade_Chainsaw.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Blade_Chainsaw/M_Blade_Chainsaw.uasset -------------------------------------------------------------------------------- /Content/Demo/Blade_Chainsaw/SK_Blade_Chainsaw.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Blade_Chainsaw/SK_Blade_Chainsaw.uasset -------------------------------------------------------------------------------- /Content/Demo/Blade_Chainsaw/SK_Blade_Chainsaw_Skeleton.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Blade_Chainsaw/SK_Blade_Chainsaw_Skeleton.uasset -------------------------------------------------------------------------------- /Content/Demo/Blade_Chainsaw/T_Blade_Chainsaw1_D.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Blade_Chainsaw/T_Blade_Chainsaw1_D.uasset -------------------------------------------------------------------------------- /Content/Demo/Blade_Chainsaw/T_Blade_Chainsaw1_M.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Blade_Chainsaw/T_Blade_Chainsaw1_M.uasset -------------------------------------------------------------------------------- /Content/Demo/Blade_Chainsaw/T_Blade_Chainsaw1_N.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Blade_Chainsaw/T_Blade_Chainsaw1_N.uasset -------------------------------------------------------------------------------- /Content/Demo/Blade_Chainsaw/T_Blade_Chainsaw2_D.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Blade_Chainsaw/T_Blade_Chainsaw2_D.uasset -------------------------------------------------------------------------------- /Content/Demo/Blade_Chainsaw/T_Blade_Chainsaw2_M.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Blade_Chainsaw/T_Blade_Chainsaw2_M.uasset -------------------------------------------------------------------------------- /Content/Demo/Blade_Chainsaw/T_Blade_Chainsaw2_N.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Blade_Chainsaw/T_Blade_Chainsaw2_N.uasset -------------------------------------------------------------------------------- /Content/Demo/Geometry/Meshes/1M_Cube.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Geometry/Meshes/1M_Cube.uasset -------------------------------------------------------------------------------- /Content/Demo/Geometry/Meshes/1M_Cube_Chamfer.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Geometry/Meshes/1M_Cube_Chamfer.uasset -------------------------------------------------------------------------------- /Content/Demo/Geometry/Meshes/Bump_StaticMesh.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Geometry/Meshes/Bump_StaticMesh.uasset -------------------------------------------------------------------------------- /Content/Demo/Geometry/Meshes/CubeMaterial.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Geometry/Meshes/CubeMaterial.uasset -------------------------------------------------------------------------------- /Content/Demo/Geometry/Meshes/LeftArm_StaticMesh.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Geometry/Meshes/LeftArm_StaticMesh.uasset -------------------------------------------------------------------------------- /Content/Demo/Geometry/Meshes/Linear_Stair_StaticMesh.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Geometry/Meshes/Linear_Stair_StaticMesh.uasset -------------------------------------------------------------------------------- /Content/Demo/Geometry/Meshes/RampMaterial.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Geometry/Meshes/RampMaterial.uasset -------------------------------------------------------------------------------- /Content/Demo/Geometry/Meshes/Ramp_StaticMesh.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Geometry/Meshes/Ramp_StaticMesh.uasset -------------------------------------------------------------------------------- /Content/Demo/Geometry/Meshes/RightArm_StaticMesh.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Geometry/Meshes/RightArm_StaticMesh.uasset -------------------------------------------------------------------------------- /Content/Demo/Geometry/Meshes/TemplateFloor.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Geometry/Meshes/TemplateFloor.uasset -------------------------------------------------------------------------------- /Content/Demo/Materials/MI_Head.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Materials/MI_Head.uasset -------------------------------------------------------------------------------- /Content/Demo/Materials/MI_Left.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Materials/MI_Left.uasset -------------------------------------------------------------------------------- /Content/Demo/Materials/MI_Right.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Materials/MI_Right.uasset -------------------------------------------------------------------------------- /Content/Demo/Materials/M_Basic.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Materials/M_Basic.uasset -------------------------------------------------------------------------------- /Content/Demo/Materials/M_Mirror.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Materials/M_Mirror.uasset -------------------------------------------------------------------------------- /Content/Demo/Materials/MirrorTexture.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Materials/MirrorTexture.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Animations/UE4_Mannequin_A-Pose.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Animations/UE4_Mannequin_A-Pose.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Materials/M_UE4Man_Body.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Materials/M_UE4Man_Body.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Materials/M_UE4Man_ChestLogo.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Materials/M_UE4Man_ChestLogo.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Materials/MaterialLayers/ML_GlossyBlack_Latex_UE4.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Materials/MaterialLayers/ML_GlossyBlack_Latex_UE4.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Materials/MaterialLayers/ML_Plastic_Shiny_Beige.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Materials/MaterialLayers/ML_Plastic_Shiny_Beige.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Materials/MaterialLayers/ML_Plastic_Shiny_Beige_LOGO.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Materials/MaterialLayers/ML_Plastic_Shiny_Beige_LOGO.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Materials/MaterialLayers/ML_SoftMetal_UE4.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Materials/MaterialLayers/ML_SoftMetal_UE4.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Materials/MaterialLayers/T_ML_Aluminum01.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Materials/MaterialLayers/T_ML_Aluminum01.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Materials/MaterialLayers/T_ML_Aluminum01_N.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Materials/MaterialLayers/T_ML_Aluminum01_N.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Materials/MaterialLayers/T_ML_Rubber_Blue_01_D.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Materials/MaterialLayers/T_ML_Rubber_Blue_01_D.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Materials/MaterialLayers/T_ML_Rubber_Blue_01_N.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Materials/MaterialLayers/T_ML_Rubber_Blue_01_N.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_Arms_Only.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_Arms_Only.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_Chest_Only.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_Chest_Only.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_Guts_Only.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_Guts_Only.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_Head.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_Head.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_Legs_Only.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_Legs_Only.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_LowerHalf.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_LowerHalf.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_Pelvis_Only.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_Pelvis_Only.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_Ribs_Only.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_Ribs_Only.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_Torso_Only.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_Torso_Only.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_UpperBody.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Mesh/SK_Mannequin_UpperBody.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Mesh/UE4_Mannequin_Skeleton.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Mesh/UE4_Mannequin_Skeleton.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_Arms_Only_PhysicsAsset.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_Arms_Only_PhysicsAsset.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_Chest_Only_PhysicsAsset.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_Chest_Only_PhysicsAsset.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_Guts_Only_PhysicsAsset.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_Guts_Only_PhysicsAsset.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_Head_PhysicsAsset.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_Head_PhysicsAsset.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_Legs_Only_PhysicsAsset.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_Legs_Only_PhysicsAsset.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_LowerHalf_PhysicsAsset.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_LowerHalf_PhysicsAsset.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_Pelvis_Only_PhysicsAsset.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_Pelvis_Only_PhysicsAsset.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_PhysicsAsset.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_PhysicsAsset.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_Ribs_Only_PhysicsAsset.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_Ribs_Only_PhysicsAsset.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_Torso_Only_PhysicsAsset.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_Torso_Only_PhysicsAsset.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_UpperBody_PhysicsAsset.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/PhysicalAssets/SK_Mannequin_UpperBody_PhysicsAsset.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Textures/UE4Man_Logo_N.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Textures/UE4Man_Logo_N.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Textures/UE4_LOGO_CARD.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Textures/UE4_LOGO_CARD.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Textures/UE4_Mannequin_MAT_MASKA.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Textures/UE4_Mannequin_MAT_MASKA.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/Character/Textures/UE4_Mannequin__normals.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/Character/Textures/UE4_Mannequin__normals.uasset -------------------------------------------------------------------------------- /Content/Demo/Modular_Mannequin/UE4_Mannequin_A-Pose.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/Modular_Mannequin/UE4_Mannequin_A-Pose.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Greystone_AO_Blendspace.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Greystone_AO_Blendspace.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Greystone_Locomotion_BS.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Greystone_Locomotion_BS.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Idle.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Idle.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Idle1.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Idle1.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Idle_AO_CC.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Idle_AO_CC.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Idle_AO_CD.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Idle_AO_CD.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Idle_AO_CU.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Idle_AO_CU.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Idle_AO_LC.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Idle_AO_LC.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Idle_AO_LD.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Idle_AO_LD.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Idle_AO_LU.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Idle_AO_LU.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Idle_AO_RC.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Idle_AO_RC.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Idle_AO_RD.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Idle_AO_RD.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Idle_AO_RU.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Idle_AO_RU.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/JogBwdSlopeLean.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/JogBwdSlopeLean.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/JogFwdSlopeLean.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/JogFwdSlopeLean.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/JogLeftSlopeLean.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/JogLeftSlopeLean.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/JogRightSlopeLean.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/JogRightSlopeLean.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Bwd.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Bwd.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Bwd_Circle_Left.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Bwd_Circle_Left.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Bwd_Circle_Right.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Bwd_Circle_Right.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Downhill_Bwd.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Downhill_Bwd.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Downhill_Fwd.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Downhill_Fwd.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Downhill_Left.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Downhill_Left.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Downhill_Right.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Downhill_Right.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Fwd.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Fwd.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Fwd_Circle_Left.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Fwd_Circle_Left.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Fwd_Circle_Right.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Fwd_Circle_Right.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Left.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Left.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Left_Circle_Left.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Left_Circle_Left.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Left_Circle_Right.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Left_Circle_Right.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Right.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Right.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Right_Circle_Left.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Right_Circle_Left.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Right_Circle_Right.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Right_Circle_Right.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Uphill_Bwd.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Uphill_Bwd.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Uphill_Fwd.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Uphill_Fwd.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Uphill_Left.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Uphill_Left.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Jog_Uphill_Right.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Jog_Uphill_Right.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Locomotion_BS.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Locomotion_BS.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/Locomotion_TravelMode_BS1D.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/Locomotion_TravelMode_BS1D.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/SprintBwdSlopeLean.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/SprintBwdSlopeLean.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/SprintFwdSlopeLean.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/SprintFwdSlopeLean.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/TravelMode_Bwd.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/TravelMode_Bwd.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/TravelMode_Bwd_Circle_Left.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/TravelMode_Bwd_Circle_Left.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/TravelMode_Bwd_Circle_Right.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/TravelMode_Bwd_Circle_Right.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/TravelMode_Downhill_Bwd.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/TravelMode_Downhill_Bwd.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/TravelMode_Downhill_Fwd.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/TravelMode_Downhill_Fwd.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/TravelMode_Fwd.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/TravelMode_Fwd.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/TravelMode_Fwd_Circle_Left.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/TravelMode_Fwd_Circle_Left.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/TravelMode_Fwd_Circle_Right.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/TravelMode_Fwd_Circle_Right.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/TravelMode_Left.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/TravelMode_Left.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/TravelMode_Right.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/TravelMode_Right.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/TravelMode_Uphill_Bwd.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/TravelMode_Uphill_Bwd.uasset -------------------------------------------------------------------------------- /Content/Demo/ParagonAnimations/TravelMode_Uphill_Fwd.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/Demo/ParagonAnimations/TravelMode_Uphill_Fwd.uasset -------------------------------------------------------------------------------- /Content/OpenMotion/OpenMotion_AnimBP.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/OpenMotion/OpenMotion_AnimBP.uasset -------------------------------------------------------------------------------- /Content/OpenMotion/OpenMotion_Character.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/OpenMotion/OpenMotion_Character.uasset -------------------------------------------------------------------------------- /Content/OpenMotionDemo.umap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/OpenMotionDemo.umap -------------------------------------------------------------------------------- /Content/UBIK/Core/I_VRChar.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/UBIK/Core/I_VRChar.uasset -------------------------------------------------------------------------------- /Content/UBIK/Core/UBIKComponent.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/UBIK/Core/UBIKComponent.uasset -------------------------------------------------------------------------------- /Content/UBIK/Core/UBIKHelpers.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/UBIK/Core/UBIKHelpers.uasset -------------------------------------------------------------------------------- /Content/UBIK/VRChar.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/UBIK/VRChar.uasset -------------------------------------------------------------------------------- /Content/UBIK/VRChar_AnimBP.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/UBIK/VRChar_AnimBP.uasset -------------------------------------------------------------------------------- /Content/UE4_Caliko/DemoIK.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/UE4_Caliko/DemoIK.uasset -------------------------------------------------------------------------------- /Content/UE4_CalikoDemo.umap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Content/UE4_CalikoDemo.umap -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Robert Chubb 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /OpenMotion.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "1.0", 5 | "FriendlyName": "OpenMotion", 6 | "Description": "", 7 | "Category": "Other", 8 | "CreatedBy": "", 9 | "CreatedByURL": "", 10 | "DocsURL": "", 11 | "MarketplaceURL": "", 12 | "SupportURL": "", 13 | "CanContainContent": true, 14 | "IsBetaVersion": false, 15 | "IsExperimentalVersion": false, 16 | "Installed": false, 17 | "Modules": [ 18 | { 19 | "Name": "OpenMotion", 20 | "Type": "Runtime", 21 | "LoadingPhase": "Default" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenMotion 2 | The goal is to create believable run-time ready character interactions within a simulated game world. 3 | 4 | We will explore Forward and Inverse Kinematics, Physical Animation, Procedural Animation, Motion Matching, and more. 5 | 6 | # Similar Projects 7 | IKinema's Full Body IK 8 | 9 | NaturalMotion's Morpheme, Endorphin and Euphoria. 10 | 11 | Dynamic Animation and Control Environment (DANCE)- by Ari Shapiro, Victor Ng-Thow-Hing and Petros Faloutsos 12 | 13 | # License and Tool used 14 | OpenMotion is an MIT license based Unreal Engine 4 Plugin and Demo Project. 15 | 16 | # Future Work 17 | A topic which closely related is Russell L. Smith's Intelligent Motion Control with an Artificial Cerebellum. 18 | 19 | If there is large interest in this project, or I'm asked specifically to, I'll see what I can't get going. 20 | 21 | # P.S. 22 | If you know of an interesting project, idea, or research paper, please let the community know about it! 23 | 24 | -------------------------------------------------------------------------------- /Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaxonRah/OpenMotion/55e57a9a58c81e7ee08099985e529344a6a7d72e/Resources/Icon128.png -------------------------------------------------------------------------------- /Source/OpenMotion/OpenMotion.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | 5 | public class OpenMotion : ModuleRules 6 | { 7 | public OpenMotion(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicIncludePaths.AddRange( 12 | new string[] { 13 | // ... add public include paths required here ... 14 | } 15 | ); 16 | 17 | 18 | PrivateIncludePaths.AddRange( 19 | new string[] { 20 | // ... add other private include paths required here ... 21 | } 22 | ); 23 | 24 | 25 | PublicDependencyModuleNames.AddRange( 26 | new string[] 27 | { 28 | "Core", 29 | // ... add other public dependencies that you statically link with here ... 30 | } 31 | ); 32 | 33 | 34 | PrivateDependencyModuleNames.AddRange( 35 | new string[] 36 | { 37 | "CoreUObject", 38 | "Engine", 39 | "Slate", 40 | "SlateCore", 41 | // ... add private dependencies that you statically link with here ... 42 | } 43 | ); 44 | 45 | 46 | DynamicallyLoadedModuleNames.AddRange( 47 | new string[] 48 | { 49 | // ... add any modules that your module loads dynamically here ... 50 | } 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Source/OpenMotion/Private/EBoneConnectionPoint.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | #include "EBoneConnectionPoint.h" -------------------------------------------------------------------------------- /Source/OpenMotion/Private/EBoneConstraintType.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | #include "EBoneConstraintType.h" -------------------------------------------------------------------------------- /Source/OpenMotion/Private/EJointType.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | #include "EJointType.h" 3 | -------------------------------------------------------------------------------- /Source/OpenMotion/Private/FabrikBone.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | // https://github.com/FedUni/caliko/blob/master/caliko/src/au/edu/federation/caliko/FabrikBone3D.java 3 | 4 | #include "FabrikBone.h" 5 | 6 | #include "OpenMotion.h" 7 | 8 | 9 | UFabrikBone::UFabrikBone(const FObjectInitializer& ObjectInitializer) 10 | { 11 | BoneConnectionPoint = EBoneConnectionPoint::BCP_End; 12 | Joint = NewObject(); 13 | } 14 | 15 | 16 | UFabrikBone* UFabrikBone::Init(FVector InStartLocation, FVector InEndLocation) 17 | 18 | { 19 | this->StartLocation = InStartLocation; 20 | this->EndLocation = InEndLocation; 21 | Length = FVector::Dist(InStartLocation, InEndLocation); 22 | return this; 23 | } 24 | 25 | UFabrikBone* UFabrikBone::Init(FVector InStartLocation, FVector InEndLocation, FName InName) 26 | { 27 | Init(InStartLocation, InEndLocation); 28 | this->Name = InName; 29 | return this; 30 | } 31 | 32 | UFabrikBone* UFabrikBone::Init(FVector InStartLocation, FVector InDirectionUV, float InLength) 33 | { 34 | if (!(InDirectionUV.Size() > 0.0f)) 35 | { 36 | UE_LOG(OpenMotionLog, Fatal, TEXT("Direction cannot be a zero vector!")); 37 | } 38 | 39 | this->Length = InLength; 40 | this->StartLocation = InStartLocation; 41 | InDirectionUV.Normalize(); 42 | this->EndLocation = InStartLocation + (InDirectionUV * InLength); 43 | return this; 44 | } 45 | 46 | UFabrikBone* UFabrikBone::Init(FVector InStartLocation, FVector InDirectionUV, float InLength, FName InName) 47 | { 48 | Init(InStartLocation, InDirectionUV, InLength); 49 | this->Name = InName; 50 | return this; 51 | } 52 | 53 | UFabrikBone* UFabrikBone::Init(FVector InStartLocation, FVector InDirectionUV, float InLength, FColor InColor) 54 | { 55 | 56 | Init(InStartLocation, InDirectionUV, InLength); 57 | Color = InColor; 58 | return this; 59 | } 60 | 61 | UFabrikBone* UFabrikBone::Init(UFabrikBone* Source) 62 | { 63 | StartLocation = Source->StartLocation; 64 | EndLocation = Source->EndLocation; 65 | 66 | // TODO: CHECK: Clone instead of ref 67 | UFabrikJoint* NewJoint = NewObject(); 68 | Joint = NewJoint->Init(Source->Joint); 69 | //Joint = Source->Joint; // Direct copy? Maybe make a clone instead? 70 | //# TODO: Joint.set(source.mJoint); 71 | 72 | Color = Source->Color; 73 | Name = Source->Name; 74 | Length = Source->Length; 75 | LineWidth = Source->LineWidth; 76 | BoneConnectionPoint = Source->BoneConnectionPoint; 77 | return this; 78 | } 79 | 80 | float UFabrikBone::LiveLength() 81 | { 82 | return FVector::Dist(StartLocation, EndLocation); 83 | } 84 | 85 | TArray UFabrikBone::GetStartLocationAsArray() 86 | { 87 | TArray Ret; 88 | Ret.Add(StartLocation.X); 89 | Ret.Add(StartLocation.Y); 90 | Ret.Add(StartLocation.Z); 91 | return Ret; 92 | //return new float[] { StartLocation.x, StartLocation.y, StartLocation.z }; 93 | } 94 | 95 | TArray UFabrikBone::GetEndLocationAsArray() 96 | { 97 | TArray Ret; 98 | Ret.Add(StartLocation.X); 99 | Ret.Add(StartLocation.Y); 100 | Ret.Add(StartLocation.Z); 101 | return Ret; 102 | //return new float[] { StartLocation.x, StartLocation.y, StartLocation.z }; 103 | } 104 | 105 | /** 106 | void UFabrikBone::SetLineWidth(float InLineWidth) 107 | { 108 | // If the specified argument is within the valid range then set it... 109 | /*if (lineWidth >= FabrikBone3D.MIN_LINE_WIDTH && lineWidth <= FabrikBone3D.MAX_LINE_WIDTH) 110 | { 111 | */ 112 | //mLineWidth = lineWidth; 113 | /*} 114 | else // ...otherwise throw an IllegalArgumentException. 115 | { 116 | 117 | throw new IllegalArgumentException("Line width must be between " + 118 | 119 | FabrikBone3D.MIN_LINE_WIDTH + " and " + 120 | 121 | FabrikBone3D.MAX_LINE_WIDTH + " inclusive."); 122 | 123 | }* 124 | }*/ 125 | 126 | FString UFabrikBone::GetDebugMsg() 127 | { 128 | //Vec3f direction = this.getDirectionUV(); 129 | /** 130 | StringBuilder sb = new StringBuilder(); 131 | sb.append("Start joint location : " + mStartLocation + NEW_LINE); 132 | sb.append("End joint location : " + mEndLocation + NEW_LINE); 133 | sb.append("Bone length : " + mLength + NEW_LINE); 134 | sb.append("Colour : " + mColour + NEW_LINE); 135 | return sb.toString();*/ 136 | return "TODO"; 137 | } -------------------------------------------------------------------------------- /Source/OpenMotion/Private/FabrikDebugComponent.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #include "FabrikDebugComponent.h" 4 | 5 | #include "FabrikStructure.h" 6 | #include "FabrikChain.h" 7 | #include "FabrikBone.h" 8 | #include "FabrikUtil.h" 9 | #include "FabrikMat3f.h" 10 | #include "EJointType.h" 11 | #include "EBoneConstraintType.h" 12 | 13 | #include "DrawDebugHelpers.h" 14 | 15 | #include "OpenMotion.h" 16 | 17 | // Sets default values for this component's properties 18 | UFabrikDebugComponent::UFabrikDebugComponent() 19 | { 20 | // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features 21 | // off to improve performance if you don't need them. 22 | PrimaryComponentTick.bCanEverTick = true; 23 | 24 | PointSize = 5.0f; 25 | LineThickness = 2.0f; 26 | DrawEnabled = true; 27 | 28 | // Constraint colours 29 | ANTICLOCKWISE_CONSTRAINT_COLOUR = FColor(255, 0, 0); 30 | CLOCKWISE_CONSTRAINT_COLOUR = FColor(0, 0, 255); 31 | BALL_JOINT_COLOUR = FColor(255, 0, 0); 32 | GLOBAL_HINGE_COLOUR = FColor(255, 255, 0); 33 | LOCAL_HINGE_COLOUR = FColor(0, 255, 255); 34 | REFERENCE_AXIS_COLOUR = FColor(255, 0, 255); 35 | 36 | // The drawn length of the rotor cone and the radius of the cone and circle describing the hinge axes 37 | CONE_LENGTH_FACTOR = 0.3f; 38 | RADIUS_FACTOR = 0.25f; 39 | NUM_CONE_LINES = 12; 40 | 41 | } 42 | 43 | 44 | // Called when the game starts 45 | void UFabrikDebugComponent::BeginPlay() 46 | { 47 | Super::BeginPlay(); 48 | 49 | rotStep = 360.0f / (float)NUM_CONE_LINES; 50 | 51 | } 52 | 53 | 54 | // Called every frame 55 | void UFabrikDebugComponent::TickComponent( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction ) 56 | { 57 | Super::TickComponent( DeltaTime, TickType, ThisTickFunction ); 58 | 59 | if (DrawEnabled == false || Structure == NULL) 60 | return; 61 | 62 | for (UFabrikChain* Chain : Structure->Chains) 63 | { 64 | DrawChainBones(Chain); 65 | DrawChainConstraints(Chain, 1); 66 | } 67 | } 68 | 69 | 70 | void UFabrikDebugComponent::DrawChainBones(UFabrikChain* Chain) 71 | { 72 | 73 | for (int i = 0; i < Chain->NumBones; i++) 74 | { 75 | UFabrikBone* Bone = Chain->GetBone(i); 76 | //UFabrikBone* End = Chain->GetBone(i + 1); 77 | 78 | if (i == 0) 79 | { 80 | DrawDebugPoint( 81 | GetWorld(), 82 | Bone->StartLocation, 83 | PointSize, //size 84 | FColor(255, 0, 255), //pink 85 | false//, //persistent (never goes away) 86 | //0.03 //point leaves a trail on moving object 87 | ); 88 | } 89 | DrawDebugPoint( 90 | GetWorld(), 91 | Bone->EndLocation, 92 | PointSize, //size 93 | FColor(255, 0, 255), //pink 94 | false//, //persistent (never goes away) 95 | //0.03 //point leaves a trail on moving object 96 | ); 97 | 98 | DrawDebugLine( 99 | GetWorld(), 100 | Bone->StartLocation, 101 | Bone->EndLocation, 102 | Bone->Color, // FColor(255, 0, 0), 103 | false, -1, 0, 104 | LineThickness 105 | ); 106 | 107 | } 108 | } 109 | 110 | void UFabrikDebugComponent::DrawConstraint(UFabrikBone* bone, FVector referenceDirection, float lineWidth/*, UFabrikMat3f* mvpMatrix*/) 111 | { 112 | float boneLength = bone->Length; 113 | FVector lineStart = bone->StartLocation; 114 | 115 | switch (bone->Joint->JointType) // .getJointType()) 116 | { 117 | case EJointType::JT_Ball: { 118 | float constraintAngleDegs = bone->Joint->RotorConstraintDegs; // GetBallJointConstraintDegs(); 119 | 120 | // If the ball joint constraint is 180 degrees then it's not really constrained, so we won't draw it 121 | if (UFabrikUtil::ApproximatelyEquals(constraintAngleDegs, 180.0f, 0.01f)) { return; } 122 | 123 | // The constraint direction is the direction of the previous bone rotated about a perpendicular axis by the constraint angle of this bone 124 | FVector constraintDirection = UFabrikUtil::RotateAboutAxisDegs(referenceDirection, constraintAngleDegs, UFabrikUtil::VectorGenPerpendicularVectorQuick(referenceDirection));// .normalised(); 125 | constraintDirection.Normalize(); 126 | 127 | // Draw the lines about the the bone (relative to the reference direction) 128 | FVector lineEnd; 129 | for (int loop = 0; loop < NUM_CONE_LINES; ++loop) 130 | { 131 | lineEnd = lineStart + (constraintDirection * (boneLength * CONE_LENGTH_FACTOR)); 132 | constraintDirection = UFabrikUtil::RotateAboutAxisDegs(constraintDirection, rotStep, referenceDirection);// .normalised(); 133 | DrawLine(lineStart, lineEnd, BALL_JOINT_COLOUR, lineWidth);// , mvpMatrix); 134 | } 135 | 136 | // Draw the circle at the top of the cone 137 | float pushDistance = (float)FMath::Cos(FMath::DegreesToRadians( constraintAngleDegs )) * boneLength; 138 | float radius = (float)FMath::Sin( FMath::DegreesToRadians( constraintAngleDegs)) * boneLength; 139 | FVector circleCentre = lineStart + (referenceDirection * (pushDistance * CONE_LENGTH_FACTOR)); 140 | DrawCircle(circleCentre, referenceDirection, radius * CONE_LENGTH_FACTOR, BALL_JOINT_COLOUR, lineWidth);// , mvpMatrix); 141 | break; 142 | } 143 | case EJointType::JT_GlobalHinge: { 144 | // Get the hinge rotation axis and draw the circle describing the hinge rotation axis 145 | FVector hingeRotationAxis = bone->Joint->RotationAxisUV;// .getJoint().getHingeRotationAxis(); 146 | float radius = boneLength * RADIUS_FACTOR; 147 | DrawCircle(lineStart, hingeRotationAxis, radius, GLOBAL_HINGE_COLOUR, lineWidth);// , mvpMatrix); 148 | 149 | // Note: While ACW rotation is negative and CW rotation about an axis is positive, we store both 150 | // of these as positive values between the range 0 to 180 degrees, as such we'll negate the 151 | // clockwise rotation value for it to turn in the correct direction. 152 | float anticlockwiseConstraintDegs = bone->Joint->HingeAnticlockwiseConstraintDegs;// getHingeJointAnticlockwiseConstraintDegs(); 153 | float clockwiseConstraintDegs = -bone->Joint->HingeClockwiseConstraintDegs;// getHingeJointClockwiseConstraintDegs(); 154 | 155 | // If both the anticlockwise (positive) and clockwise (negative) constraint angles are not 180 degrees (i.e. we 156 | // are constraining the hinge about a reference direction which lies in the plane of the hinge rotation axis)... 157 | if (!UFabrikUtil::ApproximatelyEquals(anticlockwiseConstraintDegs, 180.0f, 0.01f) && 158 | !UFabrikUtil::ApproximatelyEquals(clockwiseConstraintDegs, 180.0f, 0.01f)) 159 | { 160 | FVector hingeReferenceAxis = bone->Joint->ReferenceAxisUV;// HingeReferenceAxis; 161 | 162 | // ...then draw the hinge reference axis and ACW/CW constraints about it. 163 | DrawLine(lineStart, lineStart + (hingeReferenceAxis * (boneLength * RADIUS_FACTOR)), REFERENCE_AXIS_COLOUR, lineWidth);// , mvpMatrix); 164 | FVector anticlockwiseDirection = UFabrikUtil::RotateAboutAxisDegs(hingeReferenceAxis, anticlockwiseConstraintDegs, hingeRotationAxis); 165 | FVector clockwiseDirection = UFabrikUtil::RotateAboutAxisDegs(hingeReferenceAxis, clockwiseConstraintDegs, hingeRotationAxis); 166 | FVector anticlockwisePoint = lineStart + (anticlockwiseDirection * (radius)); 167 | FVector clockwisePoint = lineStart + (clockwiseDirection * (radius)); 168 | DrawLine(lineStart, anticlockwisePoint, ANTICLOCKWISE_CONSTRAINT_COLOUR, lineWidth);// , mvpMatrix); 169 | DrawLine(lineStart, clockwisePoint, CLOCKWISE_CONSTRAINT_COLOUR, lineWidth);// , mvpMatrix); 170 | } 171 | break; 172 | } 173 | case EJointType::JT_LocalHinge: { 174 | // Construct a rotation matrix based on the reference direction (i.e. the previous bone's direction)... 175 | UFabrikMat3f* m = UFabrikMat3f::CreateRotationMatrix(referenceDirection); 176 | 177 | // ...and transform the hinge rotation axis into the previous bone's frame of reference 178 | FVector relativeHingeRotationAxis = m->Times(bone->Joint->RotationAxisUV);// GetHingeRotationAxis());// .normalise(); 179 | relativeHingeRotationAxis.Normalize(); 180 | 181 | // Draw the circle describing the hinge rotation axis 182 | float radius = boneLength * RADIUS_FACTOR; 183 | DrawCircle(lineStart, relativeHingeRotationAxis, radius, LOCAL_HINGE_COLOUR, lineWidth);// , mvpMatrix); 184 | 185 | // Draw the hinge reference and clockwise/anticlockwise constraints if necessary 186 | float anticlockwiseConstraintDegs = bone->Joint->HingeAnticlockwiseConstraintDegs;// getHingeJointAnticlockwiseConstraintDegs(); 187 | float clockwiseConstraintDegs = -bone->Joint->HingeClockwiseConstraintDegs; // .getHingeJointClockwiseConstraintDegs(); 188 | if (!UFabrikUtil::ApproximatelyEquals(anticlockwiseConstraintDegs, 180.0f, 0.01f) && 189 | !UFabrikUtil::ApproximatelyEquals(clockwiseConstraintDegs, 180.0f, 0.01f)) 190 | { 191 | // Get the relative hinge rotation axis and draw it... 192 | FVector relativeHingeReferenceAxis = UFabrikUtil::ProjectOntoPlane(bone->Joint->ReferenceAxisUV, relativeHingeRotationAxis); //;getHingeReferenceAxis().projectOntoPlane(relativeHingeRotationAxis); 193 | relativeHingeReferenceAxis = m->Times(bone->Joint->ReferenceAxisUV);// getHingeReferenceAxis());// .normalise(); 194 | relativeHingeReferenceAxis.Normalize(); 195 | 196 | DrawLine(lineStart, lineStart + (relativeHingeReferenceAxis * radius), REFERENCE_AXIS_COLOUR, lineWidth);// , mvpMatrix); 197 | 198 | // ...as well as the clockwise and anticlockwise constraints. 199 | FVector anticlockwiseDirection = UFabrikUtil::RotateAboutAxisDegs(relativeHingeReferenceAxis, anticlockwiseConstraintDegs, relativeHingeRotationAxis); 200 | FVector clockwiseDirection = UFabrikUtil::RotateAboutAxisDegs(relativeHingeReferenceAxis, clockwiseConstraintDegs, relativeHingeRotationAxis); 201 | FVector anticlockwisePoint = lineStart + (anticlockwiseDirection * radius); 202 | FVector clockwisePoint = lineStart + (clockwiseDirection * radius); 203 | DrawLine(lineStart, anticlockwisePoint, ANTICLOCKWISE_CONSTRAINT_COLOUR, lineWidth);// , mvpMatrix); 204 | DrawLine(lineStart, clockwisePoint, CLOCKWISE_CONSTRAINT_COLOUR, lineWidth);// , mvpMatrix); 205 | } 206 | break; 207 | } 208 | 209 | } // End of switch statement 210 | } 211 | 212 | void UFabrikDebugComponent::DrawLine(FVector Start, FVector End, FColor Color, float lineWidth) 213 | { 214 | DrawDebugLine( 215 | GetWorld(), 216 | Start, 217 | End, 218 | Color, // 219 | false, -1, 0//, 220 | //1 lineWidth 221 | ); 222 | } 223 | 224 | void UFabrikDebugComponent::DrawCircle(FVector Location, FVector Axis, float Radius, FColor Color, float LineWidth) 225 | { 226 | int NUM_VERTICES = NUM_CONE_LINES; //## 227 | 228 | FVector firstPoint; 229 | FVector prevPoint; 230 | // Generate the circle data and put it into the FloatBuffer 231 | for (int vertexNumLoop = 0; vertexNumLoop < NUM_VERTICES; vertexNumLoop++) 232 | { 233 | // Create our circle in the plane perpendicular to the axis provided 234 | float angleDegs = vertexNumLoop * (360.0f / (float)NUM_VERTICES); 235 | FVector perpAxis = UFabrikUtil::VectorGenPerpendicularVectorQuick(Axis); 236 | FVector point(Radius * perpAxis.X, Radius * perpAxis.Y, Radius * perpAxis.Z); 237 | 238 | // Rotate each point about the axis given 239 | point = UFabrikUtil::RotateAboutAxisDegs(point, angleDegs, Axis); 240 | 241 | // Translate to the given location 242 | point = point + Location; 243 | 244 | if (vertexNumLoop == 0) 245 | { 246 | firstPoint = point; 247 | } 248 | else if (vertexNumLoop == NUM_VERTICES - 1) 249 | { 250 | // last point 251 | DrawLine(prevPoint, point, Color, LineWidth); 252 | DrawLine(point, firstPoint, Color, LineWidth); 253 | } 254 | else 255 | { 256 | DrawLine(prevPoint, point, Color, LineWidth); 257 | } 258 | 259 | prevPoint = point; 260 | // Point x/y/z 261 | //circleData[(vertexNumLoop * VERTEX_COMPONENTS)] = point.x; 262 | //circleData[(vertexNumLoop * VERTEX_COMPONENTS) + 1] = point.y; 263 | //circleData[(vertexNumLoop * VERTEX_COMPONENTS) + 2] = point.z; 264 | } 265 | 266 | } 267 | 268 | 269 | void UFabrikDebugComponent::DrawChainConstraints(UFabrikChain* Chain, float LineWidth) // , Mat4f mvpMatrix 270 | { 271 | int numBones = Chain->NumBones; 272 | if (numBones > 0) 273 | { 274 | // Draw the base bone, using the constraint UV as the relative direction 275 | switch (Chain->BaseboneConstraintType) 276 | { 277 | case EBoneConstraintType::BCT_None: 278 | break; 279 | case EBoneConstraintType::BCT_GlobalRotor:// GLOBAL_ROTOR: 280 | case EBoneConstraintType::BCT_GlobalHinge: // GLOBAL_HINGE: 281 | DrawConstraint(Chain->GetBone(0), Chain->BaseboneConstraintUV, LineWidth);// , mvpMatrix); 282 | break; 283 | case EBoneConstraintType::BCT_LocalRotor:// LOCAL_ROTOR: 284 | case EBoneConstraintType::BCT_LocalHinge: // LOCAL_HINGE: 285 | // If the structure hasn't been solved yet then we won't have a relative basebone constraint which we require 286 | // to draw the constraint itself - so our best option is to simply not draw the constraint until we can. 287 | if (Chain->BaseboneRelativeConstraintUV.Size() > 0.0f) 288 | { 289 | DrawConstraint(Chain->GetBone(0), Chain->BaseboneRelativeConstraintUV, LineWidth);// , mvpMatrix); 290 | } 291 | break; 292 | // No need for a default - constraint types are enums and we've covered them all. 293 | } 294 | 295 | // Draw all the bones AFTER the base bone, using the previous bone direction as the relative direction 296 | for (int loop = 1; loop < numBones; ++loop) 297 | { 298 | DrawConstraint(Chain->GetBone(loop), Chain->GetBone(loop - 1)->GetDirectionUV(), LineWidth);// , mvpMatrix); 299 | } 300 | 301 | } 302 | 303 | } 304 | 305 | 306 | /** 307 | public void drawBone(FabrikBone3D bone, Mat4f viewMatrix, Mat4f projectionMatrix, Colour4f colour) 308 | 309 | { 310 | 311 | // Clone the model and scale the clone to be twice as wide and deep, and scaled along the z-axis to match the bone length 312 | 313 | Model modelCopy = Model.clone(model); 314 | 315 | modelCopy.scale(2.0f, 2.0f, bone.length()); 316 | 317 | 318 | 319 | // Get our scaled model data 320 | 321 | modelData = modelCopy.getVertexFloatArray(); 322 | 323 | 324 | 325 | // Construct a model matrix for this bone 326 | 327 | Mat4f modelMatrix = new Mat4f(Mat3f.createRotationMatrix(bone.getDirectionUV().normalised()), bone.getStartLocation()); 328 | 329 | 330 | 331 | // Construct a ModelViewProjection and draw the model for this bone 332 | 333 | Mat4f mvpMatrix = projectionMatrix.times(viewMatrix).times(modelMatrix); 334 | 335 | this.drawModel(mLineWidth, colour, mvpMatrix); 336 | 337 | } 338 | */ -------------------------------------------------------------------------------- /Source/OpenMotion/Private/FabrikDemoActor.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | // https://github.com/FedUni/caliko/blob/master/caliko-demo/src/au/edu/federation/alansley/CalikoDemo3D.java 3 | 4 | #include "FabrikDemoActor.h" 5 | 6 | #include "FabrikStructure.h" 7 | #include "FabrikChain.h" 8 | #include "FabrikBone.h" 9 | #include "FabrikUtil.h" 10 | #include "FabrikDebugComponent.h" 11 | 12 | #include "DrawDebugHelpers.h" 13 | 14 | #include "OpenMotion.h" 15 | 16 | // Sets default values 17 | AFabrikDemoActor::AFabrikDemoActor() 18 | { 19 | // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. 20 | PrimaryActorTick.bCanEverTick = true; 21 | 22 | XAxis = FVector(1, 0, 0); 23 | YAxis = FVector(0, 1, 0); 24 | ZAxis = FVector(0, 0, 1); 25 | XAxis = FVector(1, 0, 0); 26 | 27 | DefaultBoneDirection = FVector(0, 0, -1); 28 | DefaultBoneLength = 10.0f; 29 | BoneLineWidth = 5.0f; 30 | ConstraintLineWidth = 2.0f; 31 | BaseRotationAmountDegs = 0.3f; 32 | 33 | PointSize = 5.0f; 34 | LineThickness = 2.0f; 35 | 36 | DemoType = EFabrikDemoType::FD_UnconstrainedBones; 37 | } 38 | 39 | // Called when the game starts or when spawned 40 | void AFabrikDemoActor::BeginPlay() 41 | { 42 | Super::BeginPlay(); 43 | 44 | FabrikDebugComponent = FindComponentByClass(); 45 | 46 | switch (DemoType) 47 | { 48 | case EFabrikDemoType::FD_UnconstrainedBones: DemoUnconstrainedBones();break; 49 | case EFabrikDemoType::FD_RotorBallJointConstrainedBones: DemoRotorBallJointConstrainedBones(); break; 50 | case EFabrikDemoType::FD_RotorConstrainedBaseBones: DemoRotorConstrainedBaseBones(); break; 51 | case EFabrikDemoType::FD_FreelyRotatingGlobalHinges: DemoFreelyRotatingGlobalHinges(); break; 52 | case EFabrikDemoType::FD_GlobalHingesWithReferenceAxisConstraints: DemoGlobalHingesWithReferenceAxisConstraints(); break; 53 | case EFabrikDemoType::FD_FreelyRotatingLocalHinges: DemoFreelyRotatingLocalHinges(); break; 54 | case EFabrikDemoType::FD_LocalHingesWithReferenceAxisConstraints: DemoLocalHingesWithReferenceAxisConstraints(); break; 55 | case EFabrikDemoType::FD_ConnectedChains: DemoConnectedChains(); break; 56 | case EFabrikDemoType::FD_GlobalRotorConstrainedConnectedChains: DemoGlobalRotorConstrainedConnectedChains(); break; 57 | case EFabrikDemoType::FD_LocalRotorConstrainedConnectedChains: DemoLocalRotorConstrainedConnectedChains(); break; 58 | case EFabrikDemoType::FD_ConnectedChainsWithFreelyRotatingGlobalHingedBaseboneConstraints: DemoConnectedChainsWithFreelyRotatingGlobalHingedBaseboneConstraints(); break; 59 | case EFabrikDemoType::FD_ConnectedChainsWithEmbeddedTargets: DemoConnectedChainsWithEmbeddedTargets(); break; 60 | } 61 | 62 | if (FabrikDebugComponent != NULL) 63 | { 64 | FabrikDebugComponent->Structure = this->Structure; 65 | } 66 | 67 | } 68 | 69 | // Called every frame 70 | void AFabrikDemoActor::Tick( float DeltaTime ) 71 | { 72 | Super::Tick( DeltaTime ); 73 | 74 | Structure->SolveForTarget(TargetActor->GetActorLocation()); 75 | 76 | /*for (UFabrikChain* Chain : Structure->Chains) 77 | { 78 | DrawChain(Chain); 79 | }*/ 80 | } 81 | 82 | void AFabrikDemoActor::DrawChain(UFabrikChain* Chain) 83 | { 84 | 85 | for (int i = 0; i < Chain->NumBones; i++) 86 | { 87 | UFabrikBone* Bone = Chain->GetBone(i); 88 | //UFabrikBone* End = Chain->GetBone(i + 1); 89 | 90 | if (i == 0) 91 | { 92 | DrawDebugPoint( 93 | GetWorld(), 94 | Bone->StartLocation, 95 | PointSize, //size 96 | FColor(255, 0, 255), //pink 97 | false, //persistent (never goes away) 98 | 0.03 //point leaves a trail on moving object 99 | ); 100 | } 101 | DrawDebugPoint( 102 | GetWorld(), 103 | Bone->EndLocation, 104 | PointSize, //size 105 | FColor(255, 0, 255), //pink 106 | false, //persistent (never goes away) 107 | 0.03 //point leaves a trail on moving object 108 | ); 109 | 110 | DrawDebugLine( 111 | GetWorld(), 112 | Bone->StartLocation, 113 | Bone->EndLocation, 114 | Bone->Color, // FColor(255, 0, 0), 115 | false, -1, 0, 116 | LineThickness 117 | ); 118 | 119 | } 120 | } 121 | 122 | // http://www.pvladov.com/2012/09/make-color-lighter-or-darker.html 123 | FColor AFabrikDemoActor::Brightness(FColor color, float correctionFactor) 124 | { 125 | float red = (float)color.R; 126 | float green = (float)color.G; 127 | float blue = (float)color.B; 128 | 129 | if (correctionFactor < 0) 130 | { 131 | correctionFactor = 1 + correctionFactor; 132 | red *= correctionFactor; 133 | green *= correctionFactor; 134 | blue *= correctionFactor; 135 | } 136 | else 137 | { 138 | red = (255 - red) * correctionFactor + red; 139 | green = (255 - green) * correctionFactor + green; 140 | blue = (255 - blue) * correctionFactor + blue; 141 | } 142 | 143 | return FColor((int)red, (int)green, (int)blue);// Color.FromArgb(color.A, (int)red, (int)green, (int)blue); 144 | } 145 | 146 | 147 | void AFabrikDemoActor::DemoUnconstrainedBones() 148 | { 149 | // Demo 1 150 | //demoName = "Demo 1 - Unconstrained bones"; 151 | Structure = NewObject(); // new FabrikStructure3D(demoName); 152 | FColor BoneColour = UFabrikUtil::GREEN;// FColor::Green;// new Colour4f(Utils.GREEN); 153 | 154 | // Create a new chain... 155 | UFabrikChain* Chain = NewObject(); // new FabrikChain3D(); 156 | 157 | // ...then create a basebone, set its draw colour and add it to the chain. 158 | FVector StartLoc = FVector(0.0f, 0.0f, 40.0f); 159 | FVector EndLoc = StartLoc + (DefaultBoneDirection * DefaultBoneLength); 160 | 161 | UFabrikBone* Basebone = NewObject(); // new FabrikBone3D(startLoc, endLoc); 162 | Basebone->Init(StartLoc, EndLoc); 163 | 164 | Basebone->Color = BoneColour; 165 | Chain->AddBone(Basebone); 166 | 167 | // Add additional consecutive, unconstrained bones to the chain 168 | for (int BoneLoop = 0; BoneLoop < 7; BoneLoop++) 169 | { 170 | //BoneColour = FColor(FMath::RandRange(0, 255), FMath::RandRange(0, 255), FMath::RandRange(0, 255));// (BoneLoop % 2 == 0) ? BoneColour.lighten(0.4f) : BoneColour.darken(0.4f); 171 | BoneColour = (BoneLoop % 2 == 0) ? UFabrikUtil::Lighten(BoneColour, 0.4f) : UFabrikUtil::Darken(BoneColour, 0.4f);// Brightness(BoneColour, 0.4f) : Brightness(BoneColour, -0.4f); 172 | 173 | Chain->AddConsecutiveBone(DefaultBoneDirection, DefaultBoneLength, BoneColour); 174 | } 175 | 176 | //Chain->FixedBaseMode = false; // # not part of the original demo 177 | 178 | // Finally, add the chain to the structure 179 | Structure->AddChain(Chain); 180 | } 181 | 182 | void AFabrikDemoActor::DemoRotorBallJointConstrainedBones() 183 | { 184 | //demoName = "Demo 2 - Rotor / Ball Joint Constrained Bones"; 185 | Structure = NewObject(); // new FabrikStructure3D(demoName); 186 | int numChains = 3; 187 | float rotStep = 360.0f / (float)numChains; 188 | float constraintAngleDegs = 45.0f; 189 | FColor boneColour;// = new Colour4f(); 190 | 191 | for (int chainLoop = 0; chainLoop < numChains; ++chainLoop) 192 | { 193 | // Create a new chain 194 | UFabrikChain* chain = NewObject(); // new FabrikChain3D(); 195 | 196 | // Choose the bone colour 197 | switch (chainLoop % numChains) 198 | { 199 | case 0: boneColour=UFabrikUtil::MID_RED; break; 200 | case 1: boneColour=UFabrikUtil::MID_GREEN; break; 201 | case 2: boneColour=UFabrikUtil::MID_BLUE; break; 202 | } 203 | 204 | // Set up the initial base bone location... 205 | FVector startLoc = FVector(0.0f, 0.0f, -40.0f); 206 | startLoc = UFabrikUtil::RotateYDegs(startLoc, rotStep * (float)chainLoop); 207 | FVector endLoc = FVector(startLoc); 208 | endLoc.Z -= DefaultBoneLength; 209 | 210 | // ...then create a base bone, set its colour and add it to the chain. 211 | UFabrikBone* basebone = NewObject(); //new FabrikBone3D(startLoc, endLoc); 212 | basebone->Init(startLoc, endLoc); 213 | basebone->Color = boneColour; 214 | chain->AddBone(basebone); 215 | //basebone->Joint->RotorConstraintDegs = constraintAngleDegs; 216 | // Add additional consecutive rotor (i.e. ball joint) constrained bones to the chain 217 | for (int boneLoop = 0; boneLoop < 7; boneLoop++) 218 | { 219 | boneColour = (boneLoop % 2 == 0) ? UFabrikUtil::Lighten(boneColour, 0.4f) : UFabrikUtil::Darken(boneColour, 0.4f);// boneColour.lighten(0.4f) : boneColour.darken(0.4f); 220 | chain->AddConsecutiveRotorConstrainedBoneC(DefaultBoneDirection, DefaultBoneLength, constraintAngleDegs, boneColour); 221 | //chain->AddConsecutiveBone(DefaultBoneDirection, DefaultBoneLength, boneColour); 222 | } 223 | 224 | // chain->FixedBaseMode = false; 225 | 226 | // Finally, add the chain to the structure 227 | Structure->AddChain(chain); 228 | } 229 | } 230 | 231 | void AFabrikDemoActor::DemoRotorConstrainedBaseBones() 232 | { 233 | //demoName = "Demo 3 - Rotor Constrained Base Bones"; 234 | Structure = NewObject(); // new FabrikStructure3D(demoName); 235 | int numChains = 3; 236 | float rotStep = 360.0f / (float)numChains; 237 | float baseBoneConstraintAngleDegs = 20.0f; 238 | 239 | // ... and add multiple chains to it. 240 | FColor boneColour;// = new Colour4f(); 241 | FColor baseBoneColour;// = new Colour4f(); 242 | FVector baseBoneConstraintAxis;// = new Vec3f(); 243 | 244 | for (int chainLoop = 0; chainLoop < numChains; ++chainLoop) 245 | { 246 | // Choose the bone colours and base bone constraint axes 247 | switch (chainLoop % 3) 248 | { 249 | case 0: 250 | boneColour = UFabrikUtil::MID_RED;//.set(Utils.MID_RED); 251 | baseBoneColour = UFabrikUtil::RED; // .set(Utils.RED); 252 | baseBoneConstraintAxis = UFabrikUtil::X_AXIS; 253 | break; 254 | case 1: 255 | boneColour = UFabrikUtil::MID_GREEN; 256 | baseBoneColour = UFabrikUtil::MID_GREEN; 257 | baseBoneConstraintAxis = UFabrikUtil::Y_AXIS; 258 | break; 259 | case 2: 260 | boneColour = UFabrikUtil::MID_BLUE; 261 | baseBoneColour = UFabrikUtil::BLUE; 262 | baseBoneConstraintAxis = UFabrikUtil::VectorNegated(UFabrikUtil::Z_AXIS);// .negated(); 263 | break; 264 | } 265 | 266 | // Create a new chain 267 | UFabrikChain* chain = NewObject(); // new FabrikChain3D(); 268 | 269 | // Set up the initial base bone location... 270 | FVector startLoc = FVector(0.0f, 0.0f, -40.0f); 271 | startLoc = UFabrikUtil::RotateYDegs(startLoc, rotStep * (float)chainLoop); // Vec3f.rotateYDegs(startLoc, rotStep * (float)chainLoop); 272 | FVector endLoc = startLoc + (baseBoneConstraintAxis * (DefaultBoneLength * 2.0f)); 273 | 274 | // ...then create a base bone, set its colour, add it to the chain and specify that it should be global rotor constrained. 275 | UFabrikBone* basebone = NewObject(); // new FabrikBone3D(startLoc, endLoc); 276 | basebone->Init(startLoc, endLoc); 277 | basebone->Color = baseBoneColour; 278 | chain->AddBone(basebone); 279 | chain->SetRotorBaseboneConstraint(EBoneConstraintType::BCT_GlobalRotor, baseBoneConstraintAxis, baseBoneConstraintAngleDegs); 280 | 281 | // Add additional consecutive, unconstrained bones to the chain 282 | for (int boneLoop = 0; boneLoop < 7; boneLoop++) 283 | { 284 | boneColour = (boneLoop % 2 == 0) ? UFabrikUtil::Lighten(boneColour, 0.5f) : UFabrikUtil::Darken(boneColour, 0.5f); // boneColour.lighten(0.5f) : boneColour.darken(0.5f); 285 | chain->AddConsecutiveBone(DefaultBoneDirection, DefaultBoneLength, boneColour); 286 | } 287 | 288 | // Finally, add the chain to the structure 289 | Structure->AddChain(chain); 290 | } 291 | } 292 | 293 | void AFabrikDemoActor::DemoFreelyRotatingGlobalHinges() 294 | { 295 | //demoName = "Demo 4 - Freely Rotating Global Hinges"; 296 | Structure = NewObject();// new FabrikStructure3D(demoName); 297 | int numChains = 3; 298 | float rotStep = 360.0f / (float)numChains; 299 | 300 | // We'll create a circular arrangement of 3 chains which are each constrained about different global axes. 301 | // Note: Although I've used the cardinal X/Y/Z axes here, any axis can be used. 302 | FVector globalHingeAxis;// = new Vec3f(); 303 | for (int chainLoop = 0; chainLoop < numChains; ++chainLoop) 304 | { 305 | // Set colour and axes 306 | FColor chainColour;// = new Colour4f(); 307 | switch (chainLoop % numChains) 308 | { 309 | case 0: 310 | chainColour = UFabrikUtil::RED; 311 | globalHingeAxis = UFabrikUtil::X_AXIS; 312 | break; 313 | case 1: 314 | chainColour = UFabrikUtil::GREEN; 315 | globalHingeAxis = UFabrikUtil::Y_AXIS; 316 | break; 317 | case 2: 318 | chainColour = UFabrikUtil::BLUE; 319 | globalHingeAxis = UFabrikUtil::Z_AXIS; 320 | break; 321 | } 322 | 323 | // Create a new chain 324 | UFabrikChain* chain = NewObject();// new FabrikChain3D(); 325 | 326 | // Set up the initial base bone location... 327 | FVector startLoc(0.0f, 0.0f, -40.0f); 328 | startLoc = UFabrikUtil::RotateYDegs(startLoc, rotStep * (float)chainLoop); 329 | FVector endLoc = startLoc + (DefaultBoneDirection * DefaultBoneLength); 330 | 331 | // ...then create a base bone, set its colour, and add it to the chain. 332 | UFabrikBone* basebone = NewObject();// new FabrikBone3D(startLoc, endLoc); 333 | basebone->Init(startLoc, endLoc); 334 | basebone->Color = chainColour; 335 | chain->AddBone(basebone); 336 | 337 | // Add alternating global hinge constrained and unconstrained bones to the chain 338 | for (int boneLoop = 0; boneLoop < 7; boneLoop++) 339 | { 340 | if (boneLoop % 2 == 0) 341 | { 342 | chain->AddConsecutiveFreelyRotatingHingedBoneC(DefaultBoneDirection, DefaultBoneLength, EJointType::JT_GlobalHinge, globalHingeAxis, UFabrikUtil::GREY); 343 | } 344 | else 345 | { 346 | chain->AddConsecutiveBone(DefaultBoneDirection, DefaultBoneLength, chainColour); 347 | } 348 | } 349 | 350 | // Finally, add the chain to the structure 351 | Structure->AddChain(chain); 352 | } 353 | } 354 | 355 | void AFabrikDemoActor::DemoGlobalHingesWithReferenceAxisConstraints() 356 | { 357 | //demoName = "Demo 5 - Global Hinges With Reference Axis Constraints"; 358 | Structure = NewObject();//mStructure = new FabrikStructure3D(demoName); 359 | 360 | // Create a new chain 361 | UFabrikChain* chain = NewObject();// new FabrikChain3D(); 362 | 363 | // Set up the initial base bone location... 364 | FVector startLoc(0.0f, 30.0f, -40.0f); 365 | FVector endLoc(startLoc); 366 | endLoc.Y -= DefaultBoneLength; 367 | 368 | // ...then create a base bone, set its colour, and add it to the chain. 369 | UFabrikBone* basebone = NewObject();// new FabrikBone3D(startLoc, endLoc); 370 | basebone->Init(startLoc, endLoc); 371 | basebone->Color = UFabrikUtil::YELLOW; 372 | chain->AddBone(basebone); 373 | 374 | // Add alternating global hinge constrained and unconstrained bones to the chain 375 | float cwDegs = 120.0f; 376 | float acwDegs = 120.0f; 377 | for (int boneLoop = 0; boneLoop < 8; ++boneLoop) 378 | { 379 | if (boneLoop % 2 == 0) 380 | { 381 | // Params: bone direction, bone length, joint type, hinge rotation axis, clockwise constraint angle, anticlockwise constraint angle, hinge constraint reference axis, colour 382 | // Note: There is a version of this method where you do not specify the colour - the default is to draw the bone in white. 383 | chain->AddConsecutiveHingedBoneC(UFabrikUtil::VectorNegated( UFabrikUtil::Y_AXIS), DefaultBoneLength, EJointType::JT_GlobalHinge, UFabrikUtil::Z_AXIS, cwDegs, acwDegs, UFabrikUtil::VectorNegated( UFabrikUtil::Y_AXIS), UFabrikUtil::GREY); 384 | } 385 | else 386 | { 387 | chain->AddConsecutiveBone(UFabrikUtil::VectorNegated( UFabrikUtil::Y_AXIS ), DefaultBoneLength, UFabrikUtil::MID_GREEN); 388 | } 389 | } 390 | 391 | // Finally, add the chain to the structure 392 | Structure->AddChain(chain); 393 | } 394 | 395 | void AFabrikDemoActor::DemoFreelyRotatingLocalHinges() 396 | { 397 | //demoName = "Demo 6 - Freely Rotating Local Hinges"; 398 | Structure = NewObject();//mStructure = new FabrikStructure3D(demoName); 399 | int numChains = 3; 400 | 401 | // We'll create a circular arrangement of 3 chains with alternate bones each constrained about different local axes. 402 | // Note: Local hinge rotation axes are relative to the rotation matrix of the previous bone in the chain. 403 | FVector hingeRotationAxis;// = new Vec3f();; 404 | 405 | float rotStep = 360.0f / (float)numChains; 406 | for (int loop = 0; loop < numChains; loop++) 407 | { 408 | // Set colour and axes 409 | FColor chainColour;// = new Colour4f(); 410 | switch (loop % 3) 411 | { 412 | case 0: 413 | chainColour = UFabrikUtil::RED; 414 | hingeRotationAxis = UFabrikUtil::X_AXIS; 415 | break; 416 | case 1: 417 | chainColour = UFabrikUtil::GREEN; 418 | hingeRotationAxis = UFabrikUtil::Y_AXIS; 419 | break; 420 | case 2: 421 | chainColour = UFabrikUtil::BLUE; 422 | hingeRotationAxis = UFabrikUtil::Z_AXIS; 423 | break; 424 | } 425 | 426 | // Create a new chain 427 | UFabrikChain* chain = NewObject();//FabrikChain3D chain = new FabrikChain3D(); 428 | 429 | // Set up the initial base bone location... 430 | FVector startLoc(0.0f, 0.0f, -40.0f); 431 | startLoc = UFabrikUtil::RotateYDegs(startLoc, rotStep * (float)loop); 432 | FVector endLoc = startLoc + (DefaultBoneDirection * DefaultBoneLength); 433 | 434 | // ...then create a base bone, set its colour, and add it to the chain. 435 | //FabrikBone3D basebone = new FabrikBone3D(startLoc, endLoc); 436 | UFabrikBone* basebone = NewObject();// new FabrikBone3D(startLoc, endLoc); 437 | basebone->Init(startLoc, endLoc); 438 | basebone->Color = chainColour; 439 | chain->AddBone(basebone); 440 | 441 | // Add alternating local hinge constrained and unconstrained bones to the chain 442 | for (int boneLoop = 0; boneLoop < 6; boneLoop++) 443 | { 444 | if (boneLoop % 2 == 0) 445 | { 446 | chain->AddConsecutiveFreelyRotatingHingedBoneC(DefaultBoneDirection, DefaultBoneLength, EJointType::JT_LocalHinge, hingeRotationAxis, UFabrikUtil::GREY); 447 | } 448 | else 449 | { 450 | chain->AddConsecutiveBone(DefaultBoneDirection, DefaultBoneLength, chainColour); 451 | } 452 | } 453 | 454 | // Finally, add the chain to the structure 455 | Structure->AddChain(chain); 456 | } 457 | } 458 | 459 | void AFabrikDemoActor::DemoLocalHingesWithReferenceAxisConstraints() 460 | { 461 | //demoName = "Demo 7 - Local Hinges with Reference Axis Constraints"; 462 | Structure = NewObject();//mStructure = new FabrikStructure3D(demoName); 463 | int numChains = 3; 464 | 465 | // We'll create a circular arrangement of 3 chains with alternate bones each constrained about different local axes. 466 | // Note: Local hinge rotation axes are relative to the rotation matrix of the previous bone in the chain. 467 | FVector hingeRotationAxis;// = new Vec3f(); 468 | FVector hingeReferenceAxis;// = new Vec3f(); 469 | 470 | float rotStep = 360.0f / (float)numChains; 471 | for (int loop = 0; loop < numChains; loop++) 472 | { 473 | // Set colour and axes 474 | FColor chainColour;// = new Colour4f(); 475 | switch (loop % 3) 476 | { 477 | case 0: 478 | chainColour = UFabrikUtil::RED; 479 | hingeRotationAxis = UFabrikUtil::X_AXIS; 480 | hingeReferenceAxis = UFabrikUtil::Y_AXIS; 481 | break; 482 | case 1: 483 | chainColour = UFabrikUtil::GREEN; 484 | hingeRotationAxis = UFabrikUtil::Y_AXIS; 485 | hingeReferenceAxis = UFabrikUtil::X_AXIS; 486 | break; 487 | case 2: 488 | chainColour = UFabrikUtil::BLUE; 489 | hingeRotationAxis = UFabrikUtil::Z_AXIS; 490 | hingeReferenceAxis = UFabrikUtil::Y_AXIS; 491 | break; 492 | } 493 | 494 | // Create a new chain 495 | UFabrikChain* chain = NewObject();//FabrikChain3D chain = new FabrikChain3D(); 496 | 497 | // Set up the initial base bone location... 498 | FVector startLoc(0.0f, 0.0f, -40.0f); 499 | startLoc = UFabrikUtil::RotateYDegs(startLoc, rotStep * (float)loop); 500 | FVector endLoc = startLoc + (DefaultBoneDirection * DefaultBoneLength); 501 | 502 | // ...then create a base bone, set its colour, and add it to the chain. 503 | //FabrikBone3D basebone = new FabrikBone3D(startLoc, endLoc); 504 | UFabrikBone* basebone = NewObject();// new FabrikBone3D(startLoc, endLoc); 505 | basebone->Init(startLoc, endLoc); 506 | basebone->Color = chainColour; 507 | chain->AddBone(basebone); 508 | 509 | // Add alternating local hinge constrained and unconstrained bones to the chain 510 | float constraintAngleDegs = 90.0f; 511 | for (int boneLoop = 0; boneLoop < 6; boneLoop++) 512 | { 513 | if (boneLoop % 2 == 0) 514 | { 515 | chain->AddConsecutiveHingedBoneC(DefaultBoneDirection, DefaultBoneLength, EJointType::JT_LocalHinge, hingeRotationAxis, constraintAngleDegs, constraintAngleDegs, hingeReferenceAxis, UFabrikUtil::GREY); 516 | } 517 | else 518 | { 519 | chain->AddConsecutiveBone(DefaultBoneDirection, DefaultBoneLength, chainColour); 520 | } 521 | } 522 | 523 | // Finally, add the chain to the structure 524 | Structure->AddChain(chain); 525 | } 526 | } 527 | 528 | void AFabrikDemoActor::DemoConnectedChains() 529 | { 530 | //demoName = "Demo 8 - Connected Chains"; 531 | Structure = NewObject();//mStructure = new FabrikStructure3D(demoName); 532 | FColor boneColour = UFabrikUtil::GREEN; 533 | 534 | // Create a new chain... 535 | UFabrikChain* chain = NewObject();//FabrikChain3D chain = new FabrikChain3D(); 536 | 537 | // ...then create a basebone, set its draw colour and add it to the chain. 538 | FVector startLoc(0.0f, 0.0f, 40.0f); 539 | FVector endLoc = startLoc + (DefaultBoneDirection * DefaultBoneLength); 540 | UFabrikBone* basebone = NewObject();//FabrikBone3D basebone = new FabrikBone3D(startLoc, endLoc); 541 | basebone->Init(startLoc, endLoc); 542 | basebone->Color = boneColour; 543 | chain->AddBone(basebone); 544 | 545 | // Add additional consecutive, unconstrained bones to the chain 546 | for (int boneLoop = 0; boneLoop < 5; boneLoop++) 547 | { 548 | boneColour = (boneLoop % 2 == 0) ? UFabrikUtil::Lighten( boneColour,0.4f) : UFabrikUtil::Darken( boneColour, 0.4f); 549 | chain->AddConsecutiveBone(DefaultBoneDirection, DefaultBoneLength, boneColour); 550 | } 551 | 552 | // Finally, add the chain to the structure 553 | Structure->AddChain(chain); 554 | UFabrikChain* secondChain = NewObject();// new FabrikChain3D("Second Chain"); 555 | //FabrikBone3D base = new FabrikBone3D(FVector(100.0f), new FVector(110.0f)); 556 | UFabrikBone* base = NewObject();// new FabrikBone3D(startLoc, endLoc); 557 | base->Init(FVector(100.0f), FVector(110.0f)); 558 | secondChain->AddBone(base); 559 | secondChain->AddConsecutiveBone(UFabrikUtil::X_AXIS, 20.0f); 560 | secondChain->AddConsecutiveBone(UFabrikUtil::Y_AXIS, 20.0f); 561 | secondChain->AddConsecutiveBone(UFabrikUtil::Z_AXIS, 20.0f); 562 | 563 | // Set the colour of all bones in the chain in a single call, then connect it to the chain... 564 | secondChain->SetColour (UFabrikUtil::RED); 565 | Structure->ConnectChain(secondChain, 0, 0, EBoneConnectionPoint::BCP_Start); 566 | 567 | // ...we can keep adding the same chain at various points if we like, because the chain we 568 | // connect is actually a clone of the one we provide, and not the original 'secondChain' argument. 569 | secondChain->SetColour(UFabrikUtil::WHITE); 570 | Structure->ConnectChain(secondChain, 0, 2, EBoneConnectionPoint::BCP_Start); 571 | 572 | // We can also set connect the chain to the end of a specified bone (this overrides the START/END 573 | // setting of the bone we connect to). 574 | secondChain->SetColour(UFabrikUtil::BLUE); 575 | Structure->ConnectChain(secondChain, 0, 4, EBoneConnectionPoint::BCP_End); 576 | } 577 | 578 | void AFabrikDemoActor::DemoGlobalRotorConstrainedConnectedChains() 579 | { 580 | //demoName = "Demo 9 - Global Rotor Constrained Connected Chains"; 581 | Structure = NewObject();//mStructure = new FabrikStructure3D(demoName); 582 | FColor boneColour = UFabrikUtil::GREEN;//new Colour4f(Utils.GREEN); 583 | 584 | // Create a new chain... 585 | UFabrikChain* chain = NewObject();//FabrikChain3D chain = new FabrikChain3D(); 586 | 587 | // ...then create a basebone, set its draw colour and add it to the chain. 588 | FVector startLoc(0.0f, 0.0f, 40.0f); 589 | FVector endLoc = startLoc + (DefaultBoneDirection * DefaultBoneLength); 590 | UFabrikBone* basebone = NewObject();// ->Init(startLoc, endLoc); // FabrikBone3D basebone = new FabrikBone3D(startLoc, endLoc); 591 | basebone->Init(startLoc, endLoc); 592 | 593 | basebone->Color = boneColour; 594 | chain->AddBone(basebone); 595 | 596 | // Add additional consecutive, unconstrained bones to the chain 597 | for (int boneLoop = 0; boneLoop < 7; boneLoop++) 598 | { 599 | boneColour = (boneLoop % 2 == 0) ? UFabrikUtil::Lighten(boneColour,0.4f) : UFabrikUtil::Darken(boneColour, 0.4f); 600 | chain->AddConsecutiveBone(DefaultBoneDirection, DefaultBoneLength, boneColour); 601 | } 602 | 603 | // Finally, add the chain to the structure 604 | Structure->AddChain(chain); 605 | UFabrikChain* secondChain = NewObject();//FabrikChain3D secondChain = new FabrikChain3D("Second Chain"); 606 | UFabrikBone* base = NewObject(); 607 | base->Init(FVector::ZeroVector, FVector(15.0f, 0.0f, 0.0f)); // FabrikBone3D base = new FabrikBone3D(FVector(), FVector(15.0f, 0.0f, 0.0f)); 608 | secondChain->AddBone(base); 609 | secondChain->SetRotorBaseboneConstraint(EBoneConstraintType::BCT_GlobalRotor, UFabrikUtil::X_AXIS, 45.0f); 610 | 611 | secondChain->AddConsecutiveBone(UFabrikUtil::X_AXIS, 15.0f); 612 | secondChain->AddConsecutiveBone(UFabrikUtil::X_AXIS, 15.0f); 613 | secondChain->AddConsecutiveBone(UFabrikUtil::X_AXIS, 15.0f); 614 | secondChain->SetColour(UFabrikUtil::RED); 615 | 616 | Structure->ConnectChain(secondChain, 0, 3, EBoneConnectionPoint::BCP_Start); 617 | 618 | UFabrikChain* thirdChain = NewObject();//FabrikChain3D thirdChain = new FabrikChain3D("Second Chain"); 619 | base = NewObject(); 620 | base->Init(FVector::ZeroVector, FVector(0.0f, 15.0f, 0.0f)); //base = new FabrikBone3D( FVector(), FVector(0.0f, 15.0f, 0.0f)); 621 | thirdChain->AddBone(base); 622 | thirdChain->SetRotorBaseboneConstraint(EBoneConstraintType::BCT_GlobalRotor, UFabrikUtil::Y_AXIS, 45.0f); 623 | 624 | thirdChain->AddConsecutiveBone(UFabrikUtil::Y_AXIS, 15.0f); 625 | thirdChain->AddConsecutiveBone(UFabrikUtil::Y_AXIS, 15.0f); 626 | thirdChain->AddConsecutiveBone(UFabrikUtil::Y_AXIS, 15.0f); 627 | thirdChain->SetColour(UFabrikUtil::BLUE); 628 | 629 | Structure->ConnectChain(thirdChain, 0, 6, EBoneConnectionPoint::BCP_Start); 630 | } 631 | 632 | void AFabrikDemoActor::DemoLocalRotorConstrainedConnectedChains() 633 | { 634 | //demoName = "Demo 10 - Local Rotor Constrained Connected Chains"; 635 | Structure = NewObject();//mStructure = new FabrikStructure3D(demoName); 636 | FColor boneColour = UFabrikUtil::GREEN;//new Colour4f(Utils.GREEN); 637 | 638 | // Create a new chain... 639 | UFabrikChain* chain = NewObject();//FabrikChain3D chain = new FabrikChain3D(); 640 | 641 | // ...then create a basebone, set its draw colour and add it to the chain. 642 | FVector startLoc(0.0f, 0.0f, 40.0f); 643 | FVector endLoc = startLoc + (DefaultBoneDirection * DefaultBoneLength); 644 | UFabrikBone* basebone = NewObject()->Init(startLoc, endLoc); //FabrikBone3D basebone = new FabrikBone3D(startLoc, endLoc); 645 | basebone->Color = boneColour; 646 | chain->AddBone(basebone); 647 | 648 | // Add additional consecutive, unconstrained bones to the chain 649 | for (int boneLoop = 0; boneLoop < 7; boneLoop++) 650 | { 651 | boneColour = (boneLoop % 2 == 0) ? UFabrikUtil::Lighten(boneColour,0.4f) : UFabrikUtil::Darken(boneColour, 0.4f); 652 | chain->AddConsecutiveBone(DefaultBoneDirection, DefaultBoneLength, boneColour); 653 | } 654 | 655 | // Finally, add the chain to the structure 656 | Structure->AddChain(chain); 657 | 658 | // Create a second chain which will have a relative (i.e. local) rotor basebone constraint about the X axis. 659 | UFabrikChain* secondChain = NewObject();//FabrikChain3D secondChain = new FabrikChain3D("Second Chain"); 660 | basebone = NewObject()->Init(FVector::ZeroVector, FVector(15.0f, 0.0f, 0.0f)); //new FabrikBone3D(FVector(), FVector(15.0f, 0.0f, 0.0f)); 661 | secondChain->AddBone(basebone); 662 | secondChain->SetRotorBaseboneConstraint(EBoneConstraintType::BCT_LocalRotor, UFabrikUtil::X_AXIS, 45.0f); 663 | 664 | // Add some additional bones 665 | secondChain->AddConsecutiveBone(UFabrikUtil::X_AXIS, 15.0f); 666 | secondChain->AddConsecutiveBone(UFabrikUtil::X_AXIS, 15.0f); 667 | secondChain->AddConsecutiveBone(UFabrikUtil::X_AXIS, 15.0f); 668 | secondChain->SetColour(UFabrikUtil::RED); 669 | 670 | // Connect this second chain to the start point of bone 3 in chain 0 of the structure 671 | Structure->ConnectChain(secondChain, 0, 3, EBoneConnectionPoint::BCP_Start); 672 | } 673 | 674 | void AFabrikDemoActor::DemoConnectedChainsWithFreelyRotatingGlobalHingedBaseboneConstraints() 675 | { 676 | // demoName = "Demo 11 - Connected Chains with Freely-Rotating Global Hinged Basebone Constraints"; 677 | Structure = NewObject();//mStructure = new FabrikStructure3D(demoName); 678 | FColor boneColour = UFabrikUtil::GREEN;//new Colour4f(Utils.GREEN); 679 | 680 | // Create a new chain... 681 | UFabrikChain* chain = NewObject();//FabrikChain3D chain = new FabrikChain3D(); 682 | 683 | // ...then create a basebone, set its draw colour and add it to the chain. 684 | FVector startLoc(0.0f, 0.0f, 40.0f); 685 | FVector endLoc = startLoc + (DefaultBoneDirection * DefaultBoneLength); 686 | UFabrikBone* basebone = NewObject()->Init(startLoc, endLoc); //FabrikBone3D basebone = new FabrikBone3D(startLoc, endLoc); 687 | basebone->Color = boneColour; 688 | chain->AddBone(basebone); 689 | 690 | // Add additional consecutive, unconstrained bones to the chain 691 | for (int boneLoop = 0; boneLoop < 7; boneLoop++) 692 | { 693 | boneColour = (boneLoop % 2 == 0) ? UFabrikUtil::Lighten(boneColour,0.4f) : UFabrikUtil::Darken(boneColour, 0.4f); 694 | chain->AddConsecutiveBone(DefaultBoneDirection, DefaultBoneLength, boneColour); 695 | } 696 | 697 | // Finally, add the chain to the structure 698 | Structure->AddChain(chain); 699 | 700 | // Create a second chain which will have a relative (i.e. local) rotor basebone constraint about the X axis. 701 | UFabrikChain* secondChain = NewObject();//FabrikChain3D secondChain = new FabrikChain3D("Second Chain"); 702 | UFabrikBone* base = NewObject()->Init(FVector::ZeroVector, FVector(15.0f, 0.0f, 0.0f)); //FabrikBone3D base = new FabrikBone3D(FVector(), FVector(15.0f, 0.0f, 0.0f)); 703 | secondChain->AddBone(base); 704 | 705 | // Set this second chain to have a freely rotating global hinge which rotates about the Y axis 706 | // Note: We MUST add the basebone to the chain before we can set the basebone constraint on it. 707 | secondChain->SetFreelyRotatingGlobalHingedBasebone(UFabrikUtil::Y_AXIS); 708 | 709 | // Add some additional bones 710 | secondChain->AddConsecutiveBone(UFabrikUtil::X_AXIS, 15.0f); 711 | secondChain->AddConsecutiveBone(UFabrikUtil::X_AXIS, 15.0f); 712 | secondChain->AddConsecutiveBone(UFabrikUtil::X_AXIS, 15.0f); 713 | secondChain->SetColour(UFabrikUtil::GREY); 714 | 715 | // Connect this second chain to the start point of bone 3 in chain 0 of the structure 716 | Structure->ConnectChain(secondChain, 0, 3, EBoneConnectionPoint::BCP_Start ); 717 | } 718 | 719 | void AFabrikDemoActor::DemoConnectedChainsWithEmbeddedTargets() 720 | { 721 | //demoName = "Demo 12 - Connected chains with embedded targets"; 722 | Structure = NewObject();//mStructure = new FabrikStructure3D(demoName); 723 | FColor boneColour = UFabrikUtil::GREEN;//new Colour4f(Utils.GREEN); 724 | 725 | // Create a new chain... 726 | UFabrikChain* chain = NewObject();//FabrikChain3D chain = new FabrikChain3D(); 727 | 728 | // ...then create a basebone, set its draw colour and add it to the chain. 729 | FVector startLoc(0.0f, 0.0f, 40.0f); 730 | FVector endLoc = startLoc + (DefaultBoneDirection * DefaultBoneLength); 731 | UFabrikBone* basebone = NewObject()->Init(startLoc, endLoc); //FabrikBone3D basebone = new FabrikBone3D(startLoc, endLoc); 732 | basebone->Color = boneColour; 733 | chain->AddBone(basebone); 734 | 735 | // Add additional consecutive, unconstrained bones to the chain 736 | for (int boneLoop = 0; boneLoop < 7; boneLoop++) 737 | { 738 | boneColour = (boneLoop % 2 == 0) ? UFabrikUtil::Lighten(boneColour,0.4f) : UFabrikUtil::Darken(boneColour, 0.4f); 739 | chain->AddConsecutiveBone(DefaultBoneDirection, DefaultBoneLength, boneColour); 740 | } 741 | 742 | // Finally, add the chain to the structure 743 | Structure->AddChain(chain); 744 | 745 | // Create a second chain which will have a relative (i.e. local) rotor basebone constraint about the X axis. 746 | UFabrikChain* secondChain = NewObject();//FabrikChain3D secondChain = new FabrikChain3D("Second Chain"); 747 | secondChain->UseEmbeddedTarget = true; // SetEmbeddedTargetMode(true); 748 | UFabrikBone* base = NewObject()->Init(FVector::ZeroVector, FVector(15.0f, 0.0f, 0.0f)); //FabrikBone3D base = new FabrikBone3D(FVector(), FVector(15.0f, 0.0f, 0.0f)); 749 | secondChain->AddBone(base); 750 | 751 | // Set this second chain to have a freely rotating global hinge which rotates about the Y axis 752 | // Note: We MUST add the basebone to the chain before we can set the basebone constraint on it. 753 | secondChain->SetHingeBaseboneConstraint(EBoneConstraintType::BCT_GlobalHinge, UFabrikUtil::Y_AXIS, 90.0f, 45.0f, UFabrikUtil::X_AXIS); 754 | 755 | /** Other potential options for basebone constraint types **/ 756 | //secondChain.setFreelyRotatingGlobalHingedBasebone(Y_AXIS); 757 | //secondChain.setFreelyRotatingLocalHingedBasebone(Y_AXIS); 758 | //secondChain.setHingeBaseboneConstraint(BaseboneConstraintType3D.GLOBAL_HINGE, Y_AXIS, 90.0f, 45.0f, X_AXIS); 759 | //secondChain.setRotorBaseboneConstraint(BaseboneConstraintType3D.GLOBAL_ROTOR, Z_AXIS, 30.0f, 60.0f, Y_AXIS); 760 | //secondChain.setRotorBaseboneConstraint(BaseboneConstraintType3D.LOCAL_ROTOR, Z_AXIS, 30.0f, 60.0f, Y_AXIS); 761 | 762 | // Add some additional bones 763 | secondChain->AddConsecutiveBone(UFabrikUtil::X_AXIS, 20.0f); 764 | secondChain->AddConsecutiveBone(UFabrikUtil::X_AXIS, 20.0f); 765 | secondChain->AddConsecutiveBone(UFabrikUtil::X_AXIS, 20.0f); 766 | secondChain->SetColour(UFabrikUtil::GREY); 767 | 768 | // Connect this second chain to the start point of bone 3 in chain 0 of the structure 769 | Structure->ConnectChain(secondChain, 0, 3, EBoneConnectionPoint::BCP_Start); 770 | } 771 | -------------------------------------------------------------------------------- /Source/OpenMotion/Private/FabrikJoint.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #include "FabrikJoint.h" 4 | #include "FabrikUtil.h" 5 | 6 | #include "OpenMotion.h" 7 | 8 | float UFabrikJoint::MIN_CONSTRAINT_ANGLE_DEGS = 0.0f; 9 | float UFabrikJoint::MAX_CONSTRAINT_ANGLE_DEGS = 180.0f; 10 | 11 | UFabrikJoint::UFabrikJoint(const FObjectInitializer& ObjectInitializer) 12 | { 13 | RotorConstraintDegs = MAX_CONSTRAINT_ANGLE_DEGS; 14 | 15 | HingeClockwiseConstraintDegs = MAX_CONSTRAINT_ANGLE_DEGS; 16 | 17 | HingeAnticlockwiseConstraintDegs = MAX_CONSTRAINT_ANGLE_DEGS; 18 | 19 | //RotationAxisUV; 20 | 21 | //ReferenceAxisUV;// = new Vec3f(); 22 | JointType = EJointType::JT_Ball; 23 | } 24 | 25 | UFabrikJoint* UFabrikJoint::Init(UFabrikJoint* Source) 26 | { 27 | RotorConstraintDegs = Source->RotorConstraintDegs; 28 | HingeClockwiseConstraintDegs = Source->HingeClockwiseConstraintDegs; 29 | HingeAnticlockwiseConstraintDegs = Source->HingeAnticlockwiseConstraintDegs; 30 | RotationAxisUV = Source->RotationAxisUV; 31 | ReferenceAxisUV = Source->ReferenceAxisUV; 32 | JointType = Source->JointType; 33 | BoneConnectionPoint = Source->BoneConnectionPoint; 34 | return this; 35 | } 36 | 37 | UFabrikJoint* UFabrikJoint::Clone(UFabrikJoint* Source) 38 | { 39 | UFabrikJoint* NewJoint = NewObject(); 40 | NewJoint->Init(Source); 41 | return NewJoint; 42 | } 43 | 44 | void UFabrikJoint::SetAsBallJoint(float InConstraintAngleDegs) 45 | { 46 | // Throw a RuntimeException if the rotor constraint angle is outside the range 0 to 180 degrees 47 | UFabrikJoint::ValidateConstraintAngleDegs(InConstraintAngleDegs); 48 | 49 | // Set the rotor constraint angle and the joint type to be BALL. 50 | RotorConstraintDegs = InConstraintAngleDegs; 51 | JointType = EJointType::JT_Ball; 52 | 53 | } 54 | 55 | void UFabrikJoint::SetHinge(EJointType InJointType, FVector InRotationAxis, float InClockwiseConstraintDegs, float InAnticlockwiseConstraintDegs, FVector InReferenceAxis) 56 | { 57 | // Ensure the reference axis falls within the plane of the rotation axis (i.e. they are perpendicular, so their dot product is zero) 58 | float dotP = FVector::DotProduct(InRotationAxis, InReferenceAxis); 59 | 60 | if (! UFabrikUtil::ApproximatelyEquals(dotP, 0.0f, 0.01f)) // FMath::Abs(dotP) < 0.01f) // !Utils.approximatelyEquals(Vec3f.dotProduct(rotationAxis, referenceAxis), 0.0f, 0.01f)) 61 | { 62 | //float angleDegs = FVector::an Vec3f.getAngleBetweenDegs(rotationAxis, referenceAxis); 63 | UE_LOG(OpenMotionLog, Fatal, TEXT("The reference axis must be in the plane of the hinge rotation axis - angle between them is currently: TODO")); //throw new IllegalArgumentException("The reference axis must be in the plane of the hinge rotation axis - angle between them is currently: " + angleDegs); 64 | } 65 | 66 | // Validate the constraint angles to be within the valid range and the axis isn't zero 67 | UFabrikJoint::ValidateConstraintAngleDegs(InClockwiseConstraintDegs); 68 | UFabrikJoint::ValidateConstraintAngleDegs(InAnticlockwiseConstraintDegs); 69 | UFabrikJoint::ValidateAxis(InRotationAxis); 70 | UFabrikJoint::ValidateAxis(InReferenceAxis); 71 | 72 | 73 | // Set params 74 | 75 | HingeClockwiseConstraintDegs = InClockwiseConstraintDegs; 76 | 77 | HingeAnticlockwiseConstraintDegs = InAnticlockwiseConstraintDegs; 78 | 79 | JointType = InJointType; 80 | 81 | RotationAxisUV = InRotationAxis; // set(rotationAxis.normalised()); 82 | RotationAxisUV.Normalize(); 83 | 84 | ReferenceAxisUV = InReferenceAxis;// .normalised()); 85 | ReferenceAxisUV.Normalize(); 86 | } 87 | 88 | void UFabrikJoint::SetAsGlobalHinge(FVector InGlobalRotationAxis, float InCwConstraintDegs, float InAcwConstraintDegs, FVector InGlobalReferenceAxis) 89 | { 90 | 91 | SetHinge(EJointType::JT_GlobalHinge, InGlobalRotationAxis, InCwConstraintDegs, InAcwConstraintDegs, InGlobalReferenceAxis); 92 | } 93 | 94 | void UFabrikJoint::SetAsLocalHinge(FVector InLocalRotationAxis, float InCwConstraintDegs, float InAcwConstraintDegs, FVector InLocalReferenceAxis) 95 | { 96 | SetHinge(EJointType::JT_LocalHinge, InLocalRotationAxis, InCwConstraintDegs, InAcwConstraintDegs, InLocalReferenceAxis); 97 | } 98 | 99 | 100 | // public float getHingeClockwiseConstraintDegs() 101 | // public float getHingeAnticlockwiseConstraintDegs() 102 | // public void setBallJointConstraintDegs(float angleDegs) 103 | // public float getBallJointConstraintDegs() 104 | // public void setHingeJointClockwiseConstraintDegs(float angleDegs) 105 | // public void setHingeJointAnticlockwiseConstraintDegs(float angleDegs) 106 | // public void setHingeRotationAxis(Vec3f axis) => mRotationAxisUV 107 | // public Vec3f getHingeReferenceAxis() => mReferenceAxisUV 108 | // public Vec3f getHingeRotationAxis() // mRotationAxisUV 109 | // public String toString() 110 | 111 | 112 | 113 | 114 | 115 | 116 | void UFabrikJoint::ValidateConstraintAngleDegs(float InAngleDegs) 117 | { 118 | 119 | if (InAngleDegs < UFabrikJoint::MIN_CONSTRAINT_ANGLE_DEGS || InAngleDegs > UFabrikJoint::MAX_CONSTRAINT_ANGLE_DEGS) 120 | { 121 | UE_LOG(OpenMotionLog, Fatal, TEXT("Constraint angles must be within the range")); 122 | //throw new IllegalArgumentException("Constraint angles must be within the range " + MIN_CONSTRAINT_ANGLE_DEGS + " to " + MAX_CONSTRAINT_ANGLE_DEGS + " inclusive."); 123 | } 124 | 125 | } 126 | 127 | 128 | 129 | void UFabrikJoint::ValidateAxis(FVector InAxis) 130 | { 131 | 132 | if (!(InAxis.Size() > 0.0f)) 133 | { 134 | UE_LOG(OpenMotionLog, Fatal, TEXT("Provided axis is illegal - it has a magnitude of zero.")); 135 | } 136 | 137 | } -------------------------------------------------------------------------------- /Source/OpenMotion/Private/FabrikMat3f.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | // https://github.com/FedUni/caliko/blob/master/caliko/src/au/edu/federation/utils/Mat3f.java 4 | 5 | #include "FabrikMat3f.h" 6 | 7 | #include "OpenMotion.h" 8 | 9 | 10 | UFabrikMat3f* UFabrikMat3f::CreateRotationMatrix(FVector InReferenceDirection) 11 | { 12 | FVector xAxis; 13 | FVector yAxis; 14 | InReferenceDirection.Normalize(); 15 | FVector zAxis = InReferenceDirection;// .normalise(); 16 | 17 | // Handle the singularity (i.e. bone pointing along negative Z-Axis)... 18 | if (InReferenceDirection.Z < -0.9999999f) 19 | { 20 | xAxis = FVector(1.0f, 0.0f, 0.0f); // ...in which case positive X runs directly to the right... 21 | yAxis = FVector(0.0f, 1.0f, 0.0f); // ...and positive Y runs directly upwards. 22 | } 23 | else 24 | { 25 | float a = 1.0f / (1.0f + zAxis.Z); 26 | float b = -zAxis.X * zAxis.Y * a; 27 | xAxis = FVector(1.0f - zAxis.X * zAxis.X * a, b, -zAxis.X);// .normalise(); 28 | xAxis.Normalize(); 29 | yAxis = FVector(b, 1.0f - zAxis.Y * zAxis.Y * a, -zAxis.Y);// .normalise(); 30 | } 31 | 32 | UFabrikMat3f* Res = NewObject(); 33 | Res->Init(xAxis, yAxis, zAxis); 34 | return Res;// new Mat3f(xAxis, yAxis, zAxis); 35 | } 36 | 37 | void UFabrikMat3f::Init(FVector xAxis, FVector yAxis, FVector zAxis) 38 | { 39 | m00 = xAxis.X; 40 | m01 = xAxis.Y; 41 | m02 = xAxis.Z; 42 | 43 | m10 = yAxis.X; 44 | m11 = yAxis.Y; 45 | m12 = yAxis.Z; 46 | 47 | m20 = zAxis.X; 48 | m21 = zAxis.Y; 49 | m22 = zAxis.Z; 50 | } 51 | 52 | FVector UFabrikMat3f::Times(FVector source) 53 | { 54 | return FVector(this->m00 * source.X + this->m10 * source.Y + this->m20 * source.Z, 55 | this->m01 * source.X + this->m11 * source.Y + this->m21 * source.Z, 56 | this->m02 * source.X + this->m12 * source.Y + this->m22 * source.Z); 57 | } -------------------------------------------------------------------------------- /Source/OpenMotion/Private/FabrikStructure.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #include "FabrikStructure.h" 4 | #include "FabrikChain.h" 5 | #include "FabrikBone.h" 6 | #include "FabrikMat3f.h" 7 | #include "EBoneConstraintType.h" 8 | 9 | #include "OpenMotion.h" 10 | 11 | UFabrikStructure::UFabrikStructure(const FObjectInitializer& ObjectInitializer) 12 | { 13 | NumChains = 0; 14 | } 15 | 16 | void UFabrikStructure::SolveForTarget(FVector InNewTargetLocation) 17 | { 18 | int NumChainsL = Chains.Num(); 19 | int ConnectedChainNumber; 20 | 21 | // Loop over all chains in this structure... 22 | for (int Loop = 0; Loop < NumChainsL; ++Loop) 23 | { 24 | // Get this chain, and get the number of the chain in this structure it's connected to (if any) 25 | UFabrikChain* ThisChain = Chains[Loop]; 26 | 27 | ConnectedChainNumber = ThisChain->ConnectedChainNumber;// getConnectedChainNumber(); 28 | 29 | // If this chain isn't connected to another chain then update as normal... 30 | if (ConnectedChainNumber == -1) 31 | { 32 | ThisChain->SolveForTarget(InNewTargetLocation); 33 | } 34 | else // ...however, if this chain IS connected to another chain... 35 | { 36 | // ... get the host chain and bone which this chain is connected to 37 | UFabrikChain* HostChain = Chains[ConnectedChainNumber]; 38 | UFabrikBone* HostBone = HostChain->GetBone(ThisChain->ConnectedBoneNumber); //.getConnectedBoneNumber()); 39 | 40 | if (HostBone->BoneConnectionPoint == EBoneConnectionPoint::BCP_Start) 41 | { 42 | // setBaseLocation => mFixedBaseLocation 43 | ThisChain->FixedBaseLocation = HostBone->StartLocation; // setBaseLocation(hostBone.getStartLocation()); 44 | } 45 | else 46 | { 47 | // setBaseLocation => mFixedBaseLocation 48 | ThisChain->FixedBaseLocation = HostBone->EndLocation; // setBaseLocation(hostBone.getEndLocation()); } 49 | } 50 | 51 | // Now that we've clamped the base location of this chain to the start or end point of the bone in the chain we are connected to, it's 52 | // time to deal with any base bone constraints... 53 | 54 | // What type of base bone constraint is this (connected to another) chain using? 55 | EBoneConstraintType ConstraintType = ThisChain->BaseboneConstraintType; 56 | 57 | switch (ConstraintType) 58 | { 59 | // None or global basebone constraints? Nothing to do, because these will be handled in FabrikChain3D.solveIK() as we do not 60 | // need information from another chain to handle them. 61 | case EBoneConstraintType::BCT_None: // NONE: // Nothing to do because there's no basebone constraint 62 | case EBoneConstraintType::BCT_GlobalRotor:// GLOBAL_ROTOR: // Nothing to do because the basebone constraint is not relative to bones in other chains in this structure 63 | case EBoneConstraintType::BCT_GlobalHinge: // GLOBAL_HINGE: // Nothing to do because the basebone constraint is not relative to bones in other chains in this structure 64 | break; 65 | 66 | // If we have a local rotor or hinge constraint then we must calculate the relative basebone constraint before calling updateTarget 67 | case EBoneConstraintType::BCT_LocalRotor: // LOCAL_ROTOR: 68 | case EBoneConstraintType::BCT_LocalHinge: { // LOCAL_HINGE: { 69 | // Get the direction of the bone this chain is connected to and create a rotation matrix from it. 70 | //Mat3f ConnectionBoneMatrix = Mat3f.createRotationMatrix(HostBone.getDirectionUV()); 71 | UFabrikMat3f* ConnectionBoneMatrix = UFabrikMat3f::CreateRotationMatrix(HostBone->GetDirectionUV()); 72 | // We'll then get the basebone constraint UV and multiply it by the rotation matrix of the connected bone 73 | // to make the basebone constraint UV relative to the direction of bone it's connected to. 74 | FVector RelativeBaseboneConstraintUV = ConnectionBoneMatrix->Times(ThisChain->BaseboneConstraintUV);// .normalised(); 75 | RelativeBaseboneConstraintUV.Normalize(); 76 | 77 | // Update our basebone relative constraint UV property 78 | ThisChain->BaseboneRelativeConstraintUV = RelativeBaseboneConstraintUV; 79 | 80 | // Update the relative reference constraint UV if we hav a local hinge 81 | if (ConstraintType == EBoneConstraintType::BCT_LocalHinge) 82 | { 83 | //getHingeReferenceAxis() => mReferenceAxisUV 84 | ThisChain->BaseboneRelativeReferenceConstraintUV = ConnectionBoneMatrix->Times(ThisChain->GetBone(0)->Joint->ReferenceAxisUV);// .getHingeReferenceAxis())); 85 | } 86 | break; 87 | } 88 | // No need for a default - constraint types are enums and we've covered them all. 89 | 90 | } 91 | 92 | // NOTE: If the base bone constraint type is NONE then we don't do anything with the base bone constraint of the connected chain. 93 | 94 | // Finally, update the target and solve the chain 95 | // Update the target and solve the chain 96 | if (!ThisChain->UseEmbeddedTarget) // GetEmbeddedTargetMode) 97 | { 98 | ThisChain->SolveForTarget(InNewTargetLocation); 99 | } 100 | else 101 | { 102 | ThisChain->SolveForEmbeddedTarget(); 103 | } 104 | 105 | } // End of if chain is connected to another chain section 106 | 107 | } // End of loop over chains 108 | 109 | } // End of updateTarget method 110 | 111 | 112 | void UFabrikStructure::SolveForTarget(float InTargetX, float InTargetY, float InTargetZ) 113 | { 114 | // Call our Vec3f version of updateTarget using a constructed Vec3f target location 115 | // Note: This will loop over all chains, attempting to solve each for the same target location 116 | SolveForTarget(FVector(InTargetX, InTargetY, InTargetZ)); 117 | } 118 | 119 | 120 | void UFabrikStructure::AddChain(UFabrikChain* InChain) 121 | { 122 | Chains.Add(InChain); 123 | ++NumChains; 124 | } 125 | 126 | void UFabrikStructure::RemoveChain(int InChainIndex) 127 | { 128 | 129 | Chains.RemoveAt(InChainIndex); 130 | --NumChains; 131 | } 132 | 133 | void UFabrikStructure::ConnectChain(UFabrikChain* InNewChain, int InExistingChainNumber, int InExistingBoneNumber) 134 | { 135 | // Does this chain exist? If not throw an IllegalArgumentException 136 | if (InExistingChainNumber > NumChains) 137 | { 138 | UE_LOG(OpenMotionLog, Fatal, TEXT("Cannot connect to chain TODO - no such chain (remember that chains are zero indexed).")); // throw new IllegalArgumentException("Cannot connect to chain " + existingChainNumber + " - no such chain (remember that chains are zero indexed)."); 139 | } 140 | 141 | // Do we have this bone in the specified chain? If not throw an IllegalArgumentException 142 | if (InExistingBoneNumber > Chains[InExistingChainNumber]->NumBones) 143 | { 144 | UE_LOG(OpenMotionLog, Fatal, TEXT("Cannot connect to bone TODO of chain TODO - no such bone (remember that bones are zero indexed).")); //throw new IllegalArgumentException("Cannot connect to bone " + existingBoneNumber + " of chain " + existingChainNumber + " - no such bone (remember that bones are zero indexed)."); 145 | } 146 | 147 | // Make a copy of the provided chain so any changes made to the original do not affect this chain 148 | UFabrikChain* RelativeChain = NewObject();// new FabrikChain3D(newChain); 149 | RelativeChain->Init(InNewChain); 150 | 151 | // Connect the copy of the provided chain to the specified chain and bone in this structure 152 | RelativeChain->ConnectToStructure(this, InExistingChainNumber, InExistingBoneNumber); 153 | 154 | // The chain as we were provided should be centred on the origin, so we must now make it 155 | // relative to the start location of the given bone in the given chain. 156 | 157 | // Get the connection point so we know to connect at the start or end location of the bone we're connecting to 158 | EBoneConnectionPoint ConnectionPoint = Chains[InExistingChainNumber]->GetBone(InExistingBoneNumber)->BoneConnectionPoint;// this->GetChain(existingChainNumber).getBone(existingBoneNumber).getBoneConnectionPoint(); 159 | FVector ConnectionLocation; 160 | if (ConnectionPoint == EBoneConnectionPoint::BCP_Start) 161 | { 162 | ConnectionLocation = Chains[InExistingChainNumber]->GetBone(InExistingBoneNumber)->StartLocation; 163 | } 164 | else // If it's BoneConnectionPoint.END then we set the connection point to be the end location of the bone we're connecting to 165 | { 166 | ConnectionLocation = Chains[InExistingChainNumber]->GetBone(InExistingBoneNumber)->EndLocation; 167 | } 168 | 169 | // setBaseLocation => mFixedBaseLocation 170 | RelativeChain->FixedBaseLocation = ConnectionLocation;// .setBaseLocation(ConnectionLocation); 171 | 172 | // When we have a chain connected to a another 'host' chain, the chain is which is connecting in 173 | // MUST have a fixed base, even though that means the base location is 'fixed' to the connection 174 | // point on the host chain, rather than a static location. 175 | RelativeChain->FixedBaseMode = true; //.setFixedBaseMode(true); 176 | 177 | // Translate the chain we're connecting to the connection point 178 | for (int Loop = 0; Loop < RelativeChain->NumBones; ++Loop) 179 | { 180 | FVector OrigStart = RelativeChain->GetBone(Loop)->StartLocation; 181 | FVector OrigEnd = RelativeChain->GetBone(Loop)->EndLocation; 182 | 183 | FVector TranslatedStart = OrigStart + ConnectionLocation; 184 | FVector TranslatedEnd = OrigEnd + ConnectionLocation; 185 | 186 | RelativeChain->GetBone(Loop)->StartLocation = TranslatedStart;// .setStartLocation(translatedStart); 187 | RelativeChain->GetBone(Loop)->EndLocation = TranslatedEnd; // setEndLocation(TranslatedEnd); 188 | } 189 | 190 | this->AddChain(RelativeChain); 191 | } 192 | 193 | void UFabrikStructure::ConnectChain(UFabrikChain* InNewChain, int InExistingChainNumber, int InExistingBoneNumber, EBoneConnectionPoint InBoneConnectionPoint) 194 | { 195 | // Does this chain exist? If not throw an IllegalArgumentException 196 | if (InExistingChainNumber > NumChains) 197 | { 198 | UE_LOG(OpenMotionLog, Fatal, TEXT("Cannot connect to chain TODO - no such chain (remember that chains are zero indexed).")); //throw new IllegalArgumentException("Cannot connect to chain " + existingChainNumber + " - no such chain (remember that chains are zero indexed)."); 199 | } 200 | 201 | // Do we have this bone in the specified chain? If not throw an IllegalArgumentException 202 | if (InExistingBoneNumber > Chains[InExistingChainNumber]->NumBones) 203 | { 204 | UE_LOG(OpenMotionLog, Fatal, TEXT("Cannot connect to bone TODO of chain TODO - no such bone (remember that bones are zero indexed).")); //throw new IllegalArgumentException("Cannot connect to bone " + existingBoneNumber + " of chain " + existingChainNumber + " - no such bone (remember that bones are zero indexed)."); 205 | } 206 | 207 | // Make a copy of the provided chain so any changes made to the original do not affect this chain 208 | UFabrikChain* RelativeChain = NewObject();// new FabrikChain3D(newChain); 209 | RelativeChain->Init(InNewChain); 210 | 211 | // Connect the copy of the provided chain to the specified chain and bone in this structure 212 | RelativeChain->ConnectToStructure(this, InExistingChainNumber, InExistingBoneNumber); 213 | 214 | // The chain as we were provided should be centred on the origin, so we must now make it 215 | // relative to the start location of the given bone in the given chain. 216 | 217 | // Set the connection point and use it to get the connection location 218 | Chains[InExistingChainNumber]->GetBone(InExistingBoneNumber)->BoneConnectionPoint = InBoneConnectionPoint; // this->GetChain(existingChainNumber).getBone(existingBoneNumber).setBoneConnectionPoint(boneConnectionPoint); 219 | FVector ConnectionLocation; 220 | if (InBoneConnectionPoint == EBoneConnectionPoint::BCP_Start) 221 | { 222 | ConnectionLocation = Chains[InExistingChainNumber]->GetBone(InExistingBoneNumber)->StartLocation; 223 | } 224 | else // If it's BoneConnectionPoint.END then we set the connection point to be the end location of the bone we're connecting to 225 | { 226 | ConnectionLocation = Chains[InExistingChainNumber]->GetBone(InExistingBoneNumber)->EndLocation; 227 | } 228 | 229 | // setBaseLocation() => mFixedBaseLocation 230 | RelativeChain->FixedBaseLocation = ConnectionLocation;// .setBaseLocation(connectionLocation); 231 | 232 | // When we have a chain connected to a another 'host' chain, the chain is which is connecting in 233 | // MUST have a fixed base, even though that means the base location is 'fixed' to the connection 234 | // point on the host chain, rather than a static location. 235 | RelativeChain->FixedBaseMode = true;//.setFixedBaseMode(true); 236 | 237 | // Translate the chain we're connecting to the connection point 238 | for (int Loop = 0; Loop < RelativeChain->NumBones; ++Loop) 239 | { 240 | FVector OrigStart = RelativeChain->GetBone(Loop)->StartLocation; 241 | FVector OrigEnd = RelativeChain->GetBone(Loop)->EndLocation; 242 | 243 | FVector TranslatedStart = OrigStart + ConnectionLocation; 244 | FVector TranslatedEnd = OrigEnd + ConnectionLocation; 245 | 246 | RelativeChain->GetBone(Loop)->StartLocation = TranslatedStart; 247 | RelativeChain->GetBone(Loop)->EndLocation = TranslatedEnd; 248 | } 249 | 250 | this->AddChain(RelativeChain); 251 | } 252 | 253 | void UFabrikStructure::SetFixedBaseMode(bool InFixedBaseMode) 254 | { 255 | for (int Loop = 0; Loop < NumChains; ++Loop) 256 | { 257 | Chains[Loop]->FixedBaseMode = InFixedBaseMode; 258 | } 259 | } -------------------------------------------------------------------------------- /Source/OpenMotion/Private/FabrikUtil.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #include "FabrikUtil.h" 4 | #include "FabrikMat3f.h" 5 | 6 | UFabrikUtil::UFabrikUtil(const FObjectInitializer& ObjectInitializer): Super(ObjectInitializer) {} 7 | 8 | const FColor UFabrikUtil::RED(255 * 1.0f, 255 * 0.0f, 255 * 0.0f); // 1.0f, 0.0f, 0.0f, 1.0f 9 | const FColor UFabrikUtil::GREEN(255 * 0.0f, 255 * 1.0f, 255 * 0.0f); 10 | const FColor UFabrikUtil::BLUE(255 * 0.0f, 255 * 0.0f, 255 * 1.0f); 11 | const FColor UFabrikUtil::MID_RED(255 * 0.6f, 255 * 0.0f, 255 * 0.0f); 12 | const FColor UFabrikUtil::MID_GREEN(255 * 0.0f, 255 * 0.6f, 255 * 0.0f); 13 | const FColor UFabrikUtil::MID_BLUE(255 * 0.0f, 255 * 0.0f, 255 * 0.6f); 14 | const FColor UFabrikUtil::BLACK(255 * 0.0f, 255 * 0.0f, 255 * 0.0f); 15 | const FColor UFabrikUtil::GREY(255 * 0.5f, 255 * 0.5f, 255 * 0.5f); 16 | const FColor UFabrikUtil::WHITE(255 * 1.0f, 255 * 1.0f, 255 * 1.0f); 17 | const FColor UFabrikUtil::YELLOW(255 * 1.0f, 255 * 1.0f, 255 * 0.0f); 18 | const FColor UFabrikUtil::CYAN(255 * 0.0f, 255 * 1.0f, 255 * 1.0f); 19 | const FColor UFabrikUtil::MAGENTA(255 * 1.0f, 255 * 0.0f, 255 * 1.0f); 20 | 21 | const FVector UFabrikUtil::X_AXIS(1, 0, 0); 22 | const FVector UFabrikUtil::Y_AXIS(0, 1, 0); 23 | const FVector UFabrikUtil::Z_AXIS(0, 0, 1); 24 | 25 | 26 | FVector UFabrikUtil::RotateAboutAxisRads(FVector InSource, float InAngleRads, FVector InRotationAxis) 27 | { 28 | 29 | //Mat3f rotationMatrix = new Mat3f(); 30 | UFabrikMat3f* RotationMatrix = NewObject(); 31 | 32 | float sinTheta = (float)FMath::Sin(InAngleRads); 33 | float cosTheta = (float)FMath::Cos(InAngleRads); 34 | float oneMinusCosTheta = 1.0f - cosTheta; 35 | 36 | // It's quicker to pre-calc these and reuse than calculate x * y, then y * x later (same thing). 37 | float xyOne = InRotationAxis.X * InRotationAxis.Y * oneMinusCosTheta; 38 | float xzOne = InRotationAxis.X * InRotationAxis.Z * oneMinusCosTheta; 39 | float yzOne = InRotationAxis.Y * InRotationAxis.Z * oneMinusCosTheta; 40 | 41 | // Calculate rotated x-axis 42 | RotationMatrix->m00 = InRotationAxis.X * InRotationAxis.X * oneMinusCosTheta + cosTheta; 43 | RotationMatrix->m01 = xyOne + InRotationAxis.Z * sinTheta; 44 | RotationMatrix->m02 = xzOne - InRotationAxis.Y * sinTheta; 45 | 46 | // Calculate rotated y-axis 47 | RotationMatrix->m10 = xyOne - InRotationAxis.Z * sinTheta; 48 | RotationMatrix->m11 = InRotationAxis.Y * InRotationAxis.Y * oneMinusCosTheta + cosTheta; 49 | RotationMatrix->m12 = yzOne + InRotationAxis.X * sinTheta; 50 | 51 | // Calculate rotated z-axis 52 | RotationMatrix->m20 = xzOne + InRotationAxis.Y * sinTheta; 53 | RotationMatrix->m21 = yzOne - InRotationAxis.X * sinTheta; 54 | RotationMatrix->m22 = InRotationAxis.Z * InRotationAxis.Z * oneMinusCosTheta + cosTheta; 55 | 56 | // Multiply the source by the rotation matrix we just created to perform the rotation 57 | return RotationMatrix->Times(InSource); 58 | } 59 | 60 | 61 | FVector UFabrikUtil::GetAngleLimitedUnitVectorDegs(FVector InVecToLimit, FVector InVecBaseline, float InAngleLimitDegs) 62 | { 63 | // Get the angle between the two vectors 64 | // Note: This will ALWAYS be a positive value between 0 and 180 degrees. 65 | float AngleBetweenVectorsDegs = GetAngleBetweenDegs(InVecBaseline, InVecToLimit); 66 | 67 | if (AngleBetweenVectorsDegs > InAngleLimitDegs) 68 | { 69 | // The axis which we need to rotate around is the one perpendicular to the two vectors - so we're 70 | // rotating around the vector which is the cross-product of our two vectors. 71 | // Note: We do not have to worry about both vectors being the same or pointing in opposite directions 72 | // because if they bones are the same direction they will not have an angle greater than the angle limit, 73 | // and if they point opposite directions we will approach but not quite reach the precise max angle 74 | // limit of 180.0f (I believe). 75 | InVecBaseline.Normalize(); 76 | InVecToLimit.Normalize(); 77 | 78 | //FVector correctionAxis = FVector::CrossProduct(vecBaseline.normalised(), vecToLimit.normalised()).normalise(); 79 | FVector CorrectionAxis = FVector::CrossProduct(InVecBaseline, InVecToLimit);// .normalise(); 80 | CorrectionAxis.Normalize(); 81 | //CorrectionAxis = FVector(0, 1, 0); //HACK 82 | // Our new vector is the baseline vector rotated by the max allowable angle about the correction axis 83 | 84 | FVector Res = RotateAboutAxisDegs(InVecBaseline, InAngleLimitDegs, CorrectionAxis);// .normalised(); 85 | Res.Normalize(); 86 | return Res; 87 | } 88 | else // Angle not greater than limit? Just return a normalised version of the vecToLimit 89 | { 90 | // This may already BE normalised, but we have no way of knowing without calcing the length, so best be safe and normalise. 91 | // TODO: If performance is an issue, then I could get the length, and if it's not approx. 1.0f THEN normalise otherwise just return as is. 92 | InVecToLimit.Normalize(); 93 | return InVecToLimit;// .normalised(); 94 | } 95 | } 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /Source/OpenMotion/Private/OpenMotion.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "OpenMotion.h" 4 | 5 | #define LOCTEXT_NAMESPACE "FOpenMotionModule" 6 | 7 | DEFINE_LOG_CATEGORY(OpenMotionLog); 8 | 9 | void FOpenMotionModule::StartupModule() 10 | { 11 | // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module 12 | } 13 | 14 | void FOpenMotionModule::ShutdownModule() 15 | { 16 | // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, 17 | // we call this function before unloading the module. 18 | } 19 | 20 | #undef LOCTEXT_NAMESPACE 21 | 22 | IMPLEMENT_MODULE(FOpenMotionModule, OpenMotion) -------------------------------------------------------------------------------- /Source/OpenMotion/Private/OpenMotionComponent.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Name 2020 2 | 3 | 4 | #include "OpenMotionComponent.h" 5 | #include "..\Public\OpenMotionComponent.h" 6 | 7 | #include "Engine.h" 8 | //#include "Kismet/KismetSystemLibrary.h" 9 | #include "Kismet/KismetMathLibrary.h" 10 | #include "Kismet/GameplayStatics.h" 11 | 12 | #include "GameFramework/Character.h" 13 | 14 | // Sets default values for this component's properties 15 | UOpenMotionComponent::UOpenMotionComponent() 16 | { 17 | // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features 18 | // off to improve performance if you don't need them. 19 | PrimaryComponentTick.bCanEverTick = true; 20 | 21 | // ... 22 | } 23 | 24 | 25 | // Called when the game starts 26 | void UOpenMotionComponent::BeginPlay() 27 | { 28 | Super::BeginPlay(); 29 | 30 | // ... 31 | 32 | } 33 | 34 | 35 | // Called every frame 36 | void UOpenMotionComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) 37 | { 38 | Super::TickComponent(DeltaTime, TickType, ThisTickFunction); 39 | 40 | // CustomTick(); Call this in bp, to set mesh reliably 41 | 42 | // FWorldTransforms WorldTransforms; 43 | // FShoulderTransforms ShoulderTransforms; 44 | // FComponentTransforms ComponentTransforms; 45 | // FTransformSettings TransformSettings; 46 | // FCharacterSettings CharacterSettings; 47 | 48 | } 49 | 50 | void UOpenMotionComponent::CustomTick(USkeletalMeshComponent* OwnerMesh) 51 | { 52 | ConvertTransforms(); 53 | SetShoulder(); 54 | SetLeftUpperArm(); SetRightUpperArm(); 55 | ResetUpperArmsLocation(OwnerMesh); SolveArms(); 56 | CharacterSettings.CharacterBaseTransform = GetBaseCharTransform(); 57 | 58 | if (TransformSettings.DrawDebug) 59 | { 60 | DebugDraw(); 61 | } 62 | } 63 | 64 | void UOpenMotionComponent::ConvertTransforms() 65 | { 66 | FTransform LeftHandInverseLocation = WorldTransforms.LeftHandEffector.Inverse(); 67 | FTransform RightHandInverseLocation = WorldTransforms.RightHandEffector.Inverse(); 68 | 69 | WorldTransforms.LeftHandEffector = FTransform(LeftHandInverseLocation.GetRotation(), LeftHandInverseLocation.GetLocation() + FVector(8.0f, 0.f, 0.f), LeftHandInverseLocation.GetScale3D()); 70 | WorldTransforms.RightHandEffector = FTransform(RightHandInverseLocation.GetRotation(), RightHandInverseLocation.GetLocation() + FVector(8.0f, 0.f, 0.f), RightHandInverseLocation.GetScale3D()).Inverse(); 71 | 72 | FTransform LocalComponentTransform = WorldTransforms.Component.Inverse(); 73 | ComponentTransforms.HeadEffector = WorldTransforms.HeadEffector * LocalComponentTransform; 74 | ComponentTransforms.LeftHandEffector = WorldTransforms.LeftHandEffector * LocalComponentTransform; 75 | ComponentTransforms.RightHandEffector = WorldTransforms.RightHandEffector * LocalComponentTransform; 76 | 77 | WorldTransforms.Shoulder = ComponentTransforms.Shoulder * WorldTransforms.Component; 78 | FTransform LocalShoulderTransform = WorldTransforms.Shoulder.Inverse(); 79 | ShoulderTransforms.HeadEffector = WorldTransforms.HeadEffector * LocalShoulderTransform; 80 | ShoulderTransforms.LeftHandEffector = WorldTransforms.LeftHandEffector * LocalShoulderTransform; 81 | ShoulderTransforms.RightHandEffector = WorldTransforms.RightHandEffector * LocalShoulderTransform; 82 | } 83 | 84 | void UOpenMotionComponent::SetCharacterTransforms(FTransform LeftHandEffector, FTransform RightHandEffector, FTransform HeadEffector, FTransform ComponentTransform) 85 | { 86 | WorldTransforms.LeftHandEffector = LeftHandEffector; 87 | WorldTransforms.RightHandEffector = RightHandEffector; 88 | WorldTransforms.HeadEffector = HeadEffector; 89 | WorldTransforms.Component = ComponentTransform; 90 | } 91 | 92 | void UOpenMotionComponent::SetShoulder() 93 | { 94 | FVector A = UKismetMathLibrary::Multiply_VectorFloat(UKismetMathLibrary::Vector_Down(), 0.7f) + UKismetMathLibrary::Multiply_VectorFloat(UKismetMathLibrary::Vector_Backward(), 9.f); 95 | FRotator B = FRotator(0.f, ComponentTransforms.HeadEffector.GetRotation().Z, ComponentTransforms.HeadEffector.GetRotation().X); 96 | FVector RotatedVector = UKismetMathLibrary::GreaterGreater_VectorRotator(A, B); 97 | 98 | FRotator Delta = FRotator(ComponentTransforms.HeadEffector.GetRotation().Y, 0.f, 0.f); 99 | FVector TransformedLocation = ComponentTransforms.HeadEffector.GetLocation() + RotatedVector; 100 | FTransform RotationPoint = FTransform(FRotator(0.f, 0.f, 0.f), TransformedLocation, FVector(1, 1, 1)); 101 | 102 | FVector ComponentShoulderLocation = RotatePointAroundPivot(RotationPoint, ComponentTransforms.HeadEffector, Delta).GetLocation() + FVector(0, 0, -17); 103 | FRotator ComponentShoulderRotation = FRotator(0.f, UKismetMathLibrary::RLerp(GetShoulderRotationFromHead(), GetShoulderRotationFromHands(), 0.7f, true).Yaw, 0.f); 104 | 105 | ComponentTransforms.Shoulder = FTransform(ComponentShoulderRotation, ComponentShoulderLocation, FVector(1, 1, 1)); 106 | } 107 | 108 | void UOpenMotionComponent::SetLeftUpperArm() 109 | { 110 | ShoulderTransforms.LeftUpperArm = RotateUpperArm(true, ShoulderTransforms.LeftHandEffector.GetLocation()); 111 | FRotator ModifiedRotator = UKismetMathLibrary::MakeRotFromXZ((ShoulderTransforms.LeftUpperArm * WorldTransforms.Shoulder).GetLocation() - WorldTransforms.Shoulder.GetLocation(), UKismetMathLibrary::Vector_Up()); 112 | ComponentTransforms.LeftClavicle = FTransform(ModifiedRotator, FVector(0, 0, 0), FVector(1, 1, 1)) * WorldTransforms.Component.Inverse(); 113 | } 114 | 115 | void UOpenMotionComponent::SetRightUpperArm() 116 | { 117 | ShoulderTransforms.RightUpperArm = RotateUpperArm(false, ShoulderTransforms.RightHandEffector.GetLocation()); 118 | FRotator ModifiedRotator = UKismetMathLibrary::MakeRotFromXZ((ShoulderTransforms.RightUpperArm * WorldTransforms.Shoulder).GetLocation() - WorldTransforms.Shoulder.GetLocation(), UKismetMathLibrary::Vector_Up()); 119 | ComponentTransforms.RightClavicle = FTransform(ModifiedRotator, FVector(0, 0, 0), FVector(1, 1, 1)) * WorldTransforms.Component.Inverse(); 120 | } 121 | 122 | void UOpenMotionComponent::ResetUpperArmsLocation(USkeletalMeshComponent* OwnerMesh) 123 | { 124 | if (OwnerMesh != nullptr) 125 | { 126 | FVector LeftUpperArmLocation = OwnerMesh->GetSocketLocation("UpperArm_l"); 127 | FVector RightUpperArmLocation = OwnerMesh->GetSocketLocation("UpperArm_r"); 128 | ShoulderTransforms.LeftUpperArm = FTransform(FRotator(0.f, 0.f, 0.f), WorldTransforms.Shoulder.InverseTransformPosition(LeftUpperArmLocation), FVector(1, 1, 1)); 129 | ShoulderTransforms.RightUpperArm = FTransform(FRotator(0.f, 0.f, 0.f), WorldTransforms.Shoulder.InverseTransformPosition(RightUpperArmLocation), FVector(1, 1, 1)); 130 | } 131 | } 132 | 133 | void UOpenMotionComponent::SolveArms() 134 | { 135 | FVector Local_HandLocation = FVector(ShoulderTransforms.LeftHandEffector.GetLocation()); 136 | FRotator Local_HandRotation = FRotator(ShoulderTransforms.LeftHandEffector.GetRotation()); 137 | FArmTransforms Local_BasePosition = SetElbowBasePosition(true, ShoulderTransforms.LeftLowerArm.GetLocation(), Local_HandLocation); 138 | float Local_Angle = RotateElbowByHandPosition(true, Local_HandLocation); 139 | FArmTransforms TempArms = RotateElbow(true, Local_Angle, Local_BasePosition, Local_HandLocation); 140 | float TempAngle = RotateElbowByHandRotation(TempArms.LowerArmTransform, Local_HandRotation); 141 | 142 | CharacterSettings.LeftElbowHandAngle = UKismetMathLibrary::FInterpTo( 143 | CharacterSettings.LeftElbowHandAngle, 144 | SafeguardAngle(CharacterSettings.LeftElbowHandAngle, TempAngle, 120.f), 145 | UGameplayStatics::GetWorldDeltaSeconds(GEngine->GetWorldContexts()[0].World()), 146 | TransformSettings.ElbowHandRotSpeed); 147 | 148 | FArmTransforms TempArms2 = RotateElbow(true, CharacterSettings.LeftElbowHandAngle + Local_Angle, Local_BasePosition, Local_HandLocation); 149 | ShoulderTransforms.LeftUpperArm = TempArms2.UpperArmTransform; 150 | WorldTransforms.LeftUpperArm = ShoulderTransforms.LeftUpperArm * WorldTransforms.Shoulder; 151 | 152 | ShoulderTransforms.LeftLowerArm = TempArms2.LowerArmTransform; 153 | WorldTransforms.LeftLowerArm = ShoulderTransforms.LeftLowerArm * WorldTransforms.Shoulder; 154 | FTransform TempTransform = WorldTransforms.LeftUpperArm * WorldTransforms.Component.Inverse(); 155 | FVector TempLocation = WorldTransforms.LeftHandEffector.GetLocation() - WorldTransforms.LeftUpperArm.GetLocation(); 156 | FRotator TempRotator = UKismetMathLibrary::ComposeRotators(FRotator(0.f, 0.f, UKismetMathLibrary::Max(TempLocation.Z, 0.f)), FRotator(TempTransform.GetRotation())); 157 | 158 | ComponentTransforms.LeftUpperArm = FTransform(TempRotator, TempTransform.GetLocation(), FVector(1, 1, 1)); 159 | 160 | ComponentTransforms.LeftLowerArm = WorldTransforms.LeftLowerArm * WorldTransforms.Component.Inverse(); 161 | 162 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 163 | 164 | FVector Local_HandLocation2 = FVector(ShoulderTransforms.RightHandEffector.GetLocation()); 165 | FRotator Local_HandRotation2 = FRotator(ShoulderTransforms.RightHandEffector.GetRotation()); 166 | FArmTransforms Local_BasePosition2 = SetElbowBasePosition(true, ShoulderTransforms.RightLowerArm.GetLocation(), Local_HandLocation2); 167 | float Local_Angle2 = RotateElbowByHandPosition(true, Local_HandLocation2); 168 | FArmTransforms TempArms3 = RotateElbow(true, Local_Angle2, Local_BasePosition2, Local_HandLocation2); 169 | float TempAngle2 = RotateElbowByHandRotation(TempArms3.LowerArmTransform, Local_HandRotation2); 170 | 171 | CharacterSettings.RightElbowHandAngle = UKismetMathLibrary::FInterpTo( 172 | CharacterSettings.RightElbowHandAngle, 173 | SafeguardAngle(CharacterSettings.RightElbowHandAngle, TempAngle2, 120.f), 174 | UGameplayStatics::GetWorldDeltaSeconds(GEngine->GetWorldContexts()[0].World()), 175 | TransformSettings.ElbowHandRotSpeed); 176 | 177 | FArmTransforms TempArms4 = RotateElbow(true, CharacterSettings.RightElbowHandAngle + Local_Angle2, Local_BasePosition2, Local_HandLocation2); 178 | ShoulderTransforms.RightUpperArm = TempArms4.UpperArmTransform; 179 | WorldTransforms.RightUpperArm = ShoulderTransforms.RightUpperArm * WorldTransforms.Shoulder; 180 | 181 | ShoulderTransforms.RightLowerArm = TempArms4.LowerArmTransform; 182 | WorldTransforms.RightLowerArm = ShoulderTransforms.RightLowerArm * WorldTransforms.Shoulder; 183 | FTransform TempTransform2 = WorldTransforms.RightUpperArm * WorldTransforms.Component.Inverse(); 184 | FVector TempLocation2 = WorldTransforms.RightHandEffector.GetLocation() - WorldTransforms.RightUpperArm.GetLocation(); 185 | FRotator TempRotator2 = UKismetMathLibrary::ComposeRotators(FRotator(0.f, 0.f, UKismetMathLibrary::Max(TempLocation2.Z, 0.f) * -1.f), FRotator(TempTransform2.GetRotation())); 186 | 187 | ComponentTransforms.RightUpperArm = FTransform(TempRotator2, TempTransform2.GetLocation(), FVector(1, 1, 1)); 188 | 189 | ComponentTransforms.RightLowerArm = WorldTransforms.LeftLowerArm * WorldTransforms.Component.Inverse(); 190 | } 191 | 192 | void UOpenMotionComponent::DebugDraw() 193 | { 194 | } 195 | 196 | void UOpenMotionComponent::Calibrate(float CharacterHeight) 197 | { 198 | CharacterSettings.ArmLength = (CharacterHeight / 2) - TransformSettings.UpperArmsDistance; 199 | CharacterSettings.UpperArmLength = CharacterSettings.ArmLength * (1.f - 0.48f); 200 | CharacterSettings.LowerArmLength = CharacterSettings.ArmLength * 0.48f; 201 | CharacterSettings.HeadHandAngleLimitDot = UKismetMathLibrary::DegCos(TransformSettings.HeadHandAngleLimit); 202 | } 203 | 204 | FTransform UOpenMotionComponent::RotateUpperArm(bool bIsLeftArm, FVector HandLocation) 205 | { 206 | float TempFloat = TransformSettings.UpperArmsDistance / 2.f * UKismetMathLibrary::SelectFloat(1.f, -1.f, bIsLeftArm); 207 | FVector LInitialUpperArmPos = UKismetMathLibrary::Multiply_VectorFloat(UKismetMathLibrary::Vector_Right(), TempFloat); 208 | FVector LHandUpperArmDir = HandLocation - LInitialUpperArmPos; 209 | float LForwardDistanceRatio = UKismetMathLibrary::Dot_VectorVector(LHandUpperArmDir, UKismetMathLibrary::Vector_Forward()) / CharacterSettings.ArmLength; 210 | float LUpwardsDistanceRatio = UKismetMathLibrary::Dot_VectorVector(LHandUpperArmDir, UKismetMathLibrary::Vector_Up()) / CharacterSettings.ArmLength; 211 | 212 | float LYaw = 0.f; 213 | float LRoll = 0.f; 214 | 215 | if (LForwardDistanceRatio > 0.f) 216 | { 217 | LYaw = UKismetMathLibrary::FClamp((LForwardDistanceRatio - 0.5f) * TransformSettings.DistinctShoulderRotationMultiplier, 0.f, TransformSettings.DistinctShoulderRotationLimit) + TransformSettings.ClavicleOffset; 218 | } 219 | else 220 | { 221 | LYaw = UKismetMathLibrary::FClamp((LForwardDistanceRatio - 0.08f) * TransformSettings.DistinctShoulderRotationMultiplier, TransformSettings.DistinctShoulderRotationLimit * -1.f, 0.f) + TransformSettings.ClavicleOffset; 222 | } 223 | 224 | LRoll = UKismetMathLibrary::FClamp((LUpwardsDistanceRatio - 0.2f) * TransformSettings.DistinctShoulderRotationMultiplier, 0.f, TransformSettings.DistinctShoulderRotationLimit) + TransformSettings.ClavicleOffset; 225 | 226 | return FTransform(FRotator(0.f, LYaw * UKismetMathLibrary::SelectFloat(-1.f, 1.f, bIsLeftArm), LRoll * UKismetMathLibrary::SelectFloat(-1.f, 1.f, bIsLeftArm)), LInitialUpperArmPos, FVector(1, 1, 1)).Inverse(); 227 | } 228 | 229 | FArmTransforms UOpenMotionComponent::SetElbowBasePosition(bool bIsLeftArm, FVector UpperArmLocation, FVector HandLocation) 230 | { 231 | float LUpperArmToHandLen = (UpperArmLocation - HandLocation).Size(); 232 | float LBeta = CosineRule(CharacterSettings.UpperArmLength, LUpperArmToHandLen, CharacterSettings.LowerArmLength) * UKismetMathLibrary::SelectFloat(-1.f, 1.f, bIsLeftArm); 233 | float CRule = CosineRule(CharacterSettings.LowerArmLength, CharacterSettings.UpperArmLength, LUpperArmToHandLen); 234 | float LOmega = UKismetMathLibrary::SelectFloat(180.f - CRule, CRule + 180, bIsLeftArm); 235 | FVector B = HandLocation - UpperArmLocation; 236 | UKismetMathLibrary::Vector_Normalize(B, 0.0001); 237 | FRotator Normal = FindBetweenNormals(UKismetMathLibrary::Vector_Forward(), B); 238 | FRotator Rotator = FRotator(UKismetMathLibrary::ComposeRotators(Normal, UKismetMathLibrary::RotatorFromAxisAndAngle(UKismetMathLibrary::GetUpVector(Normal), LBeta))); 239 | FTransform T1 = FTransform(Rotator, UpperArmLocation, FVector(1, 1, 1)); 240 | FTransform T2 = FTransform(FRotator(0.f, LOmega, 0.f), UKismetMathLibrary::Multiply_VectorFloat(UKismetMathLibrary::Vector_Forward(), CharacterSettings.UpperArmLength), FVector(1, 1, 1)); 241 | return FArmTransforms(T1, T2 * T1); 242 | } 243 | 244 | float UOpenMotionComponent::RotateElbowByHandPosition(bool bIsLeftArm, FVector HandLocation) 245 | { 246 | float Temp = UKismetMathLibrary::Divide_VectorFloat(HandLocation, CharacterSettings.ArmLength).Y * UKismetMathLibrary::SelectFloat(1.f, -1.f, bIsLeftArm); 247 | return TransformSettings.ElbowBaseOffsetAngle + (TransformSettings.ElbowYWeight + UKismetMathLibrary::Max(0.f, Temp + TransformSettings.ElbowYDistanceStart)); 248 | } 249 | 250 | float UOpenMotionComponent::RotateElbowByHandRotation(FTransform LowerArmLocation, FRotator HandRotation) 251 | { 252 | FVector RightVector = UKismetMathLibrary::GetRightVector(FRotator(LowerArmLocation.GetRotation())); 253 | FVector NormalizedVector = UKismetMathLibrary::ProjectVectorOnToPlane(UKismetMathLibrary::GetForwardVector(HandRotation), RightVector); 254 | UKismetMathLibrary::Vector_Normalize(NormalizedVector, 0.0001); 255 | FVector ForwardVector = UKismetMathLibrary::GetForwardVector(FRotator(LowerArmLocation.GetRotation())); 256 | float Length = (NormalizedVector - ForwardVector).Size(); 257 | float Dot = UKismetMathLibrary::Dot_VectorVector(UKismetMathLibrary::Cross_VectorVector(NormalizedVector, ForwardVector), RightVector); 258 | return (CosineRule(1.f, 1.f, Length) * UKismetMathLibrary::SelectFloat(1.f, -1.f, Dot < 0.f)) * 0.6f; 259 | } 260 | 261 | float UOpenMotionComponent::CosineRule(float AdjacentA, float AdjacentB, float Opposite) 262 | { 263 | return UKismetMathLibrary::Acos((((AdjacentA * AdjacentA) + (AdjacentB * AdjacentB)) - (Opposite * Opposite)) / (AdjacentA * AdjacentB * 2)); 264 | } 265 | 266 | FArmTransforms UOpenMotionComponent::RotateElbow(bool bIsLeftArm, float Angle, FArmTransforms UpperAndLowerArms, FVector HandLocation) 267 | { 268 | FVector UpperArmHandAxis = UpperAndLowerArms.UpperArmTransform.GetLocation() - HandLocation; 269 | FVector PointDirectionVector = UKismetMathLibrary::ProjectVectorOnToVector(UpperAndLowerArms.UpperArmTransform.GetLocation() - UpperAndLowerArms.LowerArmTransform.GetLocation(), UpperArmHandAxis); 270 | FVector PivotLocation = UpperAndLowerArms.UpperArmTransform.GetLocation() + PointDirectionVector; 271 | FVector UpperArmRotationUpVector = UpperAndLowerArms.UpperArmTransform.GetRotation().GetUpVector(); 272 | FRotator PivotRotation = FRotator(UKismetMathLibrary::MakeRotationFromAxes(UpperArmHandAxis, UKismetMathLibrary::Cross_VectorVector(UpperArmRotationUpVector, UpperArmHandAxis), UpperArmRotationUpVector)); 273 | FTransform TempTransform = FTransform(PivotRotation, PivotLocation, FVector(1, 1, 1)); 274 | FRotator TempRotator = FRotator(0.f, 0.f, UKismetMathLibrary::SelectFloat(180.f - Angle, 180.f + Angle, bIsLeftArm)); 275 | return FArmTransforms(RotatePointAroundPivot(UpperAndLowerArms.UpperArmTransform, TempTransform, TempRotator), RotatePointAroundPivot(UpperAndLowerArms.LowerArmTransform, TempTransform, TempRotator)); 276 | } 277 | 278 | float UOpenMotionComponent::SafeguardAngle(float Current, float Last, float Threshold) 279 | { 280 | return UKismetMathLibrary::SelectFloat(Last, Current, bool(UKismetMathLibrary::Abs(Last - Current) > Threshold)); 281 | } 282 | 283 | FTransform UOpenMotionComponent::RotatePointAroundPivot(FTransform Point, FTransform Pivot, FRotator Delta) 284 | { 285 | return (((Point * Pivot.Inverse()) * FTransform(Delta, FVector(0, 0, 0), FVector(1, 1, 1))) * Pivot); 286 | } 287 | 288 | FVector UOpenMotionComponent::GetDebugValues() 289 | { 290 | return FVector(); 291 | } 292 | 293 | float UOpenMotionComponent::GetHeadHandAngle(float LastAngle, FVector HandLocation, FVector HandHeadDelta) 294 | { 295 | float Local_LastAngle = LastAngle; 296 | FVector Local_SubAngle = FVector(FVector(HandLocation.X, HandLocation.Y, 0).Normalize(0.0001)); 297 | float Local_Angle = UKismetMathLibrary::Atan2(Local_SubAngle.Y, Local_SubAngle.X); 298 | 299 | float Local_Alpha = UKismetMathLibrary::MapRangeClamped(UKismetMathLibrary::VSizeXY(HandHeadDelta), 20.f, 50.f, 0.f, 1.f); 300 | 301 | bool OR = ((UKismetMathLibrary::SignOfFloat(Local_LastAngle) == UKismetMathLibrary::SignOfFloat(Local_Angle)) || Local_Angle < TransformSettings.HeadHandAngleOkSpan && Local_Angle > TransformSettings.HeadHandAngleOkSpan * -1.f); 302 | bool bPickA = ((UKismetMathLibrary::Dot_VectorVector(Local_SubAngle, UKismetMathLibrary::Vector_Forward()) > CharacterSettings.HeadHandAngleLimitDot) && OR); 303 | return UKismetMathLibrary::Lerp(0.f, UKismetMathLibrary::SelectFloat(Local_Angle, TransformSettings.HeadHandAngleLimit * UKismetMathLibrary::SignOfFloat(Local_LastAngle), bPickA), Local_Alpha); 304 | } 305 | 306 | FTransform UOpenMotionComponent::GetBaseCharTransform() 307 | { 308 | return FTransform(ComponentTransforms.Shoulder.GetRotation(), ComponentTransforms.Shoulder.GetLocation() - FVector(0.f, 0.f, 12.f + 43.25f), FVector(1, 1, 1)); 309 | } 310 | 311 | FRotator UOpenMotionComponent::GetShoulderRotationFromHead() 312 | { 313 | return FRotator(0.f, ComponentTransforms.HeadEffector.GetRotation().Z, 0.f); 314 | } 315 | 316 | FRotator UOpenMotionComponent::GetShoulderRotationFromHands() 317 | { 318 | FVector Local_TopHead = UKismetMathLibrary::GreaterGreater_VectorRotator( 319 | UKismetMathLibrary::Multiply_VectorFloat(UKismetMathLibrary::Vector_Up(), 15.f) + UKismetMathLibrary::Multiply_VectorFloat(UKismetMathLibrary::Vector_Forward(), 0.f), 320 | FRotator(WorldTransforms.HeadEffector.GetRotation())) + WorldTransforms.HeadEffector.GetLocation(); 321 | CharacterSettings.LeftHeadHandAngle = GetHeadHandAngle(CharacterSettings.LeftHeadHandAngle, UKismetMathLibrary::ComposeTransforms(WorldTransforms.LeftHandEffector, WorldTransforms.HeadEffector.Inverse()).GetLocation(), WorldTransforms.LeftHandEffector.GetLocation() - Local_TopHead); 322 | CharacterSettings.RightHeadHandAngle = GetHeadHandAngle(CharacterSettings.RightHeadHandAngle, UKismetMathLibrary::ComposeTransforms(WorldTransforms.RightHandEffector, WorldTransforms.HeadEffector.Inverse()).GetLocation(), WorldTransforms.RightHandEffector.GetLocation() - Local_TopHead); 323 | 324 | FTransform TempTransform = FTransform(FRotator(0.f, CharacterSettings.LeftHeadHandAngle + CharacterSettings.RightHeadHandAngle / 2, 0.f), FVector(0.f, 0.f, 0.f), FVector(1, 1, 1)) * WorldTransforms.HeadEffector * WorldTransforms.Component.Inverse(); 325 | return FRotator(TempTransform.GetRotation()); 326 | } 327 | 328 | FRotator UOpenMotionComponent::FindBetweenNormals(FVector A, FVector B) 329 | { 330 | float W = UKismetMathLibrary::Dot_VectorVector(A, B) + 1.f; 331 | if (W > 0.000001) 332 | { 333 | float X = UKismetMathLibrary::Cross_VectorVector(A, B).X; 334 | float Y = UKismetMathLibrary::Cross_VectorVector(A, B).Y; 335 | float Z = UKismetMathLibrary::Cross_VectorVector(A, B).Z; 336 | FQuat QQQ = FQuat(X, Y, Z, W); 337 | 338 | UKismetMathLibrary::Quat_Normalize(QQQ, 0.0001); 339 | return FRotator(QQQ.Rotator()); 340 | } 341 | else 342 | { 343 | W = 0; 344 | 345 | FVector AVec = FVector(A.Z * 1.f, 0.f, A.X); 346 | FVector BVec = FVector(0.f, A.Z * -1.f, A.Y); 347 | FVector www = UKismetMathLibrary::SelectVector(AVec, BVec, bool(UKismetMathLibrary::Abs(A.X) > UKismetMathLibrary::Abs(A.Y))); 348 | FQuat QQQ = FQuat(www.X, www.Y, www.Z, W); 349 | 350 | UKismetMathLibrary::Quat_Normalize(QQQ, 0.0001); 351 | return FRotator(QQQ.Rotator()); 352 | } 353 | } 354 | 355 | -------------------------------------------------------------------------------- /Source/OpenMotion/Private/OpenMotionLibrary.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Name 2020 2 | 3 | 4 | #include "OpenMotionLibrary.h" 5 | 6 | -------------------------------------------------------------------------------- /Source/OpenMotion/Public/EBoneConnectionPoint.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | #pragma once 3 | 4 | #include "UObject/NoExportTypes.h" 5 | #include "CoreMinimal.h" 6 | 7 | UENUM() 8 | enum class EBoneConnectionPoint : uint8 9 | { 10 | BCP_None = 0 UMETA(Hidden), 11 | BCP_Start = 1 UMETA(DisplayName = "Start"), 12 | BCP_End = 2 UMETA(DisplayName = "End") 13 | }; -------------------------------------------------------------------------------- /Source/OpenMotion/Public/EBoneConstraintType.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "UObject/NoExportTypes.h" 6 | #include "CoreMinimal.h" 7 | 8 | 9 | 10 | UENUM() 11 | enum class EBoneConstraintType : uint8 12 | { 13 | BCT_None = 0 UMETA(Hidden), 14 | BCT_NoConstraint = 1 UMETA(HiddenDisplayName = "None"), // No constraint - basebone may rotate freely 15 | BCT_GlobalRotor = 2 UMETA(DisplayName = "Global Rotor"), // World-space rotor constraint 16 | BCT_LocalRotor = 3 UMETA(DisplayName = "Local Rotor"), // Rotor constraint in the coordinate space of (i.e. relative to) the direction of the connected bone 17 | BCT_GlobalHinge = 4 UMETA(DisplayName = "Global Hinge"), // World-space hinge constraint 18 | BCT_LocalHinge = 5 UMETA(DisplayName = "Local Hinge") // Hinge constraint in the coordinate space of (i.e. relative to) the direction of the connected bone 19 | }; -------------------------------------------------------------------------------- /Source/OpenMotion/Public/EJointType.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "UObject/NoExportTypes.h" 6 | #include "CoreMinimal.h" 7 | 8 | 9 | UENUM() 10 | enum class EJointType : uint8 11 | { 12 | JT_None = 0 UMETA(Hidden), 13 | JT_Ball = 1 UMETA(DisplayName = "Ball"), 14 | JT_GlobalHinge = 2 UMETA(DisplayName = "Global Hinge"), 15 | JT_LocalHinge = 3 UMETA(DisplayName = "Local Hinge") 16 | }; -------------------------------------------------------------------------------- /Source/OpenMotion/Public/FabrikBone.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | #pragma once 3 | 4 | #include "UObject/NoExportTypes.h" 5 | #include "EBoneConnectionPoint.h" 6 | #include "FabrikJoint.h" 7 | 8 | #include "FabrikBone.generated.h" 9 | 10 | /** 11 | UENUM(BlueprintType) 12 | enum class EBoneConnectionPoint : uint8 13 | { 14 | BCP_Start UMETA(DisplayName = "Start"), 15 | BCP_End UMETA(DisplayName = "End") 16 | }; 17 | */ 18 | 19 | UCLASS() 20 | class OPENMOTION_API UFabrikBone : public UObject 21 | { 22 | GENERATED_BODY() 23 | 24 | public: 25 | UFabrikBone(const FObjectInitializer& ObjectInitializer); 26 | 27 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 28 | EBoneConnectionPoint BoneConnectionPoint; 29 | 30 | //# TODO 31 | //######## FabrikJoint3D mJoint = new FabrikJoint3D(); 32 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 33 | UFabrikJoint* Joint; 34 | 35 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 36 | FVector StartLocation; 37 | 38 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 39 | FVector EndLocation; 40 | 41 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 42 | FName Name; 43 | 44 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 45 | float Length; 46 | 47 | 48 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 49 | FColor Color; 50 | 51 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 52 | float LineWidth; 53 | 54 | /** 55 | * Return the live (i.e. live calculated) length of this bone from its current start and end locations. 56 | * 57 | * @return The 'live' calculated distance between the start and end locations of this bone. 58 | */ 59 | 60 | UFabrikBone* Init(FVector InStartLocation, FVector InEndLocation); 61 | UFabrikBone* Init(FVector InStartLocation, FVector InEndLocation, FName InName); 62 | UFabrikBone* Init(FVector InStartLocation, FVector InDirectionUV, float InLength); 63 | UFabrikBone* Init(FVector InStartLocation, FVector InDirectionUV, float InLength, FName InName); 64 | UFabrikBone* Init(FVector InStartLocation, FVector InDirectionUV, float InLength, FColor InColor); 65 | UFabrikBone* Init(UFabrikBone* Source); // Clone 66 | 67 | float LiveLength(); 68 | TArray GetStartLocationAsArray(); 69 | TArray GetEndLocationAsArray(); 70 | 71 | // TODO: public JointType getJointType() { return mJoint.getJointType(); } 72 | // public void setHingeJointClockwiseConstraintDegs(float angleDegs) { mJoint.setHingeJointClockwiseConstraintDegs(angleDegs); } 73 | // public float getHingeJointClockwiseConstraintDegs() { return mJoint.getHingeClockwiseConstraintDegs(); } 74 | // public void setHingeJointAnticlockwiseConstraintDegs(float angleDegs) { mJoint.setHingeJointAnticlockwiseConstraintDegs(angleDegs); 75 | // public float getHingeJointAnticlockwiseConstraintDegs() { return mJoint.getHingeAnticlockwiseConstraintDegs(); } 76 | // setBallJointConstraintDegs 77 | // 78 | 79 | //void SetLineWidth(float InLineWidth); 80 | FVector GetDirectionUV() 81 | { 82 | //public static Vec3f getDirectionUV(Vec3f v1, Vec3f v2) { return v2.minus(v1).normalise(); } 83 | FVector Res = (EndLocation - StartLocation);// Vec3f.getDirectionUV(mStartLocation, mEndLocation); 84 | Res.Normalize(); 85 | return Res; 86 | } 87 | 88 | FString GetDebugMsg(); 89 | }; 90 | -------------------------------------------------------------------------------- /Source/OpenMotion/Public/FabrikChain.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "UObject/NoExportTypes.h" 6 | #include "EJointType.h" 7 | #include "EBoneConstraintType.h" 8 | #include "FabrikChain.generated.h" 9 | 10 | 11 | class UFabrikJoint; 12 | class UFabrikBone; 13 | class UFabrikStructure; 14 | 15 | /** 16 | * 17 | */ 18 | UCLASS() 19 | class OPENMOTION_API UFabrikChain : public UObject 20 | { 21 | GENERATED_BODY() 22 | 23 | public: 24 | 25 | UFabrikChain(const FObjectInitializer& ObjectInitializer); 26 | 27 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 28 | TArray Chain; 29 | 30 | 31 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 32 | FName Name; 33 | 34 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 35 | float SolveDistanceThreshold; 36 | 37 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 38 | int MaxIterationAttempts; 39 | 40 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 41 | float MinIterationChange; 42 | 43 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 44 | float ChainLength; 45 | 46 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 47 | int NumBones; 48 | 49 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 50 | FVector FixedBaseLocation; 51 | 52 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 53 | bool FixedBaseMode; 54 | 55 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 56 | EBoneConstraintType BaseboneConstraintType; 57 | 58 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 59 | FVector BaseboneConstraintUV; 60 | 61 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 62 | FVector BaseboneRelativeConstraintUV; 63 | 64 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 65 | FVector BaseboneRelativeReferenceConstraintUV; 66 | 67 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 68 | FVector LastTargetLocation; 69 | 70 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 71 | float ConstraintLineWidth; 72 | 73 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 74 | FVector LastBaseLocation; 75 | 76 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 77 | float CurrentSolveDistance; 78 | 79 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 80 | int ConnectedChainNumber; 81 | 82 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 83 | int ConnectedBoneNumber; 84 | 85 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 86 | FVector EmbeddedTarget; 87 | 88 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 89 | bool UseEmbeddedTarget; 90 | 91 | FVector GetBaseLocation(); 92 | 93 | FVector CreateMaxVector() 94 | { 95 | return FVector(FLT_MAX, FLT_MAX, FLT_MAX); 96 | } 97 | 98 | float FloatMax() 99 | { 100 | return FLT_MAX, FLT_MAX, FLT_MAX; 101 | } 102 | 103 | 104 | void Init(UFabrikChain* InSource); 105 | UFabrikChain* Init(FName InName); 106 | void AddBone(UFabrikBone* InBone); 107 | 108 | void AddConsecutiveBone(FVector InDirectionUV, float InLength); 109 | void AddConsecutiveBone(FVector InDirectionUV, float InLength, FColor InColour); 110 | 111 | void AddConsecutiveFreelyRotatingHingedBone(FVector InDirectionUV, float InLength, EJointType InJointType, FVector InHingeRotationAxis); 112 | void AddConsecutiveFreelyRotatingHingedBoneC(FVector InDirectionUV, float InLength, EJointType InJointType, FVector InHingeRotationAxis, FColor InColour); 113 | 114 | void AddConsecutiveHingedBoneC(FVector InDirectionUV, 115 | float InLength, 116 | EJointType InJointType, 117 | FVector InHingeRotationAxis, 118 | float InClockwiseDegs, 119 | float InAnticlockwiseDegs, 120 | FVector InHingeReferenceAxis, 121 | FColor InColour); 122 | 123 | void AddConsecutiveHingedBone(FVector InDirectionUV, 124 | float InLength, 125 | EJointType InJointType, 126 | FVector InHingeRotationAxis, 127 | float InClockwiseDegs, 128 | float InAnticlockwiseDegs, 129 | FVector InHingeConstraintReferenceAxis); 130 | 131 | void AddConsecutiveRotorConstrainedBoneC(FVector InBoneDirectionUV, float InBoneLength, float InConstraintAngleDegs, FColor InColor); 132 | void AddConsecutiveRotorConstrainedBone(FVector InBoneDirectionUV, float InBoneLength, float InConstraintAngleDegs); 133 | UFabrikBone* GetBone(int InBoneNumber); 134 | 135 | FVector GetEffectorLocation(); 136 | float GetLiveChainLength(); 137 | void RemoveBone(int InBoneNumber); 138 | void SetRotorBaseboneConstraint(EBoneConstraintType InRotorType, FVector InConstraintAxis, float InAngleDegs); 139 | 140 | void SetHingeBaseboneConstraint(EBoneConstraintType InHingeType, FVector InHingeRotationAxis, float InCwConstraintDegs, float InAcwConstraintDegs, FVector InHingeReferenceAxis); 141 | void SetFreelyRotatingGlobalHingedBasebone(FVector InHingeRotationAxis); 142 | void SetFreelyRotatingLocalHingedBasebone(FVector InHingeRotationAxis); 143 | void SetLocalHingedBasebone(FVector InHingeRotationAxis, float InCwDegs, float InAcwDegs, FVector InHingeReferenceAxis); 144 | void SetGlobalHingedBasebone(FVector InHingeRotationAxis, float InCwDegs, float InAcwDegs, FVector InHingeReferenceAxis); 145 | //void SetBaseboneConstraintUV(FVector InConstraintUV); 146 | // public void setBaseLocation(Vec3f baseLocation) { mFixedBaseLocation = baseLocation; } 147 | 148 | //########### 149 | void ConnectToStructure(UFabrikStructure* InStructure, int InChainNumber, int InBoneNumber); 150 | void SetColour(FColor InColour); 151 | float SolveForEmbeddedTarget(); 152 | float SolveForTarget(FVector InNewTarget); 153 | 154 | // public String toString() 155 | float SolveIK(FVector InTarget); 156 | void UpdateChainLength(); 157 | //void UpdateEmbeddedTarget(FVector InNewEmbeddedTarget); 158 | TArray CloneIkChain(); 159 | }; 160 | -------------------------------------------------------------------------------- /Source/OpenMotion/Public/FabrikDebugComponent.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | #include "Components/ActorComponent.h" 5 | #include "FabrikDebugComponent.generated.h" 6 | 7 | class UFabrikStructure; 8 | class UFabrikChain; 9 | class UFabrikMat3f; 10 | class UFabrikBone; 11 | 12 | UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) 13 | class OPENMOTION_API UFabrikDebugComponent : public UActorComponent 14 | { 15 | GENERATED_BODY() 16 | 17 | public: 18 | // Sets default values for this component's properties 19 | UFabrikDebugComponent(); 20 | 21 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 22 | UFabrikStructure* Structure; 23 | 24 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Debug) 25 | bool DrawEnabled; 26 | 27 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Debug) 28 | float PointSize; 29 | 30 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Debug) 31 | float LineThickness; 32 | 33 | 34 | 35 | // Constraint colours 36 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Color) 37 | FColor ANTICLOCKWISE_CONSTRAINT_COLOUR; 38 | 39 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Color) 40 | FColor CLOCKWISE_CONSTRAINT_COLOUR; 41 | 42 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Color) 43 | FColor BALL_JOINT_COLOUR; 44 | 45 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Color) 46 | FColor GLOBAL_HINGE_COLOUR; 47 | 48 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Color) 49 | FColor LOCAL_HINGE_COLOUR; 50 | 51 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Color) 52 | FColor REFERENCE_AXIS_COLOUR; 53 | 54 | 55 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Config) 56 | float CONE_LENGTH_FACTOR; 57 | 58 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Config) 59 | float RADIUS_FACTOR; 60 | 61 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Config) 62 | int NUM_CONE_LINES; 63 | 64 | 65 | //UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Color) 66 | float rotStep; 67 | 68 | 69 | // Called when the game starts 70 | virtual void BeginPlay() override; 71 | 72 | // Called every frame 73 | virtual void TickComponent( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction ) override; 74 | 75 | 76 | void DrawChainBones(UFabrikChain* Chain); 77 | 78 | void DrawConstraint(UFabrikBone* bone, FVector referenceDirection, float lineWidth/*, UFabrikMat3f* mvpMatrix*/); 79 | void DrawLine(FVector Start, FVector End, FColor Color, float lineWidth); 80 | void DrawCircle(FVector Start, FVector Axis, float Radius, FColor Color, float LineWidth); 81 | void DrawChainConstraints(UFabrikChain* Chain, float LineWidth); 82 | }; 83 | -------------------------------------------------------------------------------- /Source/OpenMotion/Public/FabrikDemoActor.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | #include "GameFramework/Actor.h" 5 | #include "FabrikDemoActor.generated.h" 6 | 7 | class UFabrikStructure; 8 | class UFabrikChain; 9 | class UFabrikDebugComponent; 10 | 11 | UENUM(BlueprintType) 12 | enum class EFabrikDemoType : uint8 13 | { 14 | FD_UnconstrainedBones UMETA(DisplayName = "Demo 1 - Unconstrained bones"), 15 | FD_RotorBallJointConstrainedBones UMETA(DisplayName = "Demo 2 - Rotor / Ball Joint Constrained Bones"), 16 | FD_RotorConstrainedBaseBones UMETA(DisplayName = "Demo 3 - Rotor Constrained Base Bones"), 17 | FD_FreelyRotatingGlobalHinges UMETA(DisplayName = "Demo 4 - Freely Rotating Global Hinges"), 18 | FD_GlobalHingesWithReferenceAxisConstraints UMETA(DisplayName = "Demo 5 - Global Hinges With Reference Axis Constraints"), 19 | FD_FreelyRotatingLocalHinges UMETA(DisplayName = "Demo 6 - Freely Rotating Local Hinges"), 20 | FD_LocalHingesWithReferenceAxisConstraints UMETA(DisplayName = "Demo 7 - Local Hinges with Reference Axis Constraints"), 21 | FD_ConnectedChains UMETA(DisplayName = "Demo 8 - Connected Chains"), 22 | FD_GlobalRotorConstrainedConnectedChains UMETA(DisplayName = "Demo 9 - Global Rotor Constrained Connected Chains"), 23 | FD_LocalRotorConstrainedConnectedChains UMETA(DisplayName = "Demo 10 - Local Rotor Constrained Connected Chains"), 24 | FD_ConnectedChainsWithFreelyRotatingGlobalHingedBaseboneConstraints UMETA(DisplayName = "Demo 11 - Connected Chains with Freely-Rotating Global Hinged Basebone Constraints"), 25 | FD_ConnectedChainsWithEmbeddedTargets UMETA(DisplayName = "Demo 12 - Connected chains with embedded targets") 26 | }; 27 | 28 | UCLASS() 29 | class OPENMOTION_API AFabrikDemoActor : public AActor 30 | { 31 | GENERATED_BODY() 32 | 33 | public: 34 | // Sets default values for this actor's properties 35 | AFabrikDemoActor(); 36 | 37 | // Called when the game starts or when spawned 38 | virtual void BeginPlay() override; 39 | 40 | // Called every frame 41 | virtual void Tick( float DeltaSeconds ) override; 42 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 43 | UFabrikDebugComponent* FabrikDebugComponent; 44 | 45 | 46 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 47 | EFabrikDemoType DemoType; 48 | 49 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 50 | FVector XAxis; 51 | 52 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 53 | FVector YAxis; 54 | 55 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 56 | FVector ZAxis; 57 | 58 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 59 | FVector DefaultBoneDirection; 60 | 61 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 62 | float DefaultBoneLength; 63 | 64 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 65 | float BoneLineWidth; 66 | 67 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 68 | float ConstraintLineWidth; 69 | 70 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 71 | float BaseRotationAmountDegs; 72 | 73 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 74 | AActor* TargetActor; 75 | 76 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 77 | UFabrikStructure* Structure; 78 | 79 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Debug) 80 | float PointSize; 81 | 82 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Debug) 83 | float LineThickness; 84 | 85 | void DrawChain(UFabrikChain* Chain); 86 | 87 | FColor Brightness(FColor color, float correctionFactor); 88 | 89 | void DemoUnconstrainedBones(); 90 | void DemoRotorBallJointConstrainedBones(); 91 | void DemoRotorConstrainedBaseBones(); 92 | void DemoFreelyRotatingGlobalHinges(); 93 | void DemoGlobalHingesWithReferenceAxisConstraints(); 94 | void DemoFreelyRotatingLocalHinges(); 95 | void DemoLocalHingesWithReferenceAxisConstraints(); 96 | void DemoConnectedChains(); 97 | void DemoGlobalRotorConstrainedConnectedChains(); 98 | void DemoLocalRotorConstrainedConnectedChains(); 99 | void DemoConnectedChainsWithFreelyRotatingGlobalHingedBaseboneConstraints(); 100 | void DemoConnectedChainsWithEmbeddedTargets(); 101 | }; 102 | -------------------------------------------------------------------------------- /Source/OpenMotion/Public/FabrikJoint.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "UObject/NoExportTypes.h" 6 | #include "EBoneConnectionPoint.h" 7 | #include "EJointType.h" 8 | 9 | #include "FabrikJoint.generated.h" 10 | 11 | 12 | /** 13 | * 14 | */ 15 | UCLASS() 16 | class OPENMOTION_API UFabrikJoint : public UObject 17 | { 18 | GENERATED_BODY() 19 | 20 | public: 21 | static float MIN_CONSTRAINT_ANGLE_DEGS;// = 0.0f; 22 | static float MAX_CONSTRAINT_ANGLE_DEGS;// = 180.0f; 23 | 24 | public: 25 | 26 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 27 | float RotorConstraintDegs;// = MAX_CONSTRAINT_ANGLE_DEGS; 28 | 29 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 30 | float HingeClockwiseConstraintDegs;// = MAX_CONSTRAINT_ANGLE_DEGS; 31 | 32 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 33 | float HingeAnticlockwiseConstraintDegs;// = MAX_CONSTRAINT_ANGLE_DEGS; 34 | 35 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 36 | FVector RotationAxisUV;// = new Vec3f(); 37 | 38 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 39 | FVector ReferenceAxisUV;// = new Vec3f(); 40 | 41 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 42 | EJointType JointType;// = JointType.BALL; 43 | 44 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 45 | EBoneConnectionPoint BoneConnectionPoint; 46 | 47 | UFabrikJoint(const FObjectInitializer& ObjectInitializer); 48 | 49 | UFabrikJoint* Init(UFabrikJoint* Source); 50 | 51 | UFabrikJoint* Clone(UFabrikJoint* Source); 52 | 53 | void SetAsBallJoint(float InConstraintAngleDegs); 54 | void SetHinge(EJointType InJointType, FVector InRotationAxis, float InClockwiseConstraintDegs, float InAnticlockwiseConstraintDegs, FVector InReferenceAxis); 55 | void SetAsGlobalHinge(FVector InGlobalRotationAxis, float InCwConstraintDegs, float InAcwConstraintDegs, FVector InGlobalReferenceAxis); 56 | void SetAsLocalHinge(FVector InLocalRotationAxis, float InCwConstraintDegs, float InAcwConstraintDegs, FVector InLocalReferenceAxis); 57 | 58 | static void ValidateConstraintAngleDegs(float InAngleDegs); 59 | static void ValidateAxis(FVector InAxis); 60 | }; 61 | -------------------------------------------------------------------------------- /Source/OpenMotion/Public/FabrikMat3f.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "UObject/NoExportTypes.h" 6 | #include "FabrikMat3f.generated.h" 7 | 8 | UCLASS() 9 | class OPENMOTION_API UFabrikMat3f : public UObject 10 | { 11 | GENERATED_BODY() 12 | 13 | public: 14 | float m00, m01, m02; // First column - typically the direction of the positive X-axis 15 | float m10, m11, m12; // Second column - typically the direction of the positive Y-axis 16 | float m20, m21, m22; // Third column - typically the direction of the positive Z-axis 17 | 18 | 19 | static UFabrikMat3f* CreateRotationMatrix(FVector InReferenceDirection); 20 | void Init(FVector xAxis, FVector yAxis, FVector zAxis); 21 | FVector Times(FVector source); 22 | }; 23 | -------------------------------------------------------------------------------- /Source/OpenMotion/Public/FabrikStructure.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "UObject/NoExportTypes.h" 6 | #include "EBoneConnectionPoint.h" 7 | #include "FabrikStructure.generated.h" 8 | 9 | class UFabrikChain; 10 | 11 | /** 12 | * 13 | */ 14 | UCLASS() 15 | class OPENMOTION_API UFabrikStructure : public UObject 16 | { 17 | GENERATED_BODY() 18 | 19 | public: 20 | 21 | UFabrikStructure(const FObjectInitializer& ObjectInitializer); 22 | 23 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 24 | FName Name; 25 | 26 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 27 | TArray Chains;// = new ArrayList(); 28 | 29 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setting) 30 | int NumChains; 31 | 32 | void SolveForTarget(FVector InNewTargetLocation); 33 | void SolveForTarget(float InTargetX, float InTargetY, float InTargetZ); 34 | void AddChain(UFabrikChain* InChain); 35 | void RemoveChain(int InChainIndex); 36 | void ConnectChain(UFabrikChain* InNewChain, int InExistingChainNumber, int InExistingBoneNumber); 37 | void ConnectChain(UFabrikChain* InNewChain, int InExistingChainNumber, int InExistingBoneNumber, EBoneConnectionPoint InBoneConnectionPoint); 38 | 39 | void SetFixedBaseMode(bool InFixedBaseMode); 40 | }; 41 | -------------------------------------------------------------------------------- /Source/OpenMotion/Public/FabrikUtil.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "UObject/NoExportTypes.h" 6 | 7 | #include "OpenMotion.h" 8 | 9 | #include "FabrikUtil.generated.h" 10 | 11 | // https://wiki.unrealengine.com/Static_Function_Libraries,_Your_Own_Version_of_UE4_C%2B%2B,_No_Engine_Compile_Times 12 | UCLASS() 13 | class UFabrikUtil : public UObject 14 | { 15 | GENERATED_UCLASS_BODY() 16 | 17 | // static FORCEINLINE FVector VectorGenPerpendicularVectorQuick(FVector U) 18 | //FORCEINLNE function 19 | static FVector VectorGenPerpendicularVectorQuick(FVector U) 20 | { 21 | FVector Perp; 22 | 23 | if (FMath::Abs(U.Y) < 0.99f) 24 | { 25 | Perp = FVector(-U.Z, 0.0f, U.X); // cross(u, UP) 26 | } 27 | else 28 | { 29 | Perp = FVector(0.0f, U.Z, -U.Y); // cross(u, RIGHT) 30 | } 31 | 32 | Perp.Normalize(); 33 | return Perp; 34 | } 35 | 36 | static float ColorClamp( float InComponentValue) 37 | { 38 | float MIN_COMPONENT_VALUE = 0.0f; 39 | float MAX_COMPONENT_VALUE = 1.0f; 40 | if (InComponentValue > MAX_COMPONENT_VALUE) { return MAX_COMPONENT_VALUE; } 41 | else if (InComponentValue < MIN_COMPONENT_VALUE) { return MIN_COMPONENT_VALUE; } 42 | else { return InComponentValue; } 43 | } 44 | 45 | static uint8 ColorClamp8(float InComponentValue) 46 | { 47 | float C = ColorClamp(InComponentValue); 48 | return (uint8)(C * 255); 49 | } 50 | 51 | static FColor AddRGB(FColor InColor, float InRed, float InGreen, float InBlue) 52 | { 53 | FColor C; 54 | C.R = ColorClamp8((InColor.R / 255.0f) + InRed); 55 | C.G = ColorClamp8((InColor.G / 255.0f) + InGreen); 56 | C.B = ColorClamp8((InColor.B / 255.0f) + InBlue); 57 | return C; 58 | } 59 | 60 | static FColor SubtractRGB(FColor InColor, float InRed, float InGreen, float InBlue) 61 | { 62 | FColor C; 63 | C.R = ColorClamp8((InColor.R / 255.0f) - InRed); 64 | C.G = ColorClamp8((InColor.G / 255.0f) - InGreen); 65 | C.B = ColorClamp8((InColor.B / 255.0f) - InBlue); 66 | return C; 67 | } 68 | 69 | 70 | static FColor Lighten(FColor InColor, float InAmount) { return AddRGB(InColor, InAmount, InAmount, InAmount); } 71 | static FColor Darken(FColor InColor, float InAmount) { return SubtractRGB(InColor, InAmount, InAmount, InAmount); } 72 | static FColor Color(float InRed, float InGreen, float InBlue) { return FColor(ColorClamp8(InRed), ColorClamp8(InGreen), ColorClamp8(InBlue)); } 73 | 74 | static const FColor RED; 75 | static const FColor GREEN; 76 | static const FColor BLUE; 77 | static const FColor MID_RED; 78 | static const FColor MID_GREEN; 79 | static const FColor MID_BLUE; 80 | static const FColor BLACK; 81 | static const FColor GREY; 82 | static const FColor WHITE; 83 | static const FColor YELLOW; 84 | static const FColor CYAN; 85 | static const FColor MAGENTA; 86 | 87 | static const FVector X_AXIS; 88 | static const FVector Y_AXIS; 89 | static const FVector Z_AXIS; 90 | 91 | static void ValidateDirectionUV(FVector InDirectionUV) 92 | { 93 | if (!(InDirectionUV.Size() > 0.0f)) 94 | { 95 | UE_LOG(OpenMotionLog, Fatal, TEXT("FVector direction unit vector cannot be zero.")); 96 | } 97 | } 98 | 99 | static void ValidateLength(float InLength) 100 | { 101 | // Ensure that the magnitude of this direction unit vector is not zero 102 | if (InLength < 0.0f) 103 | { 104 | UE_LOG(OpenMotionLog, Fatal, TEXT("Length must be a greater than or equal to zero.")); 105 | } 106 | } 107 | 108 | static bool VectorPerpendicular(FVector InA, FVector InB) 109 | { 110 | return UFabrikUtil::ApproximatelyEquals(FVector::DotProduct(InA, InB), 0.0f, 0.01f) ? true : false; 111 | } 112 | 113 | static bool ApproximatelyEquals(float InA, float InB, float InTolerance) 114 | { 115 | return (FMath::Abs(InA - InB) <= InTolerance) ? true : false; 116 | } 117 | 118 | /** 119 | static FORCEINLINE FVector VectorGenPerpendicularVectorQuick(FVector InU) 120 | { 121 | FVector Perp; 122 | 123 | if (FMath::Abs(InU.Y) < 0.99f) 124 | { 125 | Perp = FVector(-InU.Z, 0.0f, InU.X); // cross(u, UP) 126 | } 127 | else 128 | { 129 | Perp = FVector(0.0f, InU.Z, -InU.Y); // cross(u, RIGHT) 130 | } 131 | 132 | Perp.Normalize(); 133 | return Perp; // perp.normalise(); 134 | 135 | }*/ 136 | 137 | 138 | static bool VectorApproximatelyEquals(FVector InSrc, FVector InV, float InTolerance) 139 | { 140 | if (InTolerance < 0.0f) 141 | { 142 | UE_LOG(OpenMotionLog, Fatal, TEXT("Equality threshold must be greater than or equal to 0.0f")); 143 | } 144 | 145 | // Get the absolute differences between the components 146 | float xDiff = FMath::Abs(InSrc.X - InV.X); 147 | float yDiff = FMath::Abs(InSrc.Y - InV.Y); 148 | float zDiff = FMath::Abs(InSrc.Z - InV.Z); 149 | 150 | // Return true or false 151 | return (xDiff < InTolerance && yDiff < InTolerance && zDiff < InTolerance); 152 | } 153 | 154 | static FVector VectorNegated(FVector InV) { return FVector(-InV.X, -InV.Y, -InV.Z); } 155 | 156 | 157 | static FVector ProjectOntoPlane(FVector Inv, FVector InPlaneNormal) 158 | { 159 | if (!(InPlaneNormal.Size() > 0.0f)) 160 | { 161 | UE_LOG(OpenMotionLog, Fatal, TEXT("Plane normal cannot be a zero vector.")); 162 | } 163 | 164 | // Projection of vector b onto plane with normal n is defined as: b - ( b.n / ( |n| squared )) * n 165 | // Note: |n| is length or magnitude of the vector n, NOT its (component-wise) absolute value 166 | FVector B = Inv;// .normalised(); 167 | B.Normalize(); 168 | 169 | FVector N = InPlaneNormal;// .normalised(); 170 | N.Normalize(); 171 | 172 | FVector Res = B - (N * (FVector::DotProduct(B, InPlaneNormal)));// b.minus(n.times(Vec3f.dotProduct(b, planeNormal))).normalise(); 173 | Res.Normalize(); 174 | return Res; 175 | 176 | /** IMPORTANT: We have to be careful here - even code like the below (where dotProduct uses normalised 177 | * versions of 'this' and planeNormal is off by enough to make the IK solutions oscillate: 178 | * 179 | * return this.minus( planeNormal.times( Vec3f.dotProduct(this, planeNormal) ) ).normalised(); 180 | * 181 | */ 182 | 183 | // Note: For non-normalised plane vectors we can use: 184 | // float planeNormalLength = planeNormal.length(); 185 | // return b.minus( n.times( Vec3f.dotProduct(b, n) / (planeNormalLength * planeNormalLength) ).normalised(); 186 | } 187 | 188 | static float Sign(float InValue) 189 | { 190 | if (InValue >= 0.0f) { return 1.0f; } // Implied else... 191 | return -1.0f; 192 | } 193 | 194 | 195 | static float GetAngleBetweenRads(FVector InV1, FVector InV2) 196 | { 197 | // Note: a and b are normalised within the dotProduct method. 198 | // return (float)Math.acos( Vec3f.dotProduct(v1, v2) ); 199 | return (float)FMath::Acos(FVector::DotProduct(InV1, InV2)); 200 | } 201 | 202 | static float GetAngleBetweenDegs(FVector InV1, FVector InV2) 203 | { 204 | return FMath::RadiansToDegrees(GetAngleBetweenRads(InV1, InV2)); 205 | } 206 | 207 | static float GetSignedAngleBetweenDegs(FVector InReferenceVector, FVector InOtherVector, FVector InNormalVector) 208 | { 209 | float UnsignedAngle = GetAngleBetweenDegs(InReferenceVector, InOtherVector); 210 | float SignV = Sign(FVector::DotProduct(FVector::CrossProduct(InReferenceVector, InOtherVector), InNormalVector)); 211 | return UnsignedAngle * SignV; 212 | } 213 | 214 | static FVector RotateAboutAxisRads(FVector InSource, float InAngleRads, FVector InRotationAxis); 215 | /*{ 216 | //Mat3f rotationMatrix = new Mat3f(); 217 | UFabrikMat3f* RotationMatrix = NewObject(); 218 | 219 | float sinTheta = (float)FMath::Sin(InAngleRads); 220 | float cosTheta = (float)FMath::Cos(InAngleRads); 221 | float oneMinusCosTheta = 1.0f - cosTheta; 222 | 223 | // It's quicker to pre-calc these and reuse than calculate x * y, then y * x later (same thing). 224 | float xyOne = InRotationAxis.X * InRotationAxis.Y * oneMinusCosTheta; 225 | float xzOne = InRotationAxis.X * InRotationAxis.Z * oneMinusCosTheta; 226 | float yzOne = InRotationAxis.Y * InRotationAxis.Z * oneMinusCosTheta; 227 | 228 | // Calculate rotated x-axis 229 | RotationMatrix->m00 = InRotationAxis.X * InRotationAxis.X * oneMinusCosTheta + cosTheta; 230 | RotationMatrix->m01 = xyOne + InRotationAxis.Z * sinTheta; 231 | RotationMatrix->m02 = xzOne - InRotationAxis.Y * sinTheta; 232 | 233 | // Calculate rotated y-axis 234 | RotationMatrix->m10 = xyOne - InRotationAxis.Z * sinTheta; 235 | RotationMatrix->m11 = InRotationAxis.Y * InRotationAxis.Y * oneMinusCosTheta + cosTheta; 236 | RotationMatrix->m12 = yzOne + InRotationAxis.X * sinTheta; 237 | 238 | // Calculate rotated z-axis 239 | RotationMatrix->m20 = xzOne + InRotationAxis.Y * sinTheta; 240 | RotationMatrix->m21 = yzOne - InRotationAxis.X * sinTheta; 241 | RotationMatrix->m22 = InRotationAxis.Z * InRotationAxis.Z * oneMinusCosTheta + cosTheta; 242 | 243 | // Multiply the source by the rotation matrix we just created to perform the rotation 244 | return RotationMatrix->Times(InSource); 245 | }*/ 246 | 247 | static FVector RotateAboutAxisDegs(FVector InSource, float InAngleDegs, FVector InRotationAxis) 248 | { 249 | return RotateAboutAxisRads(InSource, FMath::DegreesToRadians(InAngleDegs), InRotationAxis); // * DEGS_TO_RADS, 250 | } 251 | 252 | static FVector GetAngleLimitedUnitVectorDegs(FVector InVecToLimit, FVector InVecBaseline, float InAngleLimitDegs); 253 | 254 | 255 | static FVector RotateYRads(FVector InSource, float InAngleRads) 256 | { 257 | float CosTheta = (float)FMath::Cos(InAngleRads); 258 | float SinTheta = (float)FMath::Sin(InAngleRads); 259 | return FVector(InSource.Z * SinTheta + InSource.X * CosTheta, InSource.Y, InSource.Z * CosTheta - InSource.X * SinTheta); 260 | } 261 | 262 | 263 | static FVector RotateYDegs(FVector source, float angleDegs) { return RotateYRads(source, FMath::DegreesToRadians(angleDegs)); } 264 | 265 | //cpp function 266 | //static int32 ComplicatedGameDataAnalysis(); 267 | }; -------------------------------------------------------------------------------- /Source/OpenMotion/Public/OpenMotion.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Modules/ModuleManager.h" 7 | 8 | DECLARE_LOG_CATEGORY_EXTERN(OpenMotionLog, Log, All); 9 | 10 | class FOpenMotionModule : public IModuleInterface 11 | { 12 | public: 13 | 14 | /** IModuleInterface implementation */ 15 | virtual void StartupModule() override; 16 | virtual void ShutdownModule() override; 17 | }; 18 | -------------------------------------------------------------------------------- /Source/OpenMotion/Public/OpenMotionComponent.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Name 2020 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Components/ActorComponent.h" 7 | 8 | // 9 | 10 | #include "OpenMotionComponent.generated.h" 11 | 12 | 13 | USTRUCT(BlueprintType) 14 | struct FWorldTransforms 15 | { 16 | GENERATED_USTRUCT_BODY() 17 | 18 | // any non-UPROPERTY() struct vars are not replicated 19 | 20 | UPROPERTY(BlueprintReadWrite) 21 | FTransform HeadEffector; 22 | 23 | UPROPERTY(BlueprintReadWrite) 24 | FTransform LeftHandEffector; 25 | 26 | UPROPERTY(BlueprintReadWrite) 27 | FTransform RightHandEffector; 28 | 29 | UPROPERTY(BlueprintReadWrite) 30 | FTransform Component; 31 | 32 | UPROPERTY(BlueprintReadWrite) 33 | FTransform Shoulder; 34 | 35 | UPROPERTY(BlueprintReadWrite) 36 | FTransform LeftUpperArm; 37 | 38 | UPROPERTY(BlueprintReadWrite) 39 | FTransform LeftLowerArm; 40 | 41 | UPROPERTY(BlueprintReadWrite) 42 | FTransform RightUpperArm; 43 | 44 | UPROPERTY(BlueprintReadWrite) 45 | FTransform RightLowerArm; 46 | }; 47 | 48 | 49 | USTRUCT(BlueprintType) 50 | struct FShoulderTransforms 51 | { 52 | GENERATED_USTRUCT_BODY() 53 | 54 | UPROPERTY(BlueprintReadWrite) 55 | FTransform HeadEffector; 56 | 57 | UPROPERTY(BlueprintReadWrite) 58 | FTransform LeftHandEffector; 59 | 60 | UPROPERTY(BlueprintReadWrite) 61 | FTransform RightHandEffector; 62 | 63 | UPROPERTY(BlueprintReadWrite) 64 | FTransform Shoulder; 65 | 66 | UPROPERTY(BlueprintReadWrite) 67 | FTransform LeftUpperArm; 68 | 69 | UPROPERTY(BlueprintReadWrite) 70 | FTransform LeftLowerArm; 71 | 72 | UPROPERTY(BlueprintReadWrite) 73 | FTransform RightUpperArm; 74 | 75 | UPROPERTY(BlueprintReadWrite) 76 | FTransform RightLowerArm; 77 | }; 78 | 79 | USTRUCT(BlueprintType) 80 | struct FComponentTransforms 81 | { 82 | GENERATED_USTRUCT_BODY() 83 | 84 | UPROPERTY(BlueprintReadWrite) 85 | FTransform HeadEffector; 86 | 87 | UPROPERTY(BlueprintReadWrite) 88 | FTransform LeftHandEffector; 89 | 90 | UPROPERTY(BlueprintReadWrite) 91 | FTransform RightHandEffector; 92 | 93 | UPROPERTY(BlueprintReadWrite) 94 | FTransform Shoulder; 95 | 96 | UPROPERTY(BlueprintReadWrite) 97 | FTransform LeftClavicle; 98 | 99 | UPROPERTY(BlueprintReadWrite) 100 | FTransform RightClavicle; 101 | 102 | UPROPERTY(BlueprintReadWrite) 103 | FTransform LeftUpperArm; 104 | 105 | UPROPERTY(BlueprintReadWrite) 106 | FTransform LeftLowerArm; 107 | 108 | UPROPERTY(BlueprintReadWrite) 109 | FTransform RightUpperArm; 110 | 111 | UPROPERTY(BlueprintReadWrite) 112 | FTransform RightLowerArm; 113 | }; 114 | 115 | 116 | USTRUCT(BlueprintType) 117 | struct FTransformSettings 118 | { 119 | GENERATED_USTRUCT_BODY() 120 | 121 | UPROPERTY(BlueprintReadWrite) 122 | bool DrawDebug = true; 123 | 124 | UPROPERTY(BlueprintReadWrite) 125 | float UpperArmsDistance = 30.f; 126 | 127 | UPROPERTY(BlueprintReadWrite) 128 | float DistinctShoulderRotationMultiplier = 60.f; 129 | 130 | UPROPERTY(BlueprintReadWrite) 131 | float DistinctShoulderRotationLimit = 45.f; 132 | 133 | UPROPERTY(BlueprintReadWrite) 134 | float ClavicleOffset = 90.f; 135 | 136 | UPROPERTY(BlueprintReadWrite) 137 | float ElbowBaseOffsetAngle = 30.f; 138 | 139 | UPROPERTY(BlueprintReadWrite) 140 | float ElbowYDistanceStart = 0.2f; 141 | 142 | UPROPERTY(BlueprintReadWrite) 143 | float ElbowYWeight = 130.f; 144 | 145 | UPROPERTY(BlueprintReadWrite) 146 | float ElbowHandRotSpeed = 15.f; 147 | 148 | UPROPERTY(BlueprintReadWrite) 149 | float HeadHandAngleLimit = 50.f; 150 | 151 | UPROPERTY(BlueprintReadWrite) 152 | float HeadHandAngleOkSpan = 80.f; 153 | }; 154 | 155 | 156 | USTRUCT(BlueprintType) 157 | struct FCharacterSettings 158 | { 159 | GENERATED_USTRUCT_BODY() 160 | 161 | UPROPERTY(BlueprintReadWrite) 162 | FTransform CharacterBaseTransform; 163 | 164 | UPROPERTY(BlueprintReadWrite) 165 | float ArmLength = 0.f; 166 | 167 | UPROPERTY(BlueprintReadWrite) 168 | float LowerArmLength = 0.f; 169 | 170 | UPROPERTY(BlueprintReadWrite) 171 | float UpperArmLength = 0.f; 172 | 173 | UPROPERTY(BlueprintReadWrite) 174 | float LeftElbowHandAngle = 0.f; 175 | 176 | UPROPERTY(BlueprintReadWrite) 177 | float RightElbowHandAngle = 0.f; 178 | 179 | UPROPERTY(BlueprintReadWrite) 180 | float LeftHeadHandAngle = 0.f; 181 | 182 | UPROPERTY(BlueprintReadWrite) 183 | float RightHeadHandAngle = 0.f; 184 | 185 | UPROPERTY(BlueprintReadWrite) 186 | float HeadHandAngleLimitDot = 0.f; 187 | }; 188 | 189 | 190 | USTRUCT(BlueprintType) 191 | struct FArmTransforms 192 | { 193 | GENERATED_USTRUCT_BODY() 194 | 195 | UPROPERTY(BlueprintReadWrite) 196 | FTransform UpperArmTransform; 197 | UPROPERTY(BlueprintReadWrite) 198 | FTransform LowerArmTransform; 199 | 200 | FArmTransforms() 201 | { 202 | UpperArmTransform = FTransform(); 203 | LowerArmTransform = FTransform(); 204 | } 205 | 206 | FArmTransforms(FTransform UpperArm, FTransform LowerArm) 207 | { 208 | UpperArmTransform = UpperArm; 209 | LowerArmTransform = LowerArm; 210 | } 211 | }; 212 | 213 | 214 | UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) 215 | class OPENMOTION_API UOpenMotionComponent : public UActorComponent 216 | { 217 | GENERATED_BODY() 218 | 219 | public: 220 | // Sets default values for this component's properties 221 | UOpenMotionComponent(); 222 | 223 | UPROPERTY(BlueprintReadWrite) 224 | FWorldTransforms WorldTransforms; 225 | UPROPERTY(BlueprintReadWrite) 226 | FShoulderTransforms ShoulderTransforms; 227 | UPROPERTY(BlueprintReadWrite) 228 | FComponentTransforms ComponentTransforms; 229 | UPROPERTY(BlueprintReadWrite) 230 | FTransformSettings TransformSettings; 231 | UPROPERTY(BlueprintReadWrite) 232 | FCharacterSettings CharacterSettings; 233 | 234 | protected: 235 | // Called when the game starts 236 | virtual void BeginPlay() override; 237 | 238 | public: 239 | // Called every frame 240 | virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; 241 | 242 | UFUNCTION(BlueprintCallable, Category = "") 243 | void CustomTick(USkeletalMeshComponent* OwnerMesh); 244 | UFUNCTION(BlueprintCallable, Category = "") 245 | void ConvertTransforms(); 246 | UFUNCTION(BlueprintCallable, Category = "") 247 | void SetCharacterTransforms(FTransform LeftHandEffector, FTransform RightHandEffector, FTransform HeadEffector, FTransform ComponentTransform); 248 | UFUNCTION(BlueprintCallable, Category = "") 249 | void SetShoulder(); 250 | UFUNCTION(BlueprintCallable, Category = "") 251 | void SetLeftUpperArm(); 252 | UFUNCTION(BlueprintCallable, Category = "") 253 | void SetRightUpperArm(); 254 | UFUNCTION(BlueprintCallable, Category = "") 255 | void ResetUpperArmsLocation(USkeletalMeshComponent* OwnerMesh); 256 | UFUNCTION(BlueprintCallable, Category = "") 257 | void SolveArms(); 258 | UFUNCTION(BlueprintCallable, Category = "") 259 | void DebugDraw(); 260 | UFUNCTION(BlueprintCallable, Category = "") 261 | void Calibrate(float CharacterHeight); 262 | UFUNCTION(BlueprintCallable, Category = "") 263 | FTransform RotateUpperArm(bool bIsLeftArm, FVector HandLocation); 264 | UFUNCTION(BlueprintCallable, Category = "") 265 | FArmTransforms SetElbowBasePosition(bool bIsLeftArm, FVector UpperArmLocation, FVector HandLocation); 266 | UFUNCTION(BlueprintCallable, Category = "") 267 | float RotateElbowByHandPosition(bool bIsLeftArm, FVector HandLocation); 268 | UFUNCTION(BlueprintCallable, Category = "") 269 | float RotateElbowByHandRotation(FTransform LowerArmLocation, FRotator HandRotation); 270 | 271 | UFUNCTION(BlueprintCallable, Category = "") 272 | float CosineRule(float AdjacentA, float AdjacentB, float Opposite); 273 | UFUNCTION(BlueprintCallable, Category = "") 274 | FArmTransforms RotateElbow(bool bIsLeftArm, float Angle, FArmTransforms UpperAndLowerArms, FVector HandLocation); 275 | UFUNCTION(BlueprintCallable, Category = "") 276 | float SafeguardAngle(float Current, float Last, float Threshold); 277 | UFUNCTION(BlueprintCallable, Category = "") 278 | FTransform RotatePointAroundPivot(FTransform Point, FTransform Pivot, FRotator Delta); 279 | UFUNCTION(BlueprintCallable, Category = "") 280 | FVector GetDebugValues(); 281 | UFUNCTION(BlueprintCallable, Category = "") 282 | float GetHeadHandAngle(float LastAngle, FVector HandLocation, FVector HandHeadDelta); 283 | UFUNCTION(BlueprintCallable, Category = "") 284 | FTransform GetBaseCharTransform(); 285 | UFUNCTION(BlueprintCallable, Category = "") 286 | FRotator GetShoulderRotationFromHead(); 287 | UFUNCTION(BlueprintCallable, Category = "") 288 | FRotator GetShoulderRotationFromHands(); 289 | UFUNCTION(BlueprintCallable, Category = "") 290 | FRotator FindBetweenNormals(FVector A, FVector B); 291 | }; 292 | -------------------------------------------------------------------------------- /Source/OpenMotion/Public/OpenMotionLibrary.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Name 2020 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Kismet/BlueprintFunctionLibrary.h" 7 | #include "OpenMotionLibrary.generated.h" 8 | 9 | /** 10 | * 11 | */ 12 | UCLASS() 13 | class OPENMOTION_API UOpenMotionLibrary : public UBlueprintFunctionLibrary 14 | { 15 | GENERATED_BODY() 16 | 17 | }; 18 | --------------------------------------------------------------------------------