diff options
Diffstat (limited to 'modules')
20 files changed, 315 insertions, 126 deletions
diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp index 7343bf87af..e1eacc68b3 100644 --- a/modules/fbx/data/fbx_mesh_data.cpp +++ b/modules/fbx/data/fbx_mesh_data.cpp @@ -357,7 +357,6 @@ ImporterMeshInstance3D *FBXMeshData::create_fbx_mesh(const ImportState &state, c mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED); // Add surfaces. - int in_mesh_surface_id = 0; for (const SurfaceId *surface_id = surfaces.next(nullptr); surface_id != nullptr; surface_id = surfaces.next(surface_id)) { SurfaceData *surface = surfaces.getptr(*surface_id); @@ -377,8 +376,6 @@ ImporterMeshInstance3D *FBXMeshData::create_fbx_mesh(const ImportState &state, c } else { mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, mesh_array, blend_shapes); } - - in_mesh_surface_id += 1; } ImporterMeshInstance3D *godot_mesh = memnew(ImporterMeshInstance3D); diff --git a/modules/fbx/data/fbx_skeleton.cpp b/modules/fbx/data/fbx_skeleton.cpp index 3dc163964c..11eed2576f 100644 --- a/modules/fbx/data/fbx_skeleton.cpp +++ b/modules/fbx/data/fbx_skeleton.cpp @@ -104,6 +104,13 @@ void FBXSkeleton::init_skeleton(const ImportState &state) { print_verbose("working on bone: " + itos(bone_index) + " bone name:" + bone->bone_name); skeleton->set_bone_rest(bone->godot_bone_id, get_unscaled_transform(bone->node->pivot_transform->LocalTransform, state.scale)); + { + Transform3D base_xform = bone->node->pivot_transform->LocalTransform; + + skeleton->set_bone_pose_position(bone_index, base_xform.origin); + skeleton->set_bone_pose_rotation(bone_index, base_xform.basis.get_rotation_quaternion()); + skeleton->set_bone_pose_scale(bone_index, base_xform.basis.get_scale()); + } // lookup parent ID if (bone->valid_parent && state.fbx_bone_map.has(bone->parent_bone_id)) { diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp index e4de204cf1..879f281292 100644 --- a/modules/fbx/editor_scene_importer_fbx.cpp +++ b/modules/fbx/editor_scene_importer_fbx.cpp @@ -1011,9 +1011,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( // track count is 5. // next track id is 5. const uint64_t target_id = track.key; - int track_idx = animation->add_track(Animation::TYPE_TRANSFORM3D); - // animation->track_set_path(track_idx, node_path); Ref<FBXBone> bone; // note we must not run the below code if the entry doesn't exist, it will create dummy entries which is very bad. @@ -1037,22 +1035,21 @@ Node3D *EditorSceneImporterFBX::_generate_scene( // if this is a skeleton mapped track we can just set the path for the track. // todo: implement node paths here at some + NodePath track_path; if (state.fbx_bone_map.size() > 0 && state.fbx_bone_map.has(target_id)) { if (bone->fbx_skeleton.is_valid() && bone.is_valid()) { Ref<FBXSkeleton> fbx_skeleton = bone->fbx_skeleton; String bone_path = state.root->get_path_to(fbx_skeleton->skeleton); bone_path += ":" + fbx_skeleton->skeleton->get_bone_name(bone->godot_bone_id); print_verbose("[doc] track bone path: " + bone_path); - NodePath path = bone_path; - animation->track_set_path(track_idx, path); + track_path = bone_path; } } else if (state.fbx_target_map.has(target_id)) { //print_verbose("[doc] we have a valid target for a node animation"); Ref<FBXNode> target_node = state.fbx_target_map[target_id]; if (target_node.is_valid() && target_node->godot_node != nullptr) { String node_path = state.root->get_path_to(target_node->godot_node); - NodePath path = node_path; - animation->track_set_path(track_idx, path); + track_path = node_path; //print_verbose("[doc] node animation path: " + node_path); } } else { @@ -1186,6 +1183,30 @@ Node3D *EditorSceneImporterFBX::_generate_scene( const Vector3 def_scale = scale_keys.has_default ? scale_keys.default_value : bone_rest.basis.get_scale(); print_verbose("track defaults: p(" + def_pos + ") s(" + def_scale + ") r(" + def_rot + ")"); + int position_idx = -1; + if (pos_values.size()) { + position_idx = animation->get_track_count(); + animation->add_track(Animation::TYPE_POSITION_3D); + animation->track_set_path(position_idx, track_path); + animation->track_set_imported(position_idx, true); + } + + int rotation_idx = -1; + if (pos_values.size()) { + rotation_idx = animation->get_track_count(); + animation->add_track(Animation::TYPE_ROTATION_3D); + animation->track_set_path(rotation_idx, track_path); + animation->track_set_imported(rotation_idx, true); + } + + int scale_idx = -1; + if (pos_values.size()) { + scale_idx = animation->get_track_count(); + animation->add_track(Animation::TYPE_SCALE_3D); + animation->track_set_path(scale_idx, track_path); + animation->track_set_imported(scale_idx, true); + } + while (true) { Vector3 pos = def_pos; Quaternion rot = def_rot; @@ -1206,21 +1227,15 @@ Node3D *EditorSceneImporterFBX::_generate_scene( AssetImportAnimation::INTERP_LINEAR); } - // node animations must also include pivots - if (skeleton_bone >= 0) { - Transform3D xform = Transform3D(); - xform.basis.set_quaternion_scale(rot, scale); - xform.origin = pos; - const Transform3D t = bone_rest.affine_inverse() * xform; - - // populate this again - rot = t.basis.get_rotation_quaternion(); - rot.normalize(); - scale = t.basis.get_scale(); - pos = t.origin; + if (position_idx >= 0) { + animation->position_track_insert_key(position_idx, time, pos); + } + if (rotation_idx >= 0) { + animation->rotation_track_insert_key(rotation_idx, time, rot); + } + if (scale_idx >= 0) { + animation->scale_track_insert_key(scale_idx, time, scale); } - - animation->transform_track_insert_key(track_idx, time, pos, rot, scale); if (last) { break; diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 8bd288cf0f..47f81b455f 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -1069,7 +1069,7 @@ void GDScriptAnalyzer::resolve_node(GDScriptParser::Node *p_node) { case GDScriptParser::Node::SUBSCRIPT: case GDScriptParser::Node::TERNARY_OPERATOR: case GDScriptParser::Node::UNARY_OPERATOR: - reduce_expression(static_cast<GDScriptParser::ExpressionNode *>(p_node)); + reduce_expression(static_cast<GDScriptParser::ExpressionNode *>(p_node), true); break; case GDScriptParser::Node::BREAK: case GDScriptParser::Node::BREAKPOINT: @@ -1658,7 +1658,7 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) { p_return->set_datatype(result); } -void GDScriptAnalyzer::reduce_expression(GDScriptParser::ExpressionNode *p_expression) { +void GDScriptAnalyzer::reduce_expression(GDScriptParser::ExpressionNode *p_expression, bool p_is_root) { // This one makes some magic happen. if (p_expression == nullptr) { @@ -1686,7 +1686,7 @@ void GDScriptAnalyzer::reduce_expression(GDScriptParser::ExpressionNode *p_expre reduce_binary_op(static_cast<GDScriptParser::BinaryOpNode *>(p_expression)); break; case GDScriptParser::Node::CALL: - reduce_call(static_cast<GDScriptParser::CallNode *>(p_expression)); + reduce_call(static_cast<GDScriptParser::CallNode *>(p_expression), p_is_root); break; case GDScriptParser::Node::CAST: reduce_cast(static_cast<GDScriptParser::CastNode *>(p_expression)); @@ -1927,16 +1927,25 @@ void GDScriptAnalyzer::reduce_await(GDScriptParser::AwaitNode *p_await) { p_await->set_datatype(await_type); return; } + + GDScriptParser::DataType awaiting_type; + if (p_await->to_await->type == GDScriptParser::Node::CALL) { reduce_call(static_cast<GDScriptParser::CallNode *>(p_await->to_await), true); + awaiting_type = p_await->to_await->get_datatype(); } else { reduce_expression(p_await->to_await); } - p_await->is_constant = p_await->to_await->is_constant; - p_await->reduced_value = p_await->to_await->reduced_value; + if (p_await->to_await->is_constant) { + p_await->is_constant = p_await->to_await->is_constant; + p_await->reduced_value = p_await->to_await->reduced_value; - GDScriptParser::DataType awaiting_type = p_await->to_await->get_datatype(); + awaiting_type = p_await->to_await->get_datatype(); + } else { + awaiting_type.kind = GDScriptParser::DataType::VARIANT; + awaiting_type.type_source = GDScriptParser::DataType::UNDETECTED; + } p_await->set_datatype(awaiting_type); @@ -2056,7 +2065,7 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o p_binary_op->set_datatype(result); } -void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_await) { +void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_await, bool p_is_root) { bool all_is_constant = true; Map<int, GDScriptParser::ArrayNode *> arrays; // For array literal to potentially type when passing. for (int i = 0; i < p_call->arguments.size(); i++) { @@ -2415,7 +2424,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa } } - if (call_type.is_coroutine && !is_await) { + if (call_type.is_coroutine && !p_is_await && !p_is_root) { push_error(vformat(R"*(Function "%s()" is a coroutine, so it must be called with "await".)*", p_call->function_name), p_call->callee); } @@ -2683,6 +2692,11 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod p_identifier->is_constant = false; return; } break; + case GDScriptParser::ClassNode::Member::CLASS: { + resolve_class_interface(member.m_class); + p_identifier->set_datatype(member.m_class->get_datatype()); + return; + } break; default: break; } diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h index 2e17e15452..ce4525190b 100644 --- a/modules/gdscript/gdscript_analyzer.h +++ b/modules/gdscript/gdscript_analyzer.h @@ -78,12 +78,12 @@ class GDScriptAnalyzer { void resolve_return(GDScriptParser::ReturnNode *p_return); // Reduction functions. - void reduce_expression(GDScriptParser::ExpressionNode *p_expression); + void reduce_expression(GDScriptParser::ExpressionNode *p_expression, bool p_is_root = false); void reduce_array(GDScriptParser::ArrayNode *p_array); void reduce_assignment(GDScriptParser::AssignmentNode *p_assignment); void reduce_await(GDScriptParser::AwaitNode *p_await); void reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_op); - void reduce_call(GDScriptParser::CallNode *p_call, bool is_await = false); + void reduce_call(GDScriptParser::CallNode *p_call, bool p_is_await = false, bool p_is_root = false); void reduce_cast(GDScriptParser::CastNode *p_cast); void reduce_dictionary(GDScriptParser::DictionaryNode *p_dictionary); void reduce_get_node(GDScriptParser::GetNodeNode *p_get_node); diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 1f9aad40af..ab0fe5c37d 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -488,6 +488,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_expression); GDScriptDataType type = _gdtype_from_datatype(call->get_datatype()); GDScriptCodeGenerator::Address result = codegen.add_temporary(type); + GDScriptCodeGenerator::Address nil = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::NIL); + + GDScriptCodeGenerator::Address return_addr = p_root ? nil : result; Vector<GDScriptCodeGenerator::Address> arguments; for (int i = 0; i < call->arguments.size(); i++) { @@ -538,13 +541,13 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code if (within_await) { gen->write_call_async(result, self, call->function_name, arguments); } else { - gen->write_call(result, self, call->function_name, arguments); + gen->write_call(return_addr, self, call->function_name, arguments); } } else { if (within_await) { gen->write_call_self_async(result, call->function_name, arguments); } else { - gen->write_call_self(result, call->function_name, arguments); + gen->write_call_self(return_addr, call->function_name, arguments); } } } else if (callee->type == GDScriptParser::Node::SUBSCRIPT) { @@ -579,12 +582,12 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code gen->write_call_method_bind(result, base, method, arguments); } } else { - gen->write_call(result, base, call->function_name, arguments); + gen->write_call(return_addr, base, call->function_name, arguments); } } else if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) { gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments); } else { - gen->write_call(result, base, call->function_name, arguments); + gen->write_call(return_addr, base, call->function_name, arguments); } if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) { gen->pop_temporary(); diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 1bc7ae086f..7018c339d7 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -2098,8 +2098,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } if (result.get_type() != Variant::SIGNAL) { + // Not async, return immediately using the target from OPCODE_AWAIT_RESUME. + GET_VARIANT_PTR(target, 3); + *target = result; ip += 4; // Skip OPCODE_AWAIT_RESUME and its data. - // The stack pointer should be the same, so we don't need to set a return value. is_signal = false; } else { sig = result; diff --git a/modules/gdscript/tests/scripts/analyzer/features/class_from_parent.gd b/modules/gdscript/tests/scripts/analyzer/features/class_from_parent.gd new file mode 100644 index 0000000000..30e7deb05a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/class_from_parent.gd @@ -0,0 +1,19 @@ +class A: + var x = 3 + +class B: + var x = 4 + +class C: + var x = 5 + +class Test: + var a = A.new() + var b: B = B.new() + var c := C.new() + +func test(): + var test_instance := Test.new() + prints(test_instance.a.x) + prints(test_instance.b.x) + prints(test_instance.c.x) diff --git a/modules/gdscript/tests/scripts/analyzer/features/class_from_parent.out b/modules/gdscript/tests/scripts/analyzer/features/class_from_parent.out new file mode 100644 index 0000000000..a078e62cc7 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/class_from_parent.out @@ -0,0 +1,4 @@ +GDTEST_OK +3 +4 +5 diff --git a/modules/gdscript/tests/scripts/runtime/features/arrays_arent_shared.gd b/modules/gdscript/tests/scripts/runtime/features/arrays_arent_shared.gd new file mode 100644 index 0000000000..18174eae67 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/arrays_arent_shared.gd @@ -0,0 +1,32 @@ +# https://github.com/godotengine/godot/issues/48121 + +func test(): + var x := [] + var y := [] + x.push_back(y) + print("TEST ARRAY ADD TO SELF: " + str(len(y))) + x.clear() + + x = Array() + y = Array() + x.push_back(y) + print("TEST ARRAY ADD TO SELF: " + str(len(y))) + x.clear() + + x = Array().duplicate() + y = Array().duplicate() + x.push_back(y) + print("TEST ARRAY ADD TO SELF: " + str(len(y))) + x.clear() + + x = [].duplicate() + y = [].duplicate() + x.push_back(y) + print("TEST ARRAY ADD TO SELF: " + str(len(y))) + x.clear() + + x = Array() + y = Array() + x.push_back(y) + print("TEST ARRAY ADD TO SELF: " + str(len(y))) + x.clear() diff --git a/modules/gdscript/tests/scripts/runtime/features/arrays_arent_shared.out b/modules/gdscript/tests/scripts/runtime/features/arrays_arent_shared.out new file mode 100644 index 0000000000..f6b7d3cc39 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/arrays_arent_shared.out @@ -0,0 +1,6 @@ +GDTEST_OK +TEST ARRAY ADD TO SELF: 0 +TEST ARRAY ADD TO SELF: 0 +TEST ARRAY ADD TO SELF: 0 +TEST ARRAY ADD TO SELF: 0 +TEST ARRAY ADD TO SELF: 0 diff --git a/modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.gd b/modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.gd new file mode 100644 index 0000000000..9da61ab184 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.gd @@ -0,0 +1,8 @@ +# https://github.com/godotengine/godot/issues/50894 + +func test(): + print(await not_coroutine()) + + +func not_coroutine(): + return "awaited" diff --git a/modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.out b/modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.out new file mode 100644 index 0000000000..c2ac488e9b --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.out @@ -0,0 +1,6 @@ +GDTEST_OK +>> WARNING +>> Line: 4 +>> REDUNDANT_AWAIT +>> "await" keyword not needed in this case, because the expression isn't a coroutine nor a signal. +awaited diff --git a/modules/gdscript/tests/scripts/runtime/features/dictionaries_arent_shared.gd b/modules/gdscript/tests/scripts/runtime/features/dictionaries_arent_shared.gd new file mode 100644 index 0000000000..d5a5f8de64 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/dictionaries_arent_shared.gd @@ -0,0 +1,19 @@ +# https://github.com/godotengine/godot/issues/48121 + +func test(): + var x := Dictionary() + var y := Dictionary() + y[0]=1 + y[1]=1 + y[2]=1 + print("TEST OTHER DICTIONARY: " + str(len(x))) + x.clear() + + x = Dictionary().duplicate() + y = Dictionary().duplicate() + y[0]=1 + y[1]=1 + y[2]=1 + print("TEST OTHER DICTIONARY: " + str(len(x))) + x.clear() + return diff --git a/modules/gdscript/tests/scripts/runtime/features/dictionaries_arent_shared.out b/modules/gdscript/tests/scripts/runtime/features/dictionaries_arent_shared.out new file mode 100644 index 0000000000..0bf49f5934 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/dictionaries_arent_shared.out @@ -0,0 +1,3 @@ +GDTEST_OK +TEST OTHER DICTIONARY: 0 +TEST OTHER DICTIONARY: 0 diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index ba98592600..11f30be5a4 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -4319,6 +4319,9 @@ Error GLTFDocument::_create_skeletons(Ref<GLTFState> state) { skeleton->add_bone(node->get_name()); skeleton->set_bone_rest(bone_index, node->xform); + skeleton->set_bone_pose_position(bone_index, node->position); + skeleton->set_bone_pose_rotation(bone_index, node->rotation.normalized()); + skeleton->set_bone_pose_scale(bone_index, node->scale); if (node->parent >= 0 && state->nodes[node->parent]->skeleton == skel_i) { const int bone_parent = skeleton->find_bone(state->nodes[node->parent]->get_name()); @@ -5470,7 +5473,7 @@ void GLTFDocument::_convert_skeleton_to_gltf(Skeleton3D *p_skeleton3d, Ref<GLTFS // Note that we cannot use _gen_unique_bone_name here, because glTF spec requires all node // names to be unique regardless of whether or not they are used as joints. joint_node->set_name(_gen_unique_name(state, skeleton->get_bone_name(bone_i))); - Transform3D xform = skeleton->get_bone_rest(bone_i) * skeleton->get_bone_pose(bone_i); + Transform3D xform = skeleton->get_bone_pose(bone_i); joint_node->scale = xform.basis.get_scale(); joint_node->rotation = xform.basis.get_rotation_quaternion(); joint_node->position = xform.origin; @@ -5733,7 +5736,7 @@ struct EditorSceneImporterGLTFInterpolate<Quaternion> { template <class T> T GLTFDocument::_interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, const float p_time, const GLTFAnimation::Interpolation p_interp) { ERR_FAIL_COND_V(!p_values.size(), T()); - if (p_times.size() != p_values.size()) { + if (p_times.size() != (p_values.size() / (p_interp == GLTFAnimation::INTERP_CUBIC_SPLINE ? 3 : 1))) { ERR_PRINT_ONCE("The interpolated values are not corresponding to its times."); return p_values[0]; } @@ -5868,9 +5871,67 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, const bool transform_affects_skinned_mesh_instance = gltf_node->skeleton < 0 && gltf_node->skin >= 0; if ((track.rotation_track.values.size() || track.position_track.values.size() || track.scale_track.values.size()) && !transform_affects_skinned_mesh_instance) { //make transform track - int track_idx = animation->get_track_count(); - animation->add_track(Animation::TYPE_TRANSFORM3D); - animation->track_set_path(track_idx, transform_node_path); + int base_idx = animation->get_track_count(); + int position_idx = -1; + int rotation_idx = -1; + int scale_idx = -1; + + if (track.position_track.values.size()) { + Vector3 base_pos = state->nodes[track_i.key]->position; + bool not_default = false; //discard the track if all it contains is default values + for (int i = 0; i < track.position_track.times.size(); i++) { + Vector3 value = track.position_track.values[track.position_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i]; + if (!value.is_equal_approx(base_pos)) { + not_default = true; + break; + } + } + if (not_default) { + position_idx = base_idx; + animation->add_track(Animation::TYPE_POSITION_3D); + animation->track_set_path(position_idx, transform_node_path); + animation->track_set_imported(position_idx, true); //helps merging later + + base_idx++; + } + } + if (track.rotation_track.values.size()) { + Quaternion base_rot = state->nodes[track_i.key]->rotation.normalized(); + bool not_default = false; //discard the track if all it contains is default values + for (int i = 0; i < track.rotation_track.times.size(); i++) { + Quaternion value = track.rotation_track.values[track.rotation_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i].normalized(); + if (!value.is_equal_approx(base_rot)) { + not_default = true; + break; + } + } + if (not_default) { + rotation_idx = base_idx; + animation->add_track(Animation::TYPE_ROTATION_3D); + animation->track_set_path(rotation_idx, transform_node_path); + animation->track_set_imported(rotation_idx, true); //helps merging later + base_idx++; + } + } + if (track.scale_track.values.size()) { + Vector3 base_scale = state->nodes[track_i.key]->scale; + bool not_default = false; //discard the track if all it contains is default values + for (int i = 0; i < track.scale_track.times.size(); i++) { + Vector3 value = track.scale_track.values[track.scale_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i]; + if (!value.is_equal_approx(base_scale)) { + not_default = true; + break; + } + } + if (not_default) { + scale_idx = base_idx; + animation->add_track(Animation::TYPE_SCALE_3D); + animation->track_set_path(scale_idx, transform_node_path); + animation->track_set_imported(scale_idx, true); //helps merging later + base_idx++; + } + } + //first determine animation length const double increment = 1.0 / bake_fps; @@ -5880,15 +5941,15 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, Quaternion base_rot; Vector3 base_scale = Vector3(1, 1, 1); - if (!track.rotation_track.values.size()) { + if (rotation_idx == -1) { base_rot = state->nodes[track_i.key]->rotation.normalized(); } - if (!track.position_track.values.size()) { + if (position_idx == -1) { base_pos = state->nodes[track_i.key]->position; } - if (!track.scale_track.values.size()) { + if (scale_idx == -1) { base_scale = state->nodes[track_i.key]->scale; } @@ -5898,35 +5959,21 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, Quaternion rot = base_rot; Vector3 scale = base_scale; - if (track.position_track.times.size()) { + if (position_idx >= 0) { pos = _interpolate_track<Vector3>(track.position_track.times, track.position_track.values, time, track.position_track.interpolation); + animation->position_track_insert_key(position_idx, time, pos); } - if (track.rotation_track.times.size()) { + if (rotation_idx >= 0) { rot = _interpolate_track<Quaternion>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation); + animation->rotation_track_insert_key(rotation_idx, time, rot); } - if (track.scale_track.times.size()) { + if (scale_idx >= 0) { scale = _interpolate_track<Vector3>(track.scale_track.times, track.scale_track.values, time, track.scale_track.interpolation); + animation->scale_track_insert_key(scale_idx, time, scale); } - if (gltf_node->skeleton >= 0) { - Transform3D xform; - xform.basis.set_quaternion_scale(rot, scale); - xform.origin = pos; - - const Skeleton3D *skeleton = state->skeletons[gltf_node->skeleton]->godot_skeleton; - const int bone_idx = skeleton->find_bone(gltf_node->get_name()); - xform = skeleton->get_bone_rest(bone_idx).affine_inverse() * xform; - - rot = xform.basis.get_rotation_quaternion(); - rot.normalize(); - scale = xform.basis.get_scale(); - pos = xform.origin; - } - - animation->transform_track_insert_key(track_idx, time, pos, rot, scale); - if (last) { break; } @@ -6042,7 +6089,7 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { } else { if (skin.is_null()) { // Note that gltf_skin_key should remain null, so these can share a reference. - skin = skeleton->register_skin(nullptr)->get_skin(); + skin = skeleton->create_skin_from_rest_transforms(); } gltf_skin.instantiate(); gltf_skin->godot_skin = skin; @@ -6145,7 +6192,7 @@ void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_roo } } -GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state, GLTFAnimation::Track p_track, Ref<Animation> p_animation, Transform3D p_bone_rest, int32_t p_track_i, GLTFNodeIndex p_node_i) { +GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state, GLTFAnimation::Track p_track, Ref<Animation> p_animation, int32_t p_track_i, GLTFNodeIndex p_node_i) { Animation::InterpolationType interpolation = p_animation->track_get_interpolation_type(p_track_i); GLTFAnimation::Interpolation gltf_interpolation = GLTFAnimation::INTERP_LINEAR; @@ -6164,33 +6211,35 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state for (int32_t key_i = 0; key_i < key_count; key_i++) { times.write[key_i] = p_animation->track_get_key_time(p_track_i, key_i); } - if (track_type == Animation::TYPE_TRANSFORM3D) { - p_track.position_track.times = times; - p_track.position_track.interpolation = gltf_interpolation; - p_track.rotation_track.times = times; - p_track.rotation_track.interpolation = gltf_interpolation; + if (track_type == Animation::TYPE_SCALE_3D) { p_track.scale_track.times = times; p_track.scale_track.interpolation = gltf_interpolation; - p_track.scale_track.values.resize(key_count); - p_track.scale_track.interpolation = gltf_interpolation; + for (int32_t key_i = 0; key_i < key_count; key_i++) { + Vector3 scale; + Error err = p_animation->scale_track_get_key(p_track_i, key_i, &scale); + ERR_CONTINUE(err != OK); + p_track.scale_track.values.write[key_i] = scale; + } + } else if (track_type == Animation::TYPE_POSITION_3D) { + p_track.position_track.times = times; p_track.position_track.values.resize(key_count); p_track.position_track.interpolation = gltf_interpolation; - p_track.rotation_track.values.resize(key_count); - p_track.rotation_track.interpolation = gltf_interpolation; for (int32_t key_i = 0; key_i < key_count; key_i++) { Vector3 position; + Error err = p_animation->position_track_get_key(p_track_i, key_i, &position); + ERR_CONTINUE(err != OK); + p_track.position_track.values.write[key_i] = position; + } + } else if (track_type == Animation::TYPE_ROTATION_3D) { + p_track.rotation_track.times = times; + p_track.rotation_track.interpolation = gltf_interpolation; + p_track.rotation_track.values.resize(key_count); + for (int32_t key_i = 0; key_i < key_count; key_i++) { Quaternion rotation; - Vector3 scale; - Error err = p_animation->transform_track_get_key(p_track_i, key_i, &position, &rotation, &scale); + Error err = p_animation->rotation_track_get_key(p_track_i, key_i, &rotation); ERR_CONTINUE(err != OK); - Transform3D xform; - xform.basis.set_quaternion_scale(rotation, scale); - xform.origin = position; - xform = p_bone_rest * xform; - p_track.position_track.values.write[key_i] = xform.get_origin(); - p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quaternion(); - p_track.scale_track.values.write[key_i] = xform.basis.get_scale(); + p_track.rotation_track.values.write[key_i] = rotation; } } else if (path.find(":transform") != -1) { p_track.position_track.times = times; @@ -6282,13 +6331,10 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state Vector3 bezier_track = p_track.scale_track.values[key_i]; if (path.find("/scale:x") != -1) { bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); - bezier_track.x = p_bone_rest.affine_inverse().basis.get_scale().x * bezier_track.x; } else if (path.find("/scale:y") != -1) { bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); - bezier_track.y = p_bone_rest.affine_inverse().basis.get_scale().y * bezier_track.y; } else if (path.find("/scale:z") != -1) { bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); - bezier_track.z = p_bone_rest.affine_inverse().basis.get_scale().z * bezier_track.z; } p_track.scale_track.values.write[key_i] = bezier_track; } @@ -6311,19 +6357,15 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state Vector3 bezier_track = p_track.position_track.values[key_i]; if (path.find("/position:x") != -1) { bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); - bezier_track.x = p_bone_rest.affine_inverse().origin.x * bezier_track.x; } else if (path.find("/position:y") != -1) { bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); - bezier_track.y = p_bone_rest.affine_inverse().origin.y * bezier_track.y; } else if (path.find("/position:z") != -1) { bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); - bezier_track.z = p_bone_rest.affine_inverse().origin.z * bezier_track.z; } p_track.position_track.values.write[key_i] = bezier_track; } } } - return p_track; } @@ -6350,7 +6392,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (position_track_i) { track = position_track_i->get(); } - track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index); + track = _convert_animation_track(state, track, animation, track_i, node_index); gltf_animation->get_tracks().insert(node_index, track); } } @@ -6366,7 +6408,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (rotation_degree_track_i) { track = rotation_degree_track_i->get(); } - track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index); + track = _convert_animation_track(state, track, animation, track_i, node_index); gltf_animation->get_tracks().insert(node_index, track); } } @@ -6382,7 +6424,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (scale_track_i) { track = scale_track_i->get(); } - track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index); + track = _convert_animation_track(state, track, animation, track_i, node_index); gltf_animation->get_tracks().insert(node_index, track); } } @@ -6393,7 +6435,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, for (const KeyValue<GLTFNodeIndex, Node *> &transform_track_i : state->scene_nodes) { if (transform_track_i.value == node) { GLTFAnimation::Track track; - track = _convert_animation_track(state, track, animation, Transform3D(), track_i, transform_track_i.key); + track = _convert_animation_track(state, track, animation, track_i, transform_track_i.key); gltf_animation->get_tracks().insert(transform_track_i.key, track); } } @@ -6470,7 +6512,6 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, Ref<GLTFSkeleton> skeleton_gltf = state->skeletons[skeleton_gltf_i]; int32_t bone = skeleton->find_bone(suffix); ERR_CONTINUE(bone == -1); - Transform3D xform = skeleton->get_bone_rest(bone); if (!skeleton_gltf->godot_bone_node.has(bone)) { continue; } @@ -6480,27 +6521,24 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (property_track_i) { track = property_track_i->get(); } - track = _convert_animation_track(state, track, animation, xform, track_i, node_i); + track = _convert_animation_track(state, track, animation, track_i, node_i); gltf_animation->get_tracks()[node_i] = track; } } } else if (String(orig_track_path).find(":") == -1) { ERR_CONTINUE(!ap->get_parent()); - for (int32_t node_i = 0; node_i < ap->get_parent()->get_child_count(); node_i++) { - const Node *child = ap->get_parent()->get_child(node_i); - const Node *node = child->get_node_or_null(orig_track_path); - for (const KeyValue<GLTFNodeIndex, Node *> &scene_node_i : state->scene_nodes) { - if (scene_node_i.value == node) { - GLTFNodeIndex node_index = scene_node_i.key; - Map<int, GLTFAnimation::Track>::Element *node_track_i = gltf_animation->get_tracks().find(node_index); - GLTFAnimation::Track track; - if (node_track_i) { - track = node_track_i->get(); - } - track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index); - gltf_animation->get_tracks().insert(node_index, track); - break; + Node *godot_node = ap->get_parent()->get_node_or_null(orig_track_path); + for (const KeyValue<GLTFNodeIndex, Node *> &scene_node_i : state->scene_nodes) { + if (scene_node_i.value == godot_node) { + GLTFNodeIndex node_i = scene_node_i.key; + Map<int, GLTFAnimation::Track>::Element *node_track_i = gltf_animation->get_tracks().find(node_i); + GLTFAnimation::Track track; + if (node_track_i) { + track = node_track_i->get(); } + track = _convert_animation_track(state, track, animation, track_i, node_i); + gltf_animation->get_tracks()[node_i] = track; + break; } } } diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 7317c6a9a3..a1d82a4649 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -357,7 +357,7 @@ private: String interpolation_to_string(const GLTFAnimation::Interpolation p_interp); GLTFAnimation::Track _convert_animation_track(Ref<GLTFState> state, GLTFAnimation::Track p_track, - Ref<Animation> p_animation, Transform3D p_bone_rest, + Ref<Animation> p_animation, int32_t p_track_i, GLTFNodeIndex p_node_i); Error _encode_buffer_bins(Ref<GLTFState> state, const String &p_path); diff --git a/modules/lightmapper_rd/lm_common_inc.glsl b/modules/lightmapper_rd/lm_common_inc.glsl index 22172d50e4..58523dc1f8 100644 --- a/modules/lightmapper_rd/lm_common_inc.glsl +++ b/modules/lightmapper_rd/lm_common_inc.glsl @@ -81,3 +81,7 @@ layout(set = 0, binding = 8) uniform texture2DArray albedo_tex; layout(set = 0, binding = 9) uniform texture2DArray emission_tex; layout(set = 0, binding = 10) uniform sampler linear_sampler; + +// Fragment action constants +const uint FA_NONE = 0; +const uint FA_SMOOTHEN_POSITION = 1; diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl index 25b334c5eb..6e5c9f25ba 100644 --- a/modules/lightmapper_rd/lm_compute.glsl +++ b/modules/lightmapper_rd/lm_compute.glsl @@ -148,7 +148,7 @@ uint trace_ray(vec3 p_from, vec3 p_to ivec3 icell = ivec3(from_cell); ivec3 iendcell = ivec3(to_cell); vec3 dir_cell = normalize(rel_cell); - vec3 delta = abs(1.0 / dir_cell); //vec3(length(rel_cell)) / rel_cell); + vec3 delta = min(abs(1.0 / dir_cell), params.grid_size); // use params.grid_size as max to prevent infinity values ivec3 step = ivec3(sign(rel_cell)); vec3 side = (sign(rel_cell) * (vec3(icell) - from_cell) + (sign(rel_cell) * 0.5) + 0.5) * delta; @@ -420,20 +420,22 @@ void main() { light = textureLod(sampler2DArray(source_light, linear_sampler), uvw, 0.0).rgb; active_rays += 1.0; - } else if (trace_result == RAY_MISS && params.env_transform[0][3] == 0.0) { // Use env_transform[0][3] to indicate when we are computing the first bounce - // Did not hit a triangle, reach out for the sky - vec3 sky_dir = normalize(mat3(params.env_transform) * ray_dir); + } else if (trace_result == RAY_MISS) { + if (params.env_transform[0][3] == 0.0) { // Use env_transform[0][3] to indicate when we are computing the first bounce + // Did not hit a triangle, reach out for the sky + vec3 sky_dir = normalize(mat3(params.env_transform) * ray_dir); - vec2 st = vec2( - atan(sky_dir.x, sky_dir.z), - acos(sky_dir.y)); + vec2 st = vec2( + atan(sky_dir.x, sky_dir.z), + acos(sky_dir.y)); - if (st.x < 0.0) - st.x += PI * 2.0; + if (st.x < 0.0) + st.x += PI * 2.0; - st /= vec2(PI * 2.0, PI); + st /= vec2(PI * 2.0, PI); - light = textureLod(sampler2D(environment, linear_sampler), st, 0.0).rgb; + light = textureLod(sampler2D(environment, linear_sampler), st, 0.0).rgb; + } active_rays += 1.0; } diff --git a/modules/lightmapper_rd/lm_raster.glsl b/modules/lightmapper_rd/lm_raster.glsl index 55ca193cc1..a86968a4f3 100644 --- a/modules/lightmapper_rd/lm_raster.glsl +++ b/modules/lightmapper_rd/lm_raster.glsl @@ -12,6 +12,7 @@ layout(location = 2) out vec2 uv_interp; layout(location = 3) out vec3 barycentric; layout(location = 4) flat out uvec3 vertex_indices; layout(location = 5) flat out vec3 face_normal; +layout(location = 6) flat out uint fragment_action; layout(push_constant, binding = 0, std430) uniform Params { vec2 atlas_size; @@ -49,6 +50,14 @@ void main() { face_normal = -normalize(cross((vertices.data[vertex_indices.x].position - vertices.data[vertex_indices.y].position), (vertices.data[vertex_indices.x].position - vertices.data[vertex_indices.z].position))); + { + const float FLAT_THRESHOLD = 0.99; + const vec3 norm_a = vec3(vertices.data[vertex_indices.x].normal_xy, vertices.data[vertex_indices.x].normal_z); + const vec3 norm_b = vec3(vertices.data[vertex_indices.y].normal_xy, vertices.data[vertex_indices.y].normal_z); + const vec3 norm_c = vec3(vertices.data[vertex_indices.z].normal_xy, vertices.data[vertex_indices.z].normal_z); + fragment_action = (dot(norm_a, norm_b) < FLAT_THRESHOLD || dot(norm_a, norm_c) < FLAT_THRESHOLD || dot(norm_b, norm_c) < FLAT_THRESHOLD) ? FA_SMOOTHEN_POSITION : FA_NONE; + } + gl_Position = vec4((uv_interp + params.uv_offset) * 2.0 - 1.0, 0.0001, 1.0); } @@ -78,6 +87,7 @@ layout(location = 2) in vec2 uv_interp; layout(location = 3) in vec3 barycentric; layout(location = 4) in flat uvec3 vertex_indices; layout(location = 5) in flat vec3 face_normal; +layout(location = 6) in flat uint fragment_action; layout(location = 0) out vec4 position; layout(location = 1) out vec4 normal; @@ -86,7 +96,7 @@ layout(location = 2) out vec4 unocclude; void main() { vec3 vertex_pos = vertex_interp; - { + if (fragment_action == FA_SMOOTHEN_POSITION) { // smooth out vertex position by interpolating its projection in the 3 normal planes (normal plane is created by vertex pos and normal) // because we don't want to interpolate inwards, normals found pointing inwards are pushed out. vec3 pos_a = vertices.data[vertex_indices.x].position; |