我正在尝试编写一个像素着色器 - 我想使用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
}
答案 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来修复上述行为 - 此时它已全部工作