我目前正处理多纹理地形,但Sample的Texture2DArray功能出现问题。
在我的示例中,我使用Texture2DArray来存储一组不同的地形纹理,例如草,砂,沥青等。我的每个顶点都存储一个纹理坐标(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);
结果如我所希望的那样顺利: - )
答案 0 :(得分:1)
纹理数组不会在切片上进行采样,因此从技术上讲,这是预期的结果。
如果你想在切片之间进行插值(例如: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之间进行搜索),并最终通过更改其他一些切片来使用不同的混合模式功能