effects: Add RGB, HSV, and YUV conversion functions

This commit is contained in:
Michael Fabian 'Xaymar' Dirks 2021-02-02 22:22:47 +01:00
parent a027a57d09
commit 73f9257633
6 changed files with 113 additions and 83 deletions

View file

@ -967,7 +967,9 @@ list(APPEND PROJECT_PRIVATE_SOURCE
"source/obs/obs-tools.cpp" "source/obs/obs-tools.cpp"
) )
list(APPEND PROJECT_DATA list(APPEND PROJECT_DATA
"data/effects/color-conversion.effect" "data/effects/color_conversion_rgb_hsl.effect"
"data/effects/color_conversion_rgb_hsv.effect"
"data/effects/color_conversion_rgb_yuv.effect"
"data/effects/mipgen.effect" "data/effects/mipgen.effect"
"data/effects/pack-unpack.effect" "data/effects/pack-unpack.effect"
"data/effects/shared.effect" "data/effects/shared.effect"

View file

@ -1,81 +0,0 @@
uniform float4x4 ViewProj;
uniform texture2d image;
sampler_state primarySampler {
Filter = Linear;
AddressU = Clamp;
AddressV = Clamp;
};
struct VertDataIn {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
struct VertDataOut {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
VertDataOut VSDefault(VertDataIn v_in) {
VertDataOut vert_out;
vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj);
vert_out.uv = v_in.uv;
return vert_out;
}
// ************************************************************************** //
// RGB <-> YUV
// ************************************************************************** //
float4 RGBtoYUV(float4 rgba, float3x3 yuv) {
return float4(
rgba.r * yuv._m00 + rgba.g * yuv._m01 + rgba.b * yuv._m02,
rgba.r * yuv._m10 + rgba.g * yuv._m11 + rgba.b * yuv._m12,
rgba.r * yuv._m20 + rgba.g * yuv._m21 + rgba.b * yuv._m22,
rgba.a
) + float4(0,0.5,0.5,0);
}
float4 YUVtoRGB(float4 yuva, float3x3 yuvi) {
yuva.gb -= 0.5;
return float4(
yuva.r * yuvi._m00 + yuva.g * yuvi._m01 + yuva.b * yuvi._m02,
yuva.r * yuvi._m10 + yuva.g * yuvi._m11 + yuva.b * yuvi._m12,
yuva.r * yuvi._m20 + yuva.g * yuvi._m21 + yuva.b * yuvi._m22,
yuva.a);
}
float4 RGBToYUV_Pass(VertDataOut v_in) : TARGET {
const float3x3 mYUV709 = {
0.2126, 0.7152, 0.0722,
-0.2126, -0.7152, 0.9278,
0.7874, -0.7152, -0.0722
};
const float3x3 mYUV709n = { // Normalized
0.2126, 0.7152, 0.0722,
-0.1145721060573399, -0.3854278939426601, 0.5,
0.5, -0.4541529083058166, -0.0458470916941834
};
return RGBtoYUV(image.Sample(primarySampler, v_in.uv), mYUV709n);
}
float4 YUVToRGB_Pass(VertDataOut v_in) : TARGET {
const float3x3 mYUV709i = { // Inverse Normalized
1, 0, 1.5748,
1, -0.187324, -0.468124,
1, 1.8556, 0
};
return YUVtoRGB(image.Sample(primarySampler, v_in.uv), mYUV709i);
}
technique RGBToYUV {
pass {
vertex_shader = VSDefault(v_in);
pixel_shader = RGBToYUV_Pass(v_in);
}
}
technique YUVToRGB {
pass {
vertex_shader = VSDefault(v_in);
pixel_shader = YUVToRGB_Pass(v_in);
}
}

View file

@ -0,0 +1,56 @@
// This may have odd/incorrect results.
float3 RGBtoHSL(float3 rgb) {
float h = 0.0;
float s = 0.0;
float l = 0.0;
float r = rgb.r;
float g = rgb.g;
float b = rgb.b;
float cMin = min( r, min( g, b ) );
float cMax = max( r, max( g, b ) );
l = ( cMax + cMin ) / 2.0;
if ( cMax > cMin ) {
float cDelta = cMax - cMin;
//s = l < .05 ? cDelta / ( cMax + cMin ) : cDelta / ( 2.0 - ( cMax + cMin ) ); Original
s = l < .0 ? cDelta / ( cMax + cMin ) : cDelta / ( 2.0 - ( cMax + cMin ) );
if ( r == cMax ) {
h = ( g - b ) / cDelta;
} else if ( g == cMax ) {
h = 2.0 + ( b - r ) / cDelta;
} else {
h = 4.0 + ( r - g ) / cDelta;
}
if ( h < 0.0) {
h += 6.0;
}
h = h / 6.0;
}
return float3( h, s, l );
}
float4 RGBAtoHSLA(float4 rgba) {
return float4(RGBtoHSL(rgba.rgb), rgba.a);
}
float3 HSLtoRGB(float3 hsl) {
float3 rgb = clamp(
abs(
fmod(
hsl.x * 6.0 + float3(0.0, 4.0, 2.0),
6.0
) - 3.0
) - 1.0,
0.0,
1.0
);
return hsl.z + hsl.y * (rgb - 0.5) * (1.0 - abs(2.0 * hsl.z - 1.0));
};
float4 HSLAtoRGBA(float4 hsla) {
return float4(HSLtoRGB(hsla.rgb), hsla.a);
}

View file

@ -0,0 +1,32 @@
// Adapted from http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl
//#define RGB_HSV_FASTCONDITIONALMOVE
float3 RGBtoHSV(float3 rgb) {
const float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
const float e = 1.0e-10;
#ifdef RGB_HSV_FASTCONDITIONALMOVE
float4 p = rgb.g < rgb.b ? float4(rgb.bg, K.wz) : float4(rgb.gb, K.xy);
float4 q = rgb.r < p.x ? float4(p.xyw, rgb.r) : float4(rgb.r, p.yzx);
#else
float4 p = lerp(float4(rgb.bg, K.wz), float4(rgb.gb, K.xy), step(rgb.b, rgb.g));
float4 q = lerp(float4(p.xyw, rgb.r), float4(rgb.r, p.yzx), step(p.x, rgb.r));
#endif
float d = q.x - min(q.w, q.y);
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
float4 RGBAtoHSVA(float4 rgba) {
return float4(RGBtoHSV(rgba.rgb), rgba.a);
}
float3 HSVtoRGB(float3 hsv) {
const float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
float3 v = float3(0,0,0);
v.rgb = hsv.z * lerp(K.xxx, clamp(abs(frac(hsv.xxx + K.xyz) * 6.0 - K.www) - K.xxx, 0.0, 1.0), hsv.y);
return v;
}
float4 HSVAtoRGBA(float4 hsva) {
return float4(HSVtoRGB(hsv.rgb), hsva.a);
}

View file

@ -0,0 +1,19 @@
#define YUV_709_ float3x3(0.2126, 0.7152, 0.0722, -0.2126, -0.7152, 0.9278, 0.7874, -0.7152, -0.0722)
#define YUV_709_NORM float3x3(0.2126, 0.7152, 0.0722, -0.1145721060573399, -0.3854278939426601, 0.5, 0.5, -0.4541529083058166, -0.0458470916941834)
#define YUV_709_INVNORM float3x3(1, 0, 1.5748, 1, -0.187324, -0.468124, 1, 1.8556, 0)
float3 RGBtoYUV(float3 rgb, float3x3 m) {
return mul(m, rgb) + float3(0, .5, .5);
}
float4 RGBAtoYUVA(float4 rgba, float3x3 m) {
return float4(RGBtoYUV(rgba.rgb, m), rgba.a);
}
float3 YUVtoRGB(float3 yuv, float3x3 m) {
return mul(m, yuv - float3(0, .5, .5));
}
float4 YUVAtoRGBA(float4 yuva, float3x3 m) {
return float4(YUVtoRGB(yuva.rgb, m), yuva.a);
}

View file

@ -51,4 +51,6 @@ VertexData DefaultVertexShader(VertexData vtx) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Color Conversion // Color Conversion
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#include "color_conversion_rgb_yuv.effect"
#include "color_conversion_rgb_hsv.effect"
#include "color_conversion_rgb_hsl.effect"