浏览代码

libobs: Add optional ultrawide -> wide scaling techniques

This algorithm reduces scaling distortion on the center of the image
when scaling from ultrawide to wide.

(Jim: edited effect files to prevent an impact in performance for
standard scaling.  Now effectively generates an extra pixel shader, and
the extra code is only applied to the DrawUndistort technique, while the
original Draw technique is unaffected due to the compiler automatically
removing unused code branches via the hard-coded boolean value)

From jp9000/obs-studio#762
Take Vos 8 年之前
父节点
当前提交
ab3531caa9
共有 2 个文件被更改,包括 96 次插入36 次删除
  1. 46 16
      libobs/data/bicubic_scale.effect
  2. 50 20
      libobs/data/lanczos_scale.effect

+ 46 - 16
libobs/data/bicubic_scale.effect

@@ -10,6 +10,7 @@ uniform float4x4 color_matrix;
 uniform float3 color_range_min = {0.0, 0.0, 0.0};
 uniform float3 color_range_min = {0.0, 0.0, 0.0};
 uniform float3 color_range_max = {1.0, 1.0, 1.0};
 uniform float3 color_range_max = {1.0, 1.0, 1.0};
 uniform float2 base_dimension_i;
 uniform float2 base_dimension_i;
+uniform float undistort_factor = 1.0;
 
 
 sampler_state textureSampler {
 sampler_state textureSampler {
 	Filter    = Linear;
 	Filter    = Linear;
@@ -63,21 +64,41 @@ float4 weight4(float x)
 		weight(x + 1.0));
 		weight(x + 1.0));
 }
 }
 
 
-float4 pixel(float xpos, float ypos)
+float AspectUndistortX(float x, float a)
 {
 {
-	return image.Sample(textureSampler, float2(xpos, ypos));
+	// The higher the power, the longer the linear part will be.
+	return (1.0 - a) * (x * x * x * x * x) + a * x;
 }
 }
 
 
-float4 get_line(float ypos, float4 xpos, float4 linetaps)
+float AspectUndistortU(float u)
+{
+	// Normalize texture coord to -1.0 to 1.0 range, and back.
+	return AspectUndistortX((u - 0.5) * 2.0, undistort_factor) * 0.5 + 0.5;
+}
+
+float2 pixel_coord(float xpos, float ypos)
+{
+	return float2(AspectUndistortU(xpos), ypos);
+}
+
+float4 pixel(float xpos, float ypos, bool undistort)
+{
+	if (undistort)
+		return image.Sample(textureSampler, pixel_coord(xpos, ypos));
+	else
+		return image.Sample(textureSampler, float2(xpos, ypos));
+}
+
+float4 get_line(float ypos, float4 xpos, float4 linetaps, bool undistort)
 {
 {
 	return
 	return
-		pixel(xpos.r, ypos) * linetaps.r +
-		pixel(xpos.g, ypos) * linetaps.g +
-		pixel(xpos.b, ypos) * linetaps.b +
-		pixel(xpos.a, ypos) * linetaps.a;
+		pixel(xpos.r, ypos, undistort) * linetaps.r +
+		pixel(xpos.g, ypos, undistort) * linetaps.g +
+		pixel(xpos.b, ypos, undistort) * linetaps.b +
+		pixel(xpos.a, ypos, undistort) * linetaps.a;
 }
 }
 
 
-float4 DrawBicubic(VertData v_in)
+float4 DrawBicubic(VertData v_in, bool undistort)
 {
 {
 	float2 stepxy = base_dimension_i;
 	float2 stepxy = base_dimension_i;
 	float2 pos = v_in.uv + stepxy * 0.5;
 	float2 pos = v_in.uv + stepxy * 0.5;
@@ -100,20 +121,20 @@ float4 DrawBicubic(VertData v_in)
 	);
 	);
 
 
 	return
 	return
-		get_line(xystart.y                 , xpos, rowtaps) * coltaps.r +
-		get_line(xystart.y + stepxy.y      , xpos, rowtaps) * coltaps.g +
-		get_line(xystart.y + stepxy.y * 2.0, xpos, rowtaps) * coltaps.b +
-		get_line(xystart.y + stepxy.y * 3.0, xpos, rowtaps) * coltaps.a;
+		get_line(xystart.y                 , xpos, rowtaps, undistort) * coltaps.r +
+		get_line(xystart.y + stepxy.y      , xpos, rowtaps, undistort) * coltaps.g +
+		get_line(xystart.y + stepxy.y * 2.0, xpos, rowtaps, undistort) * coltaps.b +
+		get_line(xystart.y + stepxy.y * 3.0, xpos, rowtaps, undistort) * coltaps.a;
 }
 }
 
 
-float4 PSDrawBicubicRGBA(VertData v_in) : TARGET
+float4 PSDrawBicubicRGBA(VertData v_in, bool undistort) : TARGET
 {
 {
-	return DrawBicubic(v_in);
+	return DrawBicubic(v_in, undistort);
 }
 }
 
 
 float4 PSDrawBicubicMatrix(VertData v_in) : TARGET
 float4 PSDrawBicubicMatrix(VertData v_in) : TARGET
 {
 {
-	float4 rgba = DrawBicubic(v_in);
+	float4 rgba = DrawBicubic(v_in, false);
 	float4 yuv;
 	float4 yuv;
 
 
 	yuv.xyz = clamp(rgba.xyz, color_range_min, color_range_max);
 	yuv.xyz = clamp(rgba.xyz, color_range_min, color_range_max);
@@ -125,7 +146,16 @@ technique Draw
 	pass
 	pass
 	{
 	{
 		vertex_shader = VSDefault(v_in);
 		vertex_shader = VSDefault(v_in);
-		pixel_shader  = PSDrawBicubicRGBA(v_in);
+		pixel_shader  = PSDrawBicubicRGBA(v_in, false);
+	}
+}
+
+technique DrawUndistort
+{
+	pass
+	{
+		vertex_shader = VSDefault(v_in);
+		pixel_shader  = PSDrawBicubicRGBA(v_in, true);
 	}
 	}
 }
 }
 
 

+ 50 - 20
libobs/data/lanczos_scale.effect

@@ -10,6 +10,7 @@ uniform float4x4 color_matrix;
 uniform float3 color_range_min = {0.0, 0.0, 0.0};
 uniform float3 color_range_min = {0.0, 0.0, 0.0};
 uniform float3 color_range_max = {1.0, 1.0, 1.0};
 uniform float3 color_range_max = {1.0, 1.0, 1.0};
 uniform float2 base_dimension_i;
 uniform float2 base_dimension_i;
+uniform float undistort_factor = 1.0;
 
 
 sampler_state textureSampler
 sampler_state textureSampler
 {
 {
@@ -64,24 +65,44 @@ float3 weight3(float x, float scale)
 		weight((x * 2.0 + 2.0 * 2.0 - 3.0) * scale, 3.0));
 		weight((x * 2.0 + 2.0 * 2.0 - 3.0) * scale, 3.0));
 }
 }
 
 
-float4 pixel(float xpos, float ypos)
+float AspectUndistortX(float x, float a)
 {
 {
-	return image.Sample(textureSampler, float2(xpos, ypos));
+	// The higher the power, the longer the linear part will be.
+	return (1.0 - a) * (x * x * x * x * x) + a * x;
+}
+
+float AspectUndistortU(float u)
+{
+	// Normalize texture coord to -1.0 to 1.0 range, and back.
+	return AspectUndistortX((u - 0.5) * 2.0, undistort_factor) * 0.5 + 0.5;
+}
+
+float2 pixel_coord(float xpos, float ypos)
+{
+	return float2(AspectUndistortU(xpos), ypos);
+}
+
+float4 pixel(float xpos, float ypos, bool undistort)
+{
+	if (undistort)
+		return image.Sample(textureSampler, pixel_coord(xpos, ypos));
+	else
+		return image.Sample(textureSampler, float2(xpos, ypos));
 }
 }
 
 
 float4 get_line(float ypos, float3 xpos1, float3 xpos2, float3 rowtap1,
 float4 get_line(float ypos, float3 xpos1, float3 xpos2, float3 rowtap1,
-		float3 rowtap2)
+		float3 rowtap2, bool undistort)
 {
 {
 	return
 	return
-		pixel(xpos1.r, ypos) * rowtap1.r +
-		pixel(xpos1.g, ypos) * rowtap2.r +
-		pixel(xpos1.b, ypos) * rowtap1.g +
-		pixel(xpos2.r, ypos) * rowtap2.g +
-		pixel(xpos2.g, ypos) * rowtap1.b +
-		pixel(xpos2.b, ypos) * rowtap2.b;
+		pixel(xpos1.r, ypos, undistort) * rowtap1.r +
+		pixel(xpos1.g, ypos, undistort) * rowtap2.r +
+		pixel(xpos1.b, ypos, undistort) * rowtap1.g +
+		pixel(xpos2.r, ypos, undistort) * rowtap2.g +
+		pixel(xpos2.g, ypos, undistort) * rowtap1.b +
+		pixel(xpos2.b, ypos, undistort) * rowtap2.b;
 }
 }
 
 
-float4 DrawLanczos(FragData v_in)
+float4 DrawLanczos(FragData v_in, bool undistort)
 {
 {
 	float2 stepxy = base_dimension_i;
 	float2 stepxy = base_dimension_i;
 	float2 pos = v_in.uv + stepxy * 0.5;
 	float2 pos = v_in.uv + stepxy * 0.5;
@@ -106,22 +127,22 @@ float4 DrawLanczos(FragData v_in)
 	float3 xpos2 = float3(xystart.x + stepxy.x * 3.0, xystart.x + stepxy.x * 4.0, xystart.x + stepxy.x * 5.0);
 	float3 xpos2 = float3(xystart.x + stepxy.x * 3.0, xystart.x + stepxy.x * 4.0, xystart.x + stepxy.x * 5.0);
 
 
 	return
 	return
-		get_line(xystart.y                 , xpos1, xpos2, rowtap1, rowtap2) * coltap1.r +
-		get_line(xystart.y + stepxy.y      , xpos1, xpos2, rowtap1, rowtap2) * coltap2.r +
-		get_line(xystart.y + stepxy.y * 2.0, xpos1, xpos2, rowtap1, rowtap2) * coltap1.g +
-		get_line(xystart.y + stepxy.y * 3.0, xpos1, xpos2, rowtap1, rowtap2) * coltap2.g +
-		get_line(xystart.y + stepxy.y * 4.0, xpos1, xpos2, rowtap1, rowtap2) * coltap1.b +
-		get_line(xystart.y + stepxy.y * 5.0, xpos1, xpos2, rowtap1, rowtap2) * coltap2.b;
+		get_line(xystart.y                 , xpos1, xpos2, rowtap1, rowtap2, undistort) * coltap1.r +
+		get_line(xystart.y + stepxy.y      , xpos1, xpos2, rowtap1, rowtap2, undistort) * coltap2.r +
+		get_line(xystart.y + stepxy.y * 2.0, xpos1, xpos2, rowtap1, rowtap2, undistort) * coltap1.g +
+		get_line(xystart.y + stepxy.y * 3.0, xpos1, xpos2, rowtap1, rowtap2, undistort) * coltap2.g +
+		get_line(xystart.y + stepxy.y * 4.0, xpos1, xpos2, rowtap1, rowtap2, undistort) * coltap1.b +
+		get_line(xystart.y + stepxy.y * 5.0, xpos1, xpos2, rowtap1, rowtap2, undistort) * coltap2.b;
 }
 }
 
 
-float4 PSDrawLanczosRGBA(FragData v_in) : TARGET
+float4 PSDrawLanczosRGBA(FragData v_in, bool undistort) : TARGET
 {
 {
-	return DrawLanczos(v_in);
+	return DrawLanczos(v_in, undistort);
 }
 }
 
 
 float4 PSDrawLanczosMatrix(FragData v_in) : TARGET
 float4 PSDrawLanczosMatrix(FragData v_in) : TARGET
 {
 {
-	float4 rgba = DrawLanczos(v_in);
+	float4 rgba = DrawLanczos(v_in, false);
 	float4 yuv;
 	float4 yuv;
 
 
 	yuv.xyz = clamp(rgba.xyz, color_range_min, color_range_max);
 	yuv.xyz = clamp(rgba.xyz, color_range_min, color_range_max);
@@ -133,7 +154,16 @@ technique Draw
 	pass
 	pass
 	{
 	{
 		vertex_shader = VSDefault(v_in);
 		vertex_shader = VSDefault(v_in);
-		pixel_shader  = PSDrawLanczosRGBA(v_in);
+		pixel_shader  = PSDrawLanczosRGBA(v_in, false);
+	}
+}
+
+technique DrawUndistort
+{
+	pass
+	{
+		vertex_shader = VSDefault(v_in);
+		pixel_shader  = PSDrawLanczosRGBA(v_in, true);
 	}
 	}
 }
 }