Directx HLSL中的纹理采样器不插值

Directx HLSL中的纹理采样器不插值,directx,textures,directx-11,hlsl,pixel-shader,Directx,Textures,Directx 11,Hlsl,Pixel Shader,我目前正在处理一个多纹理的地形,我的功能有问题 在我的示例中,我使用存储一组不同的地形纹理,例如草、沙、沥青等。我的每个顶点存储一个纹理坐标(UV坐标)和我要使用的纹理索引。因此,如果索引为0,则使用第一个纹理。如果索引为1,则使用第二个纹理,依此类推。只要我的索引是一个自然数(0,1,…),这就行了。但是,如果索引是实数(如1.5f),则它将失败 为了查找问题,我将整个像素着色器缩减为: Texture2DArray DiffuseTextures : register(t0); Textur

我目前正在处理一个多纹理的地形,我的功能有问题

在我的示例中,我使用存储一组不同的地形纹理,例如草、沙、沥青等。我的每个顶点存储一个纹理坐标(UV坐标)和我要使用的纹理索引。因此,如果索引为0,则使用第一个纹理。如果索引为1,则使用第二个纹理,依此类推。只要我的索引是一个自然数(0,1,…),这就行了。但是,如果索引是实数(如1.5f),则它将失败

为了查找问题,我将整个像素着色器缩减为:

Texture2DArray DiffuseTextures : register(t0);
Texture2DArray NormalTextures : register(t1);
Texture2DArray EmissiveTextures : register(t2);
Texture2DArray SpecularTextures : register(t3);
SamplerState Sampler : register(s0);

struct PS_IN
{
    float4 pos : SV_POSITION;
    float3 nor : NORMAL;
    float3 tan : TANGENT;
    float3 bin : BINORMAL;
    float4 col : COLOR;
    float4 TextureIndices : COLOR1;
    float4 tra : COLOR2;
    float2 TextureUV : TEXCOORD0;
};

float4 PS(PS_IN input) : SV_Target
{
    float4 texCol = DiffuseTextures.Sample(Sampler, float3(input.TextureUV, input.TextureIndices.r));

    return texCol;
}
下图显示了左侧示例场景的结果。如您所见,使用的纹理之间有一个硬边界。没有插值的形式

为了检查我的纹理索引,我通过将纹理索引作为颜色返回,从上面更改了我的像素着色器:

return float4(input.TextureIndices.r, input.TextureIndices.r, input.TextureIndices.r, 1.0f);
结果可以在图像的右侧看到。纹理索引是正确的,因为它们在区间[0,1]内变化,并且您可以清楚地看到区域边界处的插值。但是,我的采样纹理不显示任何形式的插值

由于我的像素着色器非常简单,我想知道是什么导致了这种行为?DirextX中是否有任何设置对此负责

我使用DirectX 11、像素着色器ps_5_0(我还使用ps_4_0进行了测试)和DDS纹理(BC3压缩)

编辑

这是我正在使用的取样器:

SharpDX.Direct3D11.SamplerStateDescription samplerStateDescription = new SharpDX.Direct3D11.SamplerStateDescription()
{
    AddressU = SharpDX.Direct3D11.TextureAddressMode.Wrap,
    AddressV = SharpDX.Direct3D11.TextureAddressMode.Wrap,
    AddressW = SharpDX.Direct3D11.TextureAddressMode.Wrap,
    Filter = SharpDX.Direct3D11.Filter.MinMagMipLinear
};

SharpDX.Direct3D11.SamplerState samplerState = new SharpDX.Direct3D11.SamplerState(_device, samplerStateDescription);

_deviceContext.PixelShader.SetSampler(0, samplerState);
解决方案

我使用catflier提供的代码创建了一个函数,用于获取纹理颜色:

float4 GetTextureColor(Texture2DArray textureArray, float2 textureUV, float textureIndex)
{
    float tid = textureIndex;
    int id = (int)tid;
    float l = frac(tid);

    float4 texCol1 = textureArray.Sample(Sampler, float3(textureUV, id));
    float4 texCol2 = textureArray.Sample(Sampler, float3(textureUV, id + 1));

    return lerp(texCol1, texCol2, l);
}
这样,我可以通过一个简单的函数调用获得所有纹理类型(漫反射、镜面反射、发射等)所需的纹理颜色:

float4 texCol = GetTextureColor(DiffuseTextures, input.TextureUV, input.TextureIndices.r);
float4 bumpMap = GetTextureColor(NormalTextures, input.TextureUV, input.TextureIndices.g);
float4 emiCol = GetTextureColor(EmissiveTextures, input.TextureUV, input.TextureIndices.b);
float4 speCol = GetTextureColor(SpecularTextures, input.TextureUV, input.TextureIndices.a);
结果就像我希望的那样平滑::-)


纹理阵列不跨切片采样,所以从技术上讲,这是预期的结果

如果您想在切片之间插值(例如:1.5f为您提供第二个纹理的“一半”和第三个纹理的“一半”),您可以使用Texture3d,这允许这样做(但由于它将执行三线过滤,因此会花费更多的成本)

否则,您可以通过以下方式执行采样:

float4 PS(PS_IN input) : SV_Target
{
    float tid = input.TextureIndices.r;
    int id = (int)tid; 
    float l = frac(tid); //lerp amount

    float4 texCol1 = DiffuseTextures.Sample(Sampler, float3(input.TextureUV,id));
    float4 texCol2 = DiffuseTextures.Sample(Sampler, float3(input.TextureUV,id+1));
return lerp(texCol1,texCol2, l);
}


请注意,这种技术非常灵活,因为您还可以提供非相邻切片作为输入(例如,您可以在切片2和23之间进行lerp),并最终通过其他函数更改lerp来使用不同的混合模式。

它工作得非常好,谢谢。我更新了我的帖子,展示了解决方案及其结果。然而,我很确定我的代码在几个月前就可以工作了。但我很高兴,现在一切都正常了。