DX11(十):纹理映射

06/12/2020

基础纹理介绍

纹理坐标系(UV坐标系)

一张图片有横坐标轴和竖坐标轴,横坐标轴叫u,竖坐标轴叫v,原点在图片的左上角

纹理读取

DirectXTK中有DDSTextureLoader和WICTextureLoader的源文件和头文件,可以方便的解析dds和wic文件格式

createDDSTextureFromFile函数–从文件读取DDS纹理

HRESULT CreateDDSTxtureFromFile(
	ID3D11Device* d3dDevice,			//Device
	const wchar_t* szFileName,			//dds file name
	ID3D11Resource** texture,			//输出一个指向资源接口类的接口
	ID3D11ShaderResourceView** textureView,	//输出一个指向着色器资源视图的指针
	size_t maxsize = 0,
	DDS_ALPHA_MODE* alphaMode = nullptr
	
);

createWICTextureFromFile函数

HRESULT CreateWICTxtureFromFile(
	ID3D11Device* d3dDevice,			//Device
	const wchar_t* szFileName,			//dds file name
	ID3D11Resource** texture,			//输出一个指向资源接口类的接口
	ID3D11ShaderResourceView** textureView,	//输出一个指向着色器资源视图的指针
	size_t maxsize = 0
);

注意:这里主要为了创建一个ID3D11ShaderResourceView着色器资源视图,因为纹理资源不能直接使用

HLSL 变动

  • 加入uv顶点
  • 加入纹理
  • 加入采样器
Texture2D gTex:register(t0); //保存2D纹理信息
SamplerState gSamLinear:register(s0);	//确定采样器如何采样

struct VertexPosNormalTex
{
	float3 PosL:POSITION;
	float3 NormalL:NORMAL;
	float2 Tex:TEXCOORD;
};

顶点布局

struct VertexPosNormalTex
{
	DirectX::XMFLOAT3 pos;
	DirectX::XMFLOAT3 normal;
	DirectX::XMFLOAT2 tex;
	static const D3D11_INPUT_ELEMENT_DESC inputLayout[3];

};

小细节

  • HLSL有寄存器是常量缓冲区,采样器状态和纹理2D,通常我们找对应关系是跟着不同插入槽的名城,然而顶点布局设置了语义描述形式
  • 所以说HLSL结构体或者缓冲名字可以和C++名字不同,它们基本不是根据名字传递数据的

过滤器(纯理论)

  • 处理图片被放大后,像素空间变大之后,空缺的像素如何填充的问题
  • 处理图片缩小后,像素损失问题

图片放大(插值法)

常量插值法

线性插值法

图片缩小(mipmap技术)

牺牲一些内存代价的方式来获得高效的拟合效果

mipmap

各项异性过滤

对纹理采样

设置着色器资源(*SSetShaderResources)

void ID3D11DeviceContext::PSSetShaderResources(
	UINT StartSlot,										   //对应HLSL的register(t*)
	UINT NumViews,										   //着色器资源视图数目	
	ID3D11ShaderResourceView* const* ppShaderResourceViews //着色器资源视图数组
);

创建采样器状态

typedef struct D3D11_SAMPLER_DESC
{
    D3D11_FILTER Filter;                    // 所选过滤器
    D3D11_TEXTURE_ADDRESS_MODE AddressU;    // U方向寻址模式
    D3D11_TEXTURE_ADDRESS_MODE AddressV;    // V方向寻址模式
    D3D11_TEXTURE_ADDRESS_MODE AddressW;    // W方向寻址模式
    FLOAT MipLODBias;   // mipmap等级偏移值,最终算出的mipmap等级会加上该偏移值
    UINT MaxAnisotropy;                     // 最大各向异性等级(1-16)
    D3D11_COMPARISON_FUNC ComparisonFunc;   // 这节不讨论
    FLOAT BorderColor[ 4 ];     // 边界外的颜色,使用D3D11_TEXTURE_BORDER_COLOR时需要指定
    FLOAT MinLOD;   // 若mipmap等级低于MinLOD,则使用等级MinLOD。最小允许设为0
    FLOAT MaxLOD;   // 若mipmap等级高于MaxLOD,则使用等级MaxLOD。必须比MinLOD大        
} 	D3D11_SAMPLER_DESC;

// 初始化采样器状态
D3D11_SAMPLER_DESC sampDesc;
ZeroMemory(&sampDesc, sizeof(sampDesc));
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
HR(m_pd3dDevice->CreateSamplerState(&sampDesc, m_pSamplerState.GetAddressOf()));

选择过滤器

//枚举值	                        				缩小	放大	mipmap
D3D11_FILTER_MIN_MAG_MIP_POINT				//	点采样	点采样	点采样
D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR		//	点采样	点采样	线性采样
D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT	//	点采样	线性采样	点采样
D3D11_FILTER_MIN_MAG_MIP_LINEAR				//	线性采样	线性采样	线性采样
D3D11_FILTER_ANISOTROPIC					//	各向异性	各向异性	各向异性

选择寻址模式

D3D11_TEXTURE_ADDRESS_BORDER
D3D11_TEXTURE_ADDRESS_CLAMP
D3D11_TEXTURE_ADDRESS_WRAP
D3D11_TEXTURE_ADDRESS_MIRROR_ONCE
D3D11_TEXTURE_ADDRESS_MIRROR

像素着色器阶段设置采样器状态

void ID3D11DeviceContext::PSSetSamplers(
    UINT StartSlot,     // [In]起始槽索引  (s)
    UINT NumSamplers,   // [In]采样器状态数目
    ID3D11SamplerState * const * ppSamplers);   // [In]采样器数组  
    
// 像素着色阶段设置好采样器
m_pd3dImmediateContext->PSSetSamplers(0, 1, m_pSamplerState.GetAddressOf());

总结

  • 初始化图片纹理并创建着色器资源视图(CreateDDSTextureFromFile)
  • 更新HLSL着色器和顶点布局格式
  • 初始化采样器状态 (CreateSamplerState)
  • 像素着色器阶段设置好采样器和着色器资源视图 (PSSetSamplers 和 PSSetShaderResources)

后续补充

渲染管道可以创建多个顶点或者像素着色器,使用的时候需要绑定需要的着色器

HLSL 纹理采样

采取纹理的颜色

 float4 texColor = g_Tex.Sample(g_SamLinear, pIn.Tex);
 float4 litColor = texColor * (ambient + diffuse) + spec;
 litColor.a = texColor.a * g_Material.Diffuse.a;
  • Texture2D 有一个Sample函数可以在纹理中选取颜色,必须有采样器,因为如果纹理坐标超出了uv坐标,就会采取采样器的设置好的寻址模式
  • texColor影响了计算好后的环境光和漫反射光,如果没有采集到纹理颜色,会导致物体无法绘制出来

绘制不同的纹理到六面体

//六面体的索引左边
meshData.indexVec = {
		0, 1, 2, 2, 3, 0,		// 右面(+X面)
		4, 5, 6, 6, 7, 4,		// 左面(-X面)
		8, 9, 10, 10, 11, 8,	// 顶面(+Y面)
		12, 13, 14, 14, 15, 12,	// 底面(-Y面)
		16, 17, 18, 18, 19, 16, // 背面(+Z面)
		20, 21, 22, 22, 23, 20	// 正面(-Z面)
	};
// 通过不同的索引坐标决定六面体的不同面,再更改纹理资源视图
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pWoodCrate.GetAddressOf());

m_pd3dImmediateContext->DrawIndexed(6, 0, 0);  //六面体的右面

m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pAlpha.GetAddressOf());

m_pd3dImmediateContext->DrawIndexed(6, 6, 0); //六面体左面

纹理分量乘法

Texture2D g_Tex : register(t0);  //插入槽 t0 对应一个纹理视图
Texture2D g_Tex1 : register(t1);	//插入槽 t1 对应另一个纹理视图

//PS着色器中的纹理颜色分量乘法
float4 texColor = g_Tex.Sample(g_SamLinear, pIn.Tex);
float4 texColor1 = g_Tex1.Sample(g_SamLinear, pIn.Tex);
texColor = texColor * texColor1;  //分量乘法 Float4 texColor = {t1.r * t2.r, t1.g * t2.g, t1.b * t2.b, t1.a * t2.a}

X_Jun的博客园

猜你喜欢

转载自blog.csdn.net/weixin_44200074/article/details/106533582
今日推荐