Skip to content

Commit

Permalink
Implement shadowmask for DirectionalLight in BakedLightmap
Browse files Browse the repository at this point in the history
This can be used to fade distant real-time DirectionalLight shadows
with baked shadows (stored in the lightmap's alpha channel).

TODO:

- Restore support for baking lightmaps with HDR.
- Fix the resulting lightmap when denoising is enabled.
  • Loading branch information
Calinou committed Dec 31, 2021
1 parent 7fcfde9 commit 92258eb
Show file tree
Hide file tree
Showing 12 changed files with 164 additions and 50 deletions.
4 changes: 4 additions & 0 deletions doc/classes/BakedLightmap.xml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@
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>
<member name="use_shadowmask" type="bool" setter="set_use_shadowmask" getter="is_using_shadowmask" default="true">
If [code]true[/code], bakes the [DirectionalLight]s' direct light shadows into a [i]shadowmask[/i] which is stored in the lightmap textures' alpha channel. This shadowmask is used to keep static shadows visible past the DirectionalLights' [member DirectionalLight.directional_shadow_max_distance] by blending the last shadow split with the shadowmask. This in turn allows you to use a lower [member DirectionalLight.directional_shadow_max_distance] for dynamic objects. Lower real-time shadow distances improve shadow detail and performance while making shadow acne less visible.
[b]Note:[/b] Shadowmasking only supports one baked [DirectionalLight] at a time. If you have more than one [DirectionalLight] whose [member Light.light_bake_mode] isn't set to [constant Light.BAKE_DISABLED], the editor will print a warning when baking lightmaps.
</member>
</members>
<constants>
<constant name="BAKE_QUALITY_LOW" value="0" enum="BakeQuality">
Expand Down
1 change: 1 addition & 0 deletions doc/classes/Light.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
</member>
<member name="light_size" type="float" setter="set_param" getter="get_param" default="0.0">
The size of the light in Godot units. Only considered in baked lightmaps and only if [member light_bake_mode] is set to [constant BAKE_ALL]. Increasing this value will make the shadows appear blurrier. This can be used to simulate area lights to an extent.
[b]Note:[/b] [DirectionalLight]s with their bake mode set to [constant BAKE_INDIRECT] still have an adjustable [member light_size] property, but it will only be used for the baked shadowmask (see [member BakedLightmap.use_shadowmask]). This can be used to better integrate the shadowmask with real-time shadows by making it softer and less pixelated. Values between [code]0.01[/code] and [code]0.1[/code] work well for the purposes of shadowmasking.
</member>
<member name="light_specular" type="float" setter="set_param" getter="get_param" default="0.5">
The intensity of the specular blob in objects affected by the light. At [code]0[/code], the light becomes a pure diffuse light. When not baking emission, this can be used to avoid unrealistic reflections when placing lights above an emissive surface.
Expand Down
30 changes: 23 additions & 7 deletions drivers/gles2/shaders/scene.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -1816,12 +1816,13 @@ FRAGMENT_SHADER_CODE
}

#ifdef USE_LIGHTMAP
//ambient light will come entirely from lightmap is lightmap is used
#if defined(USE_LIGHTMAP_FILTER_BICUBIC)
ambient_light = texture2D_bicubic(lightmap, uv2_interp).rgb * lightmap_energy;
vec4 lightmap_sample = texture2D_bicubic(lightmap, uv2_interp);
#else
ambient_light = texture2D(lightmap, uv2_interp).rgb * lightmap_energy;
vec4 lightmap_sample = texture2D(lightmap, uv2_interp);
#endif
//ambient light will come entirely from lightmap is lightmap is used
ambient_light = lightmap_sample.rgb * lightmap_energy;
#endif

#ifdef USE_LIGHTMAP_CAPTURE
Expand Down Expand Up @@ -1938,6 +1939,16 @@ FRAGMENT_SHADER_CODE
#endif
float depth_z = -vertex.z;

#ifdef USE_LIGHTMAP
// Take the DirectionalLight's shadow color into account for the shadowmask.
// This applies even if the DirectionalLight shadow is disabled, which can be
// done to improve performance by disabling shadows for dynamic objects only.
vec3 shadowmask = mix(shadow_color.rgb, vec3(1.0), lightmap_sample.a);
#else
// No lightmaps, fallback to no shadows in the distance.
vec3 shadowmask = vec3(1.0);
#endif

#if !defined(SHADOWS_DISABLED)

#ifdef USE_SHADOW
Expand Down Expand Up @@ -2001,7 +2012,7 @@ FRAGMENT_SHADER_CODE
shadow_att = mix(shadow_att, shadow_att2, pssm_blend);
}
#endif
light_att *= mix(shadow_color.rgb, vec3(1.0), shadow_att);
light_att *= mix(shadow_color.rgb, shadowmask, shadow_att);
}

#endif //LIGHT_USE_PSSM4
Expand Down Expand Up @@ -2041,14 +2052,14 @@ FRAGMENT_SHADER_CODE
shadow_att = mix(shadow_att, shadow_att2, pssm_blend);
}
#endif
light_att *= mix(shadow_color.rgb, vec3(1.0), shadow_att);
light_att *= mix(shadow_color.rgb, shadowmask, shadow_att);
}

#endif //LIGHT_USE_PSSM2

#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2)

light_att *= mix(shadow_color.rgb, vec3(1.0), sample_shadow(light_directional_shadow, shadow_coord));
light_att *= mix(shadow_color.rgb, shadowmask, sample_shadow(light_directional_shadow, shadow_coord));
#endif //orthogonal

#else //fragment version of pssm
Expand Down Expand Up @@ -2144,11 +2155,16 @@ FRAGMENT_SHADER_CODE
}
#endif

light_att *= mix(shadow_color.rgb, vec3(1.0), shadow);
light_att *= mix(shadow_color.rgb, shadowmask, shadow);
}
}
#endif //use vertex lighting

#else
// Use the shadowmask only when past the DirectionalLight's maximum shadow distance.
// FIXME: This doesn't work when the DirectionalLight's shadow is enabled.
// It only works when the shadow is disabled.
light_att *= shadowmask;
#endif //use shadow

#endif // SHADOWS_DISABLED
Expand Down
25 changes: 20 additions & 5 deletions drivers/gles3/shaders/scene.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -2022,13 +2022,19 @@ FRAGMENT_SHADER_CODE

#endif //ubershader-runtime

// Defined outside the lightmap block to make the ubershader approach work.
vec4 lightmap_sample = vec4(1.0);

#ifdef USE_LIGHTMAP //ubershader-runtime
// Also store the alpha channel as it's used for shadowmasking further below.
#ifdef USE_LIGHTMAP_LAYERED //ubershader-runtime
ambient_light = LIGHTMAP_TEXTURE_LAYERED_SAMPLE(lightmap_array, vec3(uv2, float(lightmap_layer))).rgb * lightmap_energy;
lightmap_sample = LIGHTMAP_TEXTURE_LAYERED_SAMPLE(lightmap_array, vec3(uv2, float(lightmap_layer)));
#else //ubershader-runtime
ambient_light = LIGHTMAP_TEXTURE_SAMPLE(lightmap, uv2).rgb * lightmap_energy;
#endif //ubershader-runtime
#endif //ubershader-runtime
lightmap_sample = LIGHTMAP_TEXTURE_SAMPLE(lightmap, uv2);
#endif //USE_LIGHTMAP_LAYERED //ubershader-runtime

ambient_light = lightmap_sample.rgb * lightmap_energy;
#endif //USE_LIGHTMAP //ubershader-runtime

#ifdef USE_LIGHTMAP_CAPTURE //ubershader-runtime
{
Expand Down Expand Up @@ -2110,8 +2116,16 @@ FRAGMENT_SHADER_CODE

#ifdef USE_LIGHT_DIRECTIONAL //ubershader-runtime

// No lightmaps, fallback to no shadows in the distance.
vec3 light_attenuation = vec3(1.0);

#ifdef USE_LIGHTMAP //ubershader-runtime
// Take the DirectionalLight's shadow color into account for the shadowmask.
// This applies even if the DirectionalLight shadow is disabled, which can be
// done to improve performance by disabling shadows for dynamic objects only.
light_attenuation = mix(shadow_color_contact.rgb, vec3(1.0), lightmap_sample.a);
#endif //ubershader-runtime

float depth_z = -vertex.z;
#ifdef LIGHT_DIRECTIONAL_SHADOW //ubershader-runtime
#if !defined(SHADOWS_DISABLED)
Expand Down Expand Up @@ -2236,10 +2250,11 @@ FRAGMENT_SHADER_CODE
shadow = min(shadow, contact_shadow);
}
#endif //ubershader-runtime
light_attenuation = mix(mix(shadow_color_contact.rgb, vec3(1.0), shadow), vec3(1.0), pssm_fade);
light_attenuation = mix(mix(shadow_color_contact.rgb, light_attenuation, shadow), light_attenuation, pssm_fade);
}

#endif // !defined(SHADOWS_DISABLED)

#endif //LIGHT_DIRECTIONAL_SHADOW //ubershader-runtime

#ifdef USE_VERTEX_LIGHTING //ubershader-runtime
Expand Down
5 changes: 3 additions & 2 deletions modules/denoise/denoise_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ void *oidn_denoiser_init() {
bool oidn_denoise(void *deviceptr, float *p_floats, int p_width, int p_height) {
OIDNDeviceImpl *device = (OIDNDeviceImpl *)deviceptr;
OIDNFilter filter = oidnNewFilter(device, "RTLightmap");
oidnSetSharedFilterImage(filter, "color", (void *)p_floats, OIDN_FORMAT_FLOAT3, p_width, p_height, 0, 0, 0);
oidnSetSharedFilterImage(filter, "output", (void *)p_floats, OIDN_FORMAT_FLOAT3, p_width, p_height, 0, 0, 0);
// Pass 16-byte pixel stride to preserve the unmodified 32-bit alpha channel.
oidnSetSharedFilterImage(filter, "color", (void *)p_floats, OIDN_FORMAT_FLOAT3, p_width, p_height, 0, 16, 0);
oidnSetSharedFilterImage(filter, "output", (void *)p_floats, OIDN_FORMAT_FLOAT3, p_width, p_height, 0, 16, 0);
oidnSetFilter1b(filter, "hdr", true);
oidnCommitFilter(filter);
oidnExecuteFilter(filter);
Expand Down
4 changes: 4 additions & 0 deletions modules/denoise/denoise_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@
#define DENOISE_WRAPPER_H

void *oidn_denoiser_init();

// Expects RGBAF image data. The alpha channel is configured to be ignored by OpenImageDenoise,
// and is preserved in the output data.
bool oidn_denoise(void *device, float *p_floats, int p_width, int p_height);

void oidn_denoiser_finish(void *device);

#endif // DENOISE_WRAPPER_H
2 changes: 1 addition & 1 deletion modules/denoise/lightmap_denoiser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ void LightmapDenoiserOIDN::make_default_denoiser() {
Ref<Image> LightmapDenoiserOIDN::denoise_image(const Ref<Image> &p_image) {
Ref<Image> img = p_image->duplicate();

img->convert(Image::FORMAT_RGBF);
img->convert(Image::FORMAT_RGBAF);

PoolByteArray data = img->get_data();
{
Expand Down
66 changes: 41 additions & 25 deletions modules/lightmapper_cpu/lightmapper_cpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -831,11 +831,16 @@ void LightmapperCPU::_compute_direct_light(uint32_t p_idx, void *r_lightmap) {
}
}

Vector3 final_energy = attenuation * penumbra * light_energy * MAX(0, normal.dot(-light_to_point));
const Vector3 final_energy = attenuation * penumbra * light_energy * MAX(0, normal.dot(-light_to_point));
lightmap[p_idx].direct_light += final_energy * light.indirect_multiplier;
if (light.bake_direct) {
lightmap[p_idx].output_light += final_energy;
}

if (light.type == LIGHT_TYPE_DIRECTIONAL) {
// Store the directional shadowmask, which does not depend on the light color, energy or angle.
lightmap[p_idx].shadowmask = CLAMP(lightmap[p_idx].shadowmask - attenuation * penumbra, 0.0, 1.0);
}
}
}

Expand Down Expand Up @@ -952,7 +957,7 @@ void LightmapperCPU::_post_process(uint32_t p_idx, void *r_output) {

LocalVector<int> &indices = scene_lightmap_indices[p_idx];
LocalVector<LightmapTexel> &lightmap = scene_lightmaps[p_idx];
Vector3 *output = ((LocalVector<Vector3> *)r_output)[p_idx].ptr();
Color *output = ((LocalVector<Color> *)r_output)[p_idx].ptr();
Vector2i size = mesh.size;

// Blit texels to buffer
Expand All @@ -961,7 +966,11 @@ void LightmapperCPU::_post_process(uint32_t p_idx, void *r_output) {
for (int j = 0; j < size.x; j++) {
int idx = indices[i * size.x + j];
if (idx >= 0) {
output[i * size.x + j] = lightmap[idx].output_light;
output[i * size.x + j] = Color(
lightmap[idx].output_light.x,
lightmap[idx].output_light.y,
lightmap[idx].output_light.z,
1.0 - lightmap[idx].shadowmask);
continue; // filled, skip
}

Expand Down Expand Up @@ -993,7 +1002,11 @@ void LightmapperCPU::_post_process(uint32_t p_idx, void *r_output) {
}

if (closest_idx != -1) {
output[i * size.x + j] = lightmap[closest_idx].output_light;
output[i * size.x + j] = Color(
lightmap[closest_idx].output_light.x,
lightmap[closest_idx].output_light.y,
lightmap[closest_idx].output_light.z,
1.0 - lightmap[closest_idx].shadowmask);
}
}
}
Expand Down Expand Up @@ -1033,7 +1046,6 @@ void LightmapperCPU::_post_process(uint32_t p_idx, void *r_output) {
_dilate_lightmap(output, indices, size, margin);
_fix_seams(seams, output, size);
_dilate_lightmap(output, indices, size, margin);

indices.clear();
}

Expand Down Expand Up @@ -1120,25 +1132,25 @@ void LightmapperCPU::_compute_seams(const MeshInstance &p_mesh, LocalVector<UVSe
}
}

void LightmapperCPU::_fix_seams(const LocalVector<UVSeam> &p_seams, Vector3 *r_lightmap, Vector2i p_size) {
LocalVector<Vector3> extra_buffer;
void LightmapperCPU::_fix_seams(const LocalVector<UVSeam> &p_seams, Color *r_lightmap, Vector2i p_size) {
LocalVector<Color> extra_buffer;
extra_buffer.resize(p_size.x * p_size.y);

memcpy(extra_buffer.ptr(), r_lightmap, p_size.x * p_size.y * sizeof(Vector3));
memcpy(extra_buffer.ptr(), r_lightmap, p_size.x * p_size.y * sizeof(Color));

Vector3 *read_ptr = extra_buffer.ptr();
Vector3 *write_ptr = r_lightmap;
Color *read_ptr = extra_buffer.ptr();
Color *write_ptr = r_lightmap;

for (int i = 0; i < 5; i++) {
for (unsigned int j = 0; j < p_seams.size(); j++) {
_fix_seam(p_seams[j].edge0[0], p_seams[j].edge0[1], p_seams[j].edge1[0], p_seams[j].edge1[1], read_ptr, write_ptr, p_size);
_fix_seam(p_seams[j].edge1[0], p_seams[j].edge1[1], p_seams[j].edge0[0], p_seams[j].edge0[1], read_ptr, write_ptr, p_size);
}
memcpy(read_ptr, write_ptr, p_size.x * p_size.y * sizeof(Vector3));
memcpy(read_ptr, write_ptr, p_size.x * p_size.y * sizeof(Color));
}
}

void LightmapperCPU::_fix_seam(const Vector2 &p_pos0, const Vector2 &p_pos1, const Vector2 &p_uv0, const Vector2 &p_uv1, const Vector3 *p_read_buffer, Vector3 *r_write_buffer, const Vector2i &p_size) {
void LightmapperCPU::_fix_seam(const Vector2 &p_pos0, const Vector2 &p_pos1, const Vector2 &p_uv0, const Vector2 &p_uv1, const Color *p_read_buffer, Color *r_write_buffer, const Vector2i &p_size) {
Vector2 line[2];
line[0] = p_pos0 * p_size;
line[1] = p_pos1 * p_size;
Expand Down Expand Up @@ -1187,8 +1199,8 @@ void LightmapperCPU::_fix_seam(const Vector2 &p_pos0, const Vector2 &p_pos1, con
Vector2 current_uv = p_uv0 * (1.0 - t) + p_uv1 * t;
Vector2i sampled_point = (current_uv * p_size).floor();

Vector3 current_color = r_write_buffer[pixel.y * p_size.x + pixel.x];
Vector3 sampled_color = p_read_buffer[sampled_point.y * p_size.x + sampled_point.x];
Color current_color = r_write_buffer[pixel.y * p_size.x + pixel.x];
Color sampled_color = p_read_buffer[sampled_point.y * p_size.x + sampled_point.x];

r_write_buffer[pixel.y * p_size.x + pixel.x] = current_color * 0.6f + sampled_color * 0.4f;

Expand All @@ -1206,7 +1218,7 @@ void LightmapperCPU::_fix_seam(const Vector2 &p_pos0, const Vector2 &p_pos1, con
}
}

void LightmapperCPU::_dilate_lightmap(Vector3 *r_lightmap, const LocalVector<int> p_indices, Vector2i p_size, int margin) {
void LightmapperCPU::_dilate_lightmap(Color *r_lightmap, const LocalVector<int> p_indices, Vector2i p_size, int margin) {
for (int i = 0; i < p_size.y; i++) {
for (int j = 0; j < p_size.x; j++) {
int idx = p_indices[i * p_size.x + j];
Expand Down Expand Up @@ -1248,17 +1260,17 @@ void LightmapperCPU::_dilate_lightmap(Vector3 *r_lightmap, const LocalVector<int
}
}

void LightmapperCPU::_blit_lightmap(const Vector<Vector3> &p_src, const Vector2i &p_size, Ref<Image> &p_dst, int p_x, int p_y, bool p_with_padding) {
void LightmapperCPU::_blit_lightmap(const Vector<Color> &p_src, const Vector2i &p_size, Ref<Image> &p_dst, int p_x, int p_y, bool p_with_padding) {
int padding = p_with_padding ? 1 : 0;
ERR_FAIL_COND(p_x < padding || p_y < padding);
ERR_FAIL_COND(p_x + p_size.x > p_dst->get_width() - padding);
ERR_FAIL_COND(p_y + p_size.y > p_dst->get_height() - padding);

p_dst->lock();
for (int y = 0; y < p_size.y; y++) {
const Vector3 *__restrict src = p_src.ptr() + y * p_size.x;
const Color *__restrict src = p_src.ptr() + y * p_size.x;
for (int x = 0; x < p_size.x; x++) {
p_dst->set_pixel(p_x + x, p_y + y, Color(src->x, src->y, src->z));
p_dst->set_pixel(p_x + x, p_y + y, Color(src->r, src->g, src->b, src->a));
src++;
}
}
Expand All @@ -1268,16 +1280,16 @@ void LightmapperCPU::_blit_lightmap(const Vector<Vector3> &p_src, const Vector2i
int yy = CLAMP(y, 0, p_size.y - 1);
int idx_left = yy * p_size.x;
int idx_right = idx_left + p_size.x - 1;
p_dst->set_pixel(p_x - 1, p_y + y, Color(p_src[idx_left].x, p_src[idx_left].y, p_src[idx_left].z));
p_dst->set_pixel(p_x + p_size.x, p_y + y, Color(p_src[idx_right].x, p_src[idx_right].y, p_src[idx_right].z));
p_dst->set_pixel(p_x - 1, p_y + y, Color(p_src[idx_left].r, p_src[idx_left].g, p_src[idx_left].b, p_src[idx_left].a));
p_dst->set_pixel(p_x + p_size.x, p_y + y, Color(p_src[idx_right].r, p_src[idx_right].g, p_src[idx_right].b, p_src[idx_right].a));
}

for (int x = -1; x < p_size.x + 1; x++) {
int xx = CLAMP(x, 0, p_size.x - 1);
int idx_top = xx;
int idx_bot = idx_top + (p_size.y - 1) * p_size.x;
p_dst->set_pixel(p_x + x, p_y - 1, Color(p_src[idx_top].x, p_src[idx_top].y, p_src[idx_top].z));
p_dst->set_pixel(p_x + x, p_y + p_size.y, Color(p_src[idx_bot].x, p_src[idx_bot].y, p_src[idx_bot].z));
p_dst->set_pixel(p_x + x, p_y - 1, Color(p_src[idx_top].r, p_src[idx_top].g, p_src[idx_top].b, p_src[idx_top].a));
p_dst->set_pixel(p_x + x, p_y + p_size.y, Color(p_src[idx_bot].r, p_src[idx_bot].g, p_src[idx_bot].b, p_src[idx_bot].a));
}
}
p_dst->unlock();
Expand Down Expand Up @@ -1456,7 +1468,7 @@ LightmapperCPU::BakeError LightmapperCPU::bake(BakeQuality p_quality, bool p_use

raycaster.unref(); // Not needed anymore, free some memory.

LocalVector<LocalVector<Vector3>> lightmaps_data;
LocalVector<LocalVector<Color>> lightmaps_data;
lightmaps_data.resize(mesh_instances.size());

for (unsigned int i = 0; i < mesh_instances.size(); i++) {
Expand All @@ -1483,7 +1495,9 @@ LightmapperCPU::BakeError LightmapperCPU::bake(BakeQuality p_quality, bool p_use
for (int i = 0; i < atlas_slices; i++) {
Ref<Image> image;
image.instance();
image->create(atlas_size.x, atlas_size.y, false, Image::FORMAT_RGBH);
// FIXME: Baking alpha channel only works if image format is RGBA8, not RGBAH.
// However, using RGBA8 breaks HDR light baking, so only LDR light baking can be used for now.
image->create(atlas_size.x, atlas_size.y, false, Image::FORMAT_RGBA8);
bake_textures[i] = image;
}
} else {
Expand Down Expand Up @@ -1516,7 +1530,9 @@ LightmapperCPU::BakeError LightmapperCPU::bake(BakeQuality p_quality, bool p_use

Ref<Image> image;
image.instance();
image->create(mesh_instances[i].size.x, mesh_instances[i].size.y, false, Image::FORMAT_RGBH);
// FIXME: Baking alpha channel only works if image format is RGBA8, not RGBAH.
// However, using RGBA8 breaks HDR light baking, so only LDR light baking can be used for now.
image->create(mesh_instances[i].size.x, mesh_instances[i].size.y, false, Image::FORMAT_RGBA8);
image->set_name(mesh_name);
bake_textures[i] = image;
}
Expand Down
9 changes: 5 additions & 4 deletions modules/lightmapper_cpu/lightmapper_cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class LightmapperCPU : public Lightmapper {

Vector3 direct_light;
Vector3 output_light;
float shadowmask = 1.0;

float area_coverage;
};
Expand Down Expand Up @@ -160,11 +161,11 @@ class LightmapperCPU : public Lightmapper {

void _post_process(uint32_t p_idx, void *r_output);
void _compute_seams(const MeshInstance &p_mesh, LocalVector<UVSeam> &r_seams);
void _fix_seams(const LocalVector<UVSeam> &p_seams, Vector3 *r_lightmap, Vector2i p_size);
void _fix_seam(const Vector2 &p_pos0, const Vector2 &p_pos1, const Vector2 &p_uv0, const Vector2 &p_uv1, const Vector3 *p_read_buffer, Vector3 *r_write_buffer, const Vector2i &p_size);
void _dilate_lightmap(Vector3 *r_lightmap, const LocalVector<int> p_indices, Vector2i p_size, int margin);
void _fix_seams(const LocalVector<UVSeam> &p_seams, Color *r_lightmap, Vector2i p_size);
void _fix_seam(const Vector2 &p_pos0, const Vector2 &p_pos1, const Vector2 &p_uv0, const Vector2 &p_uv1, const Color *p_read_buffer, Color *r_write_buffer, const Vector2i &p_size);
void _dilate_lightmap(Color *r_lightmap, const LocalVector<int> p_indices, Vector2i p_size, int margin);

void _blit_lightmap(const Vector<Vector3> &p_src, const Vector2i &p_size, Ref<Image> &p_dst, int p_x, int p_y, bool p_with_padding);
void _blit_lightmap(const Vector<Color> &p_src, const Vector2i &p_size, Ref<Image> &p_dst, int p_x, int p_y, bool p_with_padding);

public:
virtual void add_albedo_texture(Ref<Texture> p_texture);
Expand Down
Loading

0 comments on commit 92258eb

Please sign in to comment.