Show texel border and more swizzle options

This commit is contained in:
Simon Lübeß
2025-02-24 23:00:46 +01:00
parent 0236130df1
commit 824c19c0b2
3 changed files with 108 additions and 23 deletions
@@ -1,3 +1,5 @@
#include "ShaderHelpers.hlsl"
Texture2DArray Texture : register(t0); Texture2DArray Texture : register(t0);
SamplerState Sampler : register(s0); SamplerState Sampler : register(s0);
@@ -7,11 +9,16 @@ SamplerState IntSampler : register(s1);
Texture2DArray<uint4> UIntTexture : register(t2); Texture2DArray<uint4> UIntTexture : register(t2);
SamplerState UIntSampler : register(s2); SamplerState UIntSampler : register(s2);
#define SWIZZLE_NONE 0 #define SWIZZLE_ZERO 0
#define SWIZZLE_R 1 #define SWIZZLE_ONE 1
#define SWIZZLE_G 2 #define SWIZZLE_R 2
#define SWIZZLE_B 3 #define SWIZZLE_G 3
#define SWIZZLE_A 4 #define SWIZZLE_B 4
#define SWIZZLE_A 5
#define SWIZZLE_ONE_MINUS_R 6
#define SWIZZLE_ONE_MINUS_G 7
#define SWIZZLE_ONE_MINUS_B 8
#define SWIZZLE_ONE_MINUS_A 9
cbuffer Constants cbuffer Constants
{ {
@@ -31,6 +38,9 @@ cbuffer Constants
float2 Texels; float2 Texels;
float4x4 WorldViewProjection; float4x4 WorldViewProjection;
bool ShowTexelBorders = true;
float TexelBorderCutoff = 10;
} }
struct VS_Input struct VS_Input
@@ -59,6 +69,12 @@ void SwizzleColor(int swizzleMode, float4 colorToSwizzle, inout float output)
{ {
switch (swizzleMode) switch (swizzleMode)
{ {
case SWIZZLE_ZERO:
output = 0.0;
break;
case SWIZZLE_ONE:
output = 1.0;
break;
case SWIZZLE_R: case SWIZZLE_R:
output = colorToSwizzle.r; output = colorToSwizzle.r;
break; break;
@@ -70,31 +86,77 @@ void SwizzleColor(int swizzleMode, float4 colorToSwizzle, inout float output)
break; break;
case SWIZZLE_A: case SWIZZLE_A:
output = colorToSwizzle.a; output = colorToSwizzle.a;
break;
case SWIZZLE_ONE_MINUS_R:
output = 1.0 - colorToSwizzle.r;
break;
case SWIZZLE_ONE_MINUS_G:
output = 1.0 - colorToSwizzle.g;
break;
case SWIZZLE_ONE_MINUS_B:
output = 1.0 - colorToSwizzle.b;
break;
case SWIZZLE_ONE_MINUS_A:
output = 1.0 - colorToSwizzle.a;
break; break;
default: default:
break; break;
} }
} }
/**
* Returns whether or not the current pixel lies on the border between two texels.
*/
void ApplyTexelBorder(float2 texelPosition, inout float4 color)
{
// Calculate derivatives of texelPosition -> how many texels to we move if we move one pixel in x/y direction
float2 dudx = ddx(texelPosition);
float2 dudy = ddy(texelPosition);
// This is the reciprocal of the screen size of one texel.
float grad = float2(length(dudx), length(dudy));
float2 pixelsPerTexel = 1.0f / grad;
// Threshold is half the size of a screen pixel in texel-space.
float2 threshold = grad / 2.0f;
// Calculate the distance between the screen pixel and the texel border in texels.
float2 fracPart = frac(texelPosition);
float2 distanceToBorder = min(fracPart, 1.0 - fracPart);
if (any(distanceToBorder < threshold))
{
// Ensure the border is always at least 0.5 luminance away from the texel.
// TODO: This can flicker while moving/zooming, because we are by design on a texel border!
float luminance = ColorToLuminance(color.rgb);
float4 borderColor = (luminance > 0.5f) ? float4(0, 0, 0, 1) : float4(1, 1, 1, 1);
color = lerp(color, borderColor, clamp((min(pixelsPerTexel.x, pixelsPerTexel.y) - TexelBorderCutoff / 2.0) / TexelBorderCutoff, 0.0f, 0.8f));
}
}
float4 PS(PS_Input input) : SV_Target0 float4 PS(PS_Input input) : SV_Target0
{ {
float4 outputColor; float4 outputColor;
float2 texelPosition = input.Texcoord * Texels;
if (Mode == 0) if (Mode == 0)
{ {
//float4 color = Texture.SampleLevel(Sampler, float3(input.Texcoord, ArraySlice), MipLevel); //float4 color = Texture.SampleLevel(Sampler, float3(input.Texcoord, ArraySlice), MipLevel);
// Quasi next neighbor // Quasi next neighbor
float4 color = Texture.Load(int4(input.Texcoord * Texels, ArraySlice, MipLevel)); float4 color = Texture.Load(int4(texelPosition, ArraySlice, MipLevel));
outputColor = float4(ColorOffset.xxx, AlphaOffset) + color * float4(ColorScale.xxx, AlphaScale); outputColor = float4(ColorOffset.xxx, AlphaOffset) + color * float4(ColorScale.xxx, AlphaScale);
} }
else if (Mode == 1) else if (Mode == 1)
{ {
int4 color = IntTexture.Load(int4(input.Texcoord * Texels, ArraySlice, MipLevel)); int4 color = IntTexture.Load(int4(texelPosition, ArraySlice, MipLevel));
outputColor = float4(ColorOffset.xxx, AlphaOffset) + color * float4(ColorScale.xxx, AlphaScale); outputColor = float4(ColorOffset.xxx, AlphaOffset) + color * float4(ColorScale.xxx, AlphaScale);
} }
else if (Mode == 2) else if (Mode == 2)
{ {
uint4 color = UIntTexture.Load(int4(input.Texcoord * Texels, ArraySlice, MipLevel)); uint4 color = UIntTexture.Load(int4(texelPosition, ArraySlice, MipLevel));
outputColor = float4(ColorOffset.xxx, AlphaOffset) + color * float4(ColorScale.xxx, AlphaScale); outputColor = float4(ColorOffset.xxx, AlphaOffset) + color * float4(ColorScale.xxx, AlphaScale);
} }
@@ -105,6 +167,11 @@ float4 PS(PS_Input input) : SV_Target0
SwizzleColor(Swizzle.b, outputColor, swizzledOutput.b); SwizzleColor(Swizzle.b, outputColor, swizzledOutput.b);
SwizzleColor(Swizzle.a, outputColor, swizzledOutput.a); SwizzleColor(Swizzle.a, outputColor, swizzledOutput.a);
if (ShowTexelBorders)
{
ApplyTexelBorder(texelPosition, swizzledOutput);
}
return swizzledOutput; return swizzledOutput;
} }
@@ -72,7 +72,7 @@ float3x3 ConstructTangentSpace(float3 normal, float3 tangent, float3 sigma)
*/ */
float ColorToLuminance(float3 rgb) float ColorToLuminance(float3 rgb)
{ {
return rgb.r * 0.212639 + rgb.g * 0.715169 + rgb.b * 0.072192; return rgb.r * 0.212639 + rgb.g * 0.715169 + rgb.b * 0.072192;
} }
/** /**
+32 -14
View File
@@ -152,11 +152,16 @@ class TextureViewer
enum ColorChannelSwizzle : int32 enum ColorChannelSwizzle : int32
{ {
None, Zero,
One,
R, R,
G, G,
B, B,
A A,
OneMinusR,
OneMinusG,
OneMinusB,
OneMinusA
} }
AssetHandle<Effect> _effect; AssetHandle<Effect> _effect;
@@ -164,6 +169,7 @@ class TextureViewer
Material _renderTargetMaterial ~ _.ReleaseRef(); Material _renderTargetMaterial ~ _.ReleaseRef();
float _zoom = 1.0f; float _zoom = 1.0f;
bool _showTexelBorder = false;
BackgroundMode _backgroundMode = .Checkerboard; BackgroundMode _backgroundMode = .Checkerboard;
ColorRGBA _backgroundColor; ColorRGBA _backgroundColor;
@@ -171,10 +177,6 @@ class TextureViewer
SampleMode _sampleMode = .Linear; SampleMode _sampleMode = .Linear;
RenderTargetGroup _targets ~ _?.ReleaseRef(); RenderTargetGroup _targets ~ _?.ReleaseRef();
/*RenderTarget2D _target ~ _?.ReleaseRef();
RenderTarget2D _idTarget ~ _?.ReleaseRef();
// TODO: we don't need depth!
DepthStencilTarget _depth ~ _?.ReleaseRef();*/
public this() public this()
{ {
@@ -281,8 +283,6 @@ class TextureViewer
if (ImGui.CollapsingHeader("Color and Transparency")) if (ImGui.CollapsingHeader("Color and Transparency"))
{ {
ImGui.TextUnformatted("Channel Swizzle:");
if (ImGui.BeginTable("ColorAndAlpha", 4)) if (ImGui.BeginTable("ColorAndAlpha", 4))
{ {
ImGui.TableNextRow(); ImGui.TableNextRow();
@@ -338,6 +338,10 @@ class TextureViewer
ImGui.Separator(); ImGui.Separator();
ImGui.Checkbox("Show texel grid", &_showTexelBorder);
ImGui.Separator();
ImGui.TextUnformatted("Channel Swizzle:"); ImGui.TextUnformatted("Channel Swizzle:");
if (ImGui.BeginTable("SwizzleTable", 9)) if (ImGui.BeginTable("SwizzleTable", 9))
@@ -376,6 +380,12 @@ class TextureViewer
if (ImGui.BeginCombo(scope $"##swizzle{text}", scope $"{swizzle}")) if (ImGui.BeginCombo(scope $"##swizzle{text}", scope $"{swizzle}"))
{ {
if (ImGui.Selectable("0", swizzle == .Zero))
swizzle = .Zero;
if (ImGui.Selectable("1", swizzle == .One))
swizzle = .One;
if (ImGui.Selectable("R", swizzle == .R)) if (ImGui.Selectable("R", swizzle == .R))
swizzle = .R; swizzle = .R;
@@ -387,9 +397,18 @@ class TextureViewer
if (ImGui.Selectable("A", swizzle == .A)) if (ImGui.Selectable("A", swizzle == .A))
swizzle = .A; swizzle = .A;
if (ImGui.Selectable("1 - R", swizzle == .OneMinusR))
swizzle = .OneMinusR;
if (ImGui.Selectable("1 - G", swizzle == .OneMinusG))
swizzle = .OneMinusG;
if (ImGui.Selectable("None", swizzle == .None)) if (ImGui.Selectable("1 - B", swizzle == .OneMinusB))
swizzle = .None; swizzle = .OneMinusB;
if (ImGui.Selectable("1 - A", swizzle == .OneMinusA))
swizzle = .OneMinusA;
ImGui.EndCombo(); ImGui.EndCombo();
} }
@@ -590,10 +609,6 @@ class TextureViewer
viewedTexture.SamplerState = SamplerStateManager.LinearClamp; viewedTexture.SamplerState = SamplerStateManager.LinearClamp;
}*/ }*/
//Renderer2D.BeginScene(_camera, .SortByTexture, _effect);
// float3(_position * .(1, -1), 0)
//RenderCommand.Clear(_depth, .Depth, 1.0f, 0);
RenderCommand.Clear(_targets, .Depth); RenderCommand.Clear(_targets, .Depth);
Matrix matrix = .Translation(float3((_position + float2(_targets.Width, _targets.Height) / 2) * .(1, -1), 0)) * .Scaling(float3(zoomedTextureSize, 1)); Matrix matrix = .Translation(float3((_position + float2(_targets.Width, _targets.Height) / 2) * .(1, -1), 0)) * .Scaling(float3(zoomedTextureSize, 1));
@@ -609,6 +624,9 @@ class TextureViewer
_renderTargetMaterial.SetVariable("MipLevel", (float)_mipLevel); _renderTargetMaterial.SetVariable("MipLevel", (float)_mipLevel);
_renderTargetMaterial.SetVariable("Swizzle", int4((int32)_swizzleR, (int32)_swizzleG, (int32)_swizzleB, (int32)_swizzleA)); _renderTargetMaterial.SetVariable("Swizzle", int4((int32)_swizzleR, (int32)_swizzleG, (int32)_swizzleB, (int32)_swizzleA));
_renderTargetMaterial.SetVariable("ShowTexelBorders", _showTexelBorder);
_renderTargetMaterial.SetVariable("TexelBorderCutoff", 10.0f);
int textureSlot = -1; int textureSlot = -1;