DirectX纹理采样函数SampleCmpLevelZero间歇性地返回空白?

时间:2013-03-15 16:25:20

标签: directx hlsl

我正在尝试编写一个像素着色器 - 我想使用Texture.SampleCmpLevelZero,因为它可以在Texture.Sample不是的循环结构中使用。

我构建了一个纹理并且可以使用Texture.Sample对其进行采样,但切换到SampleCmpLevelZero适用于前几帧,然后变为空白,然后很少但是间歇性地正确渲染。

我的场景是静态的(也是纹理数据) - 我正在渲染一个四边形并且没有任何类型的相机移动 - 我可以通过改变PS着色器功能中的单线来可靠地再现它。

有没有人见过这个?

由于

SamplerState sampPointClamp
{
    Filter = MIN_MAG_MIP_POINT;
    AddressU = Clamp;
    AddressV = Clamp;
};

SamplerComparisonState ShadowSampler
{
   // sampler state
   Filter = MIN_MAG_MIP_POINT;
   AddressU = Clamp;
   AddressV = Clamp;

   // sampler comparison state
   ComparisonFunc = LESS;
   //ComparisonFilter = COMPARISON_MIN_MAG_MIP_POINT;
};

texture2D tex;

//on the fly full screen quad
PS_IN VS(uint id : SV_VertexID)
{
    PS_IN ret;
    ret.uv = float2( id & 1, (id & 2) >> 1 );
    ret.pos = float4( ret.uv * float2( 2.0f, -2.0f ) + float2( -1.0f, 1.0f), 0.0f, 1.0f );
    return ret;
}

float4 PS( PS_IN input ) : SV_Target
{
    //return float4(tex.SampleCmpLevelZero(ShadowSampler, input.uv, 0), 0, 0, 1); // Does not work properly
    return float4(tex.Sample(sampPointClamp, input.uv).x, 0, 0, 1); // Works fine
}

2 个答案:

答案 0 :(得分:3)

样本应该在循环中正常工作:

float4 PSColUV(COLUV_PIXEL input) : SV_Target
{
    float4 output;
    for (int i = 0; i < 4; i++)
    {
        float f = float(i) / 256.0;
        float2 uv = input.UV + float2(i,i);

        output += g_txDiffuse.Sample(g_samLinear, uv);
    }
    return input.Col * output/4.0;
}

产生

      ps_4_0
      dcl_sampler s0, mode_default
      dcl_resource_texture2d (float,float,float,float) t0
      dcl_input_ps linear v1.xyzw
      dcl_input_ps linear v2.xy
      dcl_output o0.xyzw
      dcl_temps 3
   0: mov r0.xyzw, l(0,0,0,0)
   1: mov r1.x, l(0)
   2: loop
   3:   ige r1.y, r1.x, l(4)
   4:   breakc_nz r1.y
   5:   itof r1.y, r1.x
   6:   add r1.yz, r1.yyyy, v2.xxyx
   7:   sample r2.xyzw, r1.yzyy, t0.xyzw, s0
   8:   add r0.xyzw, r0.xyzw, r2.xyzw
   9:   iadd r1.x, r1.x, l(1)
  10: endloop
  11: mul r0.xyzw, r0.xyzw, v1.xyzw
  12: mul o0.xyzw, r0.xyzw, l(0.250000, 0.250000, 0.250000, 0.250000)
  13: ret

此外,您确实意识到您正在进行PCF查找而不是普通纹理样本,并且这不会为您提供纹理中的数据,而是会比较所有纹素子样本(例如8)在bilinear中)使用您的参考值(0),根据它们是否为LESS或GREATEREQUAL计算0或1,将这些布尔值过滤为0到1之间的数字

回复评论:

  

谢谢 - 我认为Sample不能处于可变长度或a的循环中   编译时未知的长度(?)。我得到的错误是“错误   X4014:循环内部不能有发散梯度操作错误:   编译表达式时出错“。在你的另一点 - 我这样做   想要一个确切的样本 - 我认为这就是我得到的 - 我只是   尝试使用纹理进行一些程序纹理生成   缓冲区作为值表,让我计算真实的纹素值   基于(u,v)等。 - AnonDev

http://msdn.microsoft.com/en-gb/library/windows/desktop/bb219848%28v=vs.85%29.aspx “每像素流量控制与屏幕渐变的相互作用”

请记住像素是在(至少)2x2块中执行的。您不能拥有导致某些像素采样的控制流,而其他像素则不能采样,也不能在控制流内进行计算,这会导致采样操作获得不同的梯度。

(嗯,你可以,但是你需要使用SampleGrad。但是!这不是你想要的。)

你说“确切”的样本。您的意思是您的资源只有一个mip映射,并且您希望获取资源中的每个纹素而不进行过滤? (即你正在做一个点过滤器?)。鉴于你对纹理的解释是一个值表,那么我不明白为什么你需要纹理成为一个mipchain,只有顶层包含有用的信息。在这种情况下,您可以使用SampleLevel(),LOD为0.这意味着衍生品不会有分歧,因为样本操作不使用衍生物!

这与SampleCmpLevelZero的工作方式相同,但SampleCmp不会:)如果你是点抽样,那么另一个好的候选者就是Load(),因为你可以给它准确的纹素位置甚至在缓冲区上使用它。因此,如果您的纹理查找位置基于像素(X,Y),那么您可以将这些直接传递到Load(在考虑半纹理像素偏移之后)。

无论如何,你真的不想使用SampleCmp / LevelZero。它做错了你想要的!它用于阴影贴图等。使用SampleLevel代替LOD为

答案 1 :(得分:0)

问题是:

SamplerComparisonState ShadowSampler
{
   // sampler state
   Filter = MIN_MAG_MIP_POINT;
   AddressU = Clamp;
   AddressV = Clamp;

   // sampler comparison state
   ComparisonFunc = LESS;
   //ComparisonFilter = COMPARISON_MIN_MAG_MIP_POINT;
};

看起来有一段时间,ComparisonFilter作为属性存在(因为它出现在文档中),例如构建http://msdn.microsoft.com/en-gb/library/windows/desktop/bb509644(v=vs.85).aspx的3/5/2013 但如果存在则不会编译。

我通过将Filter属性更改为具有值COMPARISON_MIN_MAG_MIP_POINT来修复上述行为 - 此时它已全部工作