Direct3D11:“在循环中使用梯度指令,迭代不同,强制循环展开”,警告:X3570

Nov*_*are 3 directx direct3d hlsl

我正在使用 Direct3D 11 和 Visual Studio 2015 开发图形引擎。在主绘制调用的 HLSL 着色器中,我使用百分比更接近过滤对定向光和点光源的阴影贴图进行采样,即我对周围的小正方形区域进行采样目标阴影贴图 texel 并平均结果以获得软阴影。现在,每次调用 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);
}
Run Code Online (Sandbox Code Playgroud)

该代码仍然可以正常工作,但是我收到了大量这些警告,并且不知道这是否会导致相关的性能影响。非常感谢有关警告的任何进一步信息以及可以采取的措施。

提前致谢。

Gni*_*how 7

梯度函数都是纹理采样方法,它们自己决定使用的mip-level,比如你使用的方法Sample。因此他们使用ddx( doc ) 和ddy( doc) 内部。Fragment 在 GPU 上以 2x2 块的形式计算,因此它们可以相互比较纹理坐标的差异。差异越大,使用的 mip-map-level 越高。对于动态分支,此方法不再有效,因为不能保证每个片段使用相同的计算路径,因此梯度函数在动态分支中不起作用。由于循环使用分支,编译器必须使它们静态才能使用梯度函数。这是通过在您的情况下展开来完成的,因为循环始终相同。编译器已经检测到它并通过自动编写所有步骤来编译循环以生成非分支代码。使用[unroll]( doc ) 语句,您可以提示编译器这样做并抑制警告。

您的代码的另一种方法是使用不是梯度函数的采样方法,例如SampleLevel( doc ) 在其中传递所需的 mip-map-level(在您的情况下为 0,因为您的阴影贴图没有 mip-map-级别)并且 gpu 不必确定它。据我所知,性能影响可以忽略不计,因为这种情况发生在非常低​​的级别,其中大多数功能在 gpu 上的处理速度相同,但也许您应该进行自己的测试。

一个不适用于您的情况的添加,但另一种获取文本的非梯度方法是Load( doc ) 通过整数 texel 索引直接获取特定的 texel。