我正在使用Direct3D 11和Visual Studio 2015开发图形引擎。在用于主绘制调用的HLSL着色器中,我使用百分比-更近距离过滤对定向和点光源的阴影贴图进行采样,即对一个小的目标阴影贴图纹理周围的正方形区域,并对结果求平均以得到柔和的阴影。现在,每次对shadowMap_.Sample(...)的调用都会产生一个警告:“梯度指令在具有不同迭代次数的循环中使用,迫使循环展开”(X3570)。我想解决此问题,或者,如果无法解决,请隐藏警告,因为它完全淹没了我的警告输出。
我尝试在线搜索错误消息,但找不到任何进一步的描述。我什至找不到解释什么是梯度指令。我检查了Microsoft文档中是否有其他采样器或采样函数,该采样器或采样函数使我可以用本机采样功能替换循环,但也找不到类似的东西。这是我用来采样点光源的阴影立方体贴图的函数:
float getPointShadowValue(in uint index, in float3 worldPosition)
{
// (Half-)Radius for percentage closer filtering
int hFilterRadius = 2;
// Calculate the vector inside the cube that points to the fragment
float3 fragToLight = worldPosition.xyz - pointEmitters_[index].position.xyz;
// Calculate the depth of the current fragment
float currentDepth = length(fragToLight);
float sum = 0.0;
for (float z = -hFilterRadius; z <= hFilterRadius; z++)
{
for (float y = -hFilterRadius; y <= hFilterRadius; y++)
{
for (float x = -hFilterRadius; x <= hFilterRadius; x++)
{
// Offset the currently targeted cube map texel and sample at that position
float3 off = float3(x, y, z) * 0.05;
float closestDepth = pointShadowMaps_.Sample(sampler_, float4(fragToLight + off, index)).x * farPlane_;
sum += (currentDepth - 0.1 > closestDepth ? 1.0 : 0.0);
}
}
}
// Calculate the average and return the shadow value clamped to [0, 1]
float shadow = sum / (pow(hFilterRadius * 2 + 1, 3));
return min(shadow, 1.0);
}
代码仍然可以正常工作,但是我收到了很多这样的警告,并且不知道这是否会对性能产生影响。非常感谢有关该警告的任何进一步信息以及可以采取的措施。
谢谢。
答案 0 :(得分:2)
梯度函数是所有纹理采样方法,它们可以自行确定所使用的Mip级别,例如您所使用的方法Sample
。因此,它们在内部使用ddx
(doc)和ddy
(doc)。片段在gpu上以2x2块计算,因此它们可以相互比较纹理坐标的差异。差异越大,则使用的mip-map级别越高。使用动态分支时,此方法不再起作用,因为不能保证每个片段都使用相同的计算路径,因此梯度函数在动态分支中不起作用。当循环使用分支时,编译器必须使它们变为静态才能使用梯度函数。在这种情况下,可以通过展开来完成此操作,因为循环始终相同。编译器已经检测到它,并通过自动编写所有步骤来编写非分支代码来编译您的循环。使用[unroll]
(doc)语句,可以提示编译器这样做并禁止显示警告。
代码的另一种方法是使用不是梯度函数的采样方法,例如SampleLevel
(doc),在其中传递所需的mip-map级别(本例中为0)因为您的阴影贴图没有mip-map-levels),并且gpu不必确定它。据我所知,对性能的影响可以忽略不计,因为这种情况发生在非常低的水平上,大多数功能在gpu上的处理速度都一样快,但是也许您应该自己进行测试。
另一种不适用于您的情况,但另一种用于提取文本像素的非渐变方法是Load
(doc),可通过整数texel索引直接获取特定的texel。
答案 1 :(得分:0)
如查克·沃尔本(Chuck Walbourn)所述,在for循环之前添加[unroll]语句可修复警告。这种警告类型基本上是编译器会通知您的循环无法展开,或者这样做的执行效率较低(可以在Microsoft documentation for the HLSL for-loop中进行读取)。我认为可以放心接受。