mirror of
https://github.com/Xaymar/obs-StreamFX
synced 2024-12-28 18:41:14 +00:00
effects: Add RGB, HSV, and YUV conversion functions
This commit is contained in:
parent
a027a57d09
commit
73f9257633
6 changed files with 113 additions and 83 deletions
|
@ -967,7 +967,9 @@ list(APPEND PROJECT_PRIVATE_SOURCE
|
|||
"source/obs/obs-tools.cpp"
|
||||
)
|
||||
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/pack-unpack.effect"
|
||||
"data/effects/shared.effect"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
56
data/effects/color_conversion_rgb_hsl.effect
Normal file
56
data/effects/color_conversion_rgb_hsl.effect
Normal 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);
|
||||
}
|
32
data/effects/color_conversion_rgb_hsv.effect
Normal file
32
data/effects/color_conversion_rgb_hsv.effect
Normal 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);
|
||||
}
|
19
data/effects/color_conversion_rgb_yuv.effect
Normal file
19
data/effects/color_conversion_rgb_yuv.effect
Normal 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);
|
||||
}
|
|
@ -51,4 +51,6 @@ VertexData DefaultVertexShader(VertexData vtx) {
|
|||
//------------------------------------------------------------------------------
|
||||
// Color Conversion
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "color_conversion_rgb_yuv.effect"
|
||||
#include "color_conversion_rgb_hsv.effect"
|
||||
#include "color_conversion_rgb_hsl.effect"
|
||||
|
|
Loading…
Reference in a new issue