一个纹理就是映射到我们的图形和实体表面的数据
通常此数据是颜色值,它通过一种叫做纹理映射的处理,将一张图像映射到物体表面
纹理和其他游戏资源一样 将会在运行时载入。使用函数 D3D11CreateTextureFromFile
D3DX11CreateTextureFromFileA(
ID3D11Device* pDevice, //设备驱动
LPCSTR pSrcFile, //图像数据文件路径
D3DX11_IMAGE_LOAD_INFO *pLoadInfo, //图像信息结构
ID3DX11ThreadPump* pPump, //线程pump
ID3D11Resource** ppTexture, //通过外部图片所加载的纹理对象地址调用 成功会有一个加载好的纹理
HRESULT* pHResult);
ID3D11Texture1D 处理1D或图像条类型纹理
ID3D11Texture2D 处理2D图像数据
ID3D11Texture3D 处理3D(表示体积) 图像数据
纹理贴图中的每个像素叫做纹理元素, 一个纹理元素对应一个RGB值
MIP分级机制是在相同的纹理下依次向低级别的版本递减
根据远近不同使用合适的分辨率
根据放大Magnification缩小Minification系数来决定物体的渲染程度
纹理的细节
有时需要知道来自载入的纹理的细节信息 比如尺寸和像素格式 描述结构体如下
typedef struct D3D11_TEXTURE2D_DESC
{
UINT Width;
UINT Height;
UINT MipLevels;
UINT ArraySize;
DXGI_FORMAT Format;
DXGI_SAMPLE_DESC SampleDesc;
D3D11_USAGE Usage;
UINT BindFlags;
UINT CPUAccessFlags;
UINT MiscFlags;
} D3D11_TEXTURE2D_DESC;
着色器资源视图:用于访问资源的着色器对象
ID3D11ShaderResourceView* colorMap_;
当我们载入图像到内存时,需要创建一个着色器资源视图对象
用于通过一个着色器来访问数据
采样状态变量:
一个采样状态允许我们访问一个纹理的采样状态信息
ID3D11SamplerState* colorMapSampler_;
我们执行纹理映射,需要更新顶点结构使得包含两个浮点变量用于TU和TV贴图坐标
D3D11_INPUT_ELEMENT_DESC solidColorLayout[]{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD" , 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 } //用于贴图坐标
};
整个加载函数如下:
bool TextureDemo::LoadContent() {
ID3DBlob* vsBuffer = 0;
bool compileResult = compileD3DShader("SolidGreenColor.fx", "VS_Main", "vs_4_0", &vsBuffer); //着色器编译 就是设置颜色
if (compileResult == false) {
MessageBox(0, "error loading vertex shader!!", "ERROR", MB_OK);
return false;
}
//创建定点渲染
HRESULT d3dResult;
d3dResult = d3dDevice_->CreateVertexShader(vsBuffer->GetBufferPointer(), vsBuffer->GetBufferSize(), 0, &solidColorVS_);
if (FAILED(d3dResult)) {
if (vsBuffer)
vsBuffer->Release();
return false;
}
/*。。。。。贴图的设置。。。。。*/
D3D11_INPUT_ELEMENT_DESC solidColorLayout[]{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD" , 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 } //用于贴图坐标
};
unsigned int totalLayoutElements = ARRAYSIZE(solidColorLayout);
d3dResult = d3dDevice_->CreateInputLayout(solidColorLayout, totalLayoutElements, vsBuffer->GetBufferPointer(), vsBuffer->GetBufferSize(), &inputLayout_);
vsBuffer->Release();
if (FAILED(d3dResult)) {
return false;
}
//像素着色器设置
ID3DBlob* psBuffer = 0;
compileResult = compileD3DShader("SolidGreenColor.fx", "VS_Main", "vs_4_0", &psBuffer);
if (compileResult == false) {
MessageBox(0, "error loading pixel shader!!", "ERROR", MB_OK);
return;
}
d3dResult = d3dDevice_->CreatePixelShader(vsBuffer->GetBufferPointer(), vsBuffer->GetBufferSize(), 0, &solidColorPS_);
psBuffer->Release();
if (FAILED(d3dResult)) {
return false;
}
VertexPos vertices[]{
{XMFLOAT3(1.0f, 1.0f, 1.0f), XMFLOAT2(1.0f,1.0f)},
{XMFLOAT3(1.0f, -1.0f, 1.0f), XMFLOAT2(1.0f,0.0f)},
{XMFLOAT3(-1.0f,-1.0f, 1.0f), XMFLOAT2(0.0f,0.0f)},
{XMFLOAT3(-1.0f,-1.0f, 1.0f), XMFLOAT2(0.0f,0.0f)},
{XMFLOAT3(-1.0f, 1.0f, 1.0f), XMFLOAT2(0.0f,1.0f)},
{XMFLOAT3(1.0f, 1.0f, 1.0f), XMFLOAT2(1.0f,1.0f)}
};
//创建顶点缓存
D3D11_BUFFER_DESC vertexDesc;
ZeroMemory(&vertexDesc, sizeof(vertexDesc));
vertexDesc.Usage = D3D11_USAGE_DEFAULT;
vertexDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexDesc.ByteWidth = sizeof(vertexDesc) * 3;
D3D11_SUBRESOURCE_DATA resourceData;
ZeroMemory(&resourceData, sizeof(resourceData));
resourceData.pSysMem = vertices;
d3dResult = d3dDevice_->CreateBuffer(&vertexDesc, &resourceData, &vertexBuffer_);
if (FAILED(d3dResult)) {
return false;
}
//创建资源着色器视图
d3dResult = D3DX11CreateShaderResourceViewFromFile(d3dDevice_, "decal.dds", 0, 0, &colorMap_, 0);
if (FAILED(d3dResult)) {
DXTRACE_MSG("Error loading resource view from file!!..");
return false;
}
//。。。Continue。。。
D3D11_SAMPLER_DESC colorMapDesc;
ZeroMemory(&colorMapDesc, sizeof(colorMapDesc)); //清空内存
colorMapDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
colorMapDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
colorMapDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
colorMapDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
colorMapDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
colorMapDesc.MaxLOD = D3D11_FLOAT32_MAX;
d3dResult = d3dDevice_->CreateSamplerState(&colorMapDesc, &colorMapSampler_);
if (FAILED(d3dResult)) {
DXTRACE_MSG("Error loading sampler State");
return false;
}
return true;
}
以上函数载入我们的贴图图像
载入和创建一个资源着色器对象:D3DX11CreateShaderResourceViewFromFile
HRESULT WINAPI
D3DX11CreateTextureFromFileA(
ID3D11Device* pDevice,
LPCSTR pSrcFile,
D3DX11_IMAGE_LOAD_INFO *pLoadInfo,
ID3DX11ThreadPump* pPump,
ID3D11Resource** ppTexture,
HRESULT* pHResult);
D3D11_SAMPLER_DESC
{
D3D11_FILTER Filter;
D3D11_TEXTURE_ADDRESS_MODE AddressU;
D3D11_TEXTURE_ADDRESS_MODE AddressV;
D3D11_TEXTURE_ADDRESS_MODE AddressW;
FLOAT MipLODBias;
UINT MaxAnisotropy;
D3D11_COMPARISON_FUNC ComparisonFunc;
FLOAT BorderColor[ 4 ];
FLOAT MinLOD;
FLOAT MaxLOD;
} D3D11_SAMPLER_DESC;
多种采样方式:
点采样: 直接从纹理中取得单一的值作为采样结果,而不进行修改。映射在某像素周围最接近该像素的纹理元素
双线性采样:使得的纹理渲染效果更加平滑,减少渲染中的人为现象(就是锯齿效果)
三线性采样:物体远离或者靠近时,表面纹理能够平滑过渡
各向异性采样:不同的角度采用不同的处理方式
贴图地址模式:
D3D11_TEXTURE_ADDRESS_MODE AddressU;
D3D11_TEXTURE_ADDRESS_MODE AddressV;
D3D11_TEXTURE_ADDRESS_MODE AddressW;
纹理坐标值指定在一定范围内纹理的各个尺寸
纹理坐标范围指定处理超出范围的纹理的处理方式
纹理坐标模式:
enum D3D11_TEXTURE_ADDRESS_MODE
{ D3D11_TEXTURE_ADDRESS_WRAP = 1,
D3D11_TEXTURE_ADDRESS_MIRROR = 2,
D3D11_TEXTURE_ADDRESS_CLAMP = 3,
D3D11_TEXTURE_ADDRESS_BORDER = 4,
D3D11_TEXTURE_ADDRESS_MIRROR_ONCE = 5
} D3D11_TEXTURE_ADDRESS_MODE;
只需指定最右边的顶点U贴图坐标分量为20即可
镜像(MIRROR)将会导致贴图以镜像形式重复,这里CLAMP将会简单的使值在0.0-1.0的范围
CLAMP将会简单的使值在0.0 - 1.0 的范围
MIRROR_ONCE 将会使得贴图的镜像形式出现一次
而MIRROR将会使用指定的镜像次数
BORDER 地址模式将会设置任何在0.0 - 1.0 范围之外的像素一个指定的边界颜色
添加贴图资源和设置采样状态:
PPSetShaderResource 和 PSSetSamplers
virtual void STDMETHODCALLTYPE PSSetShaderResources(
/* [annotation] */
__in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1 ) UINT StartSlot, //开始插入资源
/* [annotation] */
__in_range( 0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot ) UINT NumViews, //资源的数量
/* [annotation] */
__in_ecount(NumViews) ID3D11ShaderResourceView *const *ppShaderResourceViews) = 0; //资源数组
void TextureDemo::Render() {
if (d3dContext_ == 0)
return;
float clearColor[4] = { 0.0f, 0.0f, 0.25f, 1.0f };
d3dContext_->ClearRenderTargetView(backBufferTarget_, clearColor);
unsigned int stride = sizeof(VertexPos);
unsigned int offset = 0; //偏移量为0
d3dContext_->IASetInputLayout(inputLayout_);
d3dContext_->IASetVertexBuffers(0, 1, &vertexBuffer_, &stride, &offset);
d3dContext_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
d3dContext_->VSSetShader(solidColorVS_, 0, 0);
d3dContext_->PSSetShader(solidColorPS_, 0, 0);
//添加贴图资源和设置采样状态
d3dContext_->PSSetShaderResources(0, 1, &colorMap_);
d3dContext_->PSSetSamplers(0, 1, &colorMapSampler_);
d3dContext_->Draw(6, 0);
swapChain_->Present(0, 0);
}
为了在我们提供的渲染函数中的着色器输入中绑定这些对象 我们必须使用HLSL注册关键字register
用于注册的fx文件代码如下:
/*
Beginning DirectX 11 Game Programming
By Allen Sherrod and Wendy Jones
Texture Mapping Shader
*/
Texture2D colorMap_ : register( t0 );
SamplerState colorSampler_ : register( s0 );
struct VS_Input
{
float4 pos : POSITION;
float2 tex0 : TEXCOORD0;
};
struct PS_Input
{
float4 pos : SV_POSITION;
float2 tex0 : TEXCOORD0;
};
PS_Input VS_Main( VS_Input vertex )
{
PS_Input vsOut = ( PS_Input )0;
vsOut.pos = vertex.pos;
vsOut.tex0 = vertex.tex0;
return vsOut;
}
float4 PS_Main( PS_Input frag ) : SV_TARGET
{
return colorMap_.Sample( colorSampler_, frag.tex0 );