Added back the scene side lighmapper classes.

This commit is contained in:
Relintai 2024-07-15 21:20:48 +02:00
parent d899382c30
commit f297ccbc7d
15 changed files with 4630 additions and 0 deletions

View File

@ -0,0 +1,151 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="BakedLightmap" inherits="VisualInstance" version="3.6" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Prerendered indirect light map for a scene.
</brief_description>
<description>
Baked lightmaps are an alternative workflow for adding indirect (or baked) lighting to a scene. Unlike the [GIProbe] approach, baked lightmaps work fine on low-end PCs and mobile devices as they consume almost no resources in run-time.
[b]Procedural generation:[/b] Lightmap baking functionality is only available in the editor. This means [BakedLightmap] is not suited to procedurally generated or user-built levels. For procedurally generated or user-built levels, use [GIProbe] instead.
[b]Note:[/b] Due to how lightmaps work, most properties only have a visible effect once lightmaps are baked again.
</description>
<tutorials>
<link>$DOCS_URL/tutorials/3d/baked_lightmaps.html</link>
</tutorials>
<methods>
<method name="bake">
<return type="int" enum="BakedLightmap.BakeError" />
<argument index="0" name="from_node" type="Node" default="null" />
<argument index="1" name="data_save_path" type="String" default="&quot;&quot;" />
<description>
Bakes the lightmap, scanning from the given [code]from_node[/code] root and saves the resulting [BakedLightmapData] in [code]data_save_path[/code]. If no root node is provided, parent of this node will be used as root instead. If no save path is provided it will try to match the path from the current [member light_data].
</description>
</method>
</methods>
<members>
<member name="atlas_generate" type="bool" setter="set_generate_atlas" getter="is_generate_atlas_enabled" default="true">
If [code]true[/code], the lightmapper will merge the textures for all meshes into one or several large layered textures. If [code]false[/code], every mesh will get its own lightmap texture, which is less efficient.
[b]Note:[/b] Atlas lightmap rendering is only supported in GLES3, [i]not[/i] GLES2. Non-atlas lightmap rendering is supported by both GLES3 and GLES2. If [member ProjectSettings.rendering/quality/driver/fallback_to_gles2] is [code]true[/code], consider baking lightmaps with [member atlas_generate] set to [code]false[/code] so that the resulting lightmap is visible in both GLES3 and GLES2.
</member>
<member name="atlas_max_size" type="int" setter="set_max_atlas_size" getter="get_max_atlas_size" default="4096">
Maximum size of each lightmap layer, only used when [member atlas_generate] is enabled.
</member>
<member name="bias" type="float" setter="set_bias" getter="get_bias" default="0.005">
Raycasting bias used during baking to avoid floating point precision issues.
</member>
<member name="bounce_indirect_energy" type="float" setter="set_bounce_indirect_energy" getter="get_bounce_indirect_energy" default="1.0">
The energy multiplier for each bounce. Higher values will make indirect lighting brighter. A value of [code]1.0[/code] represents physically accurate behavior, but higher values can be used to make indirect lighting propagate more visibly when using a low number of bounces. This can be used to speed up bake times by lowering the number of [member bounces] then increasing [member bounce_indirect_energy]. Unlike [member BakedLightmapData.energy], this property does not affect direct lighting emitted by light nodes, emissive materials and the environment.
[b]Note:[/b] [member bounce_indirect_energy] only has an effect if [member bounces] is set to a value greater than or equal to [code]1[/code].
</member>
<member name="bounces" type="int" setter="set_bounces" getter="get_bounces" default="3">
Number of light bounces that are taken into account during baking. See also [member bounce_indirect_energy].
</member>
<member name="capture_cell_size" type="float" setter="set_capture_cell_size" getter="get_capture_cell_size" default="0.5">
Grid size used for real-time capture information on dynamic objects.
</member>
<member name="capture_enabled" type="bool" setter="set_capture_enabled" getter="get_capture_enabled" default="true">
When enabled, an octree containing the scene's lighting information will be computed. This octree will then be used to light dynamic objects in the scene.
</member>
<member name="capture_propagation" type="float" setter="set_capture_propagation" getter="get_capture_propagation" default="1.0">
Bias value to reduce the amount of light propagation in the captured octree.
</member>
<member name="capture_quality" type="int" setter="set_capture_quality" getter="get_capture_quality" enum="BakedLightmap.BakeQuality" default="1">
Bake quality of the capture data.
</member>
<member name="default_texels_per_unit" type="float" setter="set_default_texels_per_unit" getter="get_default_texels_per_unit" default="16.0">
If a baked mesh doesn't have a UV2 size hint, this value will be used to roughly compute a suitable lightmap size.
</member>
<member name="environment_custom_color" type="Color" setter="set_environment_custom_color" getter="get_environment_custom_color">
The environment color when [member environment_mode] is set to [constant ENVIRONMENT_MODE_CUSTOM_COLOR].
</member>
<member name="environment_custom_energy" type="float" setter="set_environment_custom_energy" getter="get_environment_custom_energy">
The energy scaling factor when when [member environment_mode] is set to [constant ENVIRONMENT_MODE_CUSTOM_COLOR] or [constant ENVIRONMENT_MODE_CUSTOM_SKY].
</member>
<member name="environment_custom_sky" type="Sky" setter="set_environment_custom_sky" getter="get_environment_custom_sky">
The [Sky] resource to use when [member environment_mode] is set o [constant ENVIRONMENT_MODE_CUSTOM_SKY].
</member>
<member name="environment_custom_sky_rotation_degrees" type="Vector3" setter="set_environment_custom_sky_rotation_degrees" getter="get_environment_custom_sky_rotation_degrees">
The rotation of the baked custom sky.
</member>
<member name="environment_min_light" type="Color" setter="set_environment_min_light" getter="get_environment_min_light" default="Color( 0, 0, 0, 1 )">
Minimum ambient light for all the lightmap texels. This doesn't take into account any occlusion from the scene's geometry, it simply ensures a minimum amount of light on all the lightmap texels. Can be used for artistic control on shadow color.
</member>
<member name="environment_mode" type="int" setter="set_environment_mode" getter="get_environment_mode" enum="BakedLightmap.EnvironmentMode" default="0">
Decides which environment to use during baking.
</member>
<member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3( 10, 10, 10 )">
Size of the baked lightmap. Only meshes inside this region will be included in the baked lightmap, also used as the bounds of the captured region for dynamic lighting.
</member>
<member name="image_path" type="String" setter="set_image_path" getter="get_image_path">
Deprecated, in previous versions it determined the location where lightmaps were be saved.
</member>
<member name="light_data" type="BakedLightmapData" setter="set_light_data" getter="get_light_data">
The calculated light data.
</member>
<member name="quality" type="int" setter="set_bake_quality" getter="get_bake_quality" enum="BakedLightmap.BakeQuality" default="1">
Determines the amount of samples per texel used in indirect light baking. The amount of samples for each quality level can be configured in the project settings.
</member>
<member name="use_color" type="bool" setter="set_use_color" getter="is_using_color" default="true">
Store full color values in the lightmap textures. When disabled, lightmap textures will store a single brightness channel. Can be disabled to reduce disk usage if the scene contains only white lights or you don't mind losing color information in indirect lighting.
</member>
<member name="use_denoiser" type="bool" setter="set_use_denoiser" getter="is_using_denoiser" default="true">
When enabled, a lightmap denoiser will be used to reduce the noise inherent to Monte Carlo based global illumination.
</member>
<member name="use_hdr" type="bool" setter="set_use_hdr" getter="is_using_hdr" default="true">
If [code]true[/code], stores the lightmap textures in a high dynamic range format (EXR). If [code]false[/code], stores the lightmap texture in a low dynamic range PNG image. This can be set to [code]false[/code] to reduce disk usage, but light values over 1.0 will be clamped and you may see banding caused by the reduced precision.
[b]Note:[/b] Setting [member use_hdr] to [code]true[/code] will decrease lightmap banding even when using the GLES2 backend or if [member ProjectSettings.rendering/quality/depth/hdr] is [code]false[/code].
</member>
</members>
<constants>
<constant name="BAKE_QUALITY_LOW" value="0" enum="BakeQuality">
The lowest bake quality mode. Fastest to calculate.
</constant>
<constant name="BAKE_QUALITY_MEDIUM" value="1" enum="BakeQuality">
The default bake quality mode.
</constant>
<constant name="BAKE_QUALITY_HIGH" value="2" enum="BakeQuality">
A higher bake quality mode. Takes longer to calculate.
</constant>
<constant name="BAKE_QUALITY_ULTRA" value="3" enum="BakeQuality">
The highest bake quality mode. Takes the longest to calculate.
</constant>
<constant name="BAKE_ERROR_OK" value="0" enum="BakeError">
Baking was successful.
</constant>
<constant name="BAKE_ERROR_NO_SAVE_PATH" value="1" enum="BakeError">
Returns if no viable save path is found. This can happen where an [member image_path] is not specified or when the save location is invalid.
</constant>
<constant name="BAKE_ERROR_NO_MESHES" value="2" enum="BakeError">
Currently unused.
</constant>
<constant name="BAKE_ERROR_CANT_CREATE_IMAGE" value="3" enum="BakeError">
Returns when the baker cannot save per-mesh textures to file.
</constant>
<constant name="BAKE_ERROR_LIGHTMAP_SIZE" value="4" enum="BakeError">
The size of the generated lightmaps is too large.
</constant>
<constant name="BAKE_ERROR_INVALID_MESH" value="5" enum="BakeError">
Some mesh contains UV2 values outside the [code][0,1][/code] range.
</constant>
<constant name="BAKE_ERROR_USER_ABORTED" value="6" enum="BakeError">
Returns if user cancels baking.
</constant>
<constant name="BAKE_ERROR_NO_LIGHTMAPPER" value="7" enum="BakeError">
Returns if lightmapper can't be created. Unless you are using a custom lightmapper, please report this as bug.
</constant>
<constant name="BAKE_ERROR_NO_ROOT" value="8" enum="BakeError">
There is no root node to start baking from. Either provide [code]from_node[/code] argument or attach this node to a parent that should be used as root.
</constant>
<constant name="ENVIRONMENT_MODE_DISABLED" value="0" enum="EnvironmentMode">
No environment is used during baking.
</constant>
<constant name="ENVIRONMENT_MODE_SCENE" value="1" enum="EnvironmentMode">
The baked environment is automatically picked from the current scene.
</constant>
<constant name="ENVIRONMENT_MODE_CUSTOM_SKY" value="2" enum="EnvironmentMode">
A custom sky is used as environment during baking.
</constant>
<constant name="ENVIRONMENT_MODE_CUSTOM_COLOR" value="3" enum="EnvironmentMode">
A custom solid color is used as environment during baking.
</constant>
</constants>
</class>

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="BakedLightmapData" inherits="Resource" version="3.6" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
<methods>
<method name="add_user">
<return type="void" />
<argument index="0" name="path" type="NodePath" />
<argument index="1" name="lightmap" type="Resource" />
<argument index="2" name="lightmap_slice" type="int" />
<argument index="3" name="lightmap_uv_rect" type="Rect2" />
<argument index="4" name="instance" type="int" />
<description>
</description>
</method>
<method name="clear_data">
<return type="void" />
<description>
</description>
</method>
<method name="clear_users">
<return type="void" />
<description>
</description>
</method>
<method name="get_user_count" qualifiers="const">
<return type="int" />
<description>
</description>
</method>
<method name="get_user_lightmap" qualifiers="const">
<return type="Resource" />
<argument index="0" name="user_idx" type="int" />
<description>
</description>
</method>
<method name="get_user_path" qualifiers="const">
<return type="NodePath" />
<argument index="0" name="user_idx" type="int" />
<description>
</description>
</method>
</methods>
<members>
<member name="bounds" type="AABB" setter="set_bounds" getter="get_bounds" default="AABB( 0, 0, 0, 0, 0, 0 )">
</member>
<member name="cell_space_transform" type="Transform" setter="set_cell_space_transform" getter="get_cell_space_transform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
</member>
<member name="cell_subdiv" type="int" setter="set_cell_subdiv" getter="get_cell_subdiv" default="1">
</member>
<member name="energy" type="float" setter="set_energy" getter="get_energy" default="1.0">
Global energy multiplier for baked and dynamic capture objects. This can be changed at run-time without having to bake lightmaps again.
To adjust only the energy of indirect lighting (without affecting direct lighting or emissive materials), adjust [member BakedLightmap.bounce_indirect_energy] and bake lightmaps again.
</member>
<member name="interior" type="bool" setter="set_interior" getter="is_interior" default="false">
Controls whether dynamic capture objects receive environment lighting or not.
</member>
<member name="octree" type="PoolByteArray" setter="set_octree" getter="get_octree" default="PoolByteArray( )">
</member>
</members>
<constants>
</constants>
</class>

View File

@ -109,6 +109,7 @@
#include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/plugins/animation_tree_editor_plugin.h" #include "editor/plugins/animation_tree_editor_plugin.h"
#include "editor/plugins/audio_stream_editor_plugin.h" #include "editor/plugins/audio_stream_editor_plugin.h"
#include "editor/plugins/baked_lightmap_editor_plugin.h"
#include "editor/plugins/bit_map_editor_plugin.h" #include "editor/plugins/bit_map_editor_plugin.h"
#include "editor/plugins/camera_editor_plugin.h" #include "editor/plugins/camera_editor_plugin.h"
#include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/canvas_item_editor_plugin.h"
@ -7171,6 +7172,7 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(CollisionPolygon2DEditorPlugin(this))); add_editor_plugin(memnew(CollisionPolygon2DEditorPlugin(this)));
add_editor_plugin(memnew(SpriteFramesEditorPlugin(this))); add_editor_plugin(memnew(SpriteFramesEditorPlugin(this)));
add_editor_plugin(memnew(TextureRegionEditorPlugin(this))); add_editor_plugin(memnew(TextureRegionEditorPlugin(this)));
add_editor_plugin(memnew(BakedLightmapEditorPlugin(this)));
add_editor_plugin(memnew(RoomManagerEditorPlugin(this))); add_editor_plugin(memnew(RoomManagerEditorPlugin(this)));
add_editor_plugin(memnew(RoomEditorPlugin(this))); add_editor_plugin(memnew(RoomEditorPlugin(this)));
add_editor_plugin(memnew(OccluderEditorPlugin(this))); add_editor_plugin(memnew(OccluderEditorPlugin(this)));

View File

@ -0,0 +1,179 @@
/**************************************************************************/
/* baked_lightmap_editor_plugin.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "baked_lightmap_editor_plugin.h"
#include "editor/editor_file_dialog.h"
void BakedLightmapEditorPlugin::_bake_select_file(const String &p_file) {
if (lightmap) {
BakedLightmap::BakeError err;
if (get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root() == lightmap) {
err = lightmap->bake(lightmap, p_file);
} else {
err = lightmap->bake(lightmap->get_parent(), p_file);
}
switch (err) {
case BakedLightmap::BAKE_ERROR_NO_SAVE_PATH: {
String scene_path = lightmap->get_filename();
if (scene_path == String()) {
scene_path = lightmap->get_owner()->get_filename();
}
if (scene_path == String()) {
EditorNode::get_singleton()->show_warning(TTR("Can't determine a save path for lightmap images.\nSave your scene and try again."));
break;
}
scene_path = scene_path.get_basename() + ".lmbake";
file_dialog->set_current_path(scene_path);
file_dialog->popup_centered_ratio();
} break;
case BakedLightmap::BAKE_ERROR_NO_MESHES:
EditorNode::get_singleton()->show_warning(TTR("No meshes to bake. Make sure they contain an UV2 channel and that the 'Use In Baked Light' and 'Generate Lightmap' flags are on."));
break;
case BakedLightmap::BAKE_ERROR_CANT_CREATE_IMAGE:
EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images, make sure path is writable."));
break;
case BakedLightmap::BAKE_ERROR_LIGHTMAP_SIZE:
EditorNode::get_singleton()->show_warning(TTR("Failed determining lightmap size. Maximum lightmap size too small?"));
break;
case BakedLightmap::BAKE_ERROR_INVALID_MESH:
EditorNode::get_singleton()->show_warning(TTR("Some mesh is invalid. Make sure the UV2 channel values are contained within the [0.0,1.0] square region."));
break;
case BakedLightmap::BAKE_ERROR_NO_LIGHTMAPPER:
EditorNode::get_singleton()->show_warning(TTR("Pandemonium editor was built without ray tracing support, lightmaps can't be baked."));
break;
default: {
}
}
}
}
void BakedLightmapEditorPlugin::_bake() {
_bake_select_file("");
}
void BakedLightmapEditorPlugin::edit(Object *p_object) {
BakedLightmap *s = Object::cast_to<BakedLightmap>(p_object);
if (!s) {
return;
}
lightmap = s;
}
bool BakedLightmapEditorPlugin::handles(Object *p_object) const {
return p_object->is_class("BakedLightmap");
}
void BakedLightmapEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
bake->show();
} else {
bake->hide();
}
}
EditorProgress *BakedLightmapEditorPlugin::tmp_progress = nullptr;
EditorProgress *BakedLightmapEditorPlugin::tmp_subprogress = nullptr;
bool BakedLightmapEditorPlugin::bake_func_step(float p_progress, const String &p_description, void *, bool p_force_refresh) {
if (!tmp_progress) {
tmp_progress = memnew(EditorProgress("bake_lightmaps", TTR("Bake Lightmaps"), 1000, true));
ERR_FAIL_COND_V(tmp_progress == nullptr, false);
}
return tmp_progress->step(p_description, p_progress * 1000, p_force_refresh);
}
bool BakedLightmapEditorPlugin::bake_func_substep(float p_progress, const String &p_description, void *, bool p_force_refresh) {
if (!tmp_subprogress) {
tmp_subprogress = memnew(EditorProgress("bake_lightmaps_substep", "", 1000, true));
ERR_FAIL_COND_V(tmp_subprogress == nullptr, false);
}
return tmp_subprogress->step(p_description, p_progress * 1000, p_force_refresh);
}
void BakedLightmapEditorPlugin::bake_func_end(uint32_t p_time_started) {
if (tmp_progress != nullptr) {
memdelete(tmp_progress);
tmp_progress = nullptr;
}
if (tmp_subprogress != nullptr) {
memdelete(tmp_subprogress);
tmp_subprogress = nullptr;
}
const int time_taken = (OS::get_singleton()->get_ticks_msec() - p_time_started) * 0.001;
if (time_taken >= 1) {
// Only print a message and request attention if baking lightmaps took at least 1 second.
// Otherwise, attempting to bake in an erroneous situation (e.g. no meshes to bake)
// would print the "done baking lightmaps" message and request attention for no good reason.
print_line(vformat("Done baking lightmaps in %02d:%02d:%02d.", time_taken / 3600, (time_taken % 3600) / 60, time_taken % 60));
// Request attention in case the user was doing something else.
// Baking lightmaps is likely the editor task that can take the most time,
// so only request the attention for baking lightmaps.
OS::get_singleton()->request_attention();
}
}
void BakedLightmapEditorPlugin::_bind_methods() {
ClassDB::bind_method("_bake", &BakedLightmapEditorPlugin::_bake);
ClassDB::bind_method("_bake_select_file", &BakedLightmapEditorPlugin::_bake_select_file);
}
BakedLightmapEditorPlugin::BakedLightmapEditorPlugin(EditorNode *p_node) {
editor = p_node;
bake = memnew(ToolButton);
bake->set_icon(editor->get_gui_base()->get_theme_icon("Bake", "EditorIcons"));
bake->set_tooltip(TTR("Bake Lightmaps"));
bake->hide();
bake->connect("pressed", this, "_bake");
file_dialog = memnew(EditorFileDialog);
file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
file_dialog->add_filter("*.lmbake ; " + TTR("LightMap Bake"));
file_dialog->set_title(TTR("Select lightmap bake file:"));
file_dialog->connect("file_selected", this, "_bake_select_file");
bake->add_child(file_dialog);
add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake);
lightmap = nullptr;
BakedLightmap::bake_step_function = bake_func_step;
BakedLightmap::bake_substep_function = bake_func_substep;
BakedLightmap::bake_end_function = bake_func_end;
}
BakedLightmapEditorPlugin::~BakedLightmapEditorPlugin() {
}

View File

@ -0,0 +1,74 @@
/**************************************************************************/
/* baked_lightmap_editor_plugin.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef BAKED_LIGHTMAP_EDITOR_PLUGIN_H
#define BAKED_LIGHTMAP_EDITOR_PLUGIN_H
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/3d/baked_lightmap.h"
#include "scene/resources/material/material.h"
class EditorFileDialog;
class BakedLightmapEditorPlugin : public EditorPlugin {
GDCLASS(BakedLightmapEditorPlugin, EditorPlugin);
BakedLightmap *lightmap;
ToolButton *bake;
EditorNode *editor;
EditorFileDialog *file_dialog;
static EditorProgress *tmp_progress;
static EditorProgress *tmp_subprogress;
static bool bake_func_step(float p_progress, const String &p_description, void *, bool p_force_refresh);
static bool bake_func_substep(float p_progress, const String &p_description, void *, bool p_force_refresh);
static void bake_func_end(uint32_t p_time_started);
void _bake_select_file(const String &p_file);
void _bake();
protected:
static void _bind_methods();
public:
virtual String get_name() const { return "BakedLightmap"; }
bool has_main_screen() const { return false; }
virtual void edit(Object *p_object);
virtual bool handles(Object *p_object) const;
virtual void make_visible(bool p_visible);
BakedLightmapEditorPlugin(EditorNode *p_node);
~BakedLightmapEditorPlugin();
};
#endif // BAKED_LIGHTMAP_EDITOR_PLUGIN_H

View File

@ -7188,6 +7188,7 @@ void SpatialEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<VisibilityNotifierGizmoPlugin>(memnew(VisibilityNotifierGizmoPlugin))); add_gizmo_plugin(Ref<VisibilityNotifierGizmoPlugin>(memnew(VisibilityNotifierGizmoPlugin)));
add_gizmo_plugin(Ref<CPUParticlesGizmoPlugin>(memnew(CPUParticlesGizmoPlugin))); add_gizmo_plugin(Ref<CPUParticlesGizmoPlugin>(memnew(CPUParticlesGizmoPlugin)));
add_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin))); add_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin)));
add_gizmo_plugin(Ref<BakedIndirectLightGizmoPlugin>(memnew(BakedIndirectLightGizmoPlugin)));
add_gizmo_plugin(Ref<CollisionObjectGizmoPlugin>(memnew(CollisionObjectGizmoPlugin))); add_gizmo_plugin(Ref<CollisionObjectGizmoPlugin>(memnew(CollisionObjectGizmoPlugin)));
add_gizmo_plugin(Ref<CollisionShapeSpatialGizmoPlugin>(memnew(CollisionShapeSpatialGizmoPlugin))); add_gizmo_plugin(Ref<CollisionShapeSpatialGizmoPlugin>(memnew(CollisionShapeSpatialGizmoPlugin)));
add_gizmo_plugin(Ref<CollisionPolygonSpatialGizmoPlugin>(memnew(CollisionPolygonSpatialGizmoPlugin))); add_gizmo_plugin(Ref<CollisionPolygonSpatialGizmoPlugin>(memnew(CollisionPolygonSpatialGizmoPlugin)));

View File

@ -56,6 +56,7 @@
#include "editor/editor_node.h" #include "editor/editor_node.h"
#include "editor/editor_settings.h" #include "editor/editor_settings.h"
#include "scene/3d/audio_stream_player_3d.h" #include "scene/3d/audio_stream_player_3d.h"
#include "scene/3d/baked_lightmap.h"
#include "scene/3d/camera.h" #include "scene/3d/camera.h"
#include "scene/3d/collision_object.h" #include "scene/3d/collision_object.h"
#include "scene/3d/collision_polygon.h" #include "scene/3d/collision_polygon.h"
@ -2848,6 +2849,135 @@ void ReflectionProbeGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
//// ////
BakedIndirectLightGizmoPlugin::BakedIndirectLightGizmoPlugin() {
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/baked_indirect_light", Color(0.5, 0.6, 1));
create_material("baked_indirect_light_material", gizmo_color);
gizmo_color.a = 0.1;
create_material("baked_indirect_light_internal_material", gizmo_color);
create_icon_material("baked_indirect_light_icon", SpatialEditor::get_singleton()->get_theme_icon("GizmoBakedLightmap", "EditorIcons"));
create_handle_material("handles");
}
String BakedIndirectLightGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_id, bool p_secondary) const {
switch (p_id) {
case 0:
return "Extents X";
case 1:
return "Extents Y";
case 2:
return "Extents Z";
}
return "";
}
Variant BakedIndirectLightGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_id, bool p_secondary) const {
BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node());
return baker->get_extents();
}
void BakedIndirectLightGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_id, bool p_secondary, Camera *p_camera, const Point2 &p_point) {
BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node());
Transform gt = baker->get_global_transform();
Transform gi = gt.affine_inverse();
Vector3 extents = baker->get_extents();
Vector3 ray_from = p_camera->project_ray_origin(p_point);
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
Vector3 axis;
axis[p_id] = 1.0;
Vector3 ra, rb;
Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
float d = ra[p_id];
if (SpatialEditor::get_singleton()->is_snap_enabled()) {
d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
}
if (d < 0.001) {
d = 0.001;
}
extents[p_id] = d;
baker->set_extents(extents);
}
void BakedIndirectLightGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node());
Vector3 restore = p_restore;
if (p_cancel) {
baker->set_extents(restore);
return;
}
UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
ur->create_action(TTR("Change Probe Extents"));
ur->add_do_method(baker, "set_extents", baker->get_extents());
ur->add_undo_method(baker, "set_extents", restore);
ur->commit_action();
}
bool BakedIndirectLightGizmoPlugin::has_gizmo(Spatial *p_spatial) {
return Object::cast_to<BakedLightmap>(p_spatial) != nullptr;
}
String BakedIndirectLightGizmoPlugin::get_gizmo_name() const {
return "BakedLightmap";
}
int BakedIndirectLightGizmoPlugin::get_priority() const {
return -1;
}
void BakedIndirectLightGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node());
Ref<Material> material = get_material("baked_indirect_light_material", p_gizmo);
Ref<Material> icon = get_material("baked_indirect_light_icon", p_gizmo);
Ref<Material> material_internal = get_material("baked_indirect_light_internal_material", p_gizmo);
p_gizmo->clear();
Vector<Vector3> lines;
Vector3 extents = baker->get_extents();
AABB aabb = AABB(-extents, extents * 2);
for (int i = 0; i < 12; i++) {
Vector3 a, b;
aabb.get_edge(i, a, b);
lines.push_back(a);
lines.push_back(b);
}
p_gizmo->add_lines(lines, material);
Vector<Vector3> handles;
for (int i = 0; i < 3; i++) {
Vector3 ax;
ax[i] = aabb.position[i] + aabb.size[i];
handles.push_back(ax);
}
if (p_gizmo->is_selected()) {
p_gizmo->add_solid_box(material_internal, aabb.get_size());
}
p_gizmo->add_unscaled_billboard(icon, 0.05);
p_gizmo->add_handles(handles, get_material("handles"));
}
////
CollisionObjectGizmoPlugin::CollisionObjectGizmoPlugin() { CollisionObjectGizmoPlugin::CollisionObjectGizmoPlugin() {
const Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); const Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
create_material("shape_material", gizmo_color); create_material("shape_material", gizmo_color);

View File

@ -453,6 +453,23 @@ public:
ReflectionProbeGizmoPlugin(); ReflectionProbeGizmoPlugin();
}; };
class BakedIndirectLightGizmoPlugin : public EditorSpatialGizmoPlugin {
GDCLASS(BakedIndirectLightGizmoPlugin, EditorSpatialGizmoPlugin);
public:
bool has_gizmo(Spatial *p_spatial);
String get_gizmo_name() const;
int get_priority() const;
void redraw(EditorSpatialGizmo *p_gizmo);
String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_id, bool p_secondary) const;
Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_id, bool p_secondary) const;
void set_handle(EditorSpatialGizmo *p_gizmo, int p_id, bool p_secondary, Camera *p_camera, const Point2 &p_point);
void commit_handle(EditorSpatialGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false);
BakedIndirectLightGizmoPlugin();
};
class CollisionObjectGizmoPlugin : public EditorSpatialGizmoPlugin { class CollisionObjectGizmoPlugin : public EditorSpatialGizmoPlugin {
GDCLASS(CollisionObjectGizmoPlugin, EditorSpatialGizmoPlugin); GDCLASS(CollisionObjectGizmoPlugin, EditorSpatialGizmoPlugin);

1668
scene/3d/baked_lightmap.cpp Normal file

File diff suppressed because it is too large Load Diff

292
scene/3d/baked_lightmap.h Normal file
View File

@ -0,0 +1,292 @@
/**************************************************************************/
/* baked_lightmap.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef BAKED_LIGHTMAP_H
#define BAKED_LIGHTMAP_H
#include "core/containers/local_vector.h"
#include "scene/resources/mesh/mesh.h"
#include "multimesh_instance.h"
#include "scene/3d/light.h"
#include "scene/3d/lightmapper.h"
#include "scene/3d/visual_instance.h"
class Sky;
class Environment3D;
class BakedLightmapData : public Resource {
GDCLASS(BakedLightmapData, Resource);
RES_BASE_EXTENSION("lmbake")
RID baked_light;
AABB bounds;
float energy;
bool interior;
int cell_subdiv;
Transform cell_space_xform;
struct User {
NodePath path;
struct {
Ref<Texture> single;
Ref<TextureLayered> layered;
} lightmap;
int lightmap_slice;
Rect2 lightmap_uv_rect;
int instance_index;
};
Vector<User> users;
void _set_user_data(const Array &p_data);
Array _get_user_data() const;
protected:
static void _bind_methods();
public:
void set_bounds(const AABB &p_bounds);
AABB get_bounds() const;
void set_octree(const PoolVector<uint8_t> &p_octree);
PoolVector<uint8_t> get_octree() const;
void set_cell_space_transform(const Transform &p_xform);
Transform get_cell_space_transform() const;
void set_cell_subdiv(int p_cell_subdiv);
int get_cell_subdiv() const;
void set_energy(float p_energy);
float get_energy() const;
void set_interior(bool p_interior);
bool is_interior() const;
void add_user(const NodePath &p_path, const Ref<Resource> &p_lightmap, int p_lightmap_slice, const Rect2 &p_lightmap_uv_rect, int p_instance);
int get_user_count() const;
NodePath get_user_path(int p_user) const;
Ref<Resource> get_user_lightmap(int p_user) const;
int get_user_lightmap_slice(int p_user) const;
Rect2 get_user_lightmap_uv_rect(int p_user) const;
int get_user_instance(int p_user) const;
void clear_users();
void clear_data();
virtual RID get_rid() const;
BakedLightmapData();
~BakedLightmapData();
};
class BakedLightmap : public VisualInstance {
GDCLASS(BakedLightmap, VisualInstance);
public:
enum BakeQuality {
BAKE_QUALITY_LOW,
BAKE_QUALITY_MEDIUM,
BAKE_QUALITY_HIGH,
BAKE_QUALITY_ULTRA
};
enum BakeError {
BAKE_ERROR_OK,
BAKE_ERROR_NO_SAVE_PATH,
BAKE_ERROR_NO_MESHES,
BAKE_ERROR_CANT_CREATE_IMAGE,
BAKE_ERROR_LIGHTMAP_SIZE,
BAKE_ERROR_INVALID_MESH,
BAKE_ERROR_USER_ABORTED,
BAKE_ERROR_NO_LIGHTMAPPER,
BAKE_ERROR_NO_ROOT,
};
enum EnvironmentMode {
ENVIRONMENT_MODE_DISABLED,
ENVIRONMENT_MODE_SCENE,
ENVIRONMENT_MODE_CUSTOM_SKY,
ENVIRONMENT_MODE_CUSTOM_COLOR
};
struct BakeStepUD {
Lightmapper::BakeStepFunc func;
void *ud;
float from_percent;
float to_percent;
};
struct LightsFound {
Transform xform;
Light *light;
};
struct MeshesFound {
Transform xform;
NodePath node_path;
int32_t subindex;
Ref<Mesh> mesh;
int32_t lightmap_scale;
Vector<Ref<Material>> overrides;
bool cast_shadows;
bool generate_lightmap;
};
private:
Vector3 extents;
float default_texels_per_unit;
float bias;
BakeQuality bake_quality;
bool generate_atlas;
int max_atlas_size;
bool capture_enabled;
int bounces;
float bounce_indirect_energy;
bool use_denoiser;
bool use_hdr;
bool use_color;
EnvironmentMode environment_mode;
Ref<Sky> environment_custom_sky;
Vector3 environment_custom_sky_rotation_degrees;
Color environment_custom_color;
float environment_custom_energy;
Color environment_min_light;
BakeQuality capture_quality;
float capture_propagation;
float capture_cell_size;
String image_path; // (Deprecated property)
Ref<BakedLightmapData> light_data;
void _assign_lightmaps();
void _clear_lightmaps();
void _get_material_images(const MeshesFound &p_found_mesh, Lightmapper::MeshData &r_mesh_data, Vector<Ref<Texture>> &r_albedo_textures, Vector<Ref<Texture>> &r_emission_textures);
Ref<Image> _get_irradiance_from_sky(Ref<Sky> p_sky, float p_energy, Vector2i p_size);
Ref<Image> _get_irradiance_map(Ref<Environment3D> p_env, Vector2i p_size);
void _find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound> &meshes, Vector<LightsFound> &lights);
Vector2i _compute_lightmap_size(const MeshesFound &p_mesh);
static bool _lightmap_bake_step_function(float p_completion, const String &p_text, void *ud, bool p_refresh);
void _save_image(String &r_base_path, Ref<Image> p_img, bool p_use_srgb);
protected:
static void _bind_methods();
void _validate_property(PropertyInfo &property) const;
void _notification(int p_what);
public:
static Lightmapper::BakeStepFunc bake_step_function;
static Lightmapper::BakeStepFunc bake_substep_function;
static Lightmapper::BakeEndFunc bake_end_function;
void set_light_data(const Ref<BakedLightmapData> &p_data);
Ref<BakedLightmapData> get_light_data() const;
void set_capture_cell_size(float p_cell_size);
float get_capture_cell_size() const;
void set_extents(const Vector3 &p_extents);
Vector3 get_extents() const;
void set_default_texels_per_unit(const float &p_extents);
float get_default_texels_per_unit() const;
void set_capture_propagation(float p_propagation);
float get_capture_propagation() const;
void set_capture_quality(BakeQuality p_quality);
BakeQuality get_capture_quality() const;
void set_bake_quality(BakeQuality p_quality);
BakeQuality get_bake_quality() const;
void set_generate_atlas(bool p_enabled);
bool is_generate_atlas_enabled() const;
void set_max_atlas_size(int p_size);
int get_max_atlas_size() const;
void set_capture_enabled(bool p_enable);
bool get_capture_enabled() const;
void set_image_path(const String &p_path);
String get_image_path() const;
void set_environment_mode(EnvironmentMode p_mode);
EnvironmentMode get_environment_mode() const;
void set_environment_custom_sky(const Ref<Sky> &p_sky);
Ref<Sky> get_environment_custom_sky() const;
void set_environment_custom_sky_rotation_degrees(const Vector3 &p_rotation);
Vector3 get_environment_custom_sky_rotation_degrees() const;
void set_environment_custom_color(const Color &p_color);
Color get_environment_custom_color() const;
void set_environment_custom_energy(float p_energy);
float get_environment_custom_energy() const;
void set_environment_min_light(Color p_min_light);
Color get_environment_min_light() const;
void set_use_denoiser(bool p_enable);
bool is_using_denoiser() const;
void set_use_hdr(bool p_enable);
bool is_using_hdr() const;
void set_use_color(bool p_enable);
bool is_using_color() const;
void set_bounces(int p_bounces);
int get_bounces() const;
void set_bounce_indirect_energy(float p_indirect_energy);
float get_bounce_indirect_energy() const;
void set_bias(float p_bias);
float get_bias() const;
AABB get_aabb() const;
PoolVector<Face3> get_faces(uint32_t p_usage_flags) const;
BakeError bake(Node *p_from_node, String p_data_save_path = "");
BakedLightmap();
};
VARIANT_ENUM_CAST(BakedLightmap::BakeQuality);
VARIANT_ENUM_CAST(BakedLightmap::BakeError);
VARIANT_ENUM_CAST(BakedLightmap::EnvironmentMode);
#endif // BAKED_LIGHTMAP_H

76
scene/3d/lightmapper.cpp Normal file
View File

@ -0,0 +1,76 @@
/**************************************************************************/
/* lightmapper.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "lightmapper.h"
LightmapDenoiser *(*LightmapDenoiser::create_function)() = nullptr;
Ref<LightmapDenoiser> LightmapDenoiser::create() {
if (create_function) {
return Ref<LightmapDenoiser>(create_function());
}
return Ref<LightmapDenoiser>();
}
LightmapRaycaster *(*LightmapRaycaster::create_function)() = nullptr;
Ref<LightmapRaycaster> LightmapRaycaster::create() {
if (create_function) {
return Ref<LightmapRaycaster>(create_function());
}
return Ref<LightmapRaycaster>();
}
Lightmapper::CreateFunc Lightmapper::create_custom = nullptr;
Lightmapper::CreateFunc Lightmapper::create_gpu = nullptr;
Lightmapper::CreateFunc Lightmapper::create_cpu = nullptr;
Ref<Lightmapper> Lightmapper::create() {
Lightmapper *lm = nullptr;
if (create_custom) {
lm = create_custom();
}
if (!lm && create_gpu) {
lm = create_gpu();
}
if (!lm && create_cpu) {
lm = create_cpu();
}
if (!lm) {
return Ref<Lightmapper>();
} else {
return Ref<Lightmapper>(lm);
}
}
Lightmapper::Lightmapper() {
}

197
scene/3d/lightmapper.h Normal file
View File

@ -0,0 +1,197 @@
/**************************************************************************/
/* lightmapper.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef LIGHTMAPPER_H
#define LIGHTMAPPER_H
#include "scene/resources/mesh/mesh.h"
#if !defined(__aligned)
#if defined(_WIN32) && defined(_MSC_VER)
#define __aligned(...) __declspec(align(__VA_ARGS__))
#else
#define __aligned(...) __attribute__((aligned(__VA_ARGS__)))
#endif
#endif
class LightmapDenoiser : public Reference {
GDCLASS(LightmapDenoiser, Reference)
protected:
static LightmapDenoiser *(*create_function)();
public:
virtual Ref<Image> denoise_image(const Ref<Image> &p_image) = 0;
static Ref<LightmapDenoiser> create();
};
class LightmapRaycaster : public Reference {
GDCLASS(LightmapRaycaster, Reference)
protected:
static LightmapRaycaster *(*create_function)();
public:
// compatible with embree3 rays
struct __aligned(16) Ray {
const static unsigned int INVALID_GEOMETRY_ID = ((unsigned int)-1); // from rtcore_common.h
/*! Default construction does nothing. */
_FORCE_INLINE_ Ray() :
geomID(INVALID_GEOMETRY_ID) {}
/*! Constructs a ray from origin, direction, and ray segment. Near
* has to be smaller than far. */
_FORCE_INLINE_ Ray(const Vector3 &org,
const Vector3 &dir,
float tnear = 0.0f,
float tfar = INFINITY) :
org(org),
tnear(tnear),
dir(dir),
time(0.0f),
tfar(tfar),
mask(-1),
u(0.0),
v(0.0),
primID(INVALID_GEOMETRY_ID),
geomID(INVALID_GEOMETRY_ID),
instID(INVALID_GEOMETRY_ID) {}
/*! Tests if we hit something. */
_FORCE_INLINE_ explicit operator bool() const { return geomID != INVALID_GEOMETRY_ID; }
public:
Vector3 org; //!< Ray origin + tnear
float tnear; //!< Start of ray segment
Vector3 dir; //!< Ray direction + tfar
float time; //!< Time of this ray for motion blur.
float tfar; //!< End of ray segment
unsigned int mask; //!< used to mask out objects during traversal
unsigned int id; //!< ray ID
unsigned int flags; //!< ray flags
Vector3 normal; //!< Not normalized geometry normal
float u; //!< Barycentric u coordinate of hit
float v; //!< Barycentric v coordinate of hit
unsigned int primID; //!< primitive ID
unsigned int geomID; //!< geometry ID
unsigned int instID; //!< instance ID
};
virtual bool intersect(Ray &p_ray) = 0;
virtual void intersect(Vector<Ray> &r_rays) = 0;
virtual void add_mesh(const Vector<Vector3> &p_vertices, const Vector<Vector3> &p_normals, const Vector<Vector2> &p_uv2s, unsigned int p_id) = 0;
virtual void set_mesh_alpha_texture(Ref<Image> p_alpha_texture, unsigned int p_id) = 0;
virtual void commit() = 0;
virtual void set_mesh_filter(const RBSet<int> &p_mesh_ids) = 0;
virtual void clear_mesh_filter() = 0;
static Ref<LightmapRaycaster> create();
};
class Lightmapper : public Reference {
GDCLASS(Lightmapper, Reference)
public:
enum LightType {
LIGHT_TYPE_DIRECTIONAL,
LIGHT_TYPE_OMNI,
LIGHT_TYPE_SPOT
};
enum BakeError {
BAKE_ERROR_LIGHTMAP_TOO_SMALL,
BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES,
BAKE_ERROR_NO_MESHES,
BAKE_ERROR_USER_ABORTED,
BAKE_ERROR_NO_RAYCASTER,
BAKE_OK
};
enum BakeQuality {
BAKE_QUALITY_LOW,
BAKE_QUALITY_MEDIUM,
BAKE_QUALITY_HIGH,
BAKE_QUALITY_ULTRA,
};
typedef Lightmapper *(*CreateFunc)();
static CreateFunc create_custom;
static CreateFunc create_gpu;
static CreateFunc create_cpu;
protected:
public:
typedef bool (*BakeStepFunc)(float, const String &, void *, bool); //progress, step description, userdata, force refresh
typedef void (*BakeEndFunc)(uint32_t); // time_started
struct MeshData {
struct TextureDef {
RID tex_rid;
Color mul;
Color add;
};
//triangle data
Vector<Vector3> points;
Vector<Vector2> uv;
Vector<Vector2> uv2;
Vector<Vector3> normal;
Vector<TextureDef> albedo;
Vector<TextureDef> emission;
Vector<int> surface_facecounts;
Variant userdata;
};
virtual void add_albedo_texture(Ref<Texture> p_texture) = 0;
virtual void add_emission_texture(Ref<Texture> p_texture) = 0;
virtual void add_mesh(const MeshData &p_mesh, Vector2i p_size) = 0;
virtual void add_directional_light(bool p_bake_direct, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_size) = 0;
virtual void add_omni_light(bool p_bake_direct, const Vector3 &p_position, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation, float p_size) = 0;
virtual void add_spot_light(bool p_bake_direct, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size) = 0;
virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bounce_indirect_energy, float p_bias, bool p_generate_atlas, int p_max_texture_size, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_step_userdata = nullptr, BakeStepFunc p_substep_function = nullptr) = 0;
virtual int get_bake_texture_count() const = 0;
virtual Ref<Image> get_bake_texture(int p_index) const = 0;
virtual int get_bake_mesh_count() const = 0;
virtual Variant get_bake_mesh_userdata(int p_index) const = 0;
virtual Rect2 get_bake_mesh_uv_scale(int p_index) const = 0;
virtual int get_bake_mesh_texture_slice(int p_index) const = 0;
static Ref<Lightmapper> create();
Lightmapper();
};
#endif // LIGHTMAPPER_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,173 @@
/**************************************************************************/
/* voxel_light_baker.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef VOXEL_LIGHT_BAKER_H
#define VOXEL_LIGHT_BAKER_H
#include "scene/3d/mesh_instance.h"
#include "scene/resources/mesh/multimesh.h"
class Material;
class VoxelLightBaker {
public:
enum DebugMode {
DEBUG_ALBEDO,
DEBUG_LIGHT
};
enum BakeQuality {
BAKE_QUALITY_LOW,
BAKE_QUALITY_MEDIUM,
BAKE_QUALITY_HIGH
};
enum BakeMode {
BAKE_MODE_CONE_TRACE,
BAKE_MODE_RAY_TRACE,
};
private:
enum {
CHILD_EMPTY = 0xFFFFFFFF
};
struct Cell {
uint32_t children[8];
float albedo[3]; //albedo in RGB24
float emission[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast)
float normal[3];
uint32_t used_sides;
float alpha; //used for upsampling
int level;
Cell() {
for (int i = 0; i < 8; i++) {
children[i] = CHILD_EMPTY;
}
for (int i = 0; i < 3; i++) {
emission[i] = 0;
albedo[i] = 0;
normal[i] = 0;
}
alpha = 0;
used_sides = 0;
level = 0;
}
};
Vector<Cell> bake_cells;
int cell_subdiv;
struct Light {
int x, y, z;
float accum[6][3]; //rgb anisotropic
float direct_accum[6][3]; //for direct bake
int next_leaf;
Light() {
x = y = z = 0;
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 3; j++) {
accum[i][j] = 0;
direct_accum[i][j] = 0;
}
}
next_leaf = 0;
}
};
int first_leaf;
Vector<Light> bake_light;
struct MaterialCache {
//128x128 textures
Vector<Color> albedo;
Vector<Color> emission;
};
RBMap<Ref<Material>, MaterialCache> material_cache;
int leaf_voxel_count;
bool direct_lights_baked;
AABB original_bounds;
AABB po2_bounds;
int axis_cell_size[3];
Transform to_cell_space;
int color_scan_cell_width;
int bake_texture_size;
float cell_size;
float propagation;
BakeQuality bake_quality;
int max_original_cells;
void _init_light_plot(int p_idx, int p_level, int p_x, int p_y, int p_z, uint32_t p_parent);
Vector<Color> _get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add);
MaterialCache _get_material_cache(Ref<Material> p_material);
void _plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb);
void _fixup_plot(int p_idx, int p_level);
void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx, DebugMode p_mode);
void _check_init_light();
uint32_t _find_cell_at_pos(const Cell *cells, int x, int y, int z);
public:
void begin_bake(int p_subdiv, const AABB &p_bounds);
void plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material);
void begin_bake_light(BakeQuality p_quality = BAKE_QUALITY_MEDIUM, float p_propagation = 0.85);
void plot_light_directional(const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_energy, bool p_direct);
void plot_light_omni(const Vector3 &p_pos, const Color &p_color, float p_energy, float p_indirect_energy, float p_radius, float p_attenutation, bool p_direct);
void plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axis, const Color &p_color, float p_energy, float p_indirect_energy, float p_radius, float p_attenutation, float p_spot_angle, float p_spot_attenuation, bool p_direct);
void end_bake();
struct LightMapData {
int width;
int height;
PoolVector<float> light;
};
PoolVector<int> create_gi_probe_data();
Ref<MultiMesh> create_debug_multimesh(DebugMode p_mode = DEBUG_ALBEDO);
PoolVector<uint8_t> create_capture_octree(int p_subdiv);
float get_cell_size() const;
Transform get_to_cell_space_xform() const;
VoxelLightBaker();
};
#endif // VOXEL_LIGHT_BAKER_H

View File

@ -72,6 +72,7 @@
#include "scene/2d/y_sort.h" #include "scene/2d/y_sort.h"
#include "scene/3d/label_3d.h" #include "scene/3d/label_3d.h"
#include "scene/3d/world_environment_3d.h" #include "scene/3d/world_environment_3d.h"
#include "scene/3d/baked_lightmap.h"
#include "scene/animation/animation_blend_space_1d.h" #include "scene/animation/animation_blend_space_1d.h"
#include "scene/animation/animation_blend_space_2d.h" #include "scene/animation/animation_blend_space_2d.h"
#include "scene/animation/animation_blend_tree.h" #include "scene/animation/animation_blend_tree.h"
@ -459,6 +460,8 @@ void register_scene_types() {
ClassDB::register_class<OmniLight>(); ClassDB::register_class<OmniLight>();
ClassDB::register_class<SpotLight>(); ClassDB::register_class<SpotLight>();
ClassDB::register_class<ReflectionProbe>(); ClassDB::register_class<ReflectionProbe>();
ClassDB::register_class<BakedLightmap>();
ClassDB::register_class<BakedLightmapData>();
ClassDB::register_class<CPUParticles>(); ClassDB::register_class<CPUParticles>();
ClassDB::register_class<Position3D>(); ClassDB::register_class<Position3D>();
ClassDB::register_class<NavigationMeshInstance>(); ClassDB::register_class<NavigationMeshInstance>();