Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# XNA+;HLSL高斯模糊产生偏移伪影_C#_Hlsl_Gaussian_Resampling - Fatal编程技术网

C# XNA+;HLSL高斯模糊产生偏移伪影

C# XNA+;HLSL高斯模糊产生偏移伪影,c#,hlsl,gaussian,resampling,C#,Hlsl,Gaussian,Resampling,所以我在XNA(3.1.是的,我知道它已经过时了。是的,我有理由使用它)和HLSL中构建了一个降采样算法。基本上,它的工作原理是对原始纹理应用高斯模糊,然后使用XNA中内置的默认最近邻重缩放来调整其大小。我的想法是,高斯模糊将给出一个近似于一个颜色区域平均值的值,因此它本质上是一种减少混叠的廉价方法。它工作得很好,速度也很快,但产生了一些有趣的人工制品——它似乎略微拉伸了图像。这通常是不明显的,但我正在下采样的一些东西是精灵表,当设置动画时,很明显精灵没有被放置到正确的位置。我想知道是否一个不同

所以我在XNA(3.1.是的,我知道它已经过时了。是的,我有理由使用它)和HLSL中构建了一个降采样算法。基本上,它的工作原理是对原始纹理应用高斯模糊,然后使用XNA中内置的默认最近邻重缩放来调整其大小。我的想法是,高斯模糊将给出一个近似于一个颜色区域平均值的值,因此它本质上是一种减少混叠的廉价方法。它工作得很好,速度也很快,但产生了一些有趣的人工制品——它似乎略微拉伸了图像。这通常是不明显的,但我正在下采样的一些东西是精灵表,当设置动画时,很明显精灵没有被放置到正确的位置。我想知道是否一个不同的重采样器(也内置在HLSL中的GPU的速度)可能是一个更好的选择,或者如果有一个错误,我可以修复。我会把我的代码贴在这里,看看有没有人能给我启发

首先是我的HLSL高斯效果文件:

#define RADIUS  7
#define KERNEL_SIZE (RADIUS * 2 + 1)

float weightX[KERNEL_SIZE];
float weightY[KERNEL_SIZE];
float2 offsetH[KERNEL_SIZE];
float2 offsetV[KERNEL_SIZE];

texture colorMapTexture;

sampler TextureSampler : register(s0);

void BlurH(inout float4 color : COLOR0, float2 texCoord : TEXCOORD0)
{
    float4 c = float4(0.0f, 0.0f, 0.0f, 0.0f);

    for (int i = 0; i < KERNEL_SIZE; ++i)
        c += tex2D(TextureSampler, texCoord + offsetH[i]) * weightX[i];

        color = c;
}

void BlurV(inout float4 color : COLOR0, float2 texCoord : TEXCOORD0)
{
    float4 c = float4(0.0f, 0.0f, 0.0f, 0.0f);

    for (int i = 0; i < KERNEL_SIZE; ++i)
        c += tex2D(TextureSampler, texCoord + offsetV[i]) * weightY[i];

        color = c;
}

technique GaussianBlur
{
    pass
    {
        PixelShader = compile ps_2_0 BlurH();
    }
    pass
    {
        PixelShader = compile ps_2_0 BlurV();
    }
}
#定义半径7
#定义内核大小(半径*2+1)
浮动权重x[内核大小];
浮动权重[内核大小];
float2偏移[内核大小];
float2 offsetV[内核大小];
纹理颜色贴图纹理;
采样器纹理采样器:寄存器(s0);
空洞模糊(inout float4颜色:COLOR0,float2 texCoord:TEXCOORD0)
{
浮动4 c=浮动4(0.0f,0.0f,0.0f,0.0f);
for(int i=0;i
以及我初始化高斯效应的代码(请注意,gaussianBound设置为8,即1+HLSL文件中的半径):

public static Effect GaussianBlur(浮动量、浮动radx、浮动rady、点刻度)
{
效果rtrn=gaussianblur.Clone(MainGame.graphicsManager.GraphicsDevice);
if(radx>=高斯波)
{
radx=高斯声波-0.000001F;
}
if(rady>=高斯波)
{
rady=高斯声波-0.000001F;
}
//如果模糊度太大,图像会变得透明,
//因此,限制可以使用多少模糊。
//降低非常小的图像的质量。
向量2[]offsetsHoriz,offsetsVert;
float[]kernelx=新的float[(int)(radx*2+1)];
浮动sigmax=radx/金额;
float[]kernely=新的float[(int)(rady*2+1)];
浮动sigmay=拉迪/金额;
//初始化内核和sigma(分别考虑x和y中的不同比例因子)
浮点数twoSigmaSquarex=2.0f*sigmax*sigmax;
float sigmaRootx=(float)Math.Sqrt(twoSigmaSquarex*Math.PI);
浮点数twoSigmaSquarey=2.0f*sigmay*sigmay;
float sigmaRooty=(float)Math.Sqrt(twoSigmaSquarey*Math.PI);
浮动总X=0.0f;
总浮动Y=0.0f;
浮动距离=0.0f;
int指数=0;
//初始化高斯常数,以及归一化总数。
offsetsHoriz=新向量2[kernelx.Length];
offsetsVert=新向量2[kernely.Length];
浮动xOffset=1.0f/刻度.X;
浮动Y偏移=1.0f/刻度Y;
//设置在HLSL着色器中使用的偏移。

对于(int i=-(int)radx;i我发现了一些东西:它与高斯模糊无关。问题是我正在用最近邻缩小,这会由于数据丢失而产生这些伪影(例如,当某个东西需要基本上位于像素5.5时,它只是将其置于像素5,给出一个位置误差).谢谢大家的帮助,但看来我得稍微重新考虑一下我的算法了


我通过添加一个额外的约束来修复它,即重采样只对整数重采样有效。其他任何操作都将重采样到最接近的可用整数样本,然后用NN缩放其余部分。这与我以前的工作非常接近,但现在由于HLSL,速度快了很多。我希望获得任意缩放algorithm,但它对我的需求来说已经足够好了。它并不完美,因为我仍然会得到偏移误差(由于数据丢失,在下采样时几乎不可能完全避免),但它们现在明显小于一个像素,因此除非您正在寻找它们,否则不会被注意到。

我有一些疑问。第二遍应该使用第一遍的结果。 否则,您可以将BlurH和BlurV组合在一起,结果将是相同的。
我没有发现任何代码使用第一次通过的结果,也没有将第一次通过的结果转换为第二次通过的结果。

如果人们不改变正确的拼写,我将不胜感激。Artefact有一个可互换的拼写,尽管在英国,它通常用e来拼写。你有没有可能把它放在一个演示项目中进行测试?我很乐意艺术效果。不容易,但我可能会得到一些屏幕截图来展示。添加了一个屏幕截图。你应该能够看到左边的图像略低于右边的图像。这两个帧是从一个精灵表中导入的,其中的帧是自动定位的。你有没有包括y处半texel的小偏移我们的模糊着色器?“请注意,为了在精确的纹理中心对纹理进行采样,必须将一个纹理的一半大小的纹理坐标偏移添加到t
 public static Effect GaussianBlur(float amount, float radx, float rady, Point scale)
        {
            Effect rtrn = gaussianblur.Clone(MainGame.graphicsManager.GraphicsDevice);

            if (radx >= gaussianBound)
            {
                radx = gaussianBound - 0.000001F;
            }
            if (rady >= gaussianBound)
            {
                rady = gaussianBound - 0.000001F;
            }
            //If blur is too great, image becomes transparent,
            //so cap how much blur can be used.
            //Reduces quality of very small images.

            Vector2[] offsetsHoriz, offsetsVert;
            float[] kernelx = new float[(int)(radx * 2 + 1)];
            float sigmax = radx / amount;
            float[] kernely = new float[(int)(rady * 2 + 1)];
            float sigmay = rady / amount;
            //Initialise kernels and sigmas (separately to allow for different scale factors in x and y)

            float twoSigmaSquarex = 2.0f * sigmax * sigmax;
            float sigmaRootx = (float)Math.Sqrt(twoSigmaSquarex * Math.PI);
            float twoSigmaSquarey = 2.0f * sigmay * sigmay;
            float sigmaRooty = (float)Math.Sqrt(twoSigmaSquarey * Math.PI);
            float totalx = 0.0f;
            float totaly = 0.0f;
            float distance = 0.0f;
            int index = 0;
            //Initialise gaussian constants, as well as totals for normalisation.

            offsetsHoriz = new Vector2[kernelx.Length];
            offsetsVert = new Vector2[kernely.Length];

            float xOffset = 1.0f / scale.X;
            float yOffset = 1.0f / scale.Y;
            //Set offsets for use in the HLSL shader.

            for (int i = -(int)radx; i <= radx; ++i)
            {
                distance = i * i;
                index = i + (int)radx;
                kernelx[index] = (float)Math.Exp(-distance / twoSigmaSquarex) / sigmaRootx;
                //Set x kernel values with gaussian function.
                totalx += kernelx[index];
                offsetsHoriz[index] = new Vector2(i * xOffset, 0.0f);
                //Set x offsets.
            }

            for (int i = -(int)rady; i <= rady; ++i)
            {
                distance = i * i;
                index = i + (int)rady;
                kernely[index] = (float)Math.Exp(-distance / twoSigmaSquarey) / sigmaRooty;
                //Set y kernel values with gaussian function.
                totaly += kernely[index];
                offsetsVert[index] = new Vector2(0.0f, i * yOffset);
                //Set y offsets.
            }

            for (int i = 0; i < kernelx.Length; ++i)
                kernelx[i] /= totalx;

            for (int i = 0; i < kernely.Length; ++i)
                kernely[i] /= totaly;

            //Normalise kernel values.

            rtrn.Parameters["weightX"].SetValue(kernelx);
            rtrn.Parameters["weightY"].SetValue(kernely);
            rtrn.Parameters["offsetH"].SetValue(offsetsHoriz);
            rtrn.Parameters["offsetV"].SetValue(offsetsVert);
            //Set HLSL values.

            return rtrn;
        }