微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么动态分支内部的纹理采样会导致不同的结果? HLSL

如何解决为什么动态分支内部的纹理采样会导致不同的结果? HLSL

我正在尝试实现基于权重的高度混合着色器。 首先,我尝试找到权重最高的 4 个层(alpha 层)。 然后从这 4 层混合。

以下是我的简化代码

// find the 4 layers with the largest weight.
void find_max_layers(float2 texCoord,out int4 max_indics)
{
    max_indics = int4(-1,-1,-1);
    max_weights = float4(.0001,.0001,.0001);
    [unroll]
    for (int Layer = 0; Layer < 2; ++Layer) // 2 is for test... 
    {
        const int surfaceIndex = (int)cSurfaceIndex[Layer];
        const float alpha = tLayerWeight.Sample(sLayerWeight,float3(texCoord,Layer)).r;
        if (alpha > max_weights.x) {
            max_indics = int4(surfaceIndex,max_indics.xyz);
            max_weights = float4(alpha,max_weights.xyz);
        }
        else if (alpha > max_weights.y) {
            max_indics.yzw = int3(surfaceIndex,max_indics.yz);
            max_weights.yzw = float3(alpha,max_weights.yz);
        }
        else if (alpha > max_weights.z) {
            max_indics.zw = int2(surfaceIndex,max_indics.z);
            max_weights.zw = float2(alpha,max_weights.z);
        }
        else if (alpha > max_weights.w) {
            max_indics.w = surfaceIndex;
            max_weights.w = alpha;
        }
    }
}

// get surface albedo,normal,height.
half get_surface_color_normal_height(int surface,float3 texCoord,out half3 color)
{
    const float surface_tiling[2] = { 64.0f,32.0f }; // hard coded for show my bugs.
    const float tiling = surface_tiling[surface];
    half4 color_h = tAlbedoMap.Sample(sLinearWrap,float3(texCoord.xy * tiling,surface));
    color = color_h.rgb;
    return color_h.w;
}

void blend_layers(float3 texCoord,out half3 albedo)
{
    int4 surfaceIndics; // [0,1,-1] or [1,-1]
    find_max_layers(texCoord.xy,surfaceIndics);
    half3 colors[4] = { (half3)0,(half3)0,(half3)0 };

    /*A: works
     if(surfaceIndics.x == 0)
      {
        get_surface_color_normal_height ( 0,texCoord,colors [ 0 ]  );
        get_surface_color_normal_height ( 1,colors [ 1 ]  );
    }else
    {
      get_surface_color_normal_height (1,colors [ 0 ]  );
      get_surface_color_normal_height ( 0,colors [ 1 ]  );
    }*/
    /*B:works
   if(surfaceIndics.x == 0)
      {
        get_surface_color_normal_height ( 0,colors [ 1 ]  );
    }else
    {
      get_surface_color_normal_height (0,colors [ 0 ]  );
      get_surface_color_normal_height ( 1,colors [ 1 ]  );
    }
    */

    //C: error!!!
    if (surfaceIndics.x != -1)
    {
        get_surface_color_normal_height(surfaceIndics.x,colors[0]);
    }
    if (surfaceIndics.y != -1)
    {
        get_surface_color_normal_height(surfaceIndics.y,colors[1]);
    }
    // output
    albedo = (colors[0] + colors[1]) * 0.5;
}

让我先简化一下问题,我有 2 个纹理 0,1 需要混合。 函数 find_max_layers 只有两个返回值:[0,-1] 或 [1,-1]。

函数 blend_layers 中的代码部分 A 和 B 工作正常。

输出图像是: A,B the right result

但是函数 blend_layers 中的代码段 C 输出了意外的结果: C,the error result

解决方法

经过一些尝试,我发现使用SampleLevel代替Sample,并且指定纹理在相同的mipmap级别进行采样,问题就会消失。
所以我判断原因是相邻像素的mipmap采样不一致。
然后我手动构建了两种不同颜色的纹理的 mipmap。得到了进一步的验证。
根据本文(http://www.aclockworkberry.com/shader-derivative-functions/)的指导,最终使用SampleGrad代替Sample来解决问题。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。