Batch of lightmapper fixes and minor improvements

- Fix objects with no material being considered as fully transparent by the lightmapper.
- Added "environment_min_light" property: gives artistic control over the shadow color.
- Fixed "Custom Color" environment mode, it was ignored before.
- Added "interior" property to BakedLightmapData: controls whether dynamic capture objects receive environment light or not.
- Automatically update dynamic capture objects when the capture data changes (also works for "energy" which used to require object movement to trigger the update).
- Added "use_in_baked_light" property to GridMap: controls whether the GridMap will be included in BakedLightmap bakes.
- Set "flush zero" and "denormal zero" mode for SSE2 instructions in the Embree raycaster. According to Embree docs it should give a performance improvement.
This commit is contained in:
JFonS 2021-03-11 13:34:57 +01:00
parent 0e0d73c011
commit e2c28675ef
24 changed files with 229 additions and 30 deletions

View file

@ -5,7 +5,6 @@
</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]Note:[/b] This node has many known bugs and will be [url=https://godotengine.org/article/godot-40-will-get-new-modernized-lightmapper]rewritten for Godot 4.0[/url]. See [url=https://github.com/godotengine/godot/issues/30929]GitHub issue #30929[/url].
</description>
<tutorials>
<link>https://docs.godotengine.org/en/3.2/tutorials/3d/baked_lightmaps.html</link>
@ -63,6 +62,9 @@
<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>

View file

@ -66,6 +66,10 @@
<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.
</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>

View file

@ -2323,6 +2323,15 @@
Returns the cell transform for this lightmap capture's octree.
</description>
</method>
<method name="lightmap_capture_is_interior" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="capture" type="RID">
</argument>
<description>
Returns [code]true[/code] if capture is in "interior" mode.
</description>
</method>
<method name="lightmap_capture_set_bounds">
<return type="void">
</return>
@ -2345,6 +2354,17 @@
Sets the energy multiplier for this lightmap capture. Equivalent to [member BakedLightmapData.energy].
</description>
</method>
<method name="lightmap_capture_set_interior">
<return type="void">
</return>
<argument index="0" name="capture" type="RID">
</argument>
<argument index="1" name="interior" type="bool">
</argument>
<description>
Sets the "interior" mode for this lightmap capture. Equivalent to [member BakedLightmapData.interior].
</description>
</method>
<method name="lightmap_capture_set_octree">
<return type="void">
</return>

View file

@ -655,6 +655,8 @@ public:
int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const { return 0; }
void lightmap_capture_set_energy(RID p_capture, float p_energy) {}
float lightmap_capture_get_energy(RID p_capture) const { return 0.0; }
void lightmap_capture_set_interior(RID p_capture, bool p_interior) {}
bool lightmap_capture_is_interior(RID p_capture) const { return false; }
const PoolVector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const {
const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND_V(!capture, NULL);

View file

@ -2598,7 +2598,6 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
if (use_lightmap_capture) { //this is per instance, must be set always if present
glUniform4fv(state.scene_shader.get_uniform_location(SceneShaderGLES2::LIGHTMAP_CAPTURES), 12, (const GLfloat *)e->instance->lightmap_capture_data.ptr());
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHTMAP_CAPTURE_SKY, false);
}
_render_geometry(e);

View file

@ -4521,6 +4521,10 @@ void RasterizerStorageGLES2::lightmap_capture_set_energy(RID p_capture, float p_
LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND(!capture);
capture->energy = p_energy;
if (!capture->update_list.in_list()) {
capture_update_list.add(&capture->update_list);
}
}
float RasterizerStorageGLES2::lightmap_capture_get_energy(RID p_capture) const {
@ -4530,6 +4534,30 @@ float RasterizerStorageGLES2::lightmap_capture_get_energy(RID p_capture) const {
return capture->energy;
}
void RasterizerStorageGLES2::lightmap_capture_set_interior(RID p_capture, bool p_interior) {
LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND(!capture);
capture->interior = p_interior;
if (!capture->update_list.in_list()) {
capture_update_list.add(&capture->update_list);
}
}
bool RasterizerStorageGLES2::lightmap_capture_is_interior(RID p_capture) const {
const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND_V(!capture, false);
return capture->interior;
}
void RasterizerStorageGLES2::update_dirty_captures() {
while (capture_update_list.first()) {
LightmapCapture *capture = capture_update_list.first()->self();
capture->instance_change_notify(false, true);
capture_update_list.remove(capture_update_list.first());
}
}
const PoolVector<RasterizerStorage::LightmapCaptureOctree> *RasterizerStorageGLES2::lightmap_capture_get_octree_ptr(RID p_capture) const {
const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND_V(!capture, NULL);
@ -6361,6 +6389,7 @@ void RasterizerStorageGLES2::update_dirty_resources() {
update_dirty_materials();
update_dirty_skeletons();
update_dirty_multimeshes();
update_dirty_captures();
}
RasterizerStorageGLES2::RasterizerStorageGLES2() {

View file

@ -1096,12 +1096,22 @@ public:
Transform cell_xform;
int cell_subdiv;
float energy;
LightmapCapture() {
bool interior;
SelfList<LightmapCapture> update_list;
LightmapCapture() :
update_list(this) {
energy = 1.0;
cell_subdiv = 1;
interior = false;
}
};
SelfList<LightmapCapture>::List capture_update_list;
void update_dirty_captures();
mutable RID_Owner<LightmapCapture> lightmap_capture_data_owner;
virtual RID lightmap_capture_create();
@ -1115,6 +1125,9 @@ public:
virtual int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const;
virtual void lightmap_capture_set_energy(RID p_capture, float p_energy);
virtual float lightmap_capture_get_energy(RID p_capture) const;
virtual void lightmap_capture_set_interior(RID p_capture, bool p_interior);
virtual bool lightmap_capture_is_interior(RID p_capture) const;
virtual const PoolVector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const;
/* PARTICLES */

View file

@ -956,8 +956,6 @@ vec4 texture2D_bicubic(sampler2D tex, vec2 uv) {
#ifdef USE_LIGHTMAP_CAPTURE
uniform mediump vec4 lightmap_captures[12];
uniform bool lightmap_capture_sky;
#endif
#ifdef USE_RADIANCE_MAP
@ -1781,8 +1779,9 @@ FRAGMENT_SHADER_CODE
captured /= sum;
if (lightmap_capture_sky) {
ambient_light = mix(ambient_light, captured.rgb, captured.a);
// Alpha channel is used to indicate if dynamic objects keep the environment lighting
if (lightmap_captures[0].a > 0.5) {
ambient_light += captured.rgb;
} else {
ambient_light = captured.rgb;
}

View file

@ -1941,7 +1941,6 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e, const Transform
} else if (!e->instance->lightmap_capture_data.empty()) {
glUniform4fv(state.scene_shader.get_uniform_location(SceneShaderGLES3::LIGHTMAP_CAPTURES), 12, (const GLfloat *)e->instance->lightmap_capture_data.ptr());
state.scene_shader.set_uniform(SceneShaderGLES3::LIGHTMAP_CAPTURE_SKY, false);
} else if (e->instance->lightmap.is_valid()) {
RasterizerStorageGLES3::Texture *lightmap = storage->texture_owner.getornull(e->instance->lightmap);

View file

@ -6385,6 +6385,10 @@ void RasterizerStorageGLES3::lightmap_capture_set_energy(RID p_capture, float p_
LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND(!capture);
capture->energy = p_energy;
if (!capture->update_list.in_list()) {
capture_update_list.add(&capture->update_list);
}
}
float RasterizerStorageGLES3::lightmap_capture_get_energy(RID p_capture) const {
@ -6394,12 +6398,35 @@ float RasterizerStorageGLES3::lightmap_capture_get_energy(RID p_capture) const {
return capture->energy;
}
void RasterizerStorageGLES3::lightmap_capture_set_interior(RID p_capture, bool p_interior) {
LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND(!capture);
capture->interior = p_interior;
if (!capture->update_list.in_list()) {
capture_update_list.add(&capture->update_list);
}
}
bool RasterizerStorageGLES3::lightmap_capture_is_interior(RID p_capture) const {
const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND_V(!capture, false);
return capture->interior;
}
const PoolVector<RasterizerStorage::LightmapCaptureOctree> *RasterizerStorageGLES3::lightmap_capture_get_octree_ptr(RID p_capture) const {
const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND_V(!capture, NULL);
return &capture->octree;
}
void RasterizerStorageGLES3::update_dirty_captures() {
while (capture_update_list.first()) {
LightmapCapture *capture = capture_update_list.first()->self();
capture->instance_change_notify(false, true);
capture_update_list.remove(capture_update_list.first());
}
}
///////
RID RasterizerStorageGLES3::particles_create() {
@ -8591,6 +8618,7 @@ void RasterizerStorageGLES3::update_dirty_resources() {
update_dirty_shaders();
update_dirty_materials();
update_particles();
update_dirty_captures();
}
RasterizerStorageGLES3::RasterizerStorageGLES3() {

View file

@ -1152,6 +1152,8 @@ public:
virtual void lightmap_capture_set_energy(RID p_capture, float p_energy);
virtual float lightmap_capture_get_energy(RID p_capture) const;
virtual void lightmap_capture_set_interior(RID p_capture, bool p_interior);
virtual bool lightmap_capture_is_interior(RID p_capture) const;
virtual const PoolVector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const;
@ -1162,12 +1164,22 @@ public:
Transform cell_xform;
int cell_subdiv;
float energy;
LightmapCapture() {
bool interior;
SelfList<LightmapCapture> update_list;
LightmapCapture() :
update_list(this) {
energy = 1.0;
cell_subdiv = 1;
interior = false;
}
};
SelfList<LightmapCapture>::List capture_update_list;
void update_dirty_captures();
mutable RID_Owner<LightmapCapture> lightmap_capture_data_owner;
/* PARTICLES */

View file

@ -1548,8 +1548,6 @@ vec4 textureArray_bicubic(sampler2DArray tex, vec3 uv) {
#ifdef USE_LIGHTMAP_CAPTURE
uniform mediump vec4[12] lightmap_captures;
uniform bool lightmap_capture_sky;
#endif
#ifdef USE_GI_PROBES
@ -1964,8 +1962,9 @@ FRAGMENT_SHADER_CODE
captured /= sum;
if (lightmap_capture_sky) {
ambient_light = mix(ambient_light, captured.rgb, captured.a);
// Alpha channel is used to indicate if dynamic objects keep the environment lighting
if (lightmap_captures[0].a > 0.5) {
ambient_light += captured.rgb;
} else {
ambient_light = captured.rgb;
}

View file

@ -230,6 +230,9 @@
<member name="mesh_library" type="MeshLibrary" setter="set_mesh_library" getter="get_mesh_library">
The assigned [MeshLibrary].
</member>
<member name="use_in_baked_light" type="bool" setter="set_use_in_baked_light" getter="get_use_in_baked_light" default="false">
Controls whether this GridMap will be baked in a [BakedLightmap] or not.
</member>
</members>
<signals>
<signal name="cell_size_changed">

View file

@ -210,6 +210,14 @@ Ref<MeshLibrary> GridMap::get_mesh_library() const {
return mesh_library;
}
void GridMap::set_use_in_baked_light(bool p_use_baked_light) {
use_in_baked_light = p_use_baked_light;
}
bool GridMap::get_use_in_baked_light() const {
return use_in_baked_light;
}
void GridMap::set_cell_size(const Vector3 &p_size) {
ERR_FAIL_COND(p_size.x < 0.001 || p_size.y < 0.001 || p_size.z < 0.001);
cell_size = p_size;
@ -864,7 +872,11 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_baked_meshes"), &GridMap::clear_baked_meshes);
ClassDB::bind_method(D_METHOD("make_baked_meshes", "gen_lightmap_uv", "lightmap_uv_texel_size"), &GridMap::make_baked_meshes, DEFVAL(false), DEFVAL(0.1));
ClassDB::bind_method(D_METHOD("set_use_in_baked_light", "use_in_baked_light"), &GridMap::set_use_in_baked_light);
ClassDB::bind_method(D_METHOD("get_use_in_baked_light"), &GridMap::get_use_in_baked_light);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh_library", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary"), "set_mesh_library", "get_mesh_library");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_in_baked_light"), "set_use_in_baked_light", "get_use_in_baked_light");
ADD_GROUP("Cell", "cell_");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cell_size"), "set_cell_size", "get_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_octant_size", PROPERTY_HINT_RANGE, "1,1024,1"), "set_octant_size", "get_octant_size");
@ -1066,6 +1078,10 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe
Array GridMap::get_bake_meshes() {
if (!use_in_baked_light) {
return Array();
}
if (!baked_meshes.size()) {
make_baked_meshes(true);
}
@ -1107,6 +1123,8 @@ GridMap::GridMap() {
navigation = NULL;
set_notify_transform(true);
recreating_octants = false;
use_in_baked_light = false;
}
GridMap::~GridMap() {

View file

@ -158,6 +158,7 @@ class GridMap : public Spatial {
Vector3::Axis clip_axis;
Ref<MeshLibrary> mesh_library;
bool use_in_baked_light;
Map<OctantKey, Octant *> octant_map;
Map<IndexKey, Cell> cell_map;
@ -230,6 +231,9 @@ public:
void set_mesh_library(const Ref<MeshLibrary> &p_mesh_library);
Ref<MeshLibrary> get_mesh_library() const;
void set_use_in_baked_light(bool p_use_baked_light);
bool get_use_in_baked_light() const;
void set_cell_size(const Vector3 &p_size);
Vector3 get_cell_size() const;

View file

@ -33,6 +33,7 @@
// From Embree.
#include <math/vec2.h>
#include <math/vec3.h>
#include <xmmintrin.h>
using namespace embree;
@ -185,12 +186,18 @@ void embree_error_handler(void *p_user_data, RTCError p_code, const char *p_str)
}
LightmapRaycasterEmbree::LightmapRaycasterEmbree() {
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
embree_device = rtcNewDevice(nullptr);
rtcSetDeviceErrorFunction(embree_device, &embree_error_handler, nullptr);
embree_scene = rtcNewScene(embree_device);
}
LightmapRaycasterEmbree::~LightmapRaycasterEmbree() {
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF);
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF);
if (embree_scene != nullptr)
rtcReleaseScene(embree_scene);
if (embree_device != nullptr)

View file

@ -87,6 +87,17 @@ float BakedLightmapData::get_energy() const {
return energy;
}
void BakedLightmapData::set_interior(bool p_interior) {
interior = p_interior;
VS::get_singleton()->lightmap_capture_set_interior(baked_light, interior);
}
bool BakedLightmapData::is_interior() const {
return interior;
}
void BakedLightmapData::add_user(const NodePath &p_path, const Ref<Resource> &p_lightmap, int p_lightmap_slice, const Rect2 &p_lightmap_uv_rect, int p_instance) {
ERR_FAIL_COND_MSG(p_lightmap.is_null(), "It's not a reference to a valid Texture object.");
@ -230,6 +241,9 @@ void BakedLightmapData::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_energy", "energy"), &BakedLightmapData::set_energy);
ClassDB::bind_method(D_METHOD("get_energy"), &BakedLightmapData::get_energy);
ClassDB::bind_method(D_METHOD("set_interior", "interior"), &BakedLightmapData::set_interior);
ClassDB::bind_method(D_METHOD("is_interior"), &BakedLightmapData::is_interior);
ClassDB::bind_method(D_METHOD("add_user", "path", "lightmap", "lightmap_slice", "lightmap_uv_rect", "instance"), &BakedLightmapData::add_user);
ClassDB::bind_method(D_METHOD("get_user_count"), &BakedLightmapData::get_user_count);
ClassDB::bind_method(D_METHOD("get_user_path", "user_idx"), &BakedLightmapData::get_user_path);
@ -241,6 +255,7 @@ void BakedLightmapData::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "cell_space_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_space_transform", "get_cell_space_transform");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_subdiv", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_subdiv", "get_cell_subdiv");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_energy", "get_energy");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior");
ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY, "octree", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_octree", "get_octree");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_user_data", "_get_user_data");
}
@ -250,6 +265,7 @@ BakedLightmapData::BakedLightmapData() {
baked_light = VS::get_singleton()->lightmap_capture_create();
energy = 1;
cell_subdiv = 1;
interior = false;
}
BakedLightmapData::~BakedLightmapData() {
@ -464,7 +480,7 @@ void BakedLightmap::_get_material_images(const MeshesFound &p_found_mesh, Lightm
}
Ref<Texture> albedo_texture;
Color albedo_add = Color(0, 0, 0, 0);
Color albedo_add = Color(1, 1, 1, 1);
Color albedo_mul = Color(1, 1, 1, 1);
Ref<Texture> emission_texture;
@ -477,6 +493,7 @@ void BakedLightmap::_get_material_images(const MeshesFound &p_found_mesh, Lightm
if (albedo_texture.is_valid()) {
albedo_mul = mat->get_albedo();
albedo_add = Color(0, 0, 0, 0);
} else {
albedo_add = mat->get_albedo();
}
@ -531,25 +548,27 @@ void BakedLightmap::_save_image(String &r_base_path, Ref<Image> r_img, bool p_us
bool hdr_grayscale = use_hdr && !use_color;
if (p_use_srgb || hdr_grayscale) {
r_img->lock();
for (int i = 0; i < r_img->get_height(); i++) {
for (int j = 0; j < r_img->get_width(); j++) {
Color c = r_img->get_pixel(j, i);
r_img->lock();
for (int i = 0; i < r_img->get_height(); i++) {
for (int j = 0; j < r_img->get_width(); j++) {
Color c = r_img->get_pixel(j, i);
if (hdr_grayscale) {
c = Color(c.get_v(), 0.0f, 0.0f);
}
c.r = MAX(c.r, environment_min_light.r);
c.g = MAX(c.g, environment_min_light.g);
c.b = MAX(c.b, environment_min_light.b);
if (p_use_srgb) {
c = c.to_srgb();
}
r_img->set_pixel(j, i, c);
if (hdr_grayscale) {
c = Color(c.get_v(), 0.0f, 0.0f);
}
if (p_use_srgb) {
c = c.to_srgb();
}
r_img->set_pixel(j, i, c);
}
r_img->unlock();
}
r_img->unlock();
if (!use_color) {
if (use_hdr) {
@ -792,7 +811,6 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_data_sa
case ENVIRONMENT_MODE_CUSTOM_SKY: {
if (environment_custom_sky.is_valid()) {
environment_image = _get_irradiance_from_sky(environment_custom_sky, Vector2i(128, 64));
print_line(vformat("env -> %s", environment_custom_sky_rotation_degrees));
environment_xform.set_euler(environment_custom_sky_rotation_degrees * Math_PI / 180.0);
}
@ -804,12 +822,13 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_data_sa
c.r *= environment_custom_energy;
c.g *= environment_custom_energy;
c.b *= environment_custom_energy;
environment_image->lock();
for (int i = 0; i < 128; i++) {
for (int j = 0; j < 64; j++) {
environment_image->set_pixel(i, j, c);
}
}
environment_image->unlock();
} break;
}
}
@ -1409,6 +1428,14 @@ float BakedLightmap::get_environment_custom_energy() const {
return environment_custom_energy;
}
void BakedLightmap::set_environment_min_light(Color p_min_light) {
environment_min_light = p_min_light;
}
Color BakedLightmap::get_environment_min_light() const {
return environment_min_light;
}
void BakedLightmap::set_bounces(int p_bounces) {
ERR_FAIL_COND(p_bounces < 0 || p_bounces > 16);
bounces = p_bounces;
@ -1486,6 +1513,9 @@ void BakedLightmap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_environment_custom_energy", "energy"), &BakedLightmap::set_environment_custom_energy);
ClassDB::bind_method(D_METHOD("get_environment_custom_energy"), &BakedLightmap::get_environment_custom_energy);
ClassDB::bind_method(D_METHOD("set_environment_min_light", "min_light"), &BakedLightmap::set_environment_min_light);
ClassDB::bind_method(D_METHOD("get_environment_min_light"), &BakedLightmap::get_environment_min_light);
ClassDB::bind_method(D_METHOD("set_use_denoiser", "use_denoiser"), &BakedLightmap::set_use_denoiser);
ClassDB::bind_method(D_METHOD("is_using_denoiser"), &BakedLightmap::is_using_denoiser);
@ -1545,6 +1575,7 @@ void BakedLightmap::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "environment_custom_sky_rotation_degrees", PROPERTY_HINT_NONE), "set_environment_custom_sky_rotation_degrees", "get_environment_custom_sky_rotation_degrees");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "environment_custom_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_environment_custom_color", "get_environment_custom_color");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "environment_custom_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_environment_custom_energy", "get_environment_custom_energy");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "environment_min_light", PROPERTY_HINT_COLOR_NO_ALPHA), "set_environment_min_light", "get_environment_min_light");
ADD_GROUP("Capture", "capture_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "capture_enabled"), "set_capture_enabled", "get_capture_enabled");
@ -1595,6 +1626,7 @@ BakedLightmap::BakedLightmap() {
environment_mode = ENVIRONMENT_MODE_DISABLED;
environment_custom_color = Color(0.2, 0.7, 1.0);
environment_custom_energy = 1.0;
environment_min_light = Color(0.0, 0.0, 0.0);
use_denoiser = true;
use_hdr = true;

View file

@ -44,6 +44,7 @@ class BakedLightmapData : public Resource {
RID baked_light;
AABB bounds;
float energy;
bool interior;
int cell_subdiv;
Transform cell_space_xform;
@ -83,6 +84,9 @@ public:
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;
@ -169,6 +173,7 @@ private:
Vector3 environment_custom_sky_rotation_degrees;
Color environment_custom_color;
float environment_custom_energy;
Color environment_min_light;
BakeQuality capture_quality;
float capture_propagation;
@ -247,6 +252,9 @@ public:
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;

View file

@ -514,6 +514,8 @@ public:
virtual int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const = 0;
virtual void lightmap_capture_set_energy(RID p_capture, float p_energy) = 0;
virtual float lightmap_capture_get_energy(RID p_capture) const = 0;
virtual void lightmap_capture_set_interior(RID p_capture, bool p_interior) = 0;
virtual bool lightmap_capture_is_interior(RID p_capture) const = 0;
virtual const PoolVector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const = 0;
/* PARTICLES */

View file

@ -396,6 +396,9 @@ public:
BIND2(lightmap_capture_set_energy, RID, float)
BIND1RC(float, lightmap_capture_get_energy, RID)
BIND2(lightmap_capture_set_interior, RID, bool)
BIND1RC(bool, lightmap_capture_is_interior, RID)
/* PARTICLES */
BIND0R(RID, particles_create)

View file

@ -1085,6 +1085,13 @@ void VisualServerScene::_update_instance(Instance *p_instance) {
VSG::storage->particles_set_emission_transform(p_instance->base, p_instance->transform);
}
if (p_instance->base_type == VS::INSTANCE_LIGHTMAP_CAPTURE) {
InstanceLightmapCaptureData *capture = static_cast<InstanceLightmapCaptureData *>(p_instance->base_data);
for (List<InstanceLightmapCaptureData::PairInfo>::Element *E = capture->geometries.front(); E; E = E->next()) {
_instance_queue_update(E->get().geometry, false, true);
}
}
if (p_instance->aabb.has_no_surface()) {
return;
}
@ -1441,6 +1448,7 @@ void VisualServerScene::_update_instance_lightmap_captures(Instance *p_instance)
for (int i = 0; i < 12; i++)
new (&p_instance->lightmap_capture_data.ptrw()[i]) Color;
bool interior = true;
//this could use some sort of blending..
for (List<Instance *>::Element *E = geom->lightmap_captures.front(); E; E = E->next()) {
const PoolVector<RasterizerStorage::LightmapCaptureOctree> *octree = VSG::storage->lightmap_capture_get_octree_ptr(E->get()->base);
@ -1456,6 +1464,7 @@ void VisualServerScene::_update_instance_lightmap_captures(Instance *p_instance)
Vector3 pos = to_cell_xform.xform(p_instance->transform.origin);
const float capture_energy = VSG::storage->lightmap_capture_get_energy(E->get()->base);
interior = interior && VSG::storage->lightmap_capture_is_interior(E->get()->base);
for (int i = 0; i < 12; i++) {
@ -1467,6 +1476,7 @@ void VisualServerScene::_update_instance_lightmap_captures(Instance *p_instance)
p_instance->lightmap_capture_data.write[i] += capture;
}
}
p_instance->lightmap_capture_data.write[0].a = interior ? 0.0f : 1.0f;
}
bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario) {

View file

@ -330,6 +330,8 @@ public:
FUNC1RC(int, lightmap_capture_get_octree_cell_subdiv, RID)
FUNC2(lightmap_capture_set_energy, RID, float)
FUNC1RC(float, lightmap_capture_get_energy, RID)
FUNC2(lightmap_capture_set_interior, RID, bool)
FUNC1RC(bool, lightmap_capture_is_interior, RID)
/* PARTICLES */

View file

@ -1830,6 +1830,8 @@ void VisualServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("lightmap_capture_get_octree", "capture"), &VisualServer::lightmap_capture_get_octree);
ClassDB::bind_method(D_METHOD("lightmap_capture_set_energy", "capture", "energy"), &VisualServer::lightmap_capture_set_energy);
ClassDB::bind_method(D_METHOD("lightmap_capture_get_energy", "capture"), &VisualServer::lightmap_capture_get_energy);
ClassDB::bind_method(D_METHOD("lightmap_capture_set_interior", "capture", "interior"), &VisualServer::lightmap_capture_set_interior);
ClassDB::bind_method(D_METHOD("lightmap_capture_is_interior", "capture"), &VisualServer::lightmap_capture_is_interior);
#endif
ClassDB::bind_method(D_METHOD("particles_create"), &VisualServer::particles_create);
ClassDB::bind_method(D_METHOD("particles_set_emitting", "particles", "emitting"), &VisualServer::particles_set_emitting);

View file

@ -558,6 +558,8 @@ public:
virtual PoolVector<uint8_t> lightmap_capture_get_octree(RID p_capture) const = 0;
virtual void lightmap_capture_set_energy(RID p_capture, float p_energy) = 0;
virtual float lightmap_capture_get_energy(RID p_capture) const = 0;
virtual void lightmap_capture_set_interior(RID p_capture, bool p_interior) = 0;
virtual bool lightmap_capture_is_interior(RID p_capture) const = 0;
/* PARTICLES API */