DirectX11编程9 贴图的采样

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012632851/article/details/83473057

环境:VS2017  语言:C++

 

总起:

这一章主要对应红龙书的第八章。

 

工程地址:https://github.com/anguangzhihen/Dx11。主要以Chapter 8_1 Crate作为讲解的基础。

 

首先让我们来看一下效果:

 

采样纹理:

这一章主要是将“被采样的纹理”和“采样状态”在C++中创建好,然后传递到Shader。

 

以下创建设置代码:

// 获取木箱子纹理
HR(CreateDDSTextureFromFile(md3dDevice, L"Textures\\WoodCrate01.dds", nullptr, &mWoodCrateDDS));

// 初始化采样器状态
D3D11_SAMPLER_DESC sampDesc;
ZeroMemory(&sampDesc, sizeof(sampDesc));
//sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampDesc.Filter = D3D11_FILTER_ANISOTROPIC;	// 过滤方法设置为各向异性
sampDesc.MaxAnisotropy = 4;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;	// 压缩方法
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
HR(md3dDevice->CreateSamplerState(&sampDesc, &mSamplerState));

// 片元着色器阶段设置采样器 
md3dImmediateContext->PSSetSamplers(0, 1, &mSamplerState);	// 对应Shader中的register(s0)
md3dImmediateContext->PSSetShaderResources(0, 1, &mWoodCrateDDS);	// 对应Shader中的regiser(t0)

我们对纹理设定的过滤方式是各向异性(Anisotropic),这种方式是在放大、缩小纹理时表现效果时最好的。其他两种方式分别是常量插值(Constant Interpolation)、线性插值(Linear Interpolation)。

 

性能消耗:常量插值 < 线性插值 < 各向异性。

 

常量插值就是直接去最近的像素点作为当前的像素值,著名的Minecraft使用的纹理处理方式正是这种,在Unity中对应的Filter Mode是Point。

 

线性插值是根据周围的像素点乘以距离权重后计算出来的值。相比于各向异性,在观察一个远近相差较大的纹理时比较模糊。

 

各向异性在采样时并不直接采样一个方形的纹理,可能会对纹理进行变换成梯形或平行四边形,所以细节效果上会更加精致。

 

使用过滤耗方法时比较严重,所以一般会采用Mipmap的技术,生成从小到大的一套图片用于采样。以空间换时间,一般会增加1/3的内存,不过这是值得的。

 

Mipmap可以由程序根据过滤方法自动生成,也可以由美术绘制而成。

 

这边注意到我们使用的贴图是DDS格式的,这是一种由NVIDIA公司开发,常用于贴图的格式。常用的是DXGI_FORMAT_BC3_UNORM,针对3种颜色通道和8bit的alpha通道。相对的如果为DXGI_FORMAT_R8G8B8A8_UNORM则是未压缩的。

 

最后我们来看一下Shader中如何进行采样。

 

申明贴图和采样状态来接受CPU传来的值:

Texture2D tex : register(t0);
SamplerState sam : register(s0);

顶点着色器中,使用一个变换矩阵来处理Tex值:

// 使用矩阵变换当前的Tex值
vout.Tex = mul(float4(vin.Tex, 0.0f, 1.0f), gTexTransform).xy;

Tex值即uv值,在生成法线和xyz坐标时同时生成。u轴是贴图的横向坐标,v轴是纵向坐标。原点为左上角,u轴向左,v轴向下,和我们平时使用的xyz轴差别较大,注意一下。

 

最后是片元着色器中的采样:

// 对图片进行采样
float4 texColor = tex.Sample(sam, pin.Tex);
// 叠加所有的光
float4 litColor = texColor * (ambient + diffuse) + spec;
litColor.a = gMaterial.Diffuse.a;

猜你喜欢

转载自blog.csdn.net/u012632851/article/details/83473057