mirror of
https://github.com/italicsjenga/slang-shaders.git
synced 2024-11-25 00:51:29 +11:00
Add average fill (#443)
* Implement average fill * Implement corner blend modes * Add copyright; Change defaults; Add some polish * Add settings delimiter * Fix settings name
This commit is contained in:
parent
407b93da55
commit
77b6ca6bed
59
border/average_fill.slangp
Normal file
59
border/average_fill.slangp
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
shaders = 7
|
||||||
|
|
||||||
|
shader0 = ../blurs/shaders/kawase/linearize.slang
|
||||||
|
scale_type0 = source
|
||||||
|
scale_x0 = 1.0
|
||||||
|
scale_y0 = 1.0
|
||||||
|
float_framebuffer0 = true
|
||||||
|
alias0 = "Input"
|
||||||
|
|
||||||
|
shader1 = shaders/average_fill/crop_and_sample_top.slang
|
||||||
|
filter_linear1 = true
|
||||||
|
scale_type1 = absolute
|
||||||
|
scale_x1 = 512
|
||||||
|
scale_y1 = 64
|
||||||
|
float_framebuffer1 = true
|
||||||
|
wrap_mode1 = mirrored_repeat
|
||||||
|
alias1 = "Top"
|
||||||
|
|
||||||
|
shader2 = shaders/average_fill/crop_and_sample_bottom.slang
|
||||||
|
filter_linear2 = true
|
||||||
|
scale_type2 = absolute
|
||||||
|
scale_x2 = 512
|
||||||
|
scale_y2 = 64
|
||||||
|
float_framebuffer2 = true
|
||||||
|
mipmap_input2 = true
|
||||||
|
alias2 = "Bottom"
|
||||||
|
|
||||||
|
shader3 = shaders/average_fill/crop_and_sample_left.slang
|
||||||
|
filter_linear3 = true
|
||||||
|
scale_type3 = absolute
|
||||||
|
scale_x3 = 64
|
||||||
|
scale_y3 = 512
|
||||||
|
float_framebuffer3 = true
|
||||||
|
mipmap_input3 = true
|
||||||
|
alias3 = "Left"
|
||||||
|
|
||||||
|
shader4 = shaders/average_fill/crop_and_sample_right.slang
|
||||||
|
filter_linear4 = true
|
||||||
|
scale_type4 = absolute
|
||||||
|
scale_x4 = 64
|
||||||
|
scale_y4 = 512
|
||||||
|
float_framebuffer4 = true
|
||||||
|
mipmap_input4 = true
|
||||||
|
alias4 = "Right"
|
||||||
|
|
||||||
|
shader5 = shaders/average_fill/compose.slang
|
||||||
|
filter_linear5 = true
|
||||||
|
scale_type5 = viewport
|
||||||
|
scale_x5 = 1.0
|
||||||
|
scale_y5 = 1.0
|
||||||
|
float_framebuffer5 = true
|
||||||
|
mipmap_input5 = true
|
||||||
|
|
||||||
|
shader6 = ../blurs/shaders/kawase/delinearize.slang
|
||||||
|
filter_linear6 = true
|
||||||
|
scale_type6 = viewport
|
||||||
|
scale_x6 = 1.0
|
||||||
|
scale_y6 = 1.0
|
||||||
|
float_framebuffer6 = true
|
189
border/shaders/average_fill/compose.slang
Normal file
189
border/shaders/average_fill/compose.slang
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
/*
|
||||||
|
Average fill v1.0 by fishku
|
||||||
|
Copyright (C) 2023
|
||||||
|
Public domain license (CC0)
|
||||||
|
|
||||||
|
This shader preset allows cropping the image on any side, and filling the
|
||||||
|
cropped area with the average color of an adjustable area next to it.
|
||||||
|
This is useful for certain games that do not render a full image to maintain
|
||||||
|
the overall aspect ratio and to avoid burn-in.
|
||||||
|
|
||||||
|
In case the image is cropped on multiple sides, different blend modes for
|
||||||
|
the corner are available. Simply change the parameter for the "corner blend
|
||||||
|
mode".
|
||||||
|
The available corner blend modes are:
|
||||||
|
0 = Draw horizontal bars on top
|
||||||
|
1 = Draw vertical bars on top
|
||||||
|
2 = Blend bars by weighted averaging
|
||||||
|
3 = Smooth angle-based blending
|
||||||
|
|
||||||
|
Changelog:
|
||||||
|
v1.0: Initial release.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "parameters.slang"
|
||||||
|
|
||||||
|
layout(push_constant) uniform Push {
|
||||||
|
vec4 InputSize;
|
||||||
|
vec4 OriginalSize;
|
||||||
|
vec4 OutputSize;
|
||||||
|
uint FrameCount;
|
||||||
|
float OS_CROP_TOP;
|
||||||
|
float OS_CROP_BOTTOM;
|
||||||
|
float OS_CROP_LEFT;
|
||||||
|
float OS_CROP_RIGHT;
|
||||||
|
float CORNER_BLEND_MODE;
|
||||||
|
float SAMPLE_SIZE;
|
||||||
|
}
|
||||||
|
param;
|
||||||
|
|
||||||
|
layout(std140, set = 0, binding = 0) uniform UBO { mat4 MVP; }
|
||||||
|
global;
|
||||||
|
|
||||||
|
#pragma stage vertex
|
||||||
|
layout(location = 0) in vec4 Position;
|
||||||
|
layout(location = 1) in vec2 TexCoord;
|
||||||
|
layout(location = 0) out vec2 vTexCoord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = global.MVP * Position;
|
||||||
|
vTexCoord = TexCoord;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma stage fragment
|
||||||
|
layout(location = 0) in vec2 vTexCoord;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
layout(set = 0, binding = 2) uniform sampler2D Input;
|
||||||
|
layout(set = 0, binding = 3) uniform sampler2D Top;
|
||||||
|
layout(set = 0, binding = 4) uniform sampler2D Bottom;
|
||||||
|
layout(set = 0, binding = 5) uniform sampler2D Left;
|
||||||
|
layout(set = 0, binding = 6) uniform sampler2D Right;
|
||||||
|
|
||||||
|
#define PI 3.1415926538
|
||||||
|
|
||||||
|
// For mipmap sampling, use a big offset to get the average of a PoT input.
|
||||||
|
#define BIG_NUMBER 9000.1
|
||||||
|
|
||||||
|
vec3 blend_corner(vec3 a, // The first color to blend
|
||||||
|
vec3 b, // The second color to blend
|
||||||
|
float wa, // The weight of the first color
|
||||||
|
float wb, // The weight of the second color
|
||||||
|
vec2 pixel_coord, // The coordinate to evaluate the blend for
|
||||||
|
vec2 corner_coord, // The coordinate of the corner of the
|
||||||
|
// content after cropping
|
||||||
|
vec2 gap_size // The component-wise distance from the corner
|
||||||
|
// of the content to the corner of the viewport
|
||||||
|
) {
|
||||||
|
switch (int(param.CORNER_BLEND_MODE)) {
|
||||||
|
case 0:
|
||||||
|
// Horizontal bars on top
|
||||||
|
return b;
|
||||||
|
case 1:
|
||||||
|
// Vertical bars on top
|
||||||
|
return a;
|
||||||
|
case 2:
|
||||||
|
// Weighted average of averages
|
||||||
|
return mix(a, b, wa / (wa + wb));
|
||||||
|
case 3:
|
||||||
|
default:
|
||||||
|
// Angle blend
|
||||||
|
const vec2 delta = (pixel_coord - corner_coord) / gap_size;
|
||||||
|
// Use absolutes to always operate in 1st quadrant.
|
||||||
|
// This makes the angle work out to be correct in all cases when
|
||||||
|
// carefully choosing argument ordering.
|
||||||
|
const float angle = atan(abs(delta.y), abs(delta.x)) / (PI * 0.5);
|
||||||
|
// Smoothstep makes the transition perceptually smoother.
|
||||||
|
return mix(a, b, smoothstep(0.0, 1.0, angle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
const vec2 pixel_coord = vTexCoord * param.InputSize.xy;
|
||||||
|
if (pixel_coord.x < param.OS_CROP_LEFT) {
|
||||||
|
const vec3 left = textureLod(Left, vec2(0.5), BIG_NUMBER).rgb;
|
||||||
|
if (pixel_coord.y < param.OS_CROP_TOP) {
|
||||||
|
// Top left corner
|
||||||
|
const vec3 top = textureLod(Top, vec2(0.5), BIG_NUMBER).rgb;
|
||||||
|
FragColor =
|
||||||
|
vec4(blend_corner(left, top,
|
||||||
|
param.InputSize.y - param.OS_CROP_TOP -
|
||||||
|
param.OS_CROP_BOTTOM,
|
||||||
|
param.InputSize.x - param.OS_CROP_LEFT -
|
||||||
|
param.OS_CROP_RIGHT,
|
||||||
|
pixel_coord,
|
||||||
|
vec2(param.OS_CROP_LEFT, param.OS_CROP_TOP),
|
||||||
|
vec2(param.OS_CROP_LEFT, param.OS_CROP_TOP)),
|
||||||
|
1.0);
|
||||||
|
} else if (pixel_coord.y < param.InputSize.y - param.OS_CROP_BOTTOM) {
|
||||||
|
// Left bar
|
||||||
|
FragColor = vec4(left, 1.0);
|
||||||
|
} else {
|
||||||
|
// Bottom left corner
|
||||||
|
const vec3 bottom = textureLod(Bottom, vec2(0.5), BIG_NUMBER).rgb;
|
||||||
|
FragColor = vec4(
|
||||||
|
blend_corner(left, bottom,
|
||||||
|
param.InputSize.y - param.OS_CROP_TOP -
|
||||||
|
param.OS_CROP_BOTTOM,
|
||||||
|
param.InputSize.x - param.OS_CROP_LEFT -
|
||||||
|
param.OS_CROP_RIGHT,
|
||||||
|
pixel_coord,
|
||||||
|
vec2(param.OS_CROP_LEFT,
|
||||||
|
param.InputSize.y - param.OS_CROP_BOTTOM),
|
||||||
|
vec2(param.OS_CROP_LEFT, param.OS_CROP_BOTTOM)),
|
||||||
|
1.0);
|
||||||
|
}
|
||||||
|
} else if (pixel_coord.x < param.InputSize.x - param.OS_CROP_RIGHT) {
|
||||||
|
if (pixel_coord.y < param.OS_CROP_TOP) {
|
||||||
|
// Top bar
|
||||||
|
FragColor = vec4(textureLod(Top, vec2(0.5), BIG_NUMBER).rgb, 1.0);
|
||||||
|
} else if (pixel_coord.y < param.InputSize.y - param.OS_CROP_BOTTOM) {
|
||||||
|
// Uncropped
|
||||||
|
// Do a sharp (nearest neighbor) resampling.
|
||||||
|
FragColor = vec4(
|
||||||
|
texture(Input, (floor(vTexCoord * param.InputSize.xy) + 0.5) *
|
||||||
|
param.InputSize.zw)
|
||||||
|
.rgb,
|
||||||
|
1.0);
|
||||||
|
} else {
|
||||||
|
// Bottom bar
|
||||||
|
FragColor =
|
||||||
|
vec4(textureLod(Bottom, vec2(0.5), BIG_NUMBER).rgb, 1.0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const vec3 right = textureLod(Right, vec2(0.5), BIG_NUMBER).rgb;
|
||||||
|
if (pixel_coord.y < param.OS_CROP_TOP) {
|
||||||
|
// Top right corner
|
||||||
|
const vec3 top = textureLod(Top, vec2(0.5), BIG_NUMBER).rgb;
|
||||||
|
FragColor =
|
||||||
|
vec4(blend_corner(right, top,
|
||||||
|
param.InputSize.y - param.OS_CROP_TOP -
|
||||||
|
param.OS_CROP_BOTTOM,
|
||||||
|
param.InputSize.x - param.OS_CROP_LEFT -
|
||||||
|
param.OS_CROP_RIGHT,
|
||||||
|
pixel_coord,
|
||||||
|
vec2(param.InputSize.x - param.OS_CROP_RIGHT,
|
||||||
|
param.OS_CROP_TOP),
|
||||||
|
vec2(param.OS_CROP_RIGHT, param.OS_CROP_TOP)),
|
||||||
|
1.0);
|
||||||
|
} else if (pixel_coord.y < param.InputSize.y - param.OS_CROP_BOTTOM) {
|
||||||
|
// Right bar
|
||||||
|
FragColor = vec4(right, 1.0);
|
||||||
|
} else {
|
||||||
|
// Bottom right corner
|
||||||
|
const vec3 bottom = textureLod(Bottom, vec2(0.5), BIG_NUMBER).rgb;
|
||||||
|
FragColor = vec4(
|
||||||
|
blend_corner(right, bottom,
|
||||||
|
param.InputSize.y - param.OS_CROP_TOP -
|
||||||
|
param.OS_CROP_BOTTOM,
|
||||||
|
param.InputSize.x - param.OS_CROP_LEFT -
|
||||||
|
param.OS_CROP_RIGHT,
|
||||||
|
pixel_coord,
|
||||||
|
vec2(param.InputSize.x - param.OS_CROP_RIGHT,
|
||||||
|
param.InputSize.y - param.OS_CROP_BOTTOM),
|
||||||
|
vec2(param.OS_CROP_RIGHT, param.OS_CROP_BOTTOM)),
|
||||||
|
1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
border/shaders/average_fill/crop_and_sample_bottom.slang
Normal file
14
border/shaders/average_fill/crop_and_sample_bottom.slang
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
// See compose.slang for copyright and other information.
|
||||||
|
|
||||||
|
#include "parameters.slang"
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#define EFF_CROP_TOP (param.InputSize.y - param.OS_CROP_BOTTOM - param.SAMPLE_SIZE)
|
||||||
|
#define EFF_CROP_BOTTOM (param.OS_CROP_BOTTOM)
|
||||||
|
#define EFF_CROP_LEFT (param.OS_CROP_LEFT)
|
||||||
|
#define EFF_CROP_RIGHT (param.OS_CROP_RIGHT)
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#include "crop_and_sample_common.slang"
|
37
border/shaders/average_fill/crop_and_sample_common.slang
Normal file
37
border/shaders/average_fill/crop_and_sample_common.slang
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// See compose.slang for copyright and other information.
|
||||||
|
|
||||||
|
layout(push_constant) uniform Push {
|
||||||
|
vec4 InputSize;
|
||||||
|
vec4 OriginalSize;
|
||||||
|
vec4 OutputSize;
|
||||||
|
uint FrameCount;
|
||||||
|
float OS_CROP_TOP;
|
||||||
|
float OS_CROP_BOTTOM;
|
||||||
|
float OS_CROP_LEFT;
|
||||||
|
float OS_CROP_RIGHT;
|
||||||
|
float SAMPLE_SIZE;
|
||||||
|
}
|
||||||
|
param;
|
||||||
|
|
||||||
|
layout(std140, set = 0, binding = 0) uniform UBO { mat4 MVP; }
|
||||||
|
global;
|
||||||
|
|
||||||
|
#pragma stage vertex
|
||||||
|
layout(location = 0) in vec4 Position;
|
||||||
|
layout(location = 1) in vec2 TexCoord;
|
||||||
|
layout(location = 0) out vec2 vTexCoord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = global.MVP * Position;
|
||||||
|
vTexCoord =
|
||||||
|
mix(vec2(EFF_CROP_LEFT, EFF_CROP_TOP) * param.InputSize.zw,
|
||||||
|
1.0 - vec2(EFF_CROP_RIGHT, EFF_CROP_BOTTOM) * param.InputSize.zw,
|
||||||
|
TexCoord);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma stage fragment
|
||||||
|
layout(location = 0) in vec2 vTexCoord;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
layout(set = 0, binding = 2) uniform sampler2D Input;
|
||||||
|
|
||||||
|
void main() { FragColor = vec4(texture(Input, vTexCoord).rgb, 1.0); }
|
14
border/shaders/average_fill/crop_and_sample_left.slang
Normal file
14
border/shaders/average_fill/crop_and_sample_left.slang
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
// See compose.slang for copyright and other information.
|
||||||
|
|
||||||
|
#include "parameters.slang"
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#define EFF_CROP_TOP (param.OS_CROP_TOP)
|
||||||
|
#define EFF_CROP_BOTTOM (param.OS_CROP_BOTTOM)
|
||||||
|
#define EFF_CROP_LEFT (param.OS_CROP_LEFT)
|
||||||
|
#define EFF_CROP_RIGHT (param.InputSize.x - param.OS_CROP_LEFT - param.SAMPLE_SIZE)
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#include "crop_and_sample_common.slang"
|
14
border/shaders/average_fill/crop_and_sample_right.slang
Normal file
14
border/shaders/average_fill/crop_and_sample_right.slang
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
// See compose.slang for copyright and other information.
|
||||||
|
|
||||||
|
#include "parameters.slang"
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#define EFF_CROP_TOP (param.OS_CROP_TOP)
|
||||||
|
#define EFF_CROP_BOTTOM (param.OS_CROP_BOTTOM)
|
||||||
|
#define EFF_CROP_LEFT (param.InputSize.x - param.OS_CROP_RIGHT - param.SAMPLE_SIZE)
|
||||||
|
#define EFF_CROP_RIGHT (param.OS_CROP_RIGHT)
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#include "crop_and_sample_common.slang"
|
14
border/shaders/average_fill/crop_and_sample_top.slang
Normal file
14
border/shaders/average_fill/crop_and_sample_top.slang
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
// See compose.slang for copyright and other information.
|
||||||
|
|
||||||
|
#include "parameters.slang"
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#define EFF_CROP_TOP (param.OS_CROP_TOP)
|
||||||
|
#define EFF_CROP_BOTTOM (param.InputSize.y - param.OS_CROP_TOP - param.SAMPLE_SIZE)
|
||||||
|
#define EFF_CROP_LEFT (param.OS_CROP_LEFT)
|
||||||
|
#define EFF_CROP_RIGHT (param.OS_CROP_RIGHT)
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#include "crop_and_sample_common.slang"
|
11
border/shaders/average_fill/parameters.slang
Normal file
11
border/shaders/average_fill/parameters.slang
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// See compose.slang for copyright and other information.
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#pragma parameter AVERAGE_FILL_SETTINGS "=== Average fill v1.0 settings ===" 0.0 0.0 1.0 1.0
|
||||||
|
#pragma parameter OS_CROP_TOP "Overscan crop top" 16.0 0.0 1024.0 1.0
|
||||||
|
#pragma parameter OS_CROP_BOTTOM "Overscan crop bottom" 16.0 0.0 1024.0 1.0
|
||||||
|
#pragma parameter OS_CROP_LEFT "Overscan crop left" 0.0 0.0 1024.0 1.0
|
||||||
|
#pragma parameter OS_CROP_RIGHT "Overscan crop right" 0.0 0.0 1024.0 1.0
|
||||||
|
#pragma parameter CORNER_BLEND_MODE "Cropped corner blend mode" 0.0 0.0 3.0 1.0
|
||||||
|
#pragma parameter SAMPLE_SIZE "No. of lines for calculating the average" 4.0 1.0 64.0 1.0
|
||||||
|
// clang-format on
|
Loading…
Reference in a new issue