diff options
Diffstat (limited to 'modules/gltf/gltf_document.cpp')
-rw-r--r-- | modules/gltf/gltf_document.cpp | 385 |
1 files changed, 103 insertions, 282 deletions
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index babdc9f33b..f5730e7137 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -30,19 +30,10 @@ #include "gltf_document.h" -#include "gltf_accessor.h" -#include "gltf_animation.h" -#include "gltf_camera.h" +#include "extensions/gltf_spec_gloss.h" #include "gltf_document_extension.h" #include "gltf_document_extension_convert_importer_mesh.h" -#include "gltf_light.h" -#include "gltf_mesh.h" -#include "gltf_node.h" -#include "gltf_skeleton.h" -#include "gltf_skin.h" -#include "gltf_spec_gloss.h" #include "gltf_state.h" -#include "gltf_texture.h" #include "core/crypto/crypto_core.h" #include "core/error/error_macros.h" @@ -59,7 +50,6 @@ #include "core/version.h" #include "drivers/png/png_driver_common.h" #include "scene/2d/node_2d.h" -#include "scene/3d/camera_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/multimesh_instance_3d.h" #include "scene/3d/node_3d.h" @@ -230,15 +220,21 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) { } Error GLTFDocument::_serialize_extensions(Ref<GLTFState> state) const { - const String texture_transform = "KHR_texture_transform"; - const String punctual_lights = "KHR_lights_punctual"; Array extensions_used; - extensions_used.push_back(punctual_lights); - extensions_used.push_back(texture_transform); - state->json["extensionsUsed"] = extensions_used; Array extensions_required; - extensions_required.push_back(texture_transform); - state->json["extensionsRequired"] = extensions_required; + if (!state->lights.is_empty()) { + extensions_used.push_back("KHR_lights_punctual"); + } + if (state->use_khr_texture_transform) { + extensions_used.push_back("KHR_texture_transform"); + extensions_required.push_back("KHR_texture_transform"); + } + if (!extensions_used.is_empty()) { + state->json["extensionsUsed"] = extensions_used; + } + if (!extensions_required.is_empty()) { + state->json["extensionsRequired"] = extensions_required; + } return OK; } @@ -439,7 +435,7 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) { node["scale"] = _vec3_to_arr(n->scale); } - if (!n->position.is_equal_approx(Vector3())) { + if (!n->position.is_zero_approx()) { node["translation"] = _vec3_to_arr(n->position); } if (n->children.size()) { @@ -790,7 +786,7 @@ Error GLTFDocument::_parse_buffers(Ref<GLTFState> state, const String &p_base_pa } else { // Relative path to an external image file. ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER); uri = uri.uri_decode(); - uri = p_base_path.plus_file(uri).replace("\\", "/"); // Fix for Windows. + uri = p_base_path.path_join(uri).replace("\\", "/"); // Fix for Windows. buffer_data = FileAccess::get_file_as_array(uri); ERR_FAIL_COND_V_MSG(buffer.size() == 0, ERR_PARSE_ERROR, "glTF: Couldn't load binary file as an array: " + uri); } @@ -934,58 +930,58 @@ Error GLTFDocument::_encode_accessors(Ref<GLTFState> state) { return OK; } -String GLTFDocument::_get_accessor_type_name(const GLTFDocument::GLTFType p_type) { - if (p_type == GLTFDocument::TYPE_SCALAR) { +String GLTFDocument::_get_accessor_type_name(const GLTFType p_type) { + if (p_type == GLTFType::TYPE_SCALAR) { return "SCALAR"; } - if (p_type == GLTFDocument::TYPE_VEC2) { + if (p_type == GLTFType::TYPE_VEC2) { return "VEC2"; } - if (p_type == GLTFDocument::TYPE_VEC3) { + if (p_type == GLTFType::TYPE_VEC3) { return "VEC3"; } - if (p_type == GLTFDocument::TYPE_VEC4) { + if (p_type == GLTFType::TYPE_VEC4) { return "VEC4"; } - if (p_type == GLTFDocument::TYPE_MAT2) { + if (p_type == GLTFType::TYPE_MAT2) { return "MAT2"; } - if (p_type == GLTFDocument::TYPE_MAT3) { + if (p_type == GLTFType::TYPE_MAT3) { return "MAT3"; } - if (p_type == GLTFDocument::TYPE_MAT4) { + if (p_type == GLTFType::TYPE_MAT4) { return "MAT4"; } ERR_FAIL_V("SCALAR"); } -GLTFDocument::GLTFType GLTFDocument::_get_type_from_str(const String &p_string) { +GLTFType GLTFDocument::_get_type_from_str(const String &p_string) { if (p_string == "SCALAR") { - return GLTFDocument::TYPE_SCALAR; + return GLTFType::TYPE_SCALAR; } if (p_string == "VEC2") { - return GLTFDocument::TYPE_VEC2; + return GLTFType::TYPE_VEC2; } if (p_string == "VEC3") { - return GLTFDocument::TYPE_VEC3; + return GLTFType::TYPE_VEC3; } if (p_string == "VEC4") { - return GLTFDocument::TYPE_VEC4; + return GLTFType::TYPE_VEC4; } if (p_string == "MAT2") { - return GLTFDocument::TYPE_MAT2; + return GLTFType::TYPE_MAT2; } if (p_string == "MAT3") { - return GLTFDocument::TYPE_MAT3; + return GLTFType::TYPE_MAT3; } if (p_string == "MAT4") { - return GLTFDocument::TYPE_MAT4; + return GLTFType::TYPE_MAT4; } - ERR_FAIL_V(GLTFDocument::TYPE_SCALAR); + ERR_FAIL_V(GLTFType::TYPE_SCALAR); } Error GLTFDocument::_parse_accessors(Ref<GLTFState> state) { @@ -1536,7 +1532,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> state, c accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_SCALAR; + const GLTFType type = GLTFType::TYPE_SCALAR; const int component_type = GLTFDocument::COMPONENT_TYPE_INT; accessor->max = type_max; @@ -1620,7 +1616,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec2(Ref<GLTFState> state, c accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC2; + const GLTFType type = GLTFType::TYPE_VEC2; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; @@ -1669,7 +1665,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_color(Ref<GLTFState> state, accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4; + const GLTFType type = GLTFType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; @@ -1734,7 +1730,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_weights(Ref<GLTFState> state accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4; + const GLTFType type = GLTFType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; @@ -1781,7 +1777,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> state, accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4; + const GLTFType type = GLTFType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_UNSIGNED_SHORT; accessor->max = type_max; @@ -1830,7 +1826,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> s accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4; + const GLTFType type = GLTFType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; @@ -1895,7 +1891,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref<GLTFState> state, accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_SCALAR; + const GLTFType type = GLTFType::TYPE_SCALAR; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; @@ -1941,7 +1937,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> state, c accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC3; + const GLTFType type = GLTFType::TYPE_VEC3; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; @@ -2009,7 +2005,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_MAT4; + const GLTFType type = GLTFType::TYPE_MAT4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; @@ -2677,7 +2673,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { } else if (a.has("JOINTS_0") && a.has("JOINTS_1")) { PackedInt32Array joints_0 = _decode_accessor_as_ints(state, a["JOINTS_0"], true); PackedInt32Array joints_1 = _decode_accessor_as_ints(state, a["JOINTS_1"], true); - ERR_FAIL_COND_V(joints_0.size() != joints_0.size(), ERR_INVALID_DATA); + ERR_FAIL_COND_V(joints_0.size() != joints_1.size(), ERR_INVALID_DATA); int32_t weight_8_count = JOINT_GROUP_SIZE * 2; Vector<int> joints; joints.resize(vertex_num * weight_8_count); @@ -3043,8 +3039,8 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path if (!da->dir_exists(new_texture_dir)) { da->make_dir(new_texture_dir); } - image->save_png(new_texture_dir.plus_file(name)); - d["uri"] = texture_dir.plus_file(name).uri_encode(); + image->save_png(new_texture_dir.path_join(name)); + d["uri"] = texture_dir.path_join(name).uri_encode(); } images.push_back(d); } @@ -3122,7 +3118,7 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat } else { // Relative path to an external image file. ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER); uri = uri.uri_decode(); - uri = p_base_path.plus_file(uri).replace("\\", "/"); // Fix for Windows. + uri = p_base_path.path_join(uri).replace("\\", "/"); // Fix for Windows. // ResourceLoader will rely on the file extension to use the relevant loader. // The spec says that if mimeType is defined, it should take precedence (e.g. // there could be a `.png` image which is actually JPEG), but there's no easy @@ -3305,7 +3301,11 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { } if (gltf_texture_index != -1) { bct["index"] = gltf_texture_index; - bct["extensions"] = _serialize_texture_transform_uv1(material); + Dictionary extensions = _serialize_texture_transform_uv1(material); + if (!extensions.is_empty()) { + bct["extensions"] = extensions; + state->use_khr_texture_transform = true; + } mr["baseColorTexture"] = bct; } } @@ -3436,7 +3436,11 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { } if (has_roughness || has_metalness) { mrt["index"] = orm_texture_index; - mrt["extensions"] = _serialize_texture_transform_uv1(material); + Dictionary extensions = _serialize_texture_transform_uv1(material); + if (!extensions.is_empty()) { + mrt["extensions"] = extensions; + state->use_khr_texture_transform = true; + } mr["metallicRoughnessTexture"] = mrt; } } @@ -4525,34 +4529,12 @@ void GLTFDocument::_remove_duplicate_skins(Ref<GLTFState> state) { } Error GLTFDocument::_serialize_lights(Ref<GLTFState> state) { + if (state->lights.is_empty()) { + return OK; + } Array lights; for (GLTFLightIndex i = 0; i < state->lights.size(); i++) { - Dictionary d; - Ref<GLTFLight> light = state->lights[i]; - Array color; - color.resize(3); - color[0] = light->color.r; - color[1] = light->color.g; - color[2] = light->color.b; - d["color"] = color; - d["type"] = light->light_type; - if (light->light_type == "spot") { - Dictionary s; - float inner_cone_angle = light->inner_cone_angle; - s["innerConeAngle"] = inner_cone_angle; - float outer_cone_angle = light->outer_cone_angle; - s["outerConeAngle"] = outer_cone_angle; - d["spot"] = s; - } - float intensity = light->intensity; - d["intensity"] = intensity; - float range = light->range; - d["range"] = range; - lights.push_back(d); - } - - if (!state->lights.size()) { - return OK; + lights.push_back(state->lights[i]->to_dictionary()); } Dictionary extensions; @@ -4574,28 +4556,7 @@ Error GLTFDocument::_serialize_cameras(Ref<GLTFState> state) { Array cameras; cameras.resize(state->cameras.size()); for (GLTFCameraIndex i = 0; i < state->cameras.size(); i++) { - Dictionary d; - - Ref<GLTFCamera> camera = state->cameras[i]; - - if (camera->get_perspective() == false) { - Dictionary og; - og["ymag"] = Math::deg2rad(camera->get_fov_size()); - og["xmag"] = Math::deg2rad(camera->get_fov_size()); - og["zfar"] = camera->get_depth_far(); - og["znear"] = camera->get_depth_near(); - d["orthographic"] = og; - d["type"] = "orthographic"; - } else if (camera->get_perspective()) { - Dictionary ppt; - // GLTF spec is in radians, Godot's camera is in degrees. - ppt["yfov"] = Math::deg2rad(camera->get_fov_size()); - ppt["zfar"] = camera->get_depth_far(); - ppt["znear"] = camera->get_depth_near(); - d["perspective"] = ppt; - d["type"] = "perspective"; - } - cameras[i] = d; + cameras[i] = state->cameras[i]->to_dictionary(); } if (!state->cameras.size()) { @@ -4625,35 +4586,10 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) { const Array &lights = lights_punctual["lights"]; for (GLTFLightIndex light_i = 0; light_i < lights.size(); light_i++) { - const Dictionary &d = lights[light_i]; - - Ref<GLTFLight> light; - light.instantiate(); - ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR); - const String &type = d["type"]; - light->light_type = type; - - if (d.has("color")) { - const Array &arr = d["color"]; - ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR); - const Color c = Color(arr[0], arr[1], arr[2]).linear_to_srgb(); - light->color = c; + Ref<GLTFLight> light = GLTFLight::from_dictionary(lights[light_i]); + if (light.is_null()) { + return Error::ERR_PARSE_ERROR; } - if (d.has("intensity")) { - light->intensity = d["intensity"]; - } - if (d.has("range")) { - light->range = d["range"]; - } - if (type == "spot") { - const Dictionary &spot = d["spot"]; - light->inner_cone_angle = spot["innerConeAngle"]; - light->outer_cone_angle = spot["outerConeAngle"]; - ERR_CONTINUE_MSG(light->inner_cone_angle >= light->outer_cone_angle, "The inner angle must be smaller than the outer angle."); - } else if (type != "point" && type != "directional") { - ERR_CONTINUE_MSG(true, "Light type is unknown."); - } - state->lights.push_back(light); } @@ -4670,39 +4606,7 @@ Error GLTFDocument::_parse_cameras(Ref<GLTFState> state) { const Array cameras = state->json["cameras"]; for (GLTFCameraIndex i = 0; i < cameras.size(); i++) { - const Dictionary &d = cameras[i]; - - Ref<GLTFCamera> camera; - camera.instantiate(); - ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR); - const String &type = d["type"]; - if (type == "orthographic") { - camera->set_perspective(false); - if (d.has("orthographic")) { - const Dictionary &og = d["orthographic"]; - // GLTF spec is in radians, Godot's camera is in degrees. - camera->set_fov_size(Math::rad2deg(real_t(og["ymag"]))); - camera->set_depth_far(og["zfar"]); - camera->set_depth_near(og["znear"]); - } else { - camera->set_fov_size(10); - } - } else if (type == "perspective") { - camera->set_perspective(true); - if (d.has("perspective")) { - const Dictionary &ppt = d["perspective"]; - // GLTF spec is in radians, Godot's camera is in degrees. - camera->set_fov_size(Math::rad2deg(real_t(ppt["yfov"]))); - camera->set_depth_far(ppt["zfar"]); - camera->set_depth_near(ppt["znear"]); - } else { - camera->set_fov_size(10); - } - } else { - ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "Camera3D should be in 'orthographic' or 'perspective'"); - } - - state->cameras.push_back(camera); + state->cameras.push_back(GLTFCamera::from_dictionary(cameras[i])); } print_verbose("glTF: Total cameras: " + itos(state->cameras.size())); @@ -4934,7 +4838,8 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) { if (d.has("name")) { const String name = d["name"]; - if (name.begins_with("loop") || name.ends_with("loop") || name.begins_with("cycle") || name.ends_with("cycle")) { + const String name_lower = name.to_lower(); + if (name_lower.begins_with("loop") || name_lower.ends_with("loop") || name_lower.begins_with("cycle") || name_lower.ends_with("cycle")) { animation->set_loop(true); } animation->set_name(_gen_unique_animation_name(state, name)); @@ -5102,7 +5007,7 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> state, MeshInst Ref<GLTFMesh> gltf_mesh; gltf_mesh.instantiate(); - Array instance_materials; + TypedArray<Material> instance_materials; for (int32_t surface_i = 0; surface_i < current_mesh->get_surface_count(); surface_i++) { Ref<Material> mat = current_mesh->get_surface_material(surface_i); if (p_mesh_instance->get_surface_override_material(surface_i).is_valid()) { @@ -5149,45 +5054,7 @@ Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, const GLTFNodeIndex print_verbose("glTF: Creating light for: " + gltf_node->get_name()); Ref<GLTFLight> l = state->lights[gltf_node->light]; - - float intensity = l->intensity; - if (intensity > 10) { - // GLTF spec has the default around 1, but Blender defaults lights to 100. - // The only sane way to handle this is to check where it came from and - // handle it accordingly. If it's over 10, it probably came from Blender. - intensity /= 100; - } - - if (l->light_type == "directional") { - DirectionalLight3D *light = memnew(DirectionalLight3D); - light->set_param(Light3D::PARAM_ENERGY, intensity); - light->set_color(l->color); - return light; - } - - const float range = CLAMP(l->range, 0, 4096); - if (l->light_type == "point") { - OmniLight3D *light = memnew(OmniLight3D); - light->set_param(OmniLight3D::PARAM_ENERGY, intensity); - light->set_param(OmniLight3D::PARAM_RANGE, range); - light->set_color(l->color); - return light; - } - if (l->light_type == "spot") { - SpotLight3D *light = memnew(SpotLight3D); - light->set_param(SpotLight3D::PARAM_ENERGY, intensity); - light->set_param(SpotLight3D::PARAM_RANGE, range); - light->set_param(SpotLight3D::PARAM_SPOT_ANGLE, Math::rad2deg(l->outer_cone_angle)); - light->set_color(l->color); - - // Line of best fit derived from guessing, see https://www.desmos.com/calculator/biiflubp8b - // The points in desmos are not exact, except for (1, infinity). - float angle_ratio = l->inner_cone_angle / l->outer_cone_angle; - float angle_attenuation = 0.2 / (1 - angle_ratio) - 0.1; - light->set_param(SpotLight3D::PARAM_SPOT_ATTENUATION, angle_attenuation); - return light; - } - return memnew(Node3D); + return l->to_node(); } Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> state, const GLTFNodeIndex node_index) { @@ -5195,31 +5062,16 @@ Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> state, const GLTFNodeInd ERR_FAIL_INDEX_V(gltf_node->camera, state->cameras.size(), nullptr); - Camera3D *camera = memnew(Camera3D); print_verbose("glTF: Creating camera for: " + gltf_node->get_name()); Ref<GLTFCamera> c = state->cameras[gltf_node->camera]; - if (c->get_perspective()) { - camera->set_perspective(c->get_fov_size(), c->get_depth_near(), c->get_depth_far()); - } else { - camera->set_orthogonal(c->get_fov_size(), c->get_depth_near(), c->get_depth_far()); - } - - return camera; + return c->to_node(); } GLTFCameraIndex GLTFDocument::_convert_camera(Ref<GLTFState> state, Camera3D *p_camera) { print_verbose("glTF: Converting camera: " + p_camera->get_name()); - Ref<GLTFCamera> c; - c.instantiate(); - - if (p_camera->get_projection() == Camera3D::Projection::PROJECTION_PERSPECTIVE) { - c->set_perspective(true); - } - c->set_fov_size(p_camera->get_fov()); - c->set_depth_far(p_camera->get_far()); - c->set_depth_near(p_camera->get_near()); + Ref<GLTFCamera> c = GLTFCamera::from_node(p_camera); GLTFCameraIndex camera_index = state->cameras.size(); state->cameras.push_back(c); return camera_index; @@ -5228,31 +5080,7 @@ GLTFCameraIndex GLTFDocument::_convert_camera(Ref<GLTFState> state, Camera3D *p_ GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> state, Light3D *p_light) { print_verbose("glTF: Converting light: " + p_light->get_name()); - Ref<GLTFLight> l; - l.instantiate(); - l->color = p_light->get_color(); - if (cast_to<DirectionalLight3D>(p_light)) { - l->light_type = "directional"; - DirectionalLight3D *light = cast_to<DirectionalLight3D>(p_light); - l->intensity = light->get_param(DirectionalLight3D::PARAM_ENERGY); - l->range = FLT_MAX; // Range for directional lights is infinite in Godot. - } else if (cast_to<OmniLight3D>(p_light)) { - l->light_type = "point"; - OmniLight3D *light = cast_to<OmniLight3D>(p_light); - l->range = light->get_param(OmniLight3D::PARAM_RANGE); - l->intensity = light->get_param(OmniLight3D::PARAM_ENERGY); - } else if (cast_to<SpotLight3D>(p_light)) { - l->light_type = "spot"; - SpotLight3D *light = cast_to<SpotLight3D>(p_light); - l->range = light->get_param(SpotLight3D::PARAM_RANGE); - l->intensity = light->get_param(SpotLight3D::PARAM_ENERGY); - l->outer_cone_angle = Math::deg2rad(light->get_param(SpotLight3D::PARAM_SPOT_ANGLE)); - - // This equation is the inverse of the import equation (which has a desmos link). - float angle_ratio = 1 - (0.2 / (0.1 + light->get_param(SpotLight3D::PARAM_SPOT_ATTENUATION))); - angle_ratio = MAX(0, angle_ratio); - l->inner_cone_angle = l->outer_cone_angle * angle_ratio; - } + Ref<GLTFLight> l = GLTFLight::from_node(p_light); GLTFLightIndex light_index = state->lights.size(); state->lights.push_back(l); @@ -5437,13 +5265,13 @@ void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex int32_t cell = p_grid_map->get_cell_item( Vector3(cell_location.x, cell_location.y, cell_location.z)); Transform3D cell_xform; - cell_xform.basis.set_orthogonal_index( + cell_xform.basis = p_grid_map->get_basis_with_orthogonal_index( p_grid_map->get_cell_item_orientation( Vector3(cell_location.x, cell_location.y, cell_location.z))); cell_xform.basis.scale(Vector3(p_grid_map->get_cell_scale(), p_grid_map->get_cell_scale(), p_grid_map->get_cell_scale())); - cell_xform.set_origin(p_grid_map->map_to_world( + cell_xform.set_origin(p_grid_map->map_to_local( Vector3(cell_location.x, cell_location.y, cell_location.z))); Ref<GLTFMesh> gltf_mesh; gltf_mesh.instantiate(); @@ -6651,45 +6479,48 @@ Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> return OK; } -Dictionary GLTFDocument::_serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material) { - Dictionary extension; - Ref<BaseMaterial3D> mat = p_material; - if (mat.is_valid()) { - Dictionary texture_transform; +Dictionary _serialize_texture_transform_uv(Vector2 p_offset, Vector2 p_scale) { + Dictionary texture_transform; + bool is_offset = p_offset != Vector2(0.0, 0.0); + if (is_offset) { Array offset; offset.resize(2); - offset[0] = mat->get_uv2_offset().x; - offset[1] = mat->get_uv2_offset().y; + offset[0] = p_offset.x; + offset[1] = p_offset.y; texture_transform["offset"] = offset; + } + bool is_scaled = p_scale != Vector2(1.0, 1.0); + if (is_scaled) { Array scale; scale.resize(2); - scale[0] = mat->get_uv2_scale().x; - scale[1] = mat->get_uv2_scale().y; + scale[0] = p_scale.x; + scale[1] = p_scale.y; texture_transform["scale"] = scale; - // Godot doesn't support texture rotation + } + Dictionary extension; + // Note: Godot doesn't support texture rotation. + if (is_offset || is_scaled) { extension["KHR_texture_transform"] = texture_transform; } return extension; } Dictionary GLTFDocument::_serialize_texture_transform_uv1(Ref<BaseMaterial3D> p_material) { - Dictionary extension; if (p_material.is_valid()) { - Dictionary texture_transform; - Array offset; - offset.resize(2); - offset[0] = p_material->get_uv1_offset().x; - offset[1] = p_material->get_uv1_offset().y; - texture_transform["offset"] = offset; - Array scale; - scale.resize(2); - scale[0] = p_material->get_uv1_scale().x; - scale[1] = p_material->get_uv1_scale().y; - texture_transform["scale"] = scale; - // Godot doesn't support texture rotation - extension["KHR_texture_transform"] = texture_transform; + Vector3 offset = p_material->get_uv1_offset(); + Vector3 scale = p_material->get_uv1_scale(); + return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); } - return extension; + return Dictionary(); +} + +Dictionary GLTFDocument::_serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material) { + if (p_material.is_valid()) { + Vector3 offset = p_material->get_uv2_offset(); + Vector3 scale = p_material->get_uv2_scale(); + return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); + } + return Dictionary(); } Error GLTFDocument::_serialize_version(Ref<GLTFState> state) { @@ -6891,7 +6722,7 @@ Node *GLTFDocument::generate_scene(Ref<GLTFState> state, int32_t p_bake_fps) { Node *root = gltf_root_node->get_parent(); ERR_FAIL_NULL_V(root, nullptr); _process_mesh_instances(state, root); - if (state->animations.size()) { + if (state->get_create_animations() && state->animations.size()) { AnimationPlayer *ap = memnew(AnimationPlayer); root->add_child(ap, true); ap->set_owner(root); @@ -6929,15 +6760,6 @@ Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> state, uint32 state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; - _convert_scene_node(state, p_node, -1, -1); - if (!state->buffers.size()) { - state->buffers.push_back(Vector<uint8_t>()); - } - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; - ERR_CONTINUE(ext.is_null()); - } - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; ERR_CONTINUE(ext.is_null()); @@ -6948,7 +6770,6 @@ Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> state, uint32 if (!state->buffers.size()) { state->buffers.push_back(Vector<uint8_t>()); } - return OK; } |