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:
parent
0e0d73c011
commit
e2c28675ef
24 changed files with 229 additions and 30 deletions
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,12 +548,15 @@ 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);
|
||||
|
||||
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 (hdr_grayscale) {
|
||||
c = Color(c.get_v(), 0.0f, 0.0f);
|
||||
}
|
||||
|
@ -549,7 +569,6 @@ void BakedLightmap::_save_image(String &r_base_path, Ref<Image> r_img, bool p_us
|
|||
}
|
||||
}
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in a new issue