纹理采样:在3D渲染中,一般我们会为每个显示在屏幕上的平面贴上纹理。在处理这个过程中,我们需要创建纹理图和与之对应的采样器,采样器的作用就是按照某种规则把纹理上的像素点采集并绘制到模型平面上。除了极少数特殊情况,一般情况下纹理大小与目标面的大小是不对等的,包括形状有时候都不一样,除此之外有用视距的原因目标平面还会出现动态缩放的情况,这个时候又存在MIP(多级纹理)这个东西,它也增加了纹理采样的复杂度。
在DX9的效果框架里,HLSL可以直接创建一个采样状态,但是由于DX11微软对效果框架的放权,导致其直接支持比较模糊。所以,我所看到比较常见的做法是在DX中构建一个采样状态对象,然后传递到相应的着色器里面。
创建一个采样器 :ID3D11Device
HRESULT CreateSamplerState(
[in] const D3D11_SAMPLER_DESC *pSamplerDesc,
[out] ID3D11SamplerState **ppSamplerState
);
传入一个D3D11_SAMPLER_DESC参数作为采样器的描述
typedef struct D3D11_SAMPLER_DESC {
D3D11_FILTER Filter; // 这个过滤器描述了三项类容
D3D11_TEXTURE_ADDRESS_MODE AddressU; // 1
D3D11_TEXTURE_ADDRESS_MODE AddressV; // 1
D3D11_TEXTURE_ADDRESS_MODE AddressW; // 1
FLOAT MipLODBias; // 这个是lod用的,如果mipmap=3,MipLODBias=2,则实际mipmap=5 UINT MaxAnisotropy; // 各向异性过滤器会用到,钳位值0-16,
D3D11_COMPARISON_FUNC ComparisonFunc; // 过滤器使用的比较?
FLOAT BorderColor[4]; // 边框颜色
FLOAT MinLOD; // mipmap的范围
FLOAT MaxLOD; // mipmap的范围
} D3D11_SAMPLER_DESC;
typedef enum D3D11_TEXTURE_ADDRESS_MODE { // 当目标面比纹理大时,超出部分按照何种方式采集
D3D11_TEXTURE_ADDRESS_WRAP = 1, // 像贴瓷砖一样不停的重复,直到目标面贴满
D3D11_TEXTURE_ADDRESS_MIRROR = 2, // 与1类似,只不过重复的时候会镜面反转一下
D3D11_TEXTURE_ADDRESS_CLAMP = 3, // 超出部分按照超边边的颜色向外拉伸,想象一下扯麦芽糖就是那个样子
D3D11_TEXTURE_ADDRESS_BORDER = 4, // 超出部分作为一个边框存在,边框的颜色为上面的第4个参数
D3D11_TEXTURE_ADDRESS_MIRROR_ONCE = 5 // 这个没弄明白
} D3D11_TEXTURE_ADDRESS_MODE;
D3D11_FILTER :
typedef enum D3D11_FILTER {
D3D11_FILTER_MIN_MAG_MIP_POINT = 0,
D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR = 0x1,
D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x4,
D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR = 0x5,
D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT = 0x10,
D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x11,
D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT = 0x14,
D3D11_FILTER_MIN_MAG_MIP_LINEAR = 0x15,
D3D11_FILTER_ANISOTROPIC = 0x55,
D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT = 0x80,
D3D11_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR = 0x81,
D3D11_FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x84,
D3D11_FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR = 0x85,
D3D11_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT = 0x90,
D3D11_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x91,
D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT = 0x94,
D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR = 0x95,
D3D11_FILTER_COMPARISON_ANISOTROPIC = 0xd5,
D3D11_FILTER_TEXT_1BIT = 0x80000000
} D3D11_FILTER;
D3D11_FILTER :其实就是缩小,放大和mipmap按照点取样,线性插值取样和各项异性插值取样进行对应映射的关系。
其实这了不是很好理解的就是点取样,线性插值取样和各项异性插值取样,这里贴一下网上的理解:
1.点取样:这个是最基本的方式,距离最近的点进行四舍五入计算,这种方式容易走样。
是不是觉得没有走样,这个图不明显,放大会出现马赛克,缩小会出现失真。
2.线性插值取样:在网上看到三次线性取样,我还以为是神马。结果是缩小,放大,mipmap都用。
感觉比第一种方式还模糊一些。
3.各项异性采样:一个屏幕像素被反映射到纹理上的区域是一块近似的平行四边形(应该不是标准的平行四边形),然后用短边决定MipMap的层,再在长边的方向上多采样几次做混合,用短边决定MipMap层就使得层数不会太深,然后再用长边多次采样混合,这样就缓解了上面提到的模糊问题。
不是很理解。
设置采样状态:
void VSSetSamplers(
[in] UINT StartSlot, // 起始坐标
[in] UINT NumSamplers, // 个数 StartSlot + NumSamplers不能大于一个常数
[in] ID3D11SamplerState *const *ppSamplers // 是一个数组
);
DX11没有SetSamplerState方法,是不是意味着所以的变量都得用map进行改变。