فهرست منبع

Avoid reimporting lightmap textures every getter call

Kongfa Waroros 2 سال پیش
والد
کامیت
c165f0cf2e
3فایلهای تغییر یافته به همراه130 افزوده شده و 96 حذف شده
  1. 5 1
      doc/classes/LightmapGIData.xml
  2. 114 93
      scene/3d/lightmap_gi.cpp
  3. 11 2
      scene/3d/lightmap_gi.h

+ 5 - 1
doc/classes/LightmapGIData.xml

@@ -54,8 +54,12 @@
 		</method>
 	</methods>
 	<members>
-		<member name="light_texture" type="TextureLayered" setter="set_light_texture" getter="get_light_texture">
+		<member name="light_texture" type="TextureLayered" setter="set_light_texture" getter="get_light_texture" is_deprecated="true">
 			The lightmap atlas texture generated by the lightmapper.
+			[i]Deprecated.[/i] The lightmap atlas can now have multiple textures. See [member lightmap_textures].
+		</member>
+		<member name="lightmap_textures" type="TextureLayered[]" setter="set_lightmap_textures" getter="get_lightmap_textures" default="[]">
+			The lightmap atlas textures generated by the lightmapper.
 		</member>
 	</members>
 </class>

+ 114 - 93
scene/3d/lightmap_gi.cpp

@@ -97,11 +97,16 @@ Array LightmapGIData::_get_user_data() const {
 	return ret;
 }
 
-void LightmapGIData::_set_light_textures_data(const Array &p_data) {
-	ERR_FAIL_COND(p_data.is_empty());
+void LightmapGIData::set_lightmap_textures(const TypedArray<TextureLayered> &p_data) {
+	light_textures = p_data;
+	if (p_data.is_empty()) {
+		light_texture = Ref<TextureLayered>();
+		_reset_lightmap_textures();
+		return;
+	}
 
 	if (p_data.size() == 1) {
-		set_light_texture(p_data[0]);
+		light_texture = p_data[0];
 	} else {
 		Vector<Ref<Image>> images;
 		for (int i = 0; i < p_data.size(); i++) {
@@ -116,73 +121,13 @@ void LightmapGIData::_set_light_textures_data(const Array &p_data) {
 		combined_texture.instantiate();
 
 		combined_texture->create_from_images(images);
-		set_light_texture(combined_texture);
+		light_texture = combined_texture;
 	}
+	_reset_lightmap_textures();
 }
 
-Array LightmapGIData::_get_light_textures_data() const {
-	Array ret;
-	if (light_texture.is_null() || light_texture->get_layers() == 0) {
-		return ret;
-	}
-
-	Vector<Ref<Image>> images;
-	for (int i = 0; i < light_texture->get_layers(); i++) {
-		images.push_back(light_texture->get_layer_data(i));
-	}
-
-	int slice_count = images.size();
-	int slice_width = images[0]->get_width();
-	int slice_height = images[0]->get_height();
-
-	int slices_per_texture = Image::MAX_HEIGHT / slice_height;
-	int texture_count = Math::ceil(slice_count / (float)slices_per_texture);
-
-	ret.resize(texture_count);
-
-	String base_name = get_path().get_basename();
-
-	int last_count = slice_count % slices_per_texture;
-	for (int i = 0; i < texture_count; i++) {
-		int texture_slice_count = (i == texture_count - 1 && last_count != 0) ? last_count : slices_per_texture;
-
-		Ref<Image> texture_image = Image::create_empty(slice_width, slice_height * texture_slice_count, false, images[0]->get_format());
-
-		for (int j = 0; j < texture_slice_count; j++) {
-			texture_image->blit_rect(images[i * slices_per_texture + j], Rect2i(0, 0, slice_width, slice_height), Point2i(0, slice_height * j));
-		}
-
-		String texture_path = texture_count > 1 ? base_name + "_" + itos(i) + ".exr" : base_name + ".exr";
-
-		Ref<ConfigFile> config;
-		config.instantiate();
-
-		if (FileAccess::exists(texture_path + ".import")) {
-			config->load(texture_path + ".import");
-		}
-
-		config->set_value("remap", "importer", "2d_array_texture");
-		config->set_value("remap", "type", "CompressedTexture2DArray");
-		if (!config->has_section_key("params", "compress/mode")) {
-			// User may want another compression, so leave it be, but default to VRAM uncompressed.
-			config->set_value("params", "compress/mode", 3);
-		}
-		config->set_value("params", "compress/channel_pack", 1);
-		config->set_value("params", "mipmaps/generate", false);
-		config->set_value("params", "slices/horizontal", 1);
-		config->set_value("params", "slices/vertical", texture_slice_count);
-
-		config->save(texture_path + ".import");
-
-		Error err = texture_image->save_exr(texture_path, false);
-		ERR_FAIL_COND_V(err, ret);
-		ResourceLoader::import(texture_path);
-		Ref<TextureLayered> t = ResourceLoader::load(texture_path); //if already loaded, it will be updated on refocus?
-		ERR_FAIL_COND_V(t.is_null(), ret);
-		ret[i] = t;
-	}
-
-	return ret;
+TypedArray<TextureLayered> LightmapGIData::get_lightmap_textures() const {
+	return light_textures;
 }
 
 RID LightmapGIData::get_rid() const {
@@ -193,18 +138,13 @@ void LightmapGIData::clear() {
 	users.clear();
 }
 
-void LightmapGIData::set_light_texture(const Ref<TextureLayered> &p_light_texture) {
-	light_texture = p_light_texture;
+void LightmapGIData::_reset_lightmap_textures() {
 	RS::get_singleton()->lightmap_set_textures(lightmap, light_texture.is_valid() ? light_texture->get_rid() : RID(), uses_spherical_harmonics);
 }
 
-Ref<TextureLayered> LightmapGIData::get_light_texture() const {
-	return light_texture;
-}
-
 void LightmapGIData::set_uses_spherical_harmonics(bool p_enable) {
 	uses_spherical_harmonics = p_enable;
-	RS::get_singleton()->lightmap_set_textures(lightmap, light_texture.is_valid() ? light_texture->get_rid() : RID(), uses_spherical_harmonics);
+	_reset_lightmap_textures();
 }
 
 bool LightmapGIData::is_using_spherical_harmonics() const {
@@ -282,15 +222,35 @@ Dictionary LightmapGIData::_get_probe_data() const {
 	return d;
 }
 
+#ifndef DISABLE_DEPRECATED
+void LightmapGIData::set_light_texture(const Ref<TextureLayered> &p_light_texture) {
+	TypedArray<TextureLayered> arr;
+	arr.append(p_light_texture);
+	set_lightmap_textures(arr);
+}
+
+Ref<TextureLayered> LightmapGIData::get_light_texture() const {
+	if (light_textures.is_empty()) {
+		return Ref<TextureLayered>();
+	}
+	return light_textures.get(0);
+}
+
+void LightmapGIData::_set_light_textures_data(const Array &p_data) {
+	set_lightmap_textures(p_data);
+}
+
+Array LightmapGIData::_get_light_textures_data() const {
+	return Array(light_textures);
+}
+#endif
+
 void LightmapGIData::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("_set_user_data", "data"), &LightmapGIData::_set_user_data);
 	ClassDB::bind_method(D_METHOD("_get_user_data"), &LightmapGIData::_get_user_data);
 
-	ClassDB::bind_method(D_METHOD("set_light_texture", "light_texture"), &LightmapGIData::set_light_texture);
-	ClassDB::bind_method(D_METHOD("get_light_texture"), &LightmapGIData::get_light_texture);
-
-	ClassDB::bind_method(D_METHOD("_set_light_textures_data", "data"), &LightmapGIData::_set_light_textures_data);
-	ClassDB::bind_method(D_METHOD("_get_light_textures_data"), &LightmapGIData::_get_light_textures_data);
+	ClassDB::bind_method(D_METHOD("set_lightmap_textures", "light_textures"), &LightmapGIData::set_lightmap_textures);
+	ClassDB::bind_method(D_METHOD("get_lightmap_textures"), &LightmapGIData::get_lightmap_textures);
 
 	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);
@@ -303,11 +263,21 @@ void LightmapGIData::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("_set_probe_data", "data"), &LightmapGIData::_set_probe_data);
 	ClassDB::bind_method(D_METHOD("_get_probe_data"), &LightmapGIData::_get_probe_data);
 
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_texture", PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered", PROPERTY_USAGE_EDITOR), "set_light_texture", "get_light_texture"); // property usage default but no save
-	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "light_textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_light_textures_data", "_get_light_textures_data");
+	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "lightmap_textures", PROPERTY_HINT_ARRAY_TYPE, "TextureLayered", PROPERTY_USAGE_NO_EDITOR), "set_lightmap_textures", "get_lightmap_textures");
 	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::DICTIONARY, "probe_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_probe_data", "_get_probe_data");
+
+#ifndef DISABLE_DEPRECATED
+	ClassDB::bind_method(D_METHOD("set_light_texture", "light_texture"), &LightmapGIData::set_light_texture);
+	ClassDB::bind_method(D_METHOD("get_light_texture"), &LightmapGIData::get_light_texture);
+
+	ClassDB::bind_method(D_METHOD("_set_light_textures_data", "data"), &LightmapGIData::_set_light_textures_data);
+	ClassDB::bind_method(D_METHOD("_get_light_textures_data"), &LightmapGIData::_get_light_textures_data);
+
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_texture", PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered", PROPERTY_USAGE_EDITOR), "set_light_texture", "get_light_texture");
+	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "light_textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_light_textures_data", "_get_light_textures_data");
+#endif
 }
 
 LightmapGIData::LightmapGIData() {
@@ -1091,6 +1061,68 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
 		return BAKE_ERROR_MESHES_INVALID;
 	}
 
+	// POSTBAKE: Save Textures.
+
+	TypedArray<TextureLayered> textures;
+	{
+		Vector<Ref<Image>> images;
+		images.resize(lightmapper->get_bake_texture_count());
+		for (int i = 0; i < images.size(); i++) {
+			images.set(i, lightmapper->get_bake_texture(i));
+		}
+
+		int slice_count = images.size();
+		int slice_width = images[0]->get_width();
+		int slice_height = images[0]->get_height();
+
+		int slices_per_texture = Image::MAX_HEIGHT / slice_height;
+		int texture_count = Math::ceil(slice_count / (float)slices_per_texture);
+
+		textures.resize(texture_count);
+
+		String base_path = p_image_data_path.get_basename();
+
+		int last_count = slice_count % slices_per_texture;
+		for (int i = 0; i < texture_count; i++) {
+			int texture_slice_count = (i == texture_count - 1 && last_count != 0) ? last_count : slices_per_texture;
+
+			Ref<Image> texture_image = Image::create_empty(slice_width, slice_height * texture_slice_count, false, images[0]->get_format());
+
+			for (int j = 0; j < texture_slice_count; j++) {
+				texture_image->blit_rect(images[i * slices_per_texture + j], Rect2i(0, 0, slice_width, slice_height), Point2i(0, slice_height * j));
+			}
+
+			String texture_path = texture_count > 1 ? base_path + "_" + itos(i) + ".exr" : base_path + ".exr";
+
+			Ref<ConfigFile> config;
+			config.instantiate();
+
+			if (FileAccess::exists(texture_path + ".import")) {
+				config->load(texture_path + ".import");
+			}
+
+			config->set_value("remap", "importer", "2d_array_texture");
+			config->set_value("remap", "type", "CompressedTexture2DArray");
+			if (!config->has_section_key("params", "compress/mode")) {
+				// User may want another compression, so leave it be, but default to VRAM uncompressed.
+				config->set_value("params", "compress/mode", 3);
+			}
+			config->set_value("params", "compress/channel_pack", 1);
+			config->set_value("params", "mipmaps/generate", false);
+			config->set_value("params", "slices/horizontal", 1);
+			config->set_value("params", "slices/vertical", texture_slice_count);
+
+			config->save(texture_path + ".import");
+
+			Error err = texture_image->save_exr(texture_path, false);
+			ERR_FAIL_COND_V(err, BAKE_ERROR_CANT_CREATE_IMAGE);
+			ResourceLoader::import(texture_path);
+			Ref<TextureLayered> t = ResourceLoader::load(texture_path); // If already loaded, it will be updated on refocus?
+			ERR_FAIL_COND_V(t.is_null(), BAKE_ERROR_CANT_CREATE_IMAGE);
+			textures[i] = t;
+		}
+	}
+
 	/* POSTBAKE: Save Light Data */
 
 	Ref<LightmapGIData> gi_data;
@@ -1102,18 +1134,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
 		gi_data.instantiate();
 	}
 
-	Ref<Texture2DArray> texture;
-	{
-		Vector<Ref<Image>> images;
-		for (int i = 0; i < lightmapper->get_bake_texture_count(); i++) {
-			images.push_back(lightmapper->get_bake_texture(i));
-		}
-
-		texture.instantiate();
-		texture->create_from_images(images);
-	}
-
-	gi_data->set_light_texture(texture);
+	gi_data->set_lightmap_textures(textures);
 	gi_data->set_uses_spherical_harmonics(directional);
 
 	for (int i = 0; i < lightmapper->get_bake_mesh_count(); i++) {

+ 11 - 2
scene/3d/lightmap_gi.h

@@ -44,6 +44,7 @@ class LightmapGIData : public Resource {
 	RES_BASE_EXTENSION("lmbake")
 
 	Ref<TextureLayered> light_texture;
+	TypedArray<TextureLayered> light_textures;
 
 	bool uses_spherical_harmonics = false;
 	bool interior = false;
@@ -65,8 +66,8 @@ class LightmapGIData : public Resource {
 	Array _get_user_data() const;
 	void _set_probe_data(const Dictionary &p_data);
 	Dictionary _get_probe_data() const;
-	void _set_light_textures_data(const Array &p_data);
-	Array _get_light_textures_data() const;
+
+	void _reset_lightmap_textures();
 
 protected:
 	static void _bind_methods();
@@ -80,9 +81,14 @@ public:
 	int get_user_lightmap_slice_index(int p_user) const;
 	void clear_users();
 
+#ifndef DISABLE_DEPRECATED
 	void set_light_texture(const Ref<TextureLayered> &p_light_texture);
 	Ref<TextureLayered> get_light_texture() const;
 
+	void _set_light_textures_data(const Array &p_data);
+	Array _get_light_textures_data() const;
+#endif
+
 	void set_uses_spherical_harmonics(bool p_enable);
 	bool is_using_spherical_harmonics() const;
 
@@ -98,6 +104,9 @@ public:
 
 	void clear();
 
+	void set_lightmap_textures(const TypedArray<TextureLayered> &p_data);
+	TypedArray<TextureLayered> get_lightmap_textures() const;
+
 	virtual RID get_rid() const override;
 	LightmapGIData();
 	~LightmapGIData();