From 1b5101723d673dddbba3108ea849ecd8ae637d21 Mon Sep 17 00:00:00 2001
From: BlueCube3310 <53150244+BlueCube3310@users.noreply.github.com>
Date: Mon, 25 Nov 2024 14:00:40 +0100
Subject: [PATCH] Add Channel Remap settings to ResourceImporterTexture
---
doc/classes/ResourceImporterTexture.xml | 58 +++++++++-
editor/import/resource_importer_texture.cpp | 112 ++++++++++++++++++++
editor/import/resource_importer_texture.h | 15 +++
3 files changed, 184 insertions(+), 1 deletion(-)
diff --git a/doc/classes/ResourceImporterTexture.xml b/doc/classes/ResourceImporterTexture.xml
index a39e48c7bfb..be08d0c0881 100644
--- a/doc/classes/ResourceImporterTexture.xml
+++ b/doc/classes/ResourceImporterTexture.xml
@@ -65,6 +65,62 @@
Unimplemented. This currently has no effect when changed.
+
+ Specifies the data source of the output image's alpha channel.
+ [b]Red:[/b] Use the values from the source image's red channel.
+ [b]Green:[/b] Use the values from the source image's green channel.
+ [b]Blue:[/b] Use the values from the source image's blue channel.
+ [b]Alpha:[/b] Use the values from the source image's alpha channel.
+ [b]Red Inverted:[/b] Use inverted values from the source image's red channel ([code]1.0 - R[/code]).
+ [b]Green Inverted:[/b] Use inverted values from the source image's green channel ([code]1.0 - G[/code]).
+ [b]Blue Inverted:[/b] Use inverted values from the source image's blue channel ([code]1.0 - B[/code]).
+ [b]Alpha Inverted:[/b] Use inverted values from the source image's alpha channel ([code]1.0 - A[/code]).
+ [b]Unused:[/b] Set the color channel's value to the default ([code]1.0[/code] for alpha, [code]0.0[/code] for red, green or blue).
+ [b]Zero:[/b] Set the color channel's value to [code]0.0[/code].
+ [b]One:[/b] Set the color channel's value to [code]1.0[/code].
+
+
+ Specifies the data source of the output image's blue channel.
+ [b]Red:[/b] Use the values from the source image's red channel.
+ [b]Green:[/b] Use the values from the source image's green channel.
+ [b]Blue:[/b] Use the values from the source image's blue channel.
+ [b]Alpha:[/b] Use the values from the source image's alpha channel.
+ [b]Red Inverted:[/b] Use inverted values from the source image's red channel ([code]1.0 - R[/code]).
+ [b]Green Inverted:[/b] Use inverted values from the source image's green channel ([code]1.0 - G[/code]).
+ [b]Blue Inverted:[/b] Use inverted values from the source image's blue channel ([code]1.0 - B[/code]).
+ [b]Alpha Inverted:[/b] Use inverted values from the source image's alpha channel ([code]1.0 - A[/code]).
+ [b]Unused:[/b] Set the color channel's value to the default ([code]1.0[/code] for alpha, [code]0.0[/code] for red, green or blue).
+ [b]Zero:[/b] Set the color channel's value to [code]0.0[/code].
+ [b]One:[/b] Set the color channel's value to [code]1.0[/code].
+
+
+ Specifies the data source of the output image's green channel.
+ [b]Red:[/b] Use the values from the source image's red channel.
+ [b]Green:[/b] Use the values from the source image's green channel.
+ [b]Blue:[/b] Use the values from the source image's blue channel.
+ [b]Alpha:[/b] Use the values from the source image's alpha channel.
+ [b]Red Inverted:[/b] Use inverted values from the source image's red channel ([code]1.0 - R[/code]).
+ [b]Green Inverted:[/b] Use inverted values from the source image's green channel ([code]1.0 - G[/code]).
+ [b]Blue Inverted:[/b] Use inverted values from the source image's blue channel ([code]1.0 - B[/code]).
+ [b]Alpha Inverted:[/b] Use inverted values from the source image's alpha channel ([code]1.0 - A[/code]).
+ [b]Unused:[/b] Set the color channel's value to the default ([code]1.0[/code] for alpha, [code]0.0[/code] for red, green or blue).
+ [b]Zero:[/b] Set the color channel's value to [code]0.0[/code].
+ [b]One:[/b] Set the color channel's value to [code]1.0[/code].
+
+
+ Specifies the data source of the output image's red channel.
+ [b]Red:[/b] Use the values from the source image's red channel.
+ [b]Green:[/b] Use the values from the source image's green channel.
+ [b]Blue:[/b] Use the values from the source image's blue channel.
+ [b]Alpha:[/b] Use the values from the source image's alpha channel.
+ [b]Red Inverted:[/b] Use inverted values from the source image's red channel ([code]1.0 - R[/code]).
+ [b]Green Inverted:[/b] Use inverted values from the source image's green channel ([code]1.0 - G[/code]).
+ [b]Blue Inverted:[/b] Use inverted values from the source image's blue channel ([code]1.0 - B[/code]).
+ [b]Alpha Inverted:[/b] Use inverted values from the source image's alpha channel ([code]1.0 - A[/code]).
+ [b]Unused:[/b] Set the color channel's value to the default ([code]1.0[/code] for alpha, [code]0.0[/code] for red, green or blue).
+ [b]Zero:[/b] Set the color channel's value to [code]0.0[/code].
+ [b]One:[/b] Set the color channel's value to [code]1.0[/code].
+
If [code]true[/code], puts pixels of the same surrounding color in transition from transparent to opaque areas. For textures displayed with bilinear filtering, this helps to reduce the outline effect when exporting images from an image editor.
It's recommended to leave this enabled (as it is by default), unless this causes issues for a particular image.
@@ -78,7 +134,7 @@
Some HDR panorama images you can find online may contain extremely bright pixels, due to being taken from real life sources without any clipping.
While these HDR panorama images are accurate to real life, this can cause the radiance map generated by Godot to contain sparkles when used as a background sky. This can be seen in material reflections (even on rough materials in extreme cases). Enabling [member process/hdr_clamp_exposure] can resolve this.
-
+
If [code]true[/code], convert the normal map from Y- (DirectX-style) to Y+ (OpenGL-style) by inverting its green color channel. This is the normal map convention expected by Godot.
More information about normal maps (including a coordinate order table for popular engines) can be found [url=http://wiki.polycount.com/wiki/Normal_Map_Technical_Details]here[/url].
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index 2b5fe352710..d84cbbe3f89 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -242,6 +242,10 @@ void ResourceImporterTexture::get_import_options(const String &p_path, Listpush_back(ImportOption(PropertyInfo(Variant::INT, "mipmaps/limit", PROPERTY_HINT_RANGE, "-1,256"), -1));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "roughness/mode", PROPERTY_HINT_ENUM, "Detect,Disabled,Red,Green,Blue,Alpha,Gray"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "roughness/src_normal", PROPERTY_HINT_FILE, "*.bmp,*.dds,*.exr,*.jpeg,*.jpg,*.hdr,*.png,*.svg,*.tga,*.webp"), ""));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "process/channel_remap/red", PROPERTY_HINT_ENUM, "Red,Green,Blue,Alpha,Inverted Red,Inverted Green,Inverted Blue,Inverted Alpha,Unused,Zero,One"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "process/channel_remap/green", PROPERTY_HINT_ENUM, "Red,Green,Blue,Alpha,Inverted Red,Inverted Green,Inverted Blue,Inverted Alpha,Unused,Zero,One"), 1));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "process/channel_remap/blue", PROPERTY_HINT_ENUM, "Red,Green,Blue,Alpha,Inverted Red,Inverted Green,Inverted Blue,Inverted Alpha,Unused,Zero,One"), 2));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "process/channel_remap/alpha", PROPERTY_HINT_ENUM, "Red,Green,Blue,Alpha,Inverted Red,Inverted Green,Inverted Blue,Inverted Alpha,Unused,Zero,One"), 3));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/fix_alpha_border"), p_preset != PRESET_3D));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/premult_alpha"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/normal_map_invert_y"), false));
@@ -440,6 +444,99 @@ Dictionary ResourceImporterTexture::_load_editor_meta(const String &p_path) cons
return f->get_var();
}
+void ResourceImporterTexture::_remap_channels(Ref &r_image, ChannelRemap p_options[4]) {
+ bool attempted_hdr_inverted = false;
+
+ if (r_image->get_format() >= Image::FORMAT_RF && r_image->get_format() <= Image::FORMAT_RGBE9995) {
+ // Formats which can hold HDR data cannot be inverted the same way as unsigned normalized ones (1.0 - channel).
+ for (int i = 0; i < 4; i++) {
+ switch (p_options[i]) {
+ case REMAP_INV_R:
+ attempted_hdr_inverted = true;
+ p_options[i] = REMAP_R;
+ break;
+ case REMAP_INV_G:
+ attempted_hdr_inverted = true;
+ p_options[i] = REMAP_G;
+ break;
+ case REMAP_INV_B:
+ attempted_hdr_inverted = true;
+ p_options[i] = REMAP_B;
+ break;
+ case REMAP_INV_A:
+ attempted_hdr_inverted = true;
+ p_options[i] = REMAP_A;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (attempted_hdr_inverted) {
+ WARN_PRINT("Attempted to use an inverted channel remap on an HDR image. The remap has been changed to its uninverted equivalent.");
+ }
+
+ if (p_options[0] == REMAP_R && p_options[1] == REMAP_G && p_options[2] == REMAP_B && p_options[3] == REMAP_A) {
+ // Default color map, do nothing.
+ return;
+ }
+
+ for (int x = 0; x < r_image->get_width(); x++) {
+ for (int y = 0; y < r_image->get_height(); y++) {
+ Color src = r_image->get_pixel(x, y);
+ Color dst;
+
+ for (int i = 0; i < 4; i++) {
+ switch (p_options[i]) {
+ case REMAP_R:
+ dst[i] = src.r;
+ break;
+ case REMAP_G:
+ dst[i] = src.g;
+ break;
+ case REMAP_B:
+ dst[i] = src.b;
+ break;
+ case REMAP_A:
+ dst[i] = src.a;
+ break;
+
+ case REMAP_INV_R:
+ dst[i] = 1.0f - src.r;
+ break;
+ case REMAP_INV_G:
+ dst[i] = 1.0f - src.g;
+ break;
+ case REMAP_INV_B:
+ dst[i] = 1.0f - src.b;
+ break;
+ case REMAP_INV_A:
+ dst[i] = 1.0f - src.a;
+ break;
+
+ case REMAP_UNUSED:
+ // For Alpha the unused value is 1, for other channels it's 0.
+ dst[i] = (i == 3) ? 1.0f : 0.0f;
+ break;
+
+ case REMAP_0:
+ dst[i] = 0.0f;
+ break;
+ case REMAP_1:
+ dst[i] = 1.0f;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ r_image->set_pixel(x, y, dst);
+ }
+ }
+}
+
void ResourceImporterTexture::_invert_y_channel(Ref &r_image) {
// Inverting the green channel can be used to flip a normal map's direction.
// There's no standard when it comes to normal map Y direction, so this is
@@ -505,6 +602,10 @@ Error ResourceImporterTexture::import(ResourceUID::ID p_source_id, const String
const String normal_map = p_options["roughness/src_normal"];
// Processing.
+ const int remap_r = p_options["process/channel_remap/red"];
+ const int remap_g = p_options["process/channel_remap/green"];
+ const int remap_b = p_options["process/channel_remap/blue"];
+ const int remap_a = p_options["process/channel_remap/alpha"];
const bool fix_alpha_border = p_options["process/fix_alpha_border"];
const bool premult_alpha = p_options["process/premult_alpha"];
const bool normal_map_invert_y = p_options["process/normal_map_invert_y"];
@@ -620,6 +721,17 @@ Error ResourceImporterTexture::import(ResourceUID::ID p_source_id, const String
}
}
+ {
+ ChannelRemap remaps[4] = {
+ (ChannelRemap)remap_r,
+ (ChannelRemap)remap_g,
+ (ChannelRemap)remap_b,
+ (ChannelRemap)remap_a,
+ };
+
+ _remap_channels(target_image, remaps);
+ }
+
// Fix alpha border.
if (fix_alpha_border) {
target_image->fix_alpha_edges();
diff --git a/editor/import/resource_importer_texture.h b/editor/import/resource_importer_texture.h
index ebe53efa94e..18a56d8d1ff 100644
--- a/editor/import/resource_importer_texture.h
+++ b/editor/import/resource_importer_texture.h
@@ -49,6 +49,20 @@ public:
COMPRESS_BASIS_UNIVERSAL
};
+ enum ChannelRemap {
+ REMAP_R,
+ REMAP_G,
+ REMAP_B,
+ REMAP_A,
+ REMAP_INV_R,
+ REMAP_INV_G,
+ REMAP_INV_B,
+ REMAP_INV_A,
+ REMAP_UNUSED,
+ REMAP_0,
+ REMAP_1,
+ };
+
protected:
enum {
MAKE_3D_FLAG = 1,
@@ -76,6 +90,7 @@ protected:
void _save_editor_meta(const Dictionary &p_metadata, const String &p_to_path);
Dictionary _load_editor_meta(const String &p_to_path) const;
+ static inline void _remap_channels(Ref &r_image, ChannelRemap p_options[4]);
static inline void _clamp_hdr_exposure(Ref &r_image);
static inline void _invert_y_channel(Ref &r_image);
static inline void _print_callback_message(const String &p_message);