| 2824 | } |
| 2825 | |
| 2826 | static void CDrawLegImpl( |
| 2827 | RiggedObject& rigged_object, |
| 2828 | Skeleton& skeleton, |
| 2829 | CScriptArrayWrapper<int>& ik_chain_start_index, |
| 2830 | CScriptArrayWrapper<int>& ik_chain_elements, |
| 2831 | CScriptArrayWrapper<float>& ik_chain_bone_lengths, |
| 2832 | CScriptArrayWrapper<BoneTransform>& skeleton_bind_transforms, |
| 2833 | CScriptArrayWrapper<BoneTransform>& inv_skeleton_bind_transforms, |
| 2834 | bool right, const BoneTransform& hip_transform, const BoneTransform& foot_transform) { |
| 2835 | int ik_chain_start = ik_chain_start_index[kLeftLegIK + (right ? 1 : 0)]; |
| 2836 | |
| 2837 | // Get important joint positions |
| 2838 | vec3 foot_tip, foot_base, ankle, knee, hip; |
| 2839 | foot_tip = GetTransformedBonePoint(&rigged_object, ik_chain_elements[ik_chain_start + 0], 1); |
| 2840 | foot_base = GetTransformedBonePoint(&rigged_object, ik_chain_elements[ik_chain_start + 0], 0); |
| 2841 | ankle = GetTransformedBonePoint(&rigged_object, ik_chain_elements[ik_chain_start + 1], 0); |
| 2842 | knee = GetTransformedBonePoint(&rigged_object, ik_chain_elements[ik_chain_start + 3], 0); |
| 2843 | hip = GetTransformedBonePoint(&rigged_object, ik_chain_elements[ik_chain_start + 5], 0); |
| 2844 | |
| 2845 | vec3 old_foot_dir = foot_tip - foot_base; |
| 2846 | float upper_foot_length = ik_chain_bone_lengths[ik_chain_start + 1]; |
| 2847 | float lower_leg_length = (ik_chain_bone_lengths[ik_chain_start + 2] + ik_chain_bone_lengths[ik_chain_start + 3]); |
| 2848 | float upper_leg_length = (ik_chain_bone_lengths[ik_chain_start + 4] + ik_chain_bone_lengths[ik_chain_start + 5]); |
| 2849 | |
| 2850 | float lower_leg_weight = ik_chain_bone_lengths[ik_chain_start + 2] / lower_leg_length; |
| 2851 | float upper_leg_weight = ik_chain_bone_lengths[ik_chain_start + 4] / upper_leg_length; |
| 2852 | |
| 2853 | vec3 old_hip = hip; |
| 2854 | float old_length = distance(foot_base, old_hip); |
| 2855 | |
| 2856 | // New hip position based on key hip transform |
| 2857 | hip = hip_transform * skeleton.points[skeleton.bones[ik_chain_elements[ik_chain_start + 5]].points[0]]; |
| 2858 | |
| 2859 | // New foot_base position based on key foot transform |
| 2860 | vec3 ik_target = foot_transform * skeleton.points[skeleton.bones[ik_chain_elements[ik_chain_start + 0]].points[0]]; |
| 2861 | |
| 2862 | quaternion rotate; |
| 2863 | GetRotationBetweenVectors(foot_base - old_hip, ik_target - hip, rotate); |
| 2864 | mat3 rotate_mat = Mat3FromQuaternion(rotate); |
| 2865 | knee = rotate_mat * (knee - old_hip) + hip; |
| 2866 | ankle = rotate_mat * (ankle - old_hip) + hip; |
| 2867 | foot_base = rotate_mat * (foot_base - old_hip) + hip; |
| 2868 | float new_length = distance(ik_target, hip); |
| 2869 | float weight = new_length / old_length; |
| 2870 | knee = mix(hip, knee, weight); |
| 2871 | ankle = mix(hip, ankle, weight); |
| 2872 | foot_base = mix(hip, foot_base, weight); |
| 2873 | foot_tip = foot_transform * skeleton.points[skeleton.bones[ik_chain_elements[ik_chain_start + 0]].points[1]]; |
| 2874 | |
| 2875 | int num_iterations = 2; |
| 2876 | |
| 2877 | for (int i = 0; i < num_iterations; ++i) { |
| 2878 | knee = hip + normalize(knee - hip) * upper_leg_length; |
| 2879 | ankle = foot_base + normalize(ankle - foot_base) * upper_foot_length; |
| 2880 | vec3 knee_ankle_vec = normalize(knee - ankle); |
| 2881 | vec3 mid = (knee + ankle) * 0.5f; |
| 2882 | ankle = mid - knee_ankle_vec * 0.5f * lower_leg_length; |
| 2883 | knee = mid + knee_ankle_vec * 0.5f * lower_leg_length; |
no test coverage detected