**Refactor sRGB import option on textures** to actually handle image contents with gamma

This commit is contained in:
2026-01-12 15:50:24 +01:00
parent 4b9fa0dcf5
commit b834dddb11
25 changed files with 196 additions and 54 deletions
Binary file not shown.
@@ -38,6 +38,7 @@ struct VertexOutput
#endif
float4 ClipExtents : TEXCOORD3;
float2 ClipOrigin : TEXCOORD4;
float2 CustomData : TEXCOORD5; // x-per-geometry type, y-features mask
#if USE_CUSTOM_VERTEX_INTERPOLATORS
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
#endif
@@ -55,6 +56,7 @@ struct PixelInput
#endif
float4 ClipExtents : TEXCOORD3;
float2 ClipOrigin : TEXCOORD4;
float2 CustomData : TEXCOORD5; // x-per-geometry type, y-features mask
#if USE_CUSTOM_VERTEX_INTERPOLATORS
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
#endif
@@ -67,6 +69,7 @@ struct MaterialInput
float3 WorldPosition;
float TwoSidedSign;
float2 TexCoord;
float2 CustomData; // x-per-geometry type, y-features mask
#if USE_VERTEX_COLOR
half4 VertexColor;
#endif
@@ -84,6 +87,7 @@ MaterialInput GetMaterialInput(Render2DVertex input, VertexOutput output)
MaterialInput result;
result.WorldPosition = output.WorldPosition;
result.TexCoord = output.TexCoord;
result.CustomData = input.CustomDataAndClipOrigin.xy;
#if USE_VERTEX_COLOR
result.VertexColor = output.VertexColor;
#endif
@@ -103,6 +107,7 @@ MaterialInput GetMaterialInput(PixelInput input)
MaterialInput result;
result.WorldPosition = input.WorldPosition;
result.TexCoord = input.TexCoord;
result.CustomData = input.CustomData;
#if USE_VERTEX_COLOR
result.VertexColor = input.VertexColor;
#endif
@@ -229,6 +234,7 @@ VertexOutput VS_GUI(Render2DVertex input)
#if USE_VERTEX_COLOR
output.VertexColor = input.Color;
#endif
output.CustomData = input.CustomDataAndClipOrigin.xy;
output.ClipOrigin = input.CustomDataAndClipOrigin.zw;
output.ClipExtents = input.ClipExtents;
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -4,7 +4,7 @@
"Major": 1,
"Minor": 12,
"Revision": 0,
"Build": 6900
"Build": 6901
},
"Company": "Flax",
"Copyright": "Copyright (c) 2012-2026 Wojciech Figat. All rights reserved.",
@@ -187,6 +187,11 @@ namespace FlaxEditor.Content.Import
// Glossiness, metalness, ambient occlusion, displacement, height, cavity or specular
_settings.Settings.Type = TextureFormatType.GrayScale;
}
else if (_settings.Settings.Type == TextureFormatType.ColorRGB)
{
// Blind guess that common color texture is sRGB
_settings.Settings.sRGB = true;
}
// Try to restore target asset texture import options (useful for fast reimport)
Editor.TryRestoreImportOptions(ref _settings.Settings, ResultUrl);
@@ -410,6 +410,22 @@ namespace FlaxEditor.Viewport.Previews
UpdateTextureRect();
}
/// <summary>
/// Draws the material
/// </summary>
protected void DrawMaterial(ref Rectangle rect)
{
var textureObj = _previewMaterial.GetParameterValue("Texture");
var removeGamma = textureObj is TextureBase texture && PixelFormatExtensions.IsSRGB(texture.Format);
if (removeGamma)
Render2D.Features |= Render2D.RenderingFeatures.RemoveGamma;
Render2D.DrawMaterial(_previewMaterial, rect);
if (removeGamma)
Render2D.Features &= ~Render2D.RenderingFeatures.RemoveGamma;
}
private void OnMipWidgetMenuOnVisibleChanged(Control control)
{
if (!control.Visible)
@@ -610,14 +626,9 @@ namespace FlaxEditor.Viewport.Previews
/// <inheritdoc />
protected override void DrawTexture(ref Rectangle rect)
{
// Background
Render2D.FillRectangle(rect, Color.Gray);
// Check if has loaded asset
if (_asset && _asset.IsLoaded)
{
Render2D.DrawMaterial(_previewMaterial, rect);
}
DrawMaterial(ref rect);
}
}
@@ -665,14 +676,9 @@ namespace FlaxEditor.Viewport.Previews
/// <inheritdoc />
protected override void DrawTexture(ref Rectangle rect)
{
// Background
Render2D.FillRectangle(rect, Color.Gray);
// Check if has loaded asset
if (_asset && _asset.IsLoaded)
{
Render2D.DrawMaterial(_previewMaterial, rect);
}
DrawMaterial(ref rect);
}
}
}
@@ -50,6 +50,17 @@ void GraphicsSettings::SetUeeHDRProbes(bool value)
UseHDRProbes = value;
}
void GraphicsSettings::OnDeserializing(const CallbackContext& context)
{
// [Deprecated on 9.01.2026, expires on 9.01.2028]
if (context.Modifier && context.Modifier->EngineBuild < 6901)
{
// Old projects were made in Gamma color space
GammaColorSpace = true;
MARK_CONTENT_DEPRECATED();
}
}
IMPLEMENT_ENGINE_SETTINGS_GETTER(GraphicsSettings, Graphics);
IMPLEMENT_ENGINE_SETTINGS_GETTER(NetworkSettings, Network);
IMPLEMENT_ENGINE_SETTINGS_GETTER(LayersAndTagsSettings, LayersAndTags);
+12 -5
View File
@@ -127,12 +127,22 @@ public:
API_FIELD(Attributes="EditorOrder(2130), Limit(256, 8192), EditorDisplay(\"Global Illumination\")")
int32 GlobalSurfaceAtlasResolution = 2048;
public:
/// <summary>
/// If checked, color space workflow will use Gamma instead of Linear. Gamma color space defines colors with an applied a gamma curve (sRGB) so they are perceptually linear.
/// This makes sense when the output of the rendering represent final color values that will be presented to a non-HDR screen.
/// </summary>
API_FIELD(Attributes="EditorOrder(3000), EditorDisplay(\"Colors\")")
bool GammaColorSpace = false;
public:
/// <summary>
/// The default Post Process settings. Can be overriden by PostFxVolume on a level locally, per camera or for a whole map.
/// </summary>
API_FIELD(Attributes="EditorOrder(10000), EditorDisplay(\"Post Process Settings\", EditorDisplayAttribute.InlineStyle)")
PostProcessSettings PostProcessSettings;
public:
/// <summary>
/// The list of fallback fonts used for text rendering. Ignored if empty.
/// </summary>
@@ -144,12 +154,9 @@ private:
/// Renamed UeeHDRProbes into UseHDRProbes
/// [Deprecated on 12.10.2022, expires on 12.10.2024]
/// </summary>
API_PROPERTY(Attributes="Serialize, Obsolete, NoUndo") DEPRECATED("Use UseHDRProbes instead.") bool GetUeeHDRProbes() const
{
return UseHDRProbes;
}
API_PROPERTY(Attributes="Serialize, Obsolete, NoUndo") DEPRECATED("Use UseHDRProbes instead.") bool GetUeeHDRProbes() const { return UseHDRProbes; }
API_PROPERTY(Attributes="Serialize, Obsolete, NoUndo") DEPRECATED("Use UseHDRProbes instead.") void SetUeeHDRProbes(bool value);
API_FUNCTION(Attributes="OnDeserializing", Hidden) void OnDeserializing(const CallbackContext& context);
public:
/// <summary>
@@ -278,6 +278,11 @@ struct FLAXENGINE_API TextureEntry
/// </summary>
TypeHint Type;
/// <summary>
/// Hints that texture contents are in sRGB color format.
/// </summary>
bool sRGB = false;
/// <summary>
/// The texture asset identifier.
/// </summary>
+51 -3
View File
@@ -7,6 +7,7 @@
#include "RotatedRectangle.h"
#include "SpriteAtlas.h"
#include "Engine/Core/Math/Matrix3x3.h"
#include "Engine/Core/Config/GraphicsSettings.h"
#include "Engine/Content/Assets/Shader.h"
#include "Engine/Content/Assets/MaterialBase.h"
#include "Engine/Content/Content.h"
@@ -18,6 +19,7 @@
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/RenderTargetPool.h"
#include "Engine/Graphics/DynamicBuffer.h"
#include "Engine/Graphics/PixelFormatExtensions.h"
#include "Engine/Graphics/Shaders/GPUShader.h"
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
#include "Engine/Graphics/Shaders/GPUVertexLayout.h"
@@ -48,6 +50,9 @@
#define RENDER2D_BLUR_MAX_SAMPLES 64
#define RENDER2D_REMOVE_GAMMA_BEGIN(t, getFormat) const bool removeGamma = IsRemoveGammaEnabled && t && PixelFormatExtensions::IsSRGB(t->getFormat()); if (removeGamma) Features |= RenderingFeatures::RemoveGamma
#define RENDER2D_REMOVE_GAMMA_END() if (removeGamma) Features &= ~RenderingFeatures::RemoveGamma
// The format for the blur effect temporary buffer
#define PS_Blur_Format PixelFormat::R8G8B8A8_UNorm
@@ -199,6 +204,7 @@ namespace
Array<Float2> Lines2;
bool IsScissorsRectEmpty;
bool IsScissorsRectEnabled;
bool IsRemoveGammaEnabled;
// Transform
// Note: we use Matrix3x3 instead of Matrix because we use only 2D transformations on CPU side
@@ -683,6 +689,7 @@ void Render2D::Begin(GPUContext* context, GPUTextureView* output, GPUTextureView
View = viewport;
ViewProjection = viewProjection;
DrawCalls.Clear();
IsRemoveGammaEnabled = GraphicsSettings::Get()->GammaColorSpace == false;
// Initialize default transform
const Matrix3x3 defaultTransform = Matrix3x3::Identity;
@@ -1583,6 +1590,7 @@ void Render2D::DrawRectangle(const Rectangle& rect, const Color& color1, const C
void Render2D::DrawTexture(GPUTextureView* rt, const Rectangle& rect, const Color& color)
{
RENDER2D_CHECK_RENDERING_STATE;
RENDER2D_REMOVE_GAMMA_BEGIN(rt, GetFormat);
Render2DDrawCall& drawCall = DrawCalls.AddOne();
drawCall.Type = DrawCallType::FillRT;
@@ -1590,11 +1598,14 @@ void Render2D::DrawTexture(GPUTextureView* rt, const Rectangle& rect, const Colo
drawCall.CountIB = 6;
drawCall.AsRT.Ptr = rt;
WriteRect(rect, color);
RENDER2D_REMOVE_GAMMA_END();
}
void Render2D::DrawTexture(GPUTexture* t, const Rectangle& rect, const Color& color)
{
RENDER2D_CHECK_RENDERING_STATE;
RENDER2D_REMOVE_GAMMA_BEGIN(t, Format);
Render2DDrawCall drawCall;
drawCall.Type = DrawCallType::FillTexture;
@@ -1603,11 +1614,14 @@ void Render2D::DrawTexture(GPUTexture* t, const Rectangle& rect, const Color& co
drawCall.AsTexture.Ptr = t;
DrawCalls.Add(drawCall);
WriteRect(rect, color);
RENDER2D_REMOVE_GAMMA_END();
}
void Render2D::DrawTexture(TextureBase* t, const Rectangle& rect, const Color& color)
{
RENDER2D_CHECK_RENDERING_STATE;
RENDER2D_REMOVE_GAMMA_BEGIN(t, Format);
Render2DDrawCall drawCall;
drawCall.Type = DrawCallType::FillTexture;
@@ -1616,6 +1630,8 @@ void Render2D::DrawTexture(TextureBase* t, const Rectangle& rect, const Color& c
drawCall.AsTexture.Ptr = t ? t->GetTexture() : nullptr;
DrawCalls.Add(drawCall);
WriteRect(rect, color);
RENDER2D_REMOVE_GAMMA_END();
}
void Render2D::DrawSprite(const SpriteHandle& spriteHandle, const Rectangle& rect, const Color& color)
@@ -1623,6 +1639,7 @@ void Render2D::DrawSprite(const SpriteHandle& spriteHandle, const Rectangle& rec
RENDER2D_CHECK_RENDERING_STATE;
if (spriteHandle.Index == INVALID_INDEX || !spriteHandle.Atlas || !spriteHandle.Atlas->GetTexture()->HasResidentMip())
return;
RENDER2D_REMOVE_GAMMA_BEGIN(spriteHandle.Atlas->GetTexture(), Format);
Sprite* sprite = &spriteHandle.Atlas->Sprites.At(spriteHandle.Index);
Render2DDrawCall& drawCall = DrawCalls.AddOne();
@@ -1631,11 +1648,14 @@ void Render2D::DrawSprite(const SpriteHandle& spriteHandle, const Rectangle& rec
drawCall.CountIB = 6;
drawCall.AsTexture.Ptr = spriteHandle.Atlas->GetTexture();
WriteRect(rect, color, sprite->Area.GetUpperLeft(), sprite->Area.GetBottomRight());
RENDER2D_REMOVE_GAMMA_END();
}
void Render2D::DrawTexturePoint(GPUTexture* t, const Rectangle& rect, const Color& color)
{
RENDER2D_CHECK_RENDERING_STATE;
RENDER2D_REMOVE_GAMMA_BEGIN(t, Format);
Render2DDrawCall& drawCall = DrawCalls.AddOne();
drawCall.Type = DrawCallType::FillTexturePoint;
@@ -1643,6 +1663,8 @@ void Render2D::DrawTexturePoint(GPUTexture* t, const Rectangle& rect, const Colo
drawCall.CountIB = 6;
drawCall.AsTexture.Ptr = t;
WriteRect(rect, color);
RENDER2D_REMOVE_GAMMA_END();
}
void Render2D::DrawSpritePoint(const SpriteHandle& spriteHandle, const Rectangle& rect, const Color& color)
@@ -1650,6 +1672,7 @@ void Render2D::DrawSpritePoint(const SpriteHandle& spriteHandle, const Rectangle
RENDER2D_CHECK_RENDERING_STATE;
if (spriteHandle.Index == INVALID_INDEX || !spriteHandle.Atlas || !spriteHandle.Atlas->GetTexture()->HasResidentMip())
return;
RENDER2D_REMOVE_GAMMA_BEGIN(spriteHandle.Atlas->GetTexture(), Format);
Sprite* sprite = &spriteHandle.Atlas->Sprites.At(spriteHandle.Index);
Render2DDrawCall& drawCall = DrawCalls.AddOne();
@@ -1658,11 +1681,14 @@ void Render2D::DrawSpritePoint(const SpriteHandle& spriteHandle, const Rectangle
drawCall.CountIB = 6;
drawCall.AsTexture.Ptr = spriteHandle.Atlas->GetTexture();
WriteRect(rect, color, sprite->Area.GetUpperLeft(), sprite->Area.GetBottomRight());
RENDER2D_REMOVE_GAMMA_END();
}
void Render2D::Draw9SlicingTexture(TextureBase* t, const Rectangle& rect, const Float4& border, const Float4& borderUVs, const Color& color)
{
RENDER2D_CHECK_RENDERING_STATE;
RENDER2D_REMOVE_GAMMA_BEGIN(t, Format);
Render2DDrawCall drawCall;
drawCall.Type = DrawCallType::FillTexture;
@@ -1676,6 +1702,7 @@ void Render2D::Draw9SlicingTexture(TextureBase* t, const Rectangle& rect, const
void Render2D::Draw9SlicingTexturePoint(TextureBase* t, const Rectangle& rect, const Float4& border, const Float4& borderUVs, const Color& color)
{
RENDER2D_CHECK_RENDERING_STATE;
RENDER2D_REMOVE_GAMMA_BEGIN(t, Format);
Render2DDrawCall drawCall;
drawCall.Type = DrawCallType::FillTexturePoint;
@@ -1691,6 +1718,7 @@ void Render2D::Draw9SlicingSprite(const SpriteHandle& spriteHandle, const Rectan
RENDER2D_CHECK_RENDERING_STATE;
if (spriteHandle.Index == INVALID_INDEX || !spriteHandle.Atlas || !spriteHandle.Atlas->GetTexture()->HasResidentMip())
return;
RENDER2D_REMOVE_GAMMA_BEGIN(spriteHandle.Atlas->GetTexture(), Format);
Sprite* sprite = &spriteHandle.Atlas->Sprites.At(spriteHandle.Index);
Render2DDrawCall& drawCall = DrawCalls.AddOne();
@@ -1699,6 +1727,8 @@ void Render2D::Draw9SlicingSprite(const SpriteHandle& spriteHandle, const Rectan
drawCall.CountIB = 6 * 9;
drawCall.AsTexture.Ptr = spriteHandle.Atlas->GetTexture();
Write9SlicingRect(rect, color, border, borderUVs, sprite->Area.Location, sprite->Area.Size);
RENDER2D_REMOVE_GAMMA_END();
}
void Render2D::Draw9SlicingSpritePoint(const SpriteHandle& spriteHandle, const Rectangle& rect, const Float4& border, const Float4& borderUVs, const Color& color)
@@ -1706,6 +1736,7 @@ void Render2D::Draw9SlicingSpritePoint(const SpriteHandle& spriteHandle, const R
RENDER2D_CHECK_RENDERING_STATE;
if (spriteHandle.Index == INVALID_INDEX || !spriteHandle.Atlas || !spriteHandle.Atlas->GetTexture()->HasResidentMip())
return;
RENDER2D_REMOVE_GAMMA_BEGIN(spriteHandle.Atlas->GetTexture(), Format);
Sprite* sprite = &spriteHandle.Atlas->Sprites.At(spriteHandle.Index);
Render2DDrawCall& drawCall = DrawCalls.AddOne();
@@ -1714,6 +1745,8 @@ void Render2D::Draw9SlicingSpritePoint(const SpriteHandle& spriteHandle, const R
drawCall.CountIB = 6 * 9;
drawCall.AsTexture.Ptr = spriteHandle.Atlas->GetTexture();
Write9SlicingRect(rect, color, border, borderUVs, sprite->Area.Location, sprite->Area.Size);
RENDER2D_REMOVE_GAMMA_END();
}
void Render2D::DrawCustom(GPUTexture* t, const Rectangle& rect, GPUPipelineState* ps, const Color& color)
@@ -1721,6 +1754,7 @@ void Render2D::DrawCustom(GPUTexture* t, const Rectangle& rect, GPUPipelineState
RENDER2D_CHECK_RENDERING_STATE;
if (ps == nullptr || !ps->IsValid())
return;
RENDER2D_REMOVE_GAMMA_BEGIN(t, Format);
Render2DDrawCall& drawCall = DrawCalls.AddOne();
drawCall.Type = DrawCallType::Custom;
@@ -1729,6 +1763,8 @@ void Render2D::DrawCustom(GPUTexture* t, const Rectangle& rect, GPUPipelineState
drawCall.AsCustom.Tex = t;
drawCall.AsCustom.Pso = ps;
WriteRect(rect, color);
RENDER2D_REMOVE_GAMMA_END();
}
#if RENDER2D_USE_LINE_AA
@@ -1949,6 +1985,9 @@ void Render2D::DrawMaterial(MaterialBase* material, const Rectangle& rect, const
if (material == nullptr || !material->IsReady() || !material->IsGUI())
return;
// Auto-remove gamma flag if it's disabled
Features &= IsRemoveGammaEnabled ? ~RenderingFeatures::None : ~RenderingFeatures::RemoveGamma;
Render2DDrawCall& drawCall = DrawCalls.AddOne();
drawCall.Type = DrawCallType::Material;
drawCall.StartIB = IBIndex;
@@ -2031,15 +2070,17 @@ void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span<Float2>& vertices
RENDER2D_CHECK_RENDERING_STATE;
CHECK(vertices.Length() % 3 == 0);
CHECK(vertices.Length() == uvs.Length());
RENDER2D_REMOVE_GAMMA_BEGIN(t, Format);
Render2DDrawCall& drawCall = DrawCalls.AddOne();
drawCall.Type = DrawCallType::FillTexture;
drawCall.StartIB = IBIndex;
drawCall.CountIB = vertices.Length();
drawCall.AsTexture.Ptr = t;
for (int32 i = 0; i < vertices.Length(); i += 3)
WriteTri(vertices[i], vertices[i + 1], vertices[i + 2], uvs[i], uvs[i + 1], uvs[i + 2]);
RENDER2D_REMOVE_GAMMA_END();
}
void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span<Float2>& vertices, const Span<Float2>& uvs, const Color& color)
@@ -2047,15 +2088,17 @@ void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span<Float2>& vertices
RENDER2D_CHECK_RENDERING_STATE;
CHECK(vertices.Length() % 3 == 0);
CHECK(vertices.Length() == uvs.Length());
RENDER2D_REMOVE_GAMMA_BEGIN(t, Format);
Render2DDrawCall& drawCall = DrawCalls.AddOne();
drawCall.Type = DrawCallType::FillTexture;
drawCall.StartIB = IBIndex;
drawCall.CountIB = vertices.Length();
drawCall.AsTexture.Ptr = t;
for (int32 i = 0; i < vertices.Length(); i += 3)
WriteTri(vertices[i], vertices[i + 1], vertices[i + 2], uvs[i], uvs[i + 1], uvs[i + 2], color, color, color);
RENDER2D_REMOVE_GAMMA_END();
}
void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span<Float2>& vertices, const Span<Float2>& uvs, const Span<Color>& colors)
@@ -2064,15 +2107,17 @@ void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span<Float2>& vertices
CHECK(vertices.Length() % 3 == 0);
CHECK(vertices.Length() == uvs.Length());
CHECK(vertices.Length() == colors.Length());
RENDER2D_REMOVE_GAMMA_BEGIN(t, Format);
Render2DDrawCall& drawCall = DrawCalls.AddOne();
drawCall.Type = DrawCallType::FillTexture;
drawCall.StartIB = IBIndex;
drawCall.CountIB = vertices.Length();
drawCall.AsTexture.Ptr = t;
for (int32 i = 0; i < vertices.Length(); i += 3)
WriteTri(vertices[i], vertices[i + 1], vertices[i + 2], uvs[i], uvs[i + 1], uvs[i + 2], colors[i], colors[i + 1], colors[i + 2]);
RENDER2D_REMOVE_GAMMA_END();
}
void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span<uint16>& indices, const Span<Float2>& vertices, const Span<Float2>& uvs, const Span<Color>& colors)
@@ -2080,6 +2125,7 @@ void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span<uint16>& indices,
RENDER2D_CHECK_RENDERING_STATE;
CHECK(vertices.Length() == uvs.Length());
CHECK(vertices.Length() == colors.Length());
RENDER2D_REMOVE_GAMMA_BEGIN(t, Format);
Render2DDrawCall& drawCall = DrawCalls.AddOne();
drawCall.Type = DrawCallType::FillTexture;
@@ -2094,6 +2140,8 @@ void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span<uint16>& indices,
const uint16 i2 = indices.Get()[i++];
WriteTri(vertices[i0], vertices[i1], vertices[i2], uvs[i0], uvs[i1], uvs[i2], colors[i0], colors[i1], colors[i2]);
}
RENDER2D_REMOVE_GAMMA_END();
}
void Render2D::FillTriangles(const Span<Float2>& vertices, const Color& color)
+5
View File
@@ -49,6 +49,11 @@ API_CLASS(Static) class FLAXENGINE_API Render2D
/// Enables automatic characters usage from fallback fonts.
/// </summary>
FallbackFonts = 2,
/// <summary>
/// Enables additional sRGB to linear color space conversion when drawing sRGB textures. This ensures that images imported with sRGB enabled in Linear workflow will be properly rendered into screen.
/// </summary>
RemoveGamma = 4,
};
struct CustomData
+14 -1
View File
@@ -2,6 +2,7 @@
#include "PostProcessingPass.h"
#include "RenderList.h"
#include "Engine/Core/Config/GraphicsSettings.h"
#include "Engine/Content/Assets/Shader.h"
#include "Engine/Content/Content.h"
#include "Engine/Graphics/GPUContext.h"
@@ -11,6 +12,8 @@
#define GB_RADIUS 6
#define GB_KERNEL_SIZE (GB_RADIUS * 2 + 1)
#define OUTPUT_LINEAR 0 // Copies scene color directly to the output
#define OUTPUT_SRGB 1 // Converts scene color from linear to sRGB
GPU_CB_STRUCT(Data{
float BloomIntensity; // Overall bloom strength multiplier
@@ -48,7 +51,7 @@ GPU_CB_STRUCT(Data{
float ChromaticDistortion;
float Time;
float Dummy1;
uint32 OutputColorSpace;
float PostExposure;
float VignetteIntensity;
float LensDirtIntensity;
@@ -360,6 +363,16 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input,
data.InputSize = Float2(static_cast<float>(w1), static_cast<float>(h1));
data.InvInputSize = Float2(1.0f / static_cast<float>(w1), 1.0f / static_cast<float>(h1));
data.InputAspect = static_cast<float>(w1) / h1;
if (GraphicsSettings::Get()->GammaColorSpace)
{
// Gamma-space colors always present image 'as-is'
data.OutputColorSpace = OUTPUT_LINEAR;
}
else
{
// Convert linear scene color into the display's sRGB curve
data.OutputColorSpace = OUTPUT_SRGB;
}
context->UpdateCB(cb0, &data);
context->BindCB(0, cb0);
@@ -463,7 +463,7 @@ bool ImportTexture(ModelData& result, AssimpImporterData& data, aiString& aFilen
return true;
}
bool ImportMaterialTexture(ModelData& result, AssimpImporterData& data, const aiMaterial* aMaterial, aiTextureType aTextureType, int32& textureIndex, TextureEntry::TypeHint type)
bool ImportMaterialTexture(ModelData& result, AssimpImporterData& data, const aiMaterial* aMaterial, aiTextureType aTextureType, int32& textureIndex, TextureEntry::TypeHint type, bool sRGB = false)
{
aiString aFilename;
if (aMaterial->GetTexture(aTextureType, 0, &aFilename, nullptr, nullptr, nullptr, nullptr) == AI_SUCCESS)
@@ -503,6 +503,7 @@ bool ImportMaterialTexture(ModelData& result, AssimpImporterData& data, const ai
auto& texture = result.Textures.AddOne();
texture.FilePath = path;
texture.Type = type;
texture.sRGB = sRGB;
texture.AssetID = Guid::Empty;
return true;
}
@@ -549,12 +550,12 @@ bool ImportMaterials(ModelData& result, AssimpImporterData& data, String& errorM
if (EnumHasAnyFlags(data.Options.ImportTypes, ImportDataTypes::Textures))
{
ImportMaterialTexture(result, data, aMaterial, aiTextureType_DIFFUSE, materialSlot.Diffuse.TextureIndex, TextureEntry::TypeHint::ColorRGB);
ImportMaterialTexture(result, data, aMaterial, aiTextureType_DIFFUSE, materialSlot.Diffuse.TextureIndex, TextureEntry::TypeHint::ColorRGB, true);
ImportMaterialTexture(result, data, aMaterial, aiTextureType_EMISSIVE, materialSlot.Emissive.TextureIndex, TextureEntry::TypeHint::ColorRGB);
ImportMaterialTexture(result, data, aMaterial, aiTextureType_NORMALS, materialSlot.Normals.TextureIndex, TextureEntry::TypeHint::Normals);
ImportMaterialTexture(result, data, aMaterial, aiTextureType_OPACITY, materialSlot.Opacity.TextureIndex, TextureEntry::TypeHint::ColorRGBA);
ImportMaterialTexture(result, data, aMaterial, aiTextureType_METALNESS, materialSlot.Metalness.TextureIndex, TextureEntry::TypeHint::ColorRGB);
ImportMaterialTexture(result, data, aMaterial, aiTextureType_DIFFUSE_ROUGHNESS, materialSlot.Roughness.TextureIndex, TextureEntry::TypeHint::ColorRGB);
ImportMaterialTexture(result, data, aMaterial, aiTextureType_DIFFUSE_ROUGHNESS, materialSlot.Roughness.TextureIndex, TextureEntry::TypeHint::ColorRGB, true);
if (materialSlot.Roughness.TextureIndex != -1 && (data.Path.EndsWith(TEXT(".gltf")) || data.Path.EndsWith(TEXT(".glb"))))
{
@@ -196,7 +196,7 @@ struct OpenFbxImporterData
#endif
}
bool ImportMaterialTexture(ModelData& result, const ofbx::Material* mat, ofbx::Texture::TextureType textureType, int32& textureIndex, TextureEntry::TypeHint type) const
bool ImportMaterialTexture(ModelData& result, const ofbx::Material* mat, ofbx::Texture::TextureType textureType, int32& textureIndex, TextureEntry::TypeHint type, bool sRGB = false) const
{
const ofbx::Texture* tex = mat->getTexture(textureType);
if (tex)
@@ -225,6 +225,7 @@ struct OpenFbxImporterData
auto& texture = result.Textures.AddOne();
texture.FilePath = path;
texture.Type = type;
texture.sRGB = sRGB;
texture.AssetID = Guid::Empty;
return true;
}
@@ -251,7 +252,7 @@ struct OpenFbxImporterData
if (EnumHasAnyFlags(Options.ImportTypes, ImportDataTypes::Textures))
{
ImportMaterialTexture(result, mat, ofbx::Texture::DIFFUSE, material.Diffuse.TextureIndex, TextureEntry::TypeHint::ColorRGB);
ImportMaterialTexture(result, mat, ofbx::Texture::DIFFUSE, material.Diffuse.TextureIndex, TextureEntry::TypeHint::ColorRGB, true);
ImportMaterialTexture(result, mat, ofbx::Texture::EMISSIVE, material.Emissive.TextureIndex, TextureEntry::TypeHint::ColorRGB);
ImportMaterialTexture(result, mat, ofbx::Texture::NORMAL, material.Normals.TextureIndex, TextureEntry::TypeHint::Normals);
@@ -1334,6 +1334,7 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option
String assetPath = GetAdditionalImportPath(autoImportOutput, importedFileNames, StringUtils::GetFileNameWithoutExtension(texture.FilePath));
#if COMPILE_WITH_ASSETS_IMPORTER
TextureTool::Options textureOptions;
textureOptions.sRGB = texture.sRGB;
switch (texture.Type)
{
case TextureEntry::TypeHint::ColorRGB:
@@ -1344,6 +1345,7 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option
break;
case TextureEntry::TypeHint::Normals:
textureOptions.Type = TextureFormatType::NormalMap;
textureOptions.sRGB = false;
break;
}
AssetsImportingManager::ImportIfEdited(texture.FilePath, assetPath, texture.AssetID, &textureOptions);
@@ -5,6 +5,7 @@
#include "TextureTool.h"
#include "Engine/Core/Log.h"
#include "Engine/Core/Math/Math.h"
#include "Engine/Core/Config/GraphicsSettings.h"
#include "Engine/Platform/File.h"
#include "Engine/Platform/CriticalSection.h"
#include "Engine/Platform/ConditionVariable.h"
@@ -665,8 +666,7 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path
if (sourceWidth != width || sourceHeight != height)
{
// During resizing we need to keep texture aspect ratio
const bool keepAspectRatio = options.KeepAspectRatio;
if (keepAspectRatio)
if (options.KeepAspectRatio)
{
const float aspectRatio = static_cast<float>(sourceWidth) / sourceHeight;
if (width >= height)
@@ -776,6 +776,14 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path
for (size_t i = 0; i < currentImage->GetImageCount(); i++)
((DirectX::Image*)currentImage->GetImages())[i].format = sourceDxgiFormat;
}
// Import as sRGB data for Linear color space
else if (options.sRGB && !GraphicsSettings::Get()->GammaColorSpace)
{
sourceDxgiFormat = ToDxgiFormat(PixelFormatExtensions::TosRGB(::ToPixelFormat(sourceDxgiFormat)));
((DirectX::TexMetadata&)currentImage->GetMetadata()).format = sourceDxgiFormat;
for (size_t i = 0; i < currentImage->GetImageCount(); i++)
((DirectX::Image*)currentImage->GetImages())[i].format = sourceDxgiFormat;
}
// Remove alpha if source texture has it but output should not, valid for compressed output only (DirectX seams to use alpha to pre-multiply colors because BC1 format has no place for alpha)
if (!keepAsIs && DirectX::HasAlpha(sourceDxgiFormat) && options.Type == TextureFormatType::ColorRGB && options.Compress)
@@ -45,7 +45,7 @@ API_CLASS(Namespace="FlaxEngine.Tools", Static) class FLAXENGINE_API TextureTool
API_FIELD(Attributes="EditorOrder(40)")
bool IndependentChannels = false;
// True if use sRGB format for texture data. Recommended for color maps and diffuse color textures.
// If checked, indicates that input file should be loaded as an sRGB image. Common for color maps and diffuse/albedo textures.
API_FIELD(Attributes="EditorOrder(50), EditorDisplay(null, \"sRGB\")")
bool sRGB = false;
@@ -6,6 +6,7 @@
#include "Engine/Core/Log.h"
#include "Engine/Core/Math/Color32.h"
#include "Engine/Core/Math/Vector2.h"
#include "Engine/Core/Config/GraphicsSettings.h"
#include "Engine/Serialization/FileWriteStream.h"
#include "Engine/Graphics/RenderTools.h"
#include "Engine/Graphics/Textures/TextureData.h"
@@ -107,7 +108,6 @@ static TextureData const* stbDecompress(const TextureData& textureData, TextureD
decompressedData->Data.Allocate(decompressedData->DepthPitch);
byte* decompressedBytes = decompressedData->Data.Get();
Color32 colors[16];
int32 blocksWidth = textureData.Width / 4;
int32 blocksHeight = textureData.Height / 4;
const TextureMipData* blocksData = textureData.GetData(0, 0);
@@ -503,8 +503,7 @@ bool TextureTool::ImportTextureStb(ImageType type, const StringView& path, Textu
if (sourceWidth != width || sourceHeight != height)
{
// During resizing we need to keep texture aspect ratio
const bool keepAspectRatio = options.KeepAspectRatio; // TODO: expose as import option
if (keepAspectRatio)
if (options.KeepAspectRatio)
{
const float aspectRatio = static_cast<float>(sourceWidth) / sourceHeight;
if (width >= height)
@@ -524,7 +523,6 @@ bool TextureTool::ImportTextureStb(ImageType type, const StringView& path, Textu
}
// Cache data
float alphaThreshold = 0.3f;
bool isPowerOfTwo = Math::IsPowerOfTwo(width) && Math::IsPowerOfTwo(height);
PixelFormat targetFormat = ToPixelFormat(options.Type, width, height, options.Compress);
if (options.sRGB)
@@ -552,6 +550,12 @@ bool TextureTool::ImportTextureStb(ImageType type, const StringView& path, Textu
return true;
}
// Import as sRGB data for Linear color space
if (options.sRGB && !GraphicsSettings::Get()->GammaColorSpace)
{
textureData.Format = PixelFormatExtensions::TosRGB(textureData.Format);
}
if (options.FlipX)
{
// TODO: impl this
+3 -6
View File
@@ -28,7 +28,7 @@ VS2PS VS(Render2DVertex input)
VS2PS output;
// Render2D::RenderingFeatures::VertexSnapping
if ((int)input.CustomDataAndClipOrigin.y & 1)
if ((int)input.CustomDataAndClipOrigin.y & RENDER2D_FEATURE_VERTEX_SNAPPING)
input.Position = (float2)(int2)input.Position;
output.Position = mul(float4(input.Position, 0, 1), ViewProjection);
@@ -45,23 +45,20 @@ META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_Image(VS2PS input) : SV_Target0
{
PerformClipping(input);
return Image.Sample(SamplerLinearClamp, input.TexCoord) * input.Color;
return GetImageColor(Image.Sample(SamplerLinearClamp, input.TexCoord), input.CustomData) * input.Color;
}
META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_ImagePoint(VS2PS input) : SV_Target0
{
PerformClipping(input);
return Image.Sample(SamplerPointClamp, input.TexCoord) * input.Color;
return GetImageColor(Image.Sample(SamplerPointClamp, input.TexCoord), input.CustomData) * input.Color;
}
META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_Color(VS2PS input) : SV_Target0
{
PerformClipping(input);
return input.Color;
}
+16 -1
View File
@@ -4,9 +4,15 @@
#define __GUI_COMMON__
#include "./Flax/Common.hlsl"
#include "./Flax/GammaCorrectionCommon.hlsl"
#define CLIPPING_ENABLE 1
// Render2D::RenderingFeatures
#define RENDER2D_FEATURE_VERTEX_SNAPPING 1
#define RENDER2D_FEATURE_FALLBACK_FONTS 2
#define RENDER2D_FEATURE_REMOVE_GAMMA 4
struct Render2DVertex
{
float2 Position : POSITION0;
@@ -21,7 +27,7 @@ struct VS2PS
float4 Position : SV_Position;
float4 Color : COLOR0;
float2 TexCoord : TEXCOORD0;
float2 CustomData : TEXCOORD1;
float2 CustomData : TEXCOORD1; // x-per-geometry type, y-features mask
float4 ClipExtents : TEXCOORD2;
float4 ClipOriginAndPos : TEXCOORD3;
};
@@ -54,4 +60,13 @@ void PerformClipping(VS2PS input)
PerformClipping(input.ClipOriginAndPos.xy, input.ClipOriginAndPos.zw, input.ClipExtents);
}
float4 GetImageColor(float4 color, float2 customData)
{
if ((int)customData.y & RENDER2D_FEATURE_REMOVE_GAMMA)
{
color.rgb = LinearToSrgb(color.rgb);
}
return color;
}
#endif
+9 -1
View File
@@ -26,6 +26,8 @@
#define GB_RADIUS 6
#define GB_KERNEL_SIZE (GB_RADIUS * 2 + 1)
#define OUTPUT_LINEAR 0 // Copies scene color directly to the output
#define OUTPUT_SRGB 1 // Converts scene color from linear to sRGB
#ifndef NO_GRADING_LUT
#define NO_GRADING_LUT 0
@@ -71,7 +73,7 @@ float2 InvInputSize;
float ChromaticDistortion;
float Time;
float Dummy1;
uint OutputColorSpace;
float PostExposure;
float VignetteIntensity;
float LensDirtIntensity;
@@ -695,6 +697,12 @@ float4 PS_Composite(Quad_VS2PS input) : SV_Target
color.rgb = ColorLookupTable(color.rgb);
#endif
if (OutputColorSpace == OUTPUT_SRGB)
{
// Convert into output display color space (sRGB)
color.rgb = LinearToSrgb(color.rgb);
}
// Film Grain
BRANCH
if (GrainAmount > 0)