diff --git a/Content/Editor/DebugMaterials/SingleColor/Decal.flax b/Content/Editor/DebugMaterials/SingleColor/Decal.flax
index b94f22bc8..4469b7b22 100644
--- a/Content/Editor/DebugMaterials/SingleColor/Decal.flax
+++ b/Content/Editor/DebugMaterials/SingleColor/Decal.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:588c29a4b239c32d4b125052e4054a29cf5140562e90ca6fac4d2952e03f66c7
-size 10397
+oid sha256:6b4d79e7fa619f29f28c38d56cc7513369cbcd8d71dd39cd1d8c33e5c9c97fe2
+size 10398
diff --git a/Content/Editor/MaterialTemplates/GUI.shader b/Content/Editor/MaterialTemplates/GUI.shader
index 22da15796..42e0179b7 100644
--- a/Content/Editor/MaterialTemplates/GUI.shader
+++ b/Content/Editor/MaterialTemplates/GUI.shader
@@ -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;
diff --git a/Content/Editor/TexturePreviewMaterial.flax b/Content/Editor/TexturePreviewMaterial.flax
index d75e19d5e..28c2d7896 100644
--- a/Content/Editor/TexturePreviewMaterial.flax
+++ b/Content/Editor/TexturePreviewMaterial.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:79de09ba0616eb6066171c2b80cdb6c4235cb52be4836d23162bb9c2585760a0
-size 11058
+oid sha256:d726a95ca50527ace0cb47eeff584ed129d69405e7068b6d1eb5a06d6fa9729a
+size 11533
diff --git a/Content/Shaders/ColorGrading.flax b/Content/Shaders/ColorGrading.flax
index 716e18593..f7074f20d 100644
--- a/Content/Shaders/ColorGrading.flax
+++ b/Content/Shaders/ColorGrading.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:bce57f0ccf6d808985f4d79cc4e15d85cae999bee598d8e93ff5b1b126bc42b8
-size 12310
+oid sha256:c0b43b79fe3ad34ebf5fa47d49e017c768b48c1bd688ba521a684bab7ef286bd
+size 12311
diff --git a/Content/Shaders/GI/DDGI.flax b/Content/Shaders/GI/DDGI.flax
index 257953bf9..6d1431236 100644
--- a/Content/Shaders/GI/DDGI.flax
+++ b/Content/Shaders/GI/DDGI.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5b017cf857f443553020e4bc7c8c8c5da3a826a2514322664a023ffa6005f7a5
-size 38217
+oid sha256:c0984d39f5226f8eac725b307c88a663d54836a820ae4d4d3cffe73b8fe6d0a2
+size 38199
diff --git a/Content/Shaders/GUI.flax b/Content/Shaders/GUI.flax
index d5e3f59fa..e243245be 100644
--- a/Content/Shaders/GUI.flax
+++ b/Content/Shaders/GUI.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4fed6a05104322f61a77f6cf69b64478518b829165a2a3ab7fc151098dcd48be
-size 4526
+oid sha256:6a9b9f62e4e04e9cfa15aae54a78024698780c33a81116c550a409aedfc89cae
+size 4621
diff --git a/Content/Shaders/PostProcessing.flax b/Content/Shaders/PostProcessing.flax
index e34c5c185..4bdb35584 100644
--- a/Content/Shaders/PostProcessing.flax
+++ b/Content/Shaders/PostProcessing.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e442c2d6607e40da68e3aa9414390386d44cc7bc8c677a1f5a5e4a536857b906
-size 22688
+oid sha256:eb59d5d69de414b28dad32c673193d138709c16bd31bb8a1cf435d329a6bd1c1
+size 22997
diff --git a/Flax.flaxproj b/Flax.flaxproj
index c74ec3990..aa3a8655f 100644
--- a/Flax.flaxproj
+++ b/Flax.flaxproj
@@ -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.",
diff --git a/Source/Editor/Content/Import/TextureImportEntry.cs b/Source/Editor/Content/Import/TextureImportEntry.cs
index e547a1b9e..a2e14aaf1 100644
--- a/Source/Editor/Content/Import/TextureImportEntry.cs
+++ b/Source/Editor/Content/Import/TextureImportEntry.cs
@@ -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);
diff --git a/Source/Editor/Viewport/Previews/TexturePreview.cs b/Source/Editor/Viewport/Previews/TexturePreview.cs
index 709bc953e..4c36a2725 100644
--- a/Source/Editor/Viewport/Previews/TexturePreview.cs
+++ b/Source/Editor/Viewport/Previews/TexturePreview.cs
@@ -410,6 +410,22 @@ namespace FlaxEditor.Viewport.Previews
UpdateTextureRect();
}
+ ///
+ /// Draws the material
+ ///
+ 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
///
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
///
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);
}
}
}
diff --git a/Source/Engine/Core/Config/GameSettings.cpp b/Source/Engine/Core/Config/GameSettings.cpp
index eb6705c9c..1f37175b4 100644
--- a/Source/Engine/Core/Config/GameSettings.cpp
+++ b/Source/Engine/Core/Config/GameSettings.cpp
@@ -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);
diff --git a/Source/Engine/Core/Config/GraphicsSettings.h b/Source/Engine/Core/Config/GraphicsSettings.h
index d8b35533a..80f657fec 100644
--- a/Source/Engine/Core/Config/GraphicsSettings.h
+++ b/Source/Engine/Core/Config/GraphicsSettings.h
@@ -127,12 +127,22 @@ public:
API_FIELD(Attributes="EditorOrder(2130), Limit(256, 8192), EditorDisplay(\"Global Illumination\")")
int32 GlobalSurfaceAtlasResolution = 2048;
+public:
+ ///
+ /// 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.
+ ///
+ API_FIELD(Attributes="EditorOrder(3000), EditorDisplay(\"Colors\")")
+ bool GammaColorSpace = false;
+
+public:
///
/// The default Post Process settings. Can be overriden by PostFxVolume on a level locally, per camera or for a whole map.
///
API_FIELD(Attributes="EditorOrder(10000), EditorDisplay(\"Post Process Settings\", EditorDisplayAttribute.InlineStyle)")
PostProcessSettings PostProcessSettings;
+public:
///
/// The list of fallback fonts used for text rendering. Ignored if empty.
///
@@ -144,12 +154,9 @@ private:
/// Renamed UeeHDRProbes into UseHDRProbes
/// [Deprecated on 12.10.2022, expires on 12.10.2024]
///
- 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:
///
diff --git a/Source/Engine/Graphics/Models/ModelData.h b/Source/Engine/Graphics/Models/ModelData.h
index 26b473e09..169ff3339 100644
--- a/Source/Engine/Graphics/Models/ModelData.h
+++ b/Source/Engine/Graphics/Models/ModelData.h
@@ -278,6 +278,11 @@ struct FLAXENGINE_API TextureEntry
///
TypeHint Type;
+ ///
+ /// Hints that texture contents are in sRGB color format.
+ ///
+ bool sRGB = false;
+
///
/// The texture asset identifier.
///
diff --git a/Source/Engine/Render2D/Render2D.cpp b/Source/Engine/Render2D/Render2D.cpp
index 5ae034bc5..aa61603d7 100644
--- a/Source/Engine/Render2D/Render2D.cpp
+++ b/Source/Engine/Render2D/Render2D.cpp
@@ -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 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& 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& vertices, const Span& uvs, const Color& color)
@@ -2047,15 +2088,17 @@ void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span& 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& vertices, const Span& uvs, const Span& colors)
@@ -2064,15 +2107,17 @@ void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span& 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& indices, const Span& vertices, const Span& uvs, const Span& colors)
@@ -2080,6 +2125,7 @@ void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span& 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& 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& vertices, const Color& color)
diff --git a/Source/Engine/Render2D/Render2D.h b/Source/Engine/Render2D/Render2D.h
index 69b6aea1c..7002d391e 100644
--- a/Source/Engine/Render2D/Render2D.h
+++ b/Source/Engine/Render2D/Render2D.h
@@ -49,6 +49,11 @@ API_CLASS(Static) class FLAXENGINE_API Render2D
/// Enables automatic characters usage from fallback fonts.
///
FallbackFonts = 2,
+
+ ///
+ /// 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.
+ ///
+ RemoveGamma = 4,
};
struct CustomData
diff --git a/Source/Engine/Renderer/PostProcessingPass.cpp b/Source/Engine/Renderer/PostProcessingPass.cpp
index 5ac204523..2bac6bf76 100644
--- a/Source/Engine/Renderer/PostProcessingPass.cpp
+++ b/Source/Engine/Renderer/PostProcessingPass.cpp
@@ -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(w1), static_cast(h1));
data.InvInputSize = Float2(1.0f / static_cast(w1), 1.0f / static_cast(h1));
data.InputAspect = static_cast(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);
diff --git a/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp b/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp
index b1340bfa7..7ede58373 100644
--- a/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp
+++ b/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp
@@ -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"))))
{
diff --git a/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp b/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp
index 81ce46d6c..acf18cb18 100644
--- a/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp
+++ b/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp
@@ -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);
diff --git a/Source/Engine/Tools/ModelTool/ModelTool.cpp b/Source/Engine/Tools/ModelTool/ModelTool.cpp
index 843822b98..aedaf12a4 100644
--- a/Source/Engine/Tools/ModelTool/ModelTool.cpp
+++ b/Source/Engine/Tools/ModelTool/ModelTool.cpp
@@ -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);
diff --git a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp
index d7199a470..cb758babd 100644
--- a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp
+++ b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp
@@ -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(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)
diff --git a/Source/Engine/Tools/TextureTool/TextureTool.h b/Source/Engine/Tools/TextureTool/TextureTool.h
index 97199680c..53f6c13a0 100644
--- a/Source/Engine/Tools/TextureTool/TextureTool.h
+++ b/Source/Engine/Tools/TextureTool/TextureTool.h
@@ -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;
diff --git a/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp b/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp
index 7c74ef3f2..99ee78780 100644
--- a/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp
+++ b/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp
@@ -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(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
diff --git a/Source/Shaders/GUI.shader b/Source/Shaders/GUI.shader
index e9eedd4a6..5d02cd60e 100644
--- a/Source/Shaders/GUI.shader
+++ b/Source/Shaders/GUI.shader
@@ -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;
}
diff --git a/Source/Shaders/GUICommon.hlsl b/Source/Shaders/GUICommon.hlsl
index 14c8b1327..1aca05862 100644
--- a/Source/Shaders/GUICommon.hlsl
+++ b/Source/Shaders/GUICommon.hlsl
@@ -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
diff --git a/Source/Shaders/PostProcessing.shader b/Source/Shaders/PostProcessing.shader
index aa70833d2..e79e0138f 100644
--- a/Source/Shaders/PostProcessing.shader
+++ b/Source/Shaders/PostProcessing.shader
@@ -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)