| 5702 | } |
| 5703 | |
| 5704 | void GLTFDocument::_parse_animation_pointer(Ref<GLTFState> p_state, const String &p_animation_json_pointer, const Ref<GLTFAnimation> p_gltf_animation, const GLTFAnimation::Interpolation p_interp, const Vector<double> &p_times, const int p_output_value_accessor_index) { |
| 5705 | // Special case: Convert TRS animation pointers to node track pos/rot/scale. |
| 5706 | // This is required to handle skeleton bones, and improves performance for regular nodes. |
| 5707 | // Mark this as unlikely because TRS animation pointers are not recommended, |
| 5708 | // since vanilla glTF animations can already animate TRS properties directly. |
| 5709 | // But having this code exist is required to be spec-compliant and handle all test files. |
| 5710 | // Note that TRS still needs to be handled in the general case as well, for KHR_interactivity. |
| 5711 | const PackedStringArray split = p_animation_json_pointer.split("/", false, 3); |
| 5712 | if (unlikely(split.size() == 3 && split[0] == "nodes" && (split[2] == "translation" || split[2] == "rotation" || split[2] == "scale" || split[2] == "matrix" || split[2] == "weights"))) { |
| 5713 | const GLTFNodeIndex node_index = split[1].to_int(); |
| 5714 | HashMap<int, GLTFAnimation::NodeTrack> &node_tracks = p_gltf_animation->get_node_tracks(); |
| 5715 | if (!node_tracks.has(node_index)) { |
| 5716 | node_tracks[node_index] = GLTFAnimation::NodeTrack(); |
| 5717 | } |
| 5718 | GLTFAnimation::NodeTrack *track = &node_tracks[node_index]; |
| 5719 | if (split[2] == "translation") { |
| 5720 | const Vector<Vector3> positions = _decode_accessor_as_vec3(p_state, p_output_value_accessor_index, false); |
| 5721 | track->position_track.interpolation = p_interp; |
| 5722 | track->position_track.times = p_times; |
| 5723 | track->position_track.values = positions; |
| 5724 | } else if (split[2] == "rotation") { |
| 5725 | const Vector<Quaternion> rotations = _decode_accessor_as_quaternion(p_state, p_output_value_accessor_index, false); |
| 5726 | track->rotation_track.interpolation = p_interp; |
| 5727 | track->rotation_track.times = p_times; |
| 5728 | track->rotation_track.values = rotations; |
| 5729 | } else if (split[2] == "scale") { |
| 5730 | const Vector<Vector3> scales = _decode_accessor_as_vec3(p_state, p_output_value_accessor_index, false); |
| 5731 | track->scale_track.interpolation = p_interp; |
| 5732 | track->scale_track.times = p_times; |
| 5733 | track->scale_track.values = scales; |
| 5734 | } else if (split[2] == "matrix") { |
| 5735 | const Vector<Transform3D> transforms = _decode_accessor_as_xform(p_state, p_output_value_accessor_index, false); |
| 5736 | track->position_track.interpolation = p_interp; |
| 5737 | track->position_track.times = p_times; |
| 5738 | track->position_track.values.resize(transforms.size()); |
| 5739 | track->rotation_track.interpolation = p_interp; |
| 5740 | track->rotation_track.times = p_times; |
| 5741 | track->rotation_track.values.resize(transforms.size()); |
| 5742 | track->scale_track.interpolation = p_interp; |
| 5743 | track->scale_track.times = p_times; |
| 5744 | track->scale_track.values.resize(transforms.size()); |
| 5745 | for (int i = 0; i < transforms.size(); i++) { |
| 5746 | track->position_track.values.write[i] = transforms[i].get_origin(); |
| 5747 | track->rotation_track.values.write[i] = transforms[i].basis.get_rotation_quaternion(); |
| 5748 | track->scale_track.values.write[i] = transforms[i].basis.get_scale(); |
| 5749 | } |
| 5750 | } else { // if (split[2] == "weights") |
| 5751 | const Vector<float> accessor_weights = _decode_accessor_as_floats(p_state, p_output_value_accessor_index, false); |
| 5752 | const GLTFMeshIndex mesh_index = p_state->nodes[node_index]->mesh; |
| 5753 | ERR_FAIL_INDEX(mesh_index, p_state->meshes.size()); |
| 5754 | const Ref<GLTFMesh> gltf_mesh = p_state->meshes[mesh_index]; |
| 5755 | const Vector<float> &blend_weights = gltf_mesh->get_blend_weights(); |
| 5756 | const int blend_weight_count = gltf_mesh->get_blend_weights().size(); |
| 5757 | const int anim_weights_size = accessor_weights.size(); |
| 5758 | // For example, if a mesh has 2 blend weights, and the accessor provides 10 values, then there are 5 frames of animation, each with 2 blend weights. |
| 5759 | ERR_FAIL_COND_MSG(blend_weight_count == 0 || ((anim_weights_size % blend_weight_count) != 0), "glTF: Cannot apply " + itos(accessor_weights.size()) + " weights to a mesh with " + itos(blend_weights.size()) + " blend weights."); |
| 5760 | const int frame_count = anim_weights_size / blend_weight_count; |
| 5761 | track->weight_tracks.resize(blend_weight_count); |
nothing calls this directly
no test coverage detected