summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--editor/import/editor_scene_importer_gltf.cpp131
-rw-r--r--editor/import/editor_scene_importer_gltf.h19
2 files changed, 144 insertions, 6 deletions
diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp
index e340f41e3b..1a232658fe 100644
--- a/editor/import/editor_scene_importer_gltf.cpp
+++ b/editor/import/editor_scene_importer_gltf.cpp
@@ -286,7 +286,16 @@ Error EditorSceneImporterGLTF::_parse_nodes(GLTFState &state) {
node->xform.basis.set_quat_scale(node->rotation, node->scale);
node->xform.origin = node->translation;
}
-
+ if (n.has("extensions")) {
+ Dictionary extensions = n["extensions"];
+ if (extensions.has("KHR_lights_punctual")) {
+ Dictionary lights_punctual = extensions["KHR_lights_punctual"];
+ if (lights_punctual.has("light")) {
+ GLTFLightIndex light = lights_punctual["light"];
+ node->light = light;
+ }
+ }
+ }
if (n.has("children")) {
const Array &children = n["children"];
for (int j = 0; j < children.size(); j++) {
@@ -2245,6 +2254,58 @@ void EditorSceneImporterGLTF::_remove_duplicate_skins(GLTFState &state) {
}
}
+Error EditorSceneImporterGLTF::_parse_lights(GLTFState &state) {
+ if (!state.json.has("extensions")) {
+ return OK;
+ }
+ Dictionary extensions = state.json["extensions"];
+ if (!extensions.has("KHR_lights_punctual")) {
+ return OK;
+ }
+ Dictionary lights_punctual = extensions["KHR_lights_punctual"];
+ if (!lights_punctual.has("lights")) {
+ return OK;
+ }
+
+ const Array &lights = lights_punctual["lights"];
+
+ for (GLTFLightIndex light_i = 0; light_i < lights.size(); light_i++) {
+ const Dictionary &d = lights[light_i];
+
+ GLTFLight light;
+ ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR);
+ const String &type = d["type"];
+ 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]).to_srgb();
+ light.color = c;
+ }
+ 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_FAIL_COND_V_MSG(light.inner_cone_angle >= light.outer_cone_angle, ERR_PARSE_ERROR, "The inner angle must be smaller than the outer angle.");
+ } else if (type != "point" && type != "directional") {
+ ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "Light type is unknown.");
+ }
+
+ state.lights.push_back(light);
+ }
+
+ print_verbose("glTF: Total lights: " + itos(state.lights.size()));
+
+ return OK;
+}
+
Error EditorSceneImporterGLTF::_parse_cameras(GLTFState &state) {
if (!state.json.has("cameras")) {
return OK;
@@ -2488,6 +2549,58 @@ MeshInstance3D *EditorSceneImporterGLTF::_generate_mesh_instance(GLTFState &stat
return mi;
}
+Light3D *EditorSceneImporterGLTF::_generate_light(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) {
+ const GLTFNode *gltf_node = state.nodes[node_index];
+
+ ERR_FAIL_INDEX_V(gltf_node->light, state.lights.size(), nullptr);
+
+ print_verbose("glTF: Creating light for: " + gltf_node->name);
+
+ const 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.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);
+ // Doubling the range will double the effective brightness, so we need double attenuation (half brightness).
+ // We want to have double intensity give double brightness, so we need half the attenuation.
+ const float attenuation = range / intensity;
+ if (l.type == "point") {
+ OmniLight3D *light = memnew(OmniLight3D);
+ light->set_param(OmniLight3D::PARAM_ATTENUATION, attenuation);
+ light->set_param(OmniLight3D::PARAM_RANGE, range);
+ light->set_color(l.color);
+ return light;
+ }
+ if (l.type == "spot") {
+ SpotLight3D *light = memnew(SpotLight3D);
+ light->set_param(SpotLight3D::PARAM_ATTENUATION, attenuation);
+ 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 nullptr;
+}
+
Camera3D *EditorSceneImporterGLTF::_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) {
const GLTFNode *gltf_node = state.nodes[node_index];
@@ -2561,6 +2674,8 @@ void EditorSceneImporterGLTF::_generate_scene_node(GLTFState &state, Node *scene
current_node = _generate_mesh_instance(state, scene_parent, node_index);
} else if (gltf_node->camera >= 0) {
current_node = _generate_camera(state, scene_parent, node_index);
+ } else if (gltf_node->light >= 0) {
+ current_node = _generate_light(state, scene_parent, node_index);
} else {
current_node = _generate_spatial(state, scene_parent, node_index);
}
@@ -3037,22 +3152,28 @@ Node *EditorSceneImporterGLTF::import_scene(const String &p_path, uint32_t p_fla
return nullptr;
}
- /* STEP 14 PARSE CAMERAS */
+ /* STEP 14 PARSE LIGHTS */
+ err = _parse_lights(state);
+ if (err != OK) {
+ return NULL;
+ }
+
+ /* STEP 15 PARSE CAMERAS */
err = _parse_cameras(state);
if (err != OK) {
return nullptr;
}
- /* STEP 15 PARSE ANIMATIONS */
+ /* STEP 16 PARSE ANIMATIONS */
err = _parse_animations(state);
if (err != OK) {
return nullptr;
}
- /* STEP 16 ASSIGN SCENE NAMES */
+ /* STEP 17 ASSIGN SCENE NAMES */
_assign_scene_names(state);
- /* STEP 17 MAKE SCENE! */
+ /* STEP 18 MAKE SCENE! */
Node3D *scene = _generate_scene(state, p_bake_fps);
return scene;
diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h
index d45410fa57..95c6b87af5 100644
--- a/editor/import/editor_scene_importer_gltf.h
+++ b/editor/import/editor_scene_importer_gltf.h
@@ -32,6 +32,7 @@
#define EDITOR_SCENE_IMPORTER_GLTF_H
#include "editor/import/resource_importer_scene.h"
+#include "scene/3d/light_3d.h"
#include "scene/3d/node_3d.h"
#include "scene/3d/skeleton_3d.h"
@@ -50,6 +51,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
typedef int GLTFImageIndex;
typedef int GLTFMaterialIndex;
typedef int GLTFMeshIndex;
+ typedef int GLTFLightIndex;
typedef int GLTFNodeIndex;
typedef int GLTFSkeletonIndex;
typedef int GLTFSkinIndex;
@@ -113,6 +115,8 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
GLTFNodeIndex fake_joint_parent = -1;
+ GLTFLightIndex light = -1;
+
GLTFNode() {}
};
@@ -218,6 +222,17 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
GLTFCamera() {}
};
+ struct GLTFLight {
+ Color color = Color(1.0f, 1.0f, 1.0f);
+ float intensity = 1.0f;
+ String type = "";
+ float range = Math_INF;
+ float inner_cone_angle = 0.0f;
+ float outer_cone_angle = Math_PI / 4.0;
+
+ GLTFLight() {}
+ };
+
struct GLTFAnimation {
bool loop = false;
@@ -271,6 +286,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
Vector<GLTFSkin> skins;
Vector<GLTFCamera> cameras;
+ Vector<GLTFLight> lights;
Set<String> unique_names;
@@ -349,12 +365,13 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
void _remove_duplicate_skins(GLTFState &state);
Error _parse_cameras(GLTFState &state);
-
+ Error _parse_lights(GLTFState &state);
Error _parse_animations(GLTFState &state);
BoneAttachment3D *_generate_bone_attachment(GLTFState &state, Skeleton3D *skeleton, const GLTFNodeIndex node_index);
MeshInstance3D *_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
Camera3D *_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
+ Light3D *_generate_light(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
Node3D *_generate_spatial(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
void _generate_scene_node(GLTFState &state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index);