Skip to content

Commit

Permalink
Implement support for bicubic lightmap filtering
Browse files Browse the repository at this point in the history
Co-authored-by: Calinou <hugo.locurcio@hugo.pro>
  • Loading branch information
BlueCube3310 and Calinou committed Mar 27, 2024
1 parent 7d151c8 commit e533ddb
Show file tree
Hide file tree
Showing 22 changed files with 290 additions and 34 deletions.
3 changes: 2 additions & 1 deletion doc/classes/LightmapGIData.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
<param index="1" name="uv_scale" type="Rect2" />
<param index="2" name="slice_index" type="int" />
<param index="3" name="sub_instance" type="int" />
<param index="4" name="texture_size" type="Vector2" />
<description>
Adds an object that is considered baked within this [LightmapGIData].
Adds an object that is considered baked within this [LightmapGIData]. [param texture_size] must match the size of the [i]entire[/i] lightmap texture, which is used for bicubic filtering when rendering the lightmap.
</description>
</method>
<method name="clear_users">
Expand Down
5 changes: 4 additions & 1 deletion drivers/gles3/rasterizer_scene_gles3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,11 @@ void RasterizerSceneGLES3::GeometryInstanceGLES3::_mark_dirty() {
RasterizerSceneGLES3::get_singleton()->geometry_instance_dirty_list.add(&dirty_list_element);
}

void RasterizerSceneGLES3::GeometryInstanceGLES3::set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) {
void RasterizerSceneGLES3::GeometryInstanceGLES3::set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index, const Vector2 &p_lightmap_texture_size) {
lightmap_instance = p_lightmap_instance;
lightmap_uv_scale = p_lightmap_uv_scale;
lightmap_slice_index = p_lightmap_slice_index;
lightmap_texture_size = p_lightmap_texture_size;

_mark_dirty();
}
Expand Down Expand Up @@ -3343,6 +3344,8 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
Vector4 uv_scale(inst->lightmap_uv_scale.position.x, inst->lightmap_uv_scale.position.y, inst->lightmap_uv_scale.size.x, inst->lightmap_uv_scale.size.y);
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::LIGHTMAP_UV_SCALE, uv_scale, shader->version, instance_variant, spec_constants);

material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::LIGHTMAP_TEXTURE_SIZE, inst->lightmap_texture_size, shader->version, instance_variant, spec_constants);

float exposure_normalization = 1.0;
if (p_render_data->camera_attributes.is_valid()) {
float enf = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
Expand Down
3 changes: 2 additions & 1 deletion drivers/gles3/rasterizer_scene_gles3.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ class RasterizerSceneGLES3 : public RendererSceneRender {
RID lightmap_instance;
Rect2 lightmap_uv_scale;
uint32_t lightmap_slice_index;
Vector2 lightmap_texture_size;
GeometryInstanceLightmapSH *lightmap_sh = nullptr;

// Used during setup.
Expand All @@ -327,7 +328,7 @@ class RasterizerSceneGLES3 : public RendererSceneRender {
dirty_list_element(this) {}

virtual void _mark_dirty() override;
virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override;
virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index, const Vector2 &p_lightmap_texture_size) override;
virtual void set_lightmap_capture(const Color *p_sh9) override;

virtual void pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) override;
Expand Down
80 changes: 80 additions & 0 deletions drivers/gles3/shaders/scene.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,11 @@ uniform lowp uint lightmap_slice;
uniform highp vec4 lightmap_uv_scale;
uniform float lightmap_exposure_normalization;

#define LIGHTMAP_BICUBIC_FILTER // FIXME: Remove this and pass when compiling shader.
#ifdef LIGHTMAP_BICUBIC_FILTER
uniform highp vec2 lightmap_texture_size;
#endif

#ifdef USE_SH_LIGHTMAP
uniform mediump mat3 lightmap_normal_xform;
#endif // USE_SH_LIGHTMAP
Expand Down Expand Up @@ -1287,6 +1292,69 @@ vec4 fog_process(vec3 vertex) {

#endif // !MODE_RENDER_DEPTH

#ifdef LIGHTMAP_BICUBIC_FILTER

// w0, w1, w2, and w3 are the four cubic B-spline basis functions
float w0(float a) {
return (1.0 / 6.0) * (a * (a * (-a + 3.0) - 3.0) + 1.0);
}

float w1(float a) {
return (1.0 / 6.0) * (a * a * (3.0 * a - 6.0) + 4.0);
}

float w2(float a) {
return (1.0 / 6.0) * (a * (a * (-3.0 * a + 3.0) + 3.0) + 1.0);
}

float w3(float a) {
return (1.0 / 6.0) * (a * a * a);
}

// g0 and g1 are the two amplitude functions
float g0(float a) {
return w0(a) + w1(a);
}

float g1(float a) {
return w2(a) + w3(a);
}

// h0 and h1 are the two offset functions
float h0(float a) {
return -1.0 + w1(a) / (w0(a) + w1(a));
}

float h1(float a) {
return 1.0 + w3(a) / (w2(a) + w3(a));
}

vec4 textureArray_bicubic(sampler2DArray tex, vec3 uv, vec2 texture_size) {
vec2 texel_size = vec2(1.0) / texture_size;

uv.xy = uv.xy * texture_size + vec2(0.5);

vec2 iuv = floor(uv.xy);
vec2 fuv = fract(uv.xy);

float g0x = g0(fuv.x);
float g1x = g1(fuv.x);
float h0x = h0(fuv.x);
float h1x = h1(fuv.x);
float h0y = h0(fuv.y);
float h1y = h1(fuv.y);

vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5)) * texel_size;
vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5)) * texel_size;
vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5)) * texel_size;
vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5)) * texel_size;

return (g0(fuv.y) * (g0x * texture(tex, vec3(p0, uv.z)) + g1x * texture(tex, vec3(p1, uv.z)))) +
(g1(fuv.y) * (g0x * texture(tex, vec3(p2, uv.z)) + g1x * texture(tex, vec3(p3, uv.z))));
}

#endif // LIGHTMAP_BICUBIC_FILTER

void main() {
//lay out everything, whatever is unused is optimized away anyway
vec3 vertex = vertex_interp;
Expand Down Expand Up @@ -1542,10 +1610,18 @@ void main() {

#ifdef USE_SH_LIGHTMAP
uvw.z *= 4.0; // SH textures use 4 times more data.

#ifdef LIGHTMAP_BICUBIC_FILTER
vec3 lm_light_l0 = textureArray_bicubic(lightmap_textures, uvw + vec3(0.0, 0.0, 0.0), lightmap_texture_size);
vec3 lm_light_l1n1 = textureArray_bicubic(lightmap_textures, uvw + vec3(0.0, 0.0, 1.0), lightmap_texture_size);
vec3 lm_light_l1_0 = textureArray_bicubic(lightmap_textures, uvw + vec3(0.0, 0.0, 2.0), lightmap_texture_size);
vec3 lm_light_l1p1 = textureArray_bicubic(lightmap_textures, uvw + vec3(0.0, 0.0, 3.0), lightmap_texture_size);
#else
vec3 lm_light_l0 = textureLod(lightmap_textures, uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb;
vec3 lm_light_l1n1 = textureLod(lightmap_textures, uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb;
vec3 lm_light_l1_0 = textureLod(lightmap_textures, uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb;
vec3 lm_light_l1p1 = textureLod(lightmap_textures, uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb;
#endif

vec3 n = normalize(lightmap_normal_xform * normal);

Expand All @@ -1559,8 +1635,12 @@ void main() {
specular_light += lm_light_l1_0 * 0.32573 * r.z * lightmap_exposure_normalization;
specular_light += lm_light_l1p1 * 0.32573 * r.x * lightmap_exposure_normalization;
}
#else
#ifdef LIGHTMAP_BICUBIC_FILTER
ambient_light += textureArray_bicubic(lightmap_textures, uvw, lightmap_texture_size).rgb * lightmap_exposure_normalization;
#else
ambient_light += textureLod(lightmap_textures, uvw, 0.0).rgb * lightmap_exposure_normalization;
#endif
#endif
}
#endif // USE_LIGHTMAP
Expand Down
26 changes: 17 additions & 9 deletions scene/3d/lightmap_gi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,13 @@
#include "scene/resources/image_texture.h"
#include "scene/resources/sky.h"

void LightmapGIData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance) {
void LightmapGIData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance, const Vector2 &p_texture_size) {
User user;
user.path = p_path;
user.uv_scale = p_uv_scale;
user.slice_index = p_slice_index;
user.sub_instance = p_sub_instance;
user.texture_size = p_texture_size;
users.push_back(user);
}

Expand Down Expand Up @@ -73,16 +74,21 @@ int LightmapGIData::get_user_lightmap_slice_index(int p_user) const {
return users[p_user].slice_index;
}

Vector2 LightmapGIData::get_user_lightmap_texture_size(int p_user) const {
ERR_FAIL_INDEX_V(p_user, users.size(), Vector2());
return users[p_user].texture_size;
}

void LightmapGIData::clear_users() {
users.clear();
}

void LightmapGIData::_set_user_data(const Array &p_data) {
ERR_FAIL_COND(p_data.is_empty());
ERR_FAIL_COND((p_data.size() % 4) != 0);
ERR_FAIL_COND((p_data.size() % 5) != 0);

for (int i = 0; i < p_data.size(); i += 4) {
add_user(p_data[i + 0], p_data[i + 1], p_data[i + 2], p_data[i + 3]);
for (int i = 0; i < p_data.size(); i += 5) {
add_user(p_data[i + 0], p_data[i + 1], p_data[i + 2], p_data[i + 3], p_data[i + 4]);
}
}

Expand All @@ -93,6 +99,7 @@ Array LightmapGIData::_get_user_data() const {
ret.push_back(users[i].uv_scale);
ret.push_back(users[i].slice_index);
ret.push_back(users[i].sub_instance);
ret.push_back(users[i].texture_size);
}
return ret;
}
Expand Down Expand Up @@ -1155,7 +1162,8 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa

Rect2 uv_scale = lightmapper->get_bake_mesh_uv_scale(i);
int slice_index = lightmapper->get_bake_mesh_texture_slice(i);
gi_data->add_user(np, uv_scale, slice_index, subindex);
Ref<Image> lightmap = lightmapper->get_bake_texture(slice_index);
gi_data->add_user(np, uv_scale, slice_index, subindex, Vector2(lightmap->get_width(), lightmap->get_height()));
}

{
Expand Down Expand Up @@ -1329,12 +1337,12 @@ void LightmapGI::_assign_lightmaps() {
if (instance_idx >= 0) {
RID instance_id = node->call("get_bake_mesh_instance", instance_idx);
if (instance_id.is_valid()) {
RS::get_singleton()->instance_geometry_set_lightmap(instance_id, get_instance(), light_data->get_user_lightmap_uv_scale(i), light_data->get_user_lightmap_slice_index(i));
RS::get_singleton()->instance_geometry_set_lightmap(instance_id, get_instance(), light_data->get_user_lightmap_uv_scale(i), light_data->get_user_lightmap_slice_index(i), light_data->get_user_lightmap_texture_size(i));
}
} else {
VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(node);
ERR_CONTINUE(!vi);
RS::get_singleton()->instance_geometry_set_lightmap(vi->get_instance(), get_instance(), light_data->get_user_lightmap_uv_scale(i), light_data->get_user_lightmap_slice_index(i));
RS::get_singleton()->instance_geometry_set_lightmap(vi->get_instance(), get_instance(), light_data->get_user_lightmap_uv_scale(i), light_data->get_user_lightmap_slice_index(i), light_data->get_user_lightmap_texture_size(i));
}
}
}
Expand All @@ -1347,12 +1355,12 @@ void LightmapGI::_clear_lightmaps() {
if (instance_idx >= 0) {
RID instance_id = node->call("get_bake_mesh_instance", instance_idx);
if (instance_id.is_valid()) {
RS::get_singleton()->instance_geometry_set_lightmap(instance_id, RID(), Rect2(), 0);
RS::get_singleton()->instance_geometry_set_lightmap(instance_id, RID(), Rect2(), 0, Vector2());
}
} else {
VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(node);
ERR_CONTINUE(!vi);
RS::get_singleton()->instance_geometry_set_lightmap(vi->get_instance(), RID(), Rect2(), 0);
RS::get_singleton()->instance_geometry_set_lightmap(vi->get_instance(), RID(), Rect2(), 0, Vector2());
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion scene/3d/lightmap_gi.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class LightmapGIData : public Resource {
NodePath path;
int32_t sub_instance = 0;
Rect2 uv_scale;
Vector2 texture_size;
int slice_index = 0;
};

Expand All @@ -73,12 +74,13 @@ class LightmapGIData : public Resource {
static void _bind_methods();

public:
void add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance = -1);
void add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance = -1, const Vector2 &p_texture_size = Vector2());
int get_user_count() const;
NodePath get_user_path(int p_user) const;
int32_t get_user_sub_instance(int p_user) const;
Rect2 get_user_lightmap_uv_scale(int p_user) const;
int get_user_lightmap_slice_index(int p_user) const;
Vector2 get_user_lightmap_texture_size(int p_user) const;
void clear_users();

#ifndef DISABLE_DEPRECATED
Expand Down
2 changes: 1 addition & 1 deletion servers/rendering/dummy/rasterizer_scene_dummy.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class RasterizerSceneDummy : public RendererSceneRender {
virtual void set_transparency(float p_transparency) override {}
virtual void set_use_baked_light(bool p_enable) override {}
virtual void set_use_dynamic_gi(bool p_enable) override {}
virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override {}
virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index, const Vector2 &p_lightmap_texture_size) override {}
virtual void set_lightmap_capture(const Color *p_sh9) override {}
virtual void set_instance_shader_uniforms_offset(int32_t p_offset) override {}
virtual void set_cast_double_sided_shadows(bool p_enable) override {}
Expand Down
2 changes: 1 addition & 1 deletion servers/rendering/renderer_geometry_instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class RenderGeometryInstance {
virtual void set_transparency(float p_transparency) = 0;
virtual void set_use_baked_light(bool p_enable) = 0;
virtual void set_use_dynamic_gi(bool p_enable) = 0;
virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) = 0;
virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index, const Vector2 &p_lightmap_texture_size) = 0;
virtual void set_lightmap_capture(const Color *p_sh9) = 0;
virtual void set_instance_shader_uniforms_offset(int32_t p_offset) = 0;
virtual void set_cast_double_sided_shadows(bool p_enable) = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,8 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, i
instance_data.lightmap_uv_scale[1] = inst->lightmap_uv_scale.position.y;
instance_data.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x;
instance_data.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y;
instance_data.lightmap_texture_size[0] = inst->lightmap_texture_size.x;
instance_data.lightmap_texture_size[1] = inst->lightmap_texture_size.y;

AABB surface_aabb = AABB(Vector3(0.0, 0.0, 0.0), Vector3(1.0, 1.0, 1.0));
uint64_t format = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_format(surface->surface);
Expand Down Expand Up @@ -4107,9 +4109,10 @@ void RenderForwardClustered::GeometryInstanceForwardClustered::set_transform(con
RenderGeometryInstanceBase::set_transform(p_transform, p_aabb, p_transformed_aabb);
}

void RenderForwardClustered::GeometryInstanceForwardClustered::set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) {
void RenderForwardClustered::GeometryInstanceForwardClustered::set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index, const Vector2 &p_lightmap_texture_size) {
lightmap_instance = p_lightmap_instance;
lightmap_uv_scale = p_lightmap_uv_scale;
lightmap_texture_size = p_lightmap_texture_size;
lightmap_slice_index = p_lightmap_slice_index;

_mark_dirty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ class RenderForwardClustered : public RendererSceneRenderRD {
float compressed_aabb_position[4];
float compressed_aabb_size[4];
float uv_scale[4];
float lightmap_texture_size[2];
uint32_t padding[2];
};

UBO ubo;
Expand Down Expand Up @@ -456,6 +458,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
// lightmap
RID lightmap_instance;
Rect2 lightmap_uv_scale;
Vector2 lightmap_texture_size; // Used for bicubic filtering in the scene shader.
uint32_t lightmap_slice_index;
GeometryInstanceLightmapSH *lightmap_sh = nullptr;

Expand Down Expand Up @@ -484,7 +487,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
virtual void _mark_dirty() override;

virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override;
virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override;
virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index, const Vector2 &p_lightmap_texture_size) override;
virtual void set_lightmap_capture(const Color *p_sh9) override;

virtual void pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) override {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1733,6 +1733,8 @@ void RenderForwardMobile::_fill_instance_data(RenderListType p_render_list, uint
instance_data.lightmap_uv_scale[1] = inst->lightmap_uv_scale.position.y;
instance_data.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x;
instance_data.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y;
instance_data.lightmap_texture_size[0] = inst->lightmap_texture_size.x;
instance_data.lightmap_texture_size[1] = inst->lightmap_texture_size.y;

AABB surface_aabb = AABB(Vector3(0.0, 0.0, 0.0), Vector3(1.0, 1.0, 1.0));
uint64_t format = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_format(surface->surface);
Expand Down Expand Up @@ -2254,9 +2256,10 @@ RenderGeometryInstance *RenderForwardMobile::geometry_instance_create(RID p_base
return ginstance;
}

void RenderForwardMobile::GeometryInstanceForwardMobile::set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) {
void RenderForwardMobile::GeometryInstanceForwardMobile::set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index, const Vector2 &p_lightmap_texture_size) {
lightmap_instance = p_lightmap_instance;
lightmap_uv_scale = p_lightmap_uv_scale;
lightmap_texture_size = p_lightmap_texture_size;
lightmap_slice_index = p_lightmap_slice_index;

_mark_dirty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ class RenderForwardMobile : public RendererSceneRenderRD {
float compressed_aabb_position[4];
float compressed_aabb_size[4];
float uv_scale[4];
float lightmap_texture_size[2];
uint32_t padding[2];
};

RID instance_buffer[RENDER_LIST_MAX];
Expand Down Expand Up @@ -470,6 +472,7 @@ class RenderForwardMobile : public RendererSceneRenderRD {
uint32_t gi_offset_cache = 0; // !BAS! Should rename this to lightmap_offset_cache, in forward clustered this was shared between gi and lightmap
RID lightmap_instance;
Rect2 lightmap_uv_scale;
Vector2 lightmap_texture_size; // Used for bicubic filtering in the scene shader.
uint32_t lightmap_slice_index;
GeometryInstanceLightmapSH *lightmap_sh = nullptr;

Expand All @@ -493,7 +496,7 @@ class RenderForwardMobile : public RendererSceneRenderRD {

virtual void _mark_dirty() override;

virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override;
virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index, const Vector2 &p_lightmap_texture_size) override;
virtual void set_lightmap_capture(const Color *p_sh9) override;

virtual void pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) override;
Expand Down

0 comments on commit e533ddb

Please sign in to comment.