Files
doom-dm/PresenterConsole/assets/shader/ascii.shader
2024-12-16 04:28:45 +03:00

120 lines
3.5 KiB
GLSL

// #type vertex
#version 460 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 aUV;
layout (location = 0) out vec2 oUV;
void main()
{
oUV = aUV;
gl_Position = vec4(aPos, 0.0, 1.0);
}
// #type fragment
#version 460 core
precision highp float;
// ConsoleColor vec3 palette (normalized)
const vec3 ConsoleColorVec3[16] = vec3[](
vec3(0.0, 0.0, 0.0), // Black
vec3(0.0, 0.0, 0.5), // DarkBlue
vec3(0.0, 0.5, 0.0), // DarkGreen
vec3(0.0, 0.5, 0.5), // DarkCyan
vec3(0.5, 0.0, 0.0), // DarkRed
vec3(0.5, 0.0, 0.5), // DarkMagenta
vec3(0.5, 0.5, 0.0), // DarkYellow
vec3(0.5, 0.5, 0.5), // Gray
vec3(0.25, 0.25, 0.25), // DarkGray
vec3(0.0, 0.0, 1.0), // Blue
vec3(0.0, 1.0, 0.0), // Green
vec3(0.0, 1.0, 1.0), // Cyan
vec3(1.0, 0.0, 0.0), // Red
vec3(1.0, 0.0, 1.0), // Magenta
vec3(1.0, 1.0, 0.0), // Yellow
vec3(1.0, 1.0, 1.0) // White
);
// RGB to LAB conversion (simplified approximation)
vec3 rgb2lab(vec3 x) {
const float epsilon = 0.008856;
const float k = 903.3;
vec3 fx;
fx.x = x.x > epsilon ? pow(x.x, 1.0 / 3.0) : (k * x.x + 16.0) / 116.0;
fx.y = x.y > epsilon ? pow(x.y, 1.0 / 3.0) : (k * x.y + 16.0) / 116.0;
fx.z = x.z > epsilon ? pow(x.z, 1.0 / 3.0) : (k * x.z + 16.0) / 116.0;
return fx;
}
// Perceptually weighted color difference (CIEDE2000-inspired)
float perceptualColorDistance(vec3 color1, vec3 color2) {
vec3 lab1 = rgb2lab(color1);
vec3 lab2 = rgb2lab(color2);
// Compute LAB-like color difference with perceptual weighting
float deltaL = lab1.x - lab2.x;
float deltaA = lab1.y - lab2.y;
float deltaB = lab1.z - lab2.z;
// Perceptual weighting
return deltaL * deltaL * 1.0 + // Lightness difference
deltaA * deltaA * 1.5 + // Green-Red difference
deltaB * deltaB * 1.5; // Blue-Yellow difference
}
// Advanced color matching considering multiple color attributes
int findMostPerceptuallyAccurateColor(vec3 color) {
int bestMatchIndex = 0;
float minDistance = perceptualColorDistance(color, ConsoleColorVec3[0]);
for (int i = 1; i < 16; i++) {
float currentDistance = perceptualColorDistance(color, ConsoleColorVec3[i]);
if (currentDistance < minDistance) {
minDistance = currentDistance;
bestMatchIndex = i;
}
}
return bestMatchIndex;
}
// Enhanced luminosity calculation considering human perception
float calculatePerceptualLuminance(vec3 color) {
// BT.709 luminance coefficients with slight adjustment
return pow(
0.2126 * pow(color.r, 2.2) +
0.7152 * pow(color.g, 2.2) +
0.0722 * pow(color.b, 2.2),
1.0 / 2.2
);
}
// Dithering function to reduce color banding
float interleavedGradientNoise(vec2 pixel) {
return fract(52.982919 * fract(0.06711056 * pixel.x + 0.00583715 * pixel.y));
}
uniform sampler2D uInputTexture;
layout (location = 0) in vec2 iUV;
layout (location = 0) out vec4 FragColor;
void main() {
vec3 pixelColor = texture(uInputTexture, iUV).rgb;
// Find most perceptually accurate console color
int colorIndex = findMostPerceptuallyAccurateColor(pixelColor);
// Calculate perceptual luminance with gamma correction
float luminance = calculatePerceptualLuminance(pixelColor);
// Output with high precision color mapping
FragColor = vec4(
luminance, // Red: Perceptual luminance
float(colorIndex) / 15.0, // Green: Normalized color index
0.0, // Blue: Unused
1.0 // Alpha
);
}