Shiandow
4th June 2014, 16:13
This post was written after I succeeded in implementing the NEDI algorithm (the one by Xin Li et al. not the nnedi3 algorithm by tritical) using shaders. I've since tried to write upscaling algorithms using variations on NEDI and other methods. The results of which can be found below.
NEDI:
For a short explanation of the NEDI algorithm see: http://chiranjivi.tripod.com/EDITut.html
NEDI's picture quality tends to be better than that of linear scaling algorithms (like Lanczos, Jinc, etc.) and in some cases beats nnedi3. It's especially good at scaling the image without aliasing. Development of this method has more or less finished, or otherwise superseded by SuperRes which uses NEDI as part of it's process.
Here is a quick comparison (these results are no longer up to date):
Nearest (http://imgur.com/BCEfaHn.jpg)
Jinc3 (http://i.imgur.com/JP3R1eZ.jpg)
nnedi3 (32 neurons) (http://i.imgur.com/gnG1WQN.jpg)
NEDI (http://i.imgur.com/NtovKwF.jpg)
The easiest way to try NEDI is to use MPDN (http://forum.doom9.org/showthread.php?t=171120)'s render script capabilities. For details on how to use renderscripts see here (http://forum.doom9.org/showthread.php?t=171120).
To use the NEDI shaders for 2x upscaling with MadVR you should set MadVR to output YCbCr, by adding an empty file called "YCbCr" in the MadVR folder (or use the RGBtoYCbCr shader), and set MadVR to use a Nearest filter for luma upscaling (using NNEDI3 will also work but is obviously slower, using any other algorithm will give incorrect results). Also make sure that you're resizing the video exactly 2x, if this doesn't fit your screen you can usually force the video player to scale 2x anyway. You should then use the NEDI-I and NEDI-II shaders (in that order) post resize, and then you need to convert the result back to RGB. For Rec. 709 media this can be done by using the YCbCrtoRGB shader, unfortunately it probably won't work for all video types.
ChromaNEDI:
ChromaNEDI is a way of using NEDI to upscale chroma using information from the luma channels.
This project has largely been abandoned after I found out that this method causes a lot of chroma bleeding. I have been able to solve this, partially, by performing the scaling in linear light but this makes the NEDI artefacts (too) visible.
Anway, the chromaNEDI shaders can be used for chroma upscaling, currently this only works for 4:2:0 subsampled video but that seems to be 99.9% of all video. The way to use these shaders with MadVR is similar to how you use the NEDI shaders but should be used pre resize instead of post resize and you should set chroma upscaling to Nearest instead of luma upscaling. It consists of three different shaders (chromaNEDI-I up to chromaNEDI-III), which must all be used in order. The first two shaders work similarly to the two passes of the NEDI algorithm, the third one is necessary to align the chroma channels with the luma channel.
The chromaNEDI shaders also have support for several different chroma patterns, you can switch between these by changing the line "#define pattern x" where x should be 1,2,3 depending on which pattern you want. Make sure that you pick the same pattern for all shaders.
Short explanation:
pattern 1 (https://upload.wikimedia.org/wikipedia/commons/thumb/5/5d/Yuvformats420samplingMPEG-2.svg/500px-Yuvformats420samplingMPEG-2.svg.png): this is most common for modern codecs.
pattern 2 (https://upload.wikimedia.org/wikipedia/commons/thumb/1/11/Yuvformats420sampling.svg/500px-Yuvformats420sampling.svg.png): used by mpeg-2, seems to be common for older codecs.
pattern 3 (https://upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Yuvformats422sampling.svg/500px-Yuvformats422sampling.svg.png): not used much but is useful for chroma-doubling (shaders should be used post-resize in that case and luma upscaling should be put to nearest. Only works for 2x resizing). You can skip the third shader when using this pattern.
SuperRes:
The SuperRes shaders use a different scaling method which can be used in combination with NEDI (or any other scaling algorithm). This method is explained in detail here (http://forum.doom9.org/showthread.php?p=1685124#post1685124). This method seems to give better results than just using NEDI, and rival those of NNEDI3. These are now also available as an MPDN renderscript.
SuperChromaRes:
With techniques similar to those of SuperRes it's also possible to do chroma scaling. One major advantage is that this makes it possible to do chroma scaling in linear light, which would normally be impossible. This can improve image quality greatly for images consisting of saturated colours (especially red) on a white background. This is also available as an MPDN renderscript, but I've also decided to make the original experimental shaders available to make it possible to try it out with other renderers. Be warned that support for these experimental shaders will be minimal, I will not be backporting all the improvements made in the renderscript, nor will I explain all the options, they also have some of the same issues as ChromaNEDI but will generally work well for HD sources.
Downloads:
SuperRes shader pack (includes NEDI) (http://www.mediafire.com/download/22o6ahnchkbzhef/Shaders.rar)
ChromaNEDI shader pack (Includes RGB <-> YCbCr conversion shaders) (http://www.mediafire.com/download/86bo6bl66cnwv2j/chromaNEDI.rar)
Experimental SuperChromaRes shaders (Includes a short manual) (http://www.mediafire.com/download/1fnutv48bb3k71k/SuperChromaRes.rar)
More information on using MPDN and renderscripts:
http://forum.doom9.org/showthread.php?t=171120
Code of the NEDI shaders:
NEDI-I:
sampler s0 : register(s0);
float4 p0 : register(c0);
#define width (p0[0])
#define height (p0[1])
#define px (1.0 / (p0[0]))
#define py (1.0 / (p0[1]))
#define offset 0.5
#define Value(xy) (tex2D(s0,tex+float2(px,py)*(xy)))//-float4(0,0.5,0.5,0))
#define Get(xy) (Value(xy)[0]+offset)
#define Get4(xy) (float2(Get(xy+2*dir[0])+Get(xy+2*dir[1]),Get(xy+2*dir[2])+Get(xy+2*dir[3])))
#define sqr(x) (dot(x,x))
#define I (float2x2(1,0,0,1))
//Conjugate residual
float2 solve(float2x2 A,float2 b) {
float2 x = 1/4.0;
float2 r = b - mul(A,x);
float2 p = r;
float2 Ar = mul(A,r);
float2 Ap = Ar;
for (int k = 0;k < 2; k++){
float a = min(100,dot(r,Ar)/dot(Ap,Ap));
x = x + a*p;
float2 rk = r; float2 Ark = Ar;
r = r - a*Ap;
Ar = mul(A,r);
float b = dot(r,Ar)/dot(rk,Ark);
p = r + b*p;
Ap = Ar + b*Ap;
}
return x;
}
//Cramer's method
float2 solvex(float2x2 A,float2 b) { return float2(determinant(float2x2(b,A[1])),determinant(float2x2(A[0],b)))/determinant(A); }
float4 main(float2 tex : TEXCOORD0) : COLOR {
float4 c0 = tex2D(s0,tex);
//Skip pixels on wrong grid
if ((frac(tex.x*width/2.0)<0.5)||(frac(tex.y*height/2.0)<0.5)) return c0;
//Define window and directions
float2 dir[4] = {{-1,-1},{1,1},{-1,1},{1,-1}};
float4x2 wind[4] = {{{-1,-1},{-1,1},{1,-1},{1,1}},{{-3,-1},{-1,3},{1,-3},{3,1}},{{-1,-3},{-3,1},{3,-1},{1,3}},{{-3,-3},{-3,3},{3,-3},{3,3}}};
//Initialization
float2x2 R = 0;
float2 r = 0;
float4 d = 0;
//Define weights
float4 lancz = {0.328511,-0.0365013,-0.0365013,0.0040557};
lancz /= dot(lancz,4);
float4 w = {1,1,1,0};
//Calculate (local) autocorrelation coefficients
for (int k = 0; k<4; k+= 1){
float4 y = float4(Get(wind[k][0]),Get(wind[k][1]),Get(wind[k][2]),Get(wind[k][3]));
float4x2 C = float4x2(Get4(wind[k][0]),Get4(wind[k][1]),Get4(wind[k][2]),Get4(wind[k][3]));
R += w[k]*mul(transpose(C),C);
r += w[k]*mul(y,C);
d += lancz[k]*(Value(wind[k][0])+Value(wind[k][1])+Value(wind[k][2])+Value(wind[k][3]));
}
//Normalize
float n = 24;
R /= n; r /= n;
//Calculate a = R^-1 . r
float e = 0.005;
float2 a = solve(R+e*e*I,r+e*e/2.0);
//Nomalize 'a' (prevents overshoot)
a = .25 + float2(.5,-.5)*clamp(a[0]-a[1],-1,1);
//Calculate result
float2x4 x = float2x4(Value(dir[0])+Value(dir[1]),Value(dir[2])+Value(dir[3]));
float4 c = mul(float1x2(a),x);
//Fallback to lanczos
float t = saturate(1-500*sqr(x[0]-x[1]));
c += t*(d-mul(float1x2(1,1)/4.0,x));
return c;//+float4(0,0.5,0.5,0);
}
NEDI-II:
sampler s0 : register(s0);
float4 p0 : register(c0);
#define width (p0[0])
#define height (p0[1])
#define px (1.0 / (p0[0]))
#define py (1.0 / (p0[1]))
#define offset 0.5
#define Value(xy) (tex2D(s0,tex+float2(px,py)*(xy)))//-float4(0,0.5,0.5,0))
#define Get(xy) (Value(xy)[0]+offset)
#define Get4(xy) (float2(Get(xy+2*dir[0])+Get(xy+2*dir[1]),Get(xy+2*dir[2])+Get(xy+2*dir[3])))
#define sqr(x) (dot(x,x))
#define I (float2x2(1,0,0,1))
//Conjugate residual
float2 solve(float2x2 A,float2 b) {
float2 x = 1/4.0;
float2 r = b - mul(A,x);
float2 p = r;
float2 Ar = mul(A,r);
float2 Ap = Ar;
for (int k = 0;k < 2; k++){
float a = min(100,dot(r,Ar)/dot(Ap,Ap));
x = x + a*p;
float2 rk = r; float2 Ark = Ar;
r = r - a*Ap;
Ar = mul(A,r);
float b = dot(r,Ar)/dot(rk,Ark);
p = r + b*p;
Ap = Ar + b*Ap;
}
return x;
}
//Cramer's method
float2 solvex(float2x2 A,float2 b) { return float2(determinant(float2x2(b,A[1])),determinant(float2x2(A[0],b)))/determinant(A); }
float4 main(float2 tex : TEXCOORD0) : COLOR {
float4 c0 = tex2D(s0,tex);
//Skip pixels on wrong grid
if ((frac(tex.x*width/2.0)<0.5)&&(frac(tex.y*height/2.0)<0.5)) return c0;
if ((frac(tex.x*width/2.0)>0.5)&&(frac(tex.y*height/2.0)>0.5)) return c0;
//Define window and directions
float2 dir[4] = {{-1,0},{1,0},{0,1},{0,-1}};
float4x2 wind[4] = {{{-1,0},{1,0},{0,1},{0,-1}},{{-1,2},{1,-2},{2,1},{-2,-1}},{{-1,-2},{1,2},{-2,1},{2,-1}},{{-3,0},{3,0},{0,3},{0,-3}}};
//Initialization
float2x2 R = 0;
float2 r = 0;
float4 d = 0;
//Define weights
float4 lancz = {0.328511,-0.0365013,-0.0365013,0.0040557};
lancz /= dot(lancz,4);
float4 w = {1,1,1,0};
//Calculate (local) autocorrelation coefficients
for (int k = 0; k<4; k+= 1){
float4 y = float4(Get(wind[k][0]),Get(wind[k][1]),Get(wind[k][2]),Get(wind[k][3]));
float4x2 C = float4x2(Get4(wind[k][0]),Get4(wind[k][1]),Get4(wind[k][2]),Get4(wind[k][3]));
R += w[k]*mul(transpose(C),C);
r += w[k]*mul(y,C);
d += lancz[k]*(Value(wind[k][0])+Value(wind[k][1])+Value(wind[k][2])+Value(wind[k][3]));
}
//Normalize
float n = 24;
R /= n; r /= n;
//Calculate a = R^-1 . r
float e = 0.005;
float2 a = solve(R+e*e*I,r+e*e/2.0);
//Nomalize 'a' (prevents overshoot)
a = .25 + float2(.5,-.5)*clamp(a[0]-a[1],-1,1);
//Calculate result
float2x4 x = float2x4(Value(dir[0])+Value(dir[1]),Value(dir[2])+Value(dir[3]));
float4 c = mul(float1x2(a),x);
//Fallback to lanczos
float t = saturate(1-500*sqr(x[0]-x[1]));
c += t*(d-mul(float1x2(1,1)/4.0,x));
return c;//+float4(0,0.5,0.5,0);
}
NEDI:
For a short explanation of the NEDI algorithm see: http://chiranjivi.tripod.com/EDITut.html
NEDI's picture quality tends to be better than that of linear scaling algorithms (like Lanczos, Jinc, etc.) and in some cases beats nnedi3. It's especially good at scaling the image without aliasing. Development of this method has more or less finished, or otherwise superseded by SuperRes which uses NEDI as part of it's process.
Here is a quick comparison (these results are no longer up to date):
Nearest (http://imgur.com/BCEfaHn.jpg)
Jinc3 (http://i.imgur.com/JP3R1eZ.jpg)
nnedi3 (32 neurons) (http://i.imgur.com/gnG1WQN.jpg)
NEDI (http://i.imgur.com/NtovKwF.jpg)
The easiest way to try NEDI is to use MPDN (http://forum.doom9.org/showthread.php?t=171120)'s render script capabilities. For details on how to use renderscripts see here (http://forum.doom9.org/showthread.php?t=171120).
To use the NEDI shaders for 2x upscaling with MadVR you should set MadVR to output YCbCr, by adding an empty file called "YCbCr" in the MadVR folder (or use the RGBtoYCbCr shader), and set MadVR to use a Nearest filter for luma upscaling (using NNEDI3 will also work but is obviously slower, using any other algorithm will give incorrect results). Also make sure that you're resizing the video exactly 2x, if this doesn't fit your screen you can usually force the video player to scale 2x anyway. You should then use the NEDI-I and NEDI-II shaders (in that order) post resize, and then you need to convert the result back to RGB. For Rec. 709 media this can be done by using the YCbCrtoRGB shader, unfortunately it probably won't work for all video types.
ChromaNEDI:
ChromaNEDI is a way of using NEDI to upscale chroma using information from the luma channels.
This project has largely been abandoned after I found out that this method causes a lot of chroma bleeding. I have been able to solve this, partially, by performing the scaling in linear light but this makes the NEDI artefacts (too) visible.
Anway, the chromaNEDI shaders can be used for chroma upscaling, currently this only works for 4:2:0 subsampled video but that seems to be 99.9% of all video. The way to use these shaders with MadVR is similar to how you use the NEDI shaders but should be used pre resize instead of post resize and you should set chroma upscaling to Nearest instead of luma upscaling. It consists of three different shaders (chromaNEDI-I up to chromaNEDI-III), which must all be used in order. The first two shaders work similarly to the two passes of the NEDI algorithm, the third one is necessary to align the chroma channels with the luma channel.
The chromaNEDI shaders also have support for several different chroma patterns, you can switch between these by changing the line "#define pattern x" where x should be 1,2,3 depending on which pattern you want. Make sure that you pick the same pattern for all shaders.
Short explanation:
pattern 1 (https://upload.wikimedia.org/wikipedia/commons/thumb/5/5d/Yuvformats420samplingMPEG-2.svg/500px-Yuvformats420samplingMPEG-2.svg.png): this is most common for modern codecs.
pattern 2 (https://upload.wikimedia.org/wikipedia/commons/thumb/1/11/Yuvformats420sampling.svg/500px-Yuvformats420sampling.svg.png): used by mpeg-2, seems to be common for older codecs.
pattern 3 (https://upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Yuvformats422sampling.svg/500px-Yuvformats422sampling.svg.png): not used much but is useful for chroma-doubling (shaders should be used post-resize in that case and luma upscaling should be put to nearest. Only works for 2x resizing). You can skip the third shader when using this pattern.
SuperRes:
The SuperRes shaders use a different scaling method which can be used in combination with NEDI (or any other scaling algorithm). This method is explained in detail here (http://forum.doom9.org/showthread.php?p=1685124#post1685124). This method seems to give better results than just using NEDI, and rival those of NNEDI3. These are now also available as an MPDN renderscript.
SuperChromaRes:
With techniques similar to those of SuperRes it's also possible to do chroma scaling. One major advantage is that this makes it possible to do chroma scaling in linear light, which would normally be impossible. This can improve image quality greatly for images consisting of saturated colours (especially red) on a white background. This is also available as an MPDN renderscript, but I've also decided to make the original experimental shaders available to make it possible to try it out with other renderers. Be warned that support for these experimental shaders will be minimal, I will not be backporting all the improvements made in the renderscript, nor will I explain all the options, they also have some of the same issues as ChromaNEDI but will generally work well for HD sources.
Downloads:
SuperRes shader pack (includes NEDI) (http://www.mediafire.com/download/22o6ahnchkbzhef/Shaders.rar)
ChromaNEDI shader pack (Includes RGB <-> YCbCr conversion shaders) (http://www.mediafire.com/download/86bo6bl66cnwv2j/chromaNEDI.rar)
Experimental SuperChromaRes shaders (Includes a short manual) (http://www.mediafire.com/download/1fnutv48bb3k71k/SuperChromaRes.rar)
More information on using MPDN and renderscripts:
http://forum.doom9.org/showthread.php?t=171120
Code of the NEDI shaders:
NEDI-I:
sampler s0 : register(s0);
float4 p0 : register(c0);
#define width (p0[0])
#define height (p0[1])
#define px (1.0 / (p0[0]))
#define py (1.0 / (p0[1]))
#define offset 0.5
#define Value(xy) (tex2D(s0,tex+float2(px,py)*(xy)))//-float4(0,0.5,0.5,0))
#define Get(xy) (Value(xy)[0]+offset)
#define Get4(xy) (float2(Get(xy+2*dir[0])+Get(xy+2*dir[1]),Get(xy+2*dir[2])+Get(xy+2*dir[3])))
#define sqr(x) (dot(x,x))
#define I (float2x2(1,0,0,1))
//Conjugate residual
float2 solve(float2x2 A,float2 b) {
float2 x = 1/4.0;
float2 r = b - mul(A,x);
float2 p = r;
float2 Ar = mul(A,r);
float2 Ap = Ar;
for (int k = 0;k < 2; k++){
float a = min(100,dot(r,Ar)/dot(Ap,Ap));
x = x + a*p;
float2 rk = r; float2 Ark = Ar;
r = r - a*Ap;
Ar = mul(A,r);
float b = dot(r,Ar)/dot(rk,Ark);
p = r + b*p;
Ap = Ar + b*Ap;
}
return x;
}
//Cramer's method
float2 solvex(float2x2 A,float2 b) { return float2(determinant(float2x2(b,A[1])),determinant(float2x2(A[0],b)))/determinant(A); }
float4 main(float2 tex : TEXCOORD0) : COLOR {
float4 c0 = tex2D(s0,tex);
//Skip pixels on wrong grid
if ((frac(tex.x*width/2.0)<0.5)||(frac(tex.y*height/2.0)<0.5)) return c0;
//Define window and directions
float2 dir[4] = {{-1,-1},{1,1},{-1,1},{1,-1}};
float4x2 wind[4] = {{{-1,-1},{-1,1},{1,-1},{1,1}},{{-3,-1},{-1,3},{1,-3},{3,1}},{{-1,-3},{-3,1},{3,-1},{1,3}},{{-3,-3},{-3,3},{3,-3},{3,3}}};
//Initialization
float2x2 R = 0;
float2 r = 0;
float4 d = 0;
//Define weights
float4 lancz = {0.328511,-0.0365013,-0.0365013,0.0040557};
lancz /= dot(lancz,4);
float4 w = {1,1,1,0};
//Calculate (local) autocorrelation coefficients
for (int k = 0; k<4; k+= 1){
float4 y = float4(Get(wind[k][0]),Get(wind[k][1]),Get(wind[k][2]),Get(wind[k][3]));
float4x2 C = float4x2(Get4(wind[k][0]),Get4(wind[k][1]),Get4(wind[k][2]),Get4(wind[k][3]));
R += w[k]*mul(transpose(C),C);
r += w[k]*mul(y,C);
d += lancz[k]*(Value(wind[k][0])+Value(wind[k][1])+Value(wind[k][2])+Value(wind[k][3]));
}
//Normalize
float n = 24;
R /= n; r /= n;
//Calculate a = R^-1 . r
float e = 0.005;
float2 a = solve(R+e*e*I,r+e*e/2.0);
//Nomalize 'a' (prevents overshoot)
a = .25 + float2(.5,-.5)*clamp(a[0]-a[1],-1,1);
//Calculate result
float2x4 x = float2x4(Value(dir[0])+Value(dir[1]),Value(dir[2])+Value(dir[3]));
float4 c = mul(float1x2(a),x);
//Fallback to lanczos
float t = saturate(1-500*sqr(x[0]-x[1]));
c += t*(d-mul(float1x2(1,1)/4.0,x));
return c;//+float4(0,0.5,0.5,0);
}
NEDI-II:
sampler s0 : register(s0);
float4 p0 : register(c0);
#define width (p0[0])
#define height (p0[1])
#define px (1.0 / (p0[0]))
#define py (1.0 / (p0[1]))
#define offset 0.5
#define Value(xy) (tex2D(s0,tex+float2(px,py)*(xy)))//-float4(0,0.5,0.5,0))
#define Get(xy) (Value(xy)[0]+offset)
#define Get4(xy) (float2(Get(xy+2*dir[0])+Get(xy+2*dir[1]),Get(xy+2*dir[2])+Get(xy+2*dir[3])))
#define sqr(x) (dot(x,x))
#define I (float2x2(1,0,0,1))
//Conjugate residual
float2 solve(float2x2 A,float2 b) {
float2 x = 1/4.0;
float2 r = b - mul(A,x);
float2 p = r;
float2 Ar = mul(A,r);
float2 Ap = Ar;
for (int k = 0;k < 2; k++){
float a = min(100,dot(r,Ar)/dot(Ap,Ap));
x = x + a*p;
float2 rk = r; float2 Ark = Ar;
r = r - a*Ap;
Ar = mul(A,r);
float b = dot(r,Ar)/dot(rk,Ark);
p = r + b*p;
Ap = Ar + b*Ap;
}
return x;
}
//Cramer's method
float2 solvex(float2x2 A,float2 b) { return float2(determinant(float2x2(b,A[1])),determinant(float2x2(A[0],b)))/determinant(A); }
float4 main(float2 tex : TEXCOORD0) : COLOR {
float4 c0 = tex2D(s0,tex);
//Skip pixels on wrong grid
if ((frac(tex.x*width/2.0)<0.5)&&(frac(tex.y*height/2.0)<0.5)) return c0;
if ((frac(tex.x*width/2.0)>0.5)&&(frac(tex.y*height/2.0)>0.5)) return c0;
//Define window and directions
float2 dir[4] = {{-1,0},{1,0},{0,1},{0,-1}};
float4x2 wind[4] = {{{-1,0},{1,0},{0,1},{0,-1}},{{-1,2},{1,-2},{2,1},{-2,-1}},{{-1,-2},{1,2},{-2,1},{2,-1}},{{-3,0},{3,0},{0,3},{0,-3}}};
//Initialization
float2x2 R = 0;
float2 r = 0;
float4 d = 0;
//Define weights
float4 lancz = {0.328511,-0.0365013,-0.0365013,0.0040557};
lancz /= dot(lancz,4);
float4 w = {1,1,1,0};
//Calculate (local) autocorrelation coefficients
for (int k = 0; k<4; k+= 1){
float4 y = float4(Get(wind[k][0]),Get(wind[k][1]),Get(wind[k][2]),Get(wind[k][3]));
float4x2 C = float4x2(Get4(wind[k][0]),Get4(wind[k][1]),Get4(wind[k][2]),Get4(wind[k][3]));
R += w[k]*mul(transpose(C),C);
r += w[k]*mul(y,C);
d += lancz[k]*(Value(wind[k][0])+Value(wind[k][1])+Value(wind[k][2])+Value(wind[k][3]));
}
//Normalize
float n = 24;
R /= n; r /= n;
//Calculate a = R^-1 . r
float e = 0.005;
float2 a = solve(R+e*e*I,r+e*e/2.0);
//Nomalize 'a' (prevents overshoot)
a = .25 + float2(.5,-.5)*clamp(a[0]-a[1],-1,1);
//Calculate result
float2x4 x = float2x4(Value(dir[0])+Value(dir[1]),Value(dir[2])+Value(dir[3]));
float4 c = mul(float1x2(a),x);
//Fallback to lanczos
float t = saturate(1-500*sqr(x[0]-x[1]));
c += t*(d-mul(float1x2(1,1)/4.0,x));
return c;//+float4(0,0.5,0.5,0);
}