0

我正在尝试编写一个像素着色器 - 我想使用 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
}
4

2 回答 2

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 个)使用您的参考值 (0),计算 0 或 1,具体取决于它们是否小于或大于您的参考值,将这些布尔值过滤为 0 和 1 之间的数字

回复评论:

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

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

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

(嗯,你可以,但你需要为此使用SampleGrad。但是!在这种情况下,这不是你想要的。)

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

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

无论如何,你真的不想使用 SampleCmp/LevelZero。它做错了你所追求的事情!它用于阴影贴图等。请改用LOD 为 0 的SampleLevel

于 2013-03-19T15:34:04.133 回答
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/的 build 3/5/2013 bb509644(v=vs.85).aspx 但如果存在则不会编译。

我通过将 Filter 属性更改为具有值 COMPARISON_MIN_MAG_MIP_POINT 来修复上述行为 - 那时一切正常

于 2013-03-17T17:00:39.987 回答