1
0
Fork 0
This commit is contained in:
Rudolph Bester 2025-02-28 01:36:38 +01:00 committed by GitHub
commit d5948d0d00
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 81 additions and 77 deletions

View File

@ -812,34 +812,34 @@ LightmapperRD::BakeError LightmapperRD::_dilate(RenderingDevice *rd, Ref<RDShade
return BAKE_OK; return BAKE_OK;
} }
LightmapperRD::BakeError LightmapperRD::_pack_l1(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices) { // LightmapperRD::BakeError LightmapperRD::_pack_l1(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices) {
Vector<RD::Uniform> uniforms = dilate_or_denoise_common_uniforms(source_light_tex, dest_light_tex); // Vector<RD::Uniform> uniforms = dilate_or_denoise_common_uniforms(source_light_tex, dest_light_tex);
//
RID compute_shader_pack = rd->shader_create_from_spirv(compute_shader->get_spirv_stages("pack_coeffs")); // RID compute_shader_pack = rd->shader_create_from_spirv(compute_shader->get_spirv_stages("pack_coeffs"));
ERR_FAIL_COND_V(compute_shader_pack.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen // ERR_FAIL_COND_V(compute_shader_pack.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen
RID compute_shader_pack_pipeline = rd->compute_pipeline_create(compute_shader_pack); // RID compute_shader_pack_pipeline = rd->compute_pipeline_create(compute_shader_pack);
//
RID dilate_uniform_set = rd->uniform_set_create(uniforms, compute_shader_pack, 1); // RID dilate_uniform_set = rd->uniform_set_create(uniforms, compute_shader_pack, 1);
//
RD::ComputeListID compute_list = rd->compute_list_begin(); // RD::ComputeListID compute_list = rd->compute_list_begin();
rd->compute_list_bind_compute_pipeline(compute_list, compute_shader_pack_pipeline); // rd->compute_list_bind_compute_pipeline(compute_list, compute_shader_pack_pipeline);
rd->compute_list_bind_uniform_set(compute_list, compute_base_uniform_set, 0); // rd->compute_list_bind_uniform_set(compute_list, compute_base_uniform_set, 0);
rd->compute_list_bind_uniform_set(compute_list, dilate_uniform_set, 1); // rd->compute_list_bind_uniform_set(compute_list, dilate_uniform_set, 1);
push_constant.region_ofs[0] = 0; // push_constant.region_ofs[0] = 0;
push_constant.region_ofs[1] = 0; // push_constant.region_ofs[1] = 0;
Vector3i group_size(Math::division_round_up(atlas_size.x, 8), Math::division_round_up(atlas_size.y, 8), 1); //restore group size // Vector3i group_size(Math::division_round_up(atlas_size.x, 8), Math::division_round_up(atlas_size.y, 8), 1); //restore group size
//
for (int i = 0; i < atlas_slices; i++) { // for (int i = 0; i < atlas_slices; i++) {
push_constant.atlas_slice = i; // push_constant.atlas_slice = i;
rd->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant)); // rd->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
rd->compute_list_dispatch(compute_list, group_size.x, group_size.y, group_size.z); // rd->compute_list_dispatch(compute_list, group_size.x, group_size.y, group_size.z);
//no barrier, let them run all together // //no barrier, let them run all together
} // }
rd->compute_list_end(); // rd->compute_list_end();
rd->free(compute_shader_pack); // rd->free(compute_shader_pack);
//
return BAKE_OK; // return BAKE_OK;
} // }
Error LightmapperRD::_store_pfm(RenderingDevice *p_rd, RID p_atlas_tex, int p_index, const Size2i &p_atlas_size, const String &p_name, bool p_shadowmask) { Error LightmapperRD::_store_pfm(RenderingDevice *p_rd, RID p_atlas_tex, int p_index, const Size2i &p_atlas_size, const String &p_name, bool p_shadowmask) {
Vector<uint8_t> data = p_rd->texture_get_data(p_atlas_tex, p_index); Vector<uint8_t> data = p_rd->texture_get_data(p_atlas_tex, p_index);
@ -2259,13 +2259,13 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
} }
} }
if (p_bake_sh) { // if (p_bake_sh) {
SWAP(light_accum_tex, light_accum_tex2); // SWAP(light_accum_tex, light_accum_tex2);
BakeError error = _pack_l1(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, light_accum_tex, atlas_size, atlas_slices); // BakeError error = _pack_l1(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, light_accum_tex, atlas_size, atlas_slices);
if (unlikely(error != BAKE_OK)) { // if (unlikely(error != BAKE_OK)) {
return error; // return error;
} // }
} // }
#ifdef DEBUG_TEXTURES #ifdef DEBUG_TEXTURES

View File

@ -282,7 +282,7 @@ class LightmapperRD : public Lightmapper {
BakeError _dilate(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices); BakeError _dilate(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices);
BakeError _denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, int p_denoiser_range, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function, void *p_bake_userdata); BakeError _denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, int p_denoiser_range, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function, void *p_bake_userdata);
BakeError _pack_l1(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices); // BakeError _pack_l1(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices);
Error _store_pfm(RenderingDevice *p_rd, RID p_atlas_tex, int p_index, const Size2i &p_atlas_size, const String &p_name, bool p_shadowmask); Error _store_pfm(RenderingDevice *p_rd, RID p_atlas_tex, int p_index, const Size2i &p_atlas_size, const String &p_name, bool p_shadowmask);
Ref<Image> _read_pfm(const String &p_name, bool p_shadowmask); Ref<Image> _read_pfm(const String &p_name, bool p_shadowmask);

View File

@ -6,7 +6,7 @@ dilate = "#define MODE_DILATE";
unocclude = "#define MODE_UNOCCLUDE"; unocclude = "#define MODE_UNOCCLUDE";
light_probes = "#define MODE_LIGHT_PROBES"; light_probes = "#define MODE_LIGHT_PROBES";
denoise = "#define MODE_DENOISE"; denoise = "#define MODE_DENOISE";
pack_coeffs = "#define MODE_PACK_L1_COEFFS"; //pack_coeffs = "#define MODE_PACK_L1_COEFFS";
#[compute] #[compute]
@ -66,7 +66,7 @@ layout(rgba8, set = 1, binding = 5) uniform restrict writeonly image2DArray shad
layout(set = 1, binding = 5) uniform texture2D environment; layout(set = 1, binding = 5) uniform texture2D environment;
#endif #endif
#if defined(MODE_DILATE) || defined(MODE_DENOISE) || defined(MODE_PACK_L1_COEFFS) #if defined(MODE_DILATE) || defined(MODE_DENOISE) // || defined(MODE_PACK_L1_COEFFS)
layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2DArray dest_light; layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2DArray dest_light;
layout(set = 1, binding = 1) uniform texture2DArray source_light; layout(set = 1, binding = 1) uniform texture2DArray source_light;
#endif #endif
@ -861,15 +861,19 @@ void main() {
light_for_texture += light; light_for_texture += light;
#ifdef USE_SH_LIGHTMAPS #ifdef USE_SH_LIGHTMAPS
// These coefficients include the factored out SH evaluation, diffuse convolution, and final application, as well as the BRDF 1/PI and the spherical monte carlo factor. // Since we don't want to double attenuate the light we need to undo attenuation based on the surface
// LO: 1/(2*sqrtPI) * 1/(2*sqrtPI) * PI * PI * 1/PI = 0.25 // normal before encoding it into SH coefficients
// L1: sqrt(3/(4*pi)) * sqrt(3/(4*pi)) * (PI*2/3) * (2 * PI) * 1/PI = 1.0 if (dot(normal, light_dir) > 0.0) {
// Note: This only works because we aren't scaling, rotating, or combing harmonics, we are just directing applying them in the shader. light /= dot(normal, light_dir);
}
// Different coefficients are used because we are directly encoding point lights.
// L0: Zero is used since the lighting should be able to attenuate to zero (at 90 degrees)
// L1: 1 is to no increase or decrease the lights intensity. This should match dynamic lighting.
float c[4] = float[]( float c[4] = float[](
0.25, //l0 0, //l0
light_dir.y, //l1n1 light_dir.y, //l1n1
light_dir.z, //l1n0 light_dir.z, //l1n0 (Should always be positive)
light_dir.x //l1p1 light_dir.x //l1p1
); );

View File

@ -204,13 +204,13 @@ bool LightmapGIData::is_using_spherical_harmonics() const {
return uses_spherical_harmonics; return uses_spherical_harmonics;
} }
void LightmapGIData::_set_uses_packed_directional(bool p_enable) { // void LightmapGIData::_set_uses_packed_directional(bool p_enable) {
_uses_packed_directional = p_enable; // _uses_packed_directional = p_enable;
} // }
bool LightmapGIData::_is_using_packed_directional() const { // bool LightmapGIData::_is_using_packed_directional() const {
return _uses_packed_directional; // return _uses_packed_directional;
} // }
void LightmapGIData::update_shadowmask_mode(ShadowmaskMode p_mode) { void LightmapGIData::update_shadowmask_mode(ShadowmaskMode p_mode) {
RS::get_singleton()->lightmap_set_shadowmask_mode(lightmap, (RS::ShadowmaskMode)p_mode); RS::get_singleton()->lightmap_set_shadowmask_mode(lightmap, (RS::ShadowmaskMode)p_mode);
@ -327,8 +327,8 @@ void LightmapGIData::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_uses_spherical_harmonics", "uses_spherical_harmonics"), &LightmapGIData::set_uses_spherical_harmonics); ClassDB::bind_method(D_METHOD("set_uses_spherical_harmonics", "uses_spherical_harmonics"), &LightmapGIData::set_uses_spherical_harmonics);
ClassDB::bind_method(D_METHOD("is_using_spherical_harmonics"), &LightmapGIData::is_using_spherical_harmonics); ClassDB::bind_method(D_METHOD("is_using_spherical_harmonics"), &LightmapGIData::is_using_spherical_harmonics);
ClassDB::bind_method(D_METHOD("_set_uses_packed_directional", "_uses_packed_directional"), &LightmapGIData::_set_uses_packed_directional); // ClassDB::bind_method(D_METHOD("_set_uses_packed_directional", "_uses_packed_directional"), &LightmapGIData::_set_uses_packed_directional);
ClassDB::bind_method(D_METHOD("_is_using_packed_directional"), &LightmapGIData::_is_using_packed_directional); // ClassDB::bind_method(D_METHOD("_is_using_packed_directional"), &LightmapGIData::_is_using_packed_directional);
ClassDB::bind_method(D_METHOD("add_user", "path", "uv_scale", "slice_index", "sub_instance"), &LightmapGIData::add_user); ClassDB::bind_method(D_METHOD("add_user", "path", "uv_scale", "slice_index", "sub_instance"), &LightmapGIData::add_user);
ClassDB::bind_method(D_METHOD("get_user_count"), &LightmapGIData::get_user_count); ClassDB::bind_method(D_METHOD("get_user_count"), &LightmapGIData::get_user_count);
@ -343,7 +343,7 @@ void LightmapGIData::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uses_spherical_harmonics", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_uses_spherical_harmonics", "is_using_spherical_harmonics"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uses_spherical_harmonics", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_uses_spherical_harmonics", "is_using_spherical_harmonics");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_user_data", "_get_user_data"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_user_data", "_get_user_data");
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "probe_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_probe_data", "_get_probe_data"); ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "probe_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_probe_data", "_get_probe_data");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "_uses_packed_directional", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_uses_packed_directional", "_is_using_packed_directional"); // ADD_PROPERTY(PropertyInfo(Variant::BOOL, "_uses_packed_directional", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_uses_packed_directional", "_is_using_packed_directional");
#ifndef DISABLE_DEPRECATED #ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_light_texture", "light_texture"), &LightmapGIData::set_light_texture); ClassDB::bind_method(D_METHOD("set_light_texture", "light_texture"), &LightmapGIData::set_light_texture);
@ -807,7 +807,7 @@ void LightmapGI::_gen_new_positions_from_octree(const GenProbesOctree *p_cell, f
} }
} }
LightmapGI::BakeError LightmapGI::_save_and_reimport_atlas_textures(const Ref<Lightmapper> p_lightmapper, const String &p_base_name, TypedArray<TextureLayered> &r_textures, bool p_is_shadowmask) const { LightmapGI::BakeError LightmapGI::_save_and_reimport_atlas_textures(const Ref<Lightmapper> p_lightmapper, const String &p_base_name, TypedArray<TextureLayered> &r_textures, bool p_is_shadowmask, bool p_compress) const {
Vector<Ref<Image>> images; Vector<Ref<Image>> images;
images.resize(p_is_shadowmask ? p_lightmapper->get_shadowmask_texture_count() : p_lightmapper->get_bake_texture_count()); images.resize(p_is_shadowmask ? p_lightmapper->get_shadowmask_texture_count() : p_lightmapper->get_bake_texture_count());
@ -849,7 +849,7 @@ LightmapGI::BakeError LightmapGI::_save_and_reimport_atlas_textures(const Ref<Li
config->set_value("remap", "type", "CompressedTexture2DArray"); config->set_value("remap", "type", "CompressedTexture2DArray");
if (!config->has_section_key("params", "compress/mode")) { if (!config->has_section_key("params", "compress/mode")) {
// Do not override an existing compression mode. // Do not override an existing compression mode.
config->set_value("params", "compress/mode", 2); config->set_value("params", "compress/mode", p_compress ? 2 : 3);
} }
config->set_value("params", "compress/channel_pack", 1); config->set_value("params", "compress/channel_pack", 1);
config->set_value("params", "mipmaps/generate", false); config->set_value("params", "mipmaps/generate", false);
@ -1289,12 +1289,12 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
const bool save_shadowmask = shadowmask_mode != LightmapGIData::SHADOWMASK_MODE_NONE && shadowmask_texture_count > 0; const bool save_shadowmask = shadowmask_mode != LightmapGIData::SHADOWMASK_MODE_NONE && shadowmask_texture_count > 0;
// Save the lightmap atlases. // Save the lightmap atlases.
BakeError save_err = _save_and_reimport_atlas_textures(lightmapper, texture_filename, lightmap_textures, false); BakeError save_err = _save_and_reimport_atlas_textures(lightmapper, texture_filename, lightmap_textures, false, false);
ERR_FAIL_COND_V(save_err != BAKE_ERROR_OK, save_err); ERR_FAIL_COND_V(save_err != BAKE_ERROR_OK, save_err);
if (save_shadowmask) { if (save_shadowmask) {
// Save the shadowmask atlases. // Save the shadowmask atlases.
save_err = _save_and_reimport_atlas_textures(lightmapper, texture_filename + "_shadow", shadowmask_textures, true); save_err = _save_and_reimport_atlas_textures(lightmapper, texture_filename + "_shadow", shadowmask_textures, true, true);
ERR_FAIL_COND_V(save_err != BAKE_ERROR_OK, save_err); ERR_FAIL_COND_V(save_err != BAKE_ERROR_OK, save_err);
} }
@ -1319,7 +1319,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
} }
gi_data->set_uses_spherical_harmonics(directional); gi_data->set_uses_spherical_harmonics(directional);
gi_data->_set_uses_packed_directional(directional); // New SH lightmaps are packed automatically. // gi_data->_set_uses_packed_directional(directional); // New SH lightmaps are packed automatically.
for (int i = 0; i < lightmapper->get_bake_mesh_count(); i++) { for (int i = 0; i < lightmapper->get_bake_mesh_count(); i++) {
Dictionary d = lightmapper->get_bake_mesh_userdata(i); Dictionary d = lightmapper->get_bake_mesh_userdata(i);
@ -1485,12 +1485,12 @@ void LightmapGI::_notification(int p_what) {
switch (p_what) { switch (p_what) {
case NOTIFICATION_POST_ENTER_TREE: { case NOTIFICATION_POST_ENTER_TREE: {
if (light_data.is_valid()) { if (light_data.is_valid()) {
ERR_FAIL_COND_MSG( // ERR_FAIL_COND_MSG(
light_data->is_using_spherical_harmonics() && !light_data->_is_using_packed_directional(), // light_data->is_using_spherical_harmonics() && !light_data->_is_using_packed_directional(),
vformat( // vformat(
"%s (%s): The directional lightmap textures are stored in a format that isn't supported anymore. Please bake lightmaps again to make lightmaps display from this node again.", // "%s (%s): The directional lightmap textures are stored in a format that isn't supported anymore. Please bake lightmaps again to make lightmaps display from this node again.",
get_light_data()->get_path(), get_name())); // get_light_data()->get_path(), get_name()));
//
if (last_owner && last_owner != get_owner()) { if (last_owner && last_owner != get_owner()) {
light_data->clear_users(); light_data->clear_users();
} }

View File

@ -64,7 +64,7 @@ private:
bool uses_spherical_harmonics = false; bool uses_spherical_harmonics = false;
bool interior = false; bool interior = false;
bool _uses_packed_directional = false; // bool _uses_packed_directional = false;
RID lightmap; RID lightmap;
AABB bounds; AABB bounds;
@ -110,8 +110,8 @@ public:
void set_uses_spherical_harmonics(bool p_enable); void set_uses_spherical_harmonics(bool p_enable);
bool is_using_spherical_harmonics() const; bool is_using_spherical_harmonics() const;
void _set_uses_packed_directional(bool p_enable); // void _set_uses_packed_directional(bool p_enable);
bool _is_using_packed_directional() const; // bool _is_using_packed_directional() const;
void update_shadowmask_mode(ShadowmaskMode p_mode); void update_shadowmask_mode(ShadowmaskMode p_mode);
ShadowmaskMode get_shadowmask_mode() const; ShadowmaskMode get_shadowmask_mode() const;
@ -273,7 +273,7 @@ private:
void _plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cell_size, const Vector3 *p_triangle); void _plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cell_size, const Vector3 *p_triangle);
void _gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool> &positions_used, const AABB &p_bounds); void _gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool> &positions_used, const AABB &p_bounds);
BakeError _save_and_reimport_atlas_textures(const Ref<Lightmapper> p_lightmapper, const String &p_base_name, TypedArray<TextureLayered> &r_textures, bool p_is_shadowmask = false) const; BakeError _save_and_reimport_atlas_textures(const Ref<Lightmapper> p_lightmapper, const String &p_base_name, TypedArray<TextureLayered> &r_textures, bool p_is_shadowmask = false, bool p_compress = false) const;
protected: protected:
void _validate_property(PropertyInfo &p_property) const; void _validate_property(PropertyInfo &p_property) const;

View File

@ -1690,23 +1690,23 @@ void fragment_shader(in SceneData scene_data) {
if (sc_use_lightmap_bicubic_filter()) { if (sc_use_lightmap_bicubic_filter()) {
lm_light_l0 = textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 0.0), lightmaps.data[ofs].light_texture_size).rgb; lm_light_l0 = textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 0.0), lightmaps.data[ofs].light_texture_size).rgb;
lm_light_l1n1 = (textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 1.0), lightmaps.data[ofs].light_texture_size).rgb - vec3(0.5)) * 2.0; lm_light_l1n1 = textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 1.0), lightmaps.data[ofs].light_texture_size).rgb;
lm_light_l1_0 = (textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 2.0), lightmaps.data[ofs].light_texture_size).rgb - vec3(0.5)) * 2.0; lm_light_l1_0 = textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 2.0), lightmaps.data[ofs].light_texture_size).rgb;
lm_light_l1p1 = (textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 3.0), lightmaps.data[ofs].light_texture_size).rgb - vec3(0.5)) * 2.0; lm_light_l1p1 = textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 3.0), lightmaps.data[ofs].light_texture_size).rgb;
} else { } else {
lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb; lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb;
lm_light_l1n1 = (textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb - vec3(0.5)) * 2.0; lm_light_l1n1 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb;
lm_light_l1_0 = (textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb - vec3(0.5)) * 2.0; lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb;
lm_light_l1p1 = (textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb - vec3(0.5)) * 2.0; lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb;
} }
vec3 n = normalize(lightmaps.data[ofs].normal_xform * normal); vec3 n = normalize(lightmaps.data[ofs].normal_xform * normal);
float en = lightmaps.data[ofs].exposure_normalization; float en = lightmaps.data[ofs].exposure_normalization;
ambient_light += lm_light_l0 * en; ambient_light += lm_light_l0 * en;
ambient_light += lm_light_l1n1 * n.y * (lm_light_l0 * en * 4.0); ambient_light += lm_light_l1n1 * n.y * en;
ambient_light += lm_light_l1_0 * n.z * (lm_light_l0 * en * 4.0); ambient_light += lm_light_l1_0 * n.z * en;
ambient_light += lm_light_l1p1 * n.x * (lm_light_l0 * en * 4.0); ambient_light += lm_light_l1p1 * n.x * en;
} else { } else {
if (sc_use_lightmap_bicubic_filter()) { if (sc_use_lightmap_bicubic_filter()) {