Merge pull request #39450 from aaronfranke/gltf-light
Add GLTF light import
This commit is contained in:
commit
46e0e13252
@ -286,7 +286,16 @@ Error EditorSceneImporterGLTF::_parse_nodes(GLTFState &state) {
|
|||||||
node->xform.basis.set_quat_scale(node->rotation, node->scale);
|
node->xform.basis.set_quat_scale(node->rotation, node->scale);
|
||||||
node->xform.origin = node->translation;
|
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")) {
|
if (n.has("children")) {
|
||||||
const Array &children = n["children"];
|
const Array &children = n["children"];
|
||||||
for (int j = 0; j < children.size(); j++) {
|
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) {
|
Error EditorSceneImporterGLTF::_parse_cameras(GLTFState &state) {
|
||||||
if (!state.json.has("cameras")) {
|
if (!state.json.has("cameras")) {
|
||||||
return OK;
|
return OK;
|
||||||
@ -2488,6 +2549,58 @@ MeshInstance3D *EditorSceneImporterGLTF::_generate_mesh_instance(GLTFState &stat
|
|||||||
return mi;
|
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) {
|
Camera3D *EditorSceneImporterGLTF::_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) {
|
||||||
const GLTFNode *gltf_node = state.nodes[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);
|
current_node = _generate_mesh_instance(state, scene_parent, node_index);
|
||||||
} else if (gltf_node->camera >= 0) {
|
} else if (gltf_node->camera >= 0) {
|
||||||
current_node = _generate_camera(state, scene_parent, node_index);
|
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 {
|
} else {
|
||||||
current_node = _generate_spatial(state, scene_parent, node_index);
|
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;
|
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);
|
err = _parse_cameras(state);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* STEP 15 PARSE ANIMATIONS */
|
/* STEP 16 PARSE ANIMATIONS */
|
||||||
err = _parse_animations(state);
|
err = _parse_animations(state);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* STEP 16 ASSIGN SCENE NAMES */
|
/* STEP 17 ASSIGN SCENE NAMES */
|
||||||
_assign_scene_names(state);
|
_assign_scene_names(state);
|
||||||
|
|
||||||
/* STEP 17 MAKE SCENE! */
|
/* STEP 18 MAKE SCENE! */
|
||||||
Node3D *scene = _generate_scene(state, p_bake_fps);
|
Node3D *scene = _generate_scene(state, p_bake_fps);
|
||||||
|
|
||||||
return scene;
|
return scene;
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#define EDITOR_SCENE_IMPORTER_GLTF_H
|
#define EDITOR_SCENE_IMPORTER_GLTF_H
|
||||||
|
|
||||||
#include "editor/import/resource_importer_scene.h"
|
#include "editor/import/resource_importer_scene.h"
|
||||||
|
#include "scene/3d/light_3d.h"
|
||||||
#include "scene/3d/node_3d.h"
|
#include "scene/3d/node_3d.h"
|
||||||
#include "scene/3d/skeleton_3d.h"
|
#include "scene/3d/skeleton_3d.h"
|
||||||
|
|
||||||
@ -50,6 +51,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
|
|||||||
typedef int GLTFImageIndex;
|
typedef int GLTFImageIndex;
|
||||||
typedef int GLTFMaterialIndex;
|
typedef int GLTFMaterialIndex;
|
||||||
typedef int GLTFMeshIndex;
|
typedef int GLTFMeshIndex;
|
||||||
|
typedef int GLTFLightIndex;
|
||||||
typedef int GLTFNodeIndex;
|
typedef int GLTFNodeIndex;
|
||||||
typedef int GLTFSkeletonIndex;
|
typedef int GLTFSkeletonIndex;
|
||||||
typedef int GLTFSkinIndex;
|
typedef int GLTFSkinIndex;
|
||||||
@ -113,6 +115,8 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
|
|||||||
|
|
||||||
GLTFNodeIndex fake_joint_parent = -1;
|
GLTFNodeIndex fake_joint_parent = -1;
|
||||||
|
|
||||||
|
GLTFLightIndex light = -1;
|
||||||
|
|
||||||
GLTFNode() {}
|
GLTFNode() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -218,6 +222,17 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
|
|||||||
GLTFCamera() {}
|
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 {
|
struct GLTFAnimation {
|
||||||
bool loop = false;
|
bool loop = false;
|
||||||
|
|
||||||
@ -271,6 +286,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
|
|||||||
|
|
||||||
Vector<GLTFSkin> skins;
|
Vector<GLTFSkin> skins;
|
||||||
Vector<GLTFCamera> cameras;
|
Vector<GLTFCamera> cameras;
|
||||||
|
Vector<GLTFLight> lights;
|
||||||
|
|
||||||
Set<String> unique_names;
|
Set<String> unique_names;
|
||||||
|
|
||||||
@ -349,12 +365,13 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
|
|||||||
void _remove_duplicate_skins(GLTFState &state);
|
void _remove_duplicate_skins(GLTFState &state);
|
||||||
|
|
||||||
Error _parse_cameras(GLTFState &state);
|
Error _parse_cameras(GLTFState &state);
|
||||||
|
Error _parse_lights(GLTFState &state);
|
||||||
Error _parse_animations(GLTFState &state);
|
Error _parse_animations(GLTFState &state);
|
||||||
|
|
||||||
BoneAttachment3D *_generate_bone_attachment(GLTFState &state, Skeleton3D *skeleton, const GLTFNodeIndex node_index);
|
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);
|
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);
|
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);
|
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);
|
void _generate_scene_node(GLTFState &state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index);
|
||||||
|
Loading…
Reference in New Issue
Block a user