每个笔记的介绍内容是跟着教材书走的,这次记录的是纹理的使用环节
单靠修改每个顶点的属性来描绘整个世界显然是不太科学的,消耗太大了,所以就用到了纹理。 简单的来说,纹理就是把2D图片运用到了3D中,给3D模型贴上一个图片。
知识一:纹理坐标
因为纹理是2D的,模型是3D的,需要一个3D到2D的转换。在DX中贴图的左上角为顶点,u轴向右,v轴向下,其中u和v的取值范围是0~1。意思是不管贴图大小是64*64,还是256*256,图片中心点的纹理坐标都是(0.5,0.5)。(纹理坐标系,也称为纹理空间)
要添加纹理坐标的话,顶点的结构体,数据,以及描述就需要修改了
struct SimpleVertex
{
XMFLOAT3 Pos;
XMFLOAT2 Tex;<span style="white-space:pre"> </span>//纹理坐标
};
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "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 },//纹理坐标描述,注意格式为<span style="font-family: Arial, Helvetica, sans-serif;">DXGI_FORMAT_R32G32_FLOAT</span>
};
纹理数据通常从图像文件中读取到一个ID3D11Texture2D的对象中,但是纹理资源不能直接绑定在管线上(立即执行上下文中),需要为纹理资源创建一个资源视图,然后将试图绑定至上下文(后台缓存也是这样的)
通过书,代码示例等发现三种用法:
第一种:
第一步:调用D3DX10CreateTextureFromFile来读取图像文件,并创建一个ID3D11Texture2D的对象
第二步:调用ID3D11device::CreateShaderResourseView创建着色器试图
第二种:
第一步:使用函数D3D11CreateShaderResourceViewFile
ID3D11ShaderResourceView *mFireMap
D3DX11CreateShaderResourceViewFromFile(pDevice,"Fire.bmp",0,0,&mFireMap,0);<span style="white-space:pre"> </span>//第一个是设备指针,第二个图像文件,第三个图像信息一般为null,第一个使用新线程,我们这里不使用多线程,第五个着色器资源视图指针,第六个,如果线程设置的NULL,这里必须的NULL。
第二步:在.fx文件中声明纹理结构
Texture2D Texture;
第三步:在C++中获取.fx中的texture接口,并绑定资源
ID3D11EffectShaderResourceVariable* mfxFireMap;
mfxFireMap = mFX->GetVariableByName("Texture")->AsShaderResource();
mfxFireMap->SetResource(mFireMap);
</pre><p></p><p><span style="font-size:12px"></span></p>第三种:<p><span style="font-size:12px; white-space:pre"></span><span style="font-size:12px">这种用法运用到了后面的知识“模板“,深度/模板缓存</span><span style="font-size:12px; white-space:pre"></span></p><pre name="code" class="cpp"> ID3D11Texture2D* g_pDepthStencil = NULL; <span style="white-space:pre"> </span>//纹理指针
D3D11_TEXTURE2D_DESC descDepth;<span style="white-space:pre"> </span>//纹理结构
ZeroMemory( &descDepth, sizeof(descDepth) );
descDepth.Width = width;<span style="white-space:pre"> </span>//纹理宽高
descDepth.Height = height;
descDepth.MipLevels = 1;<span style="white-space:pre"> </span>//是否用到多重纹理
descDepth.ArraySize = 1;
descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;<span style="white-space:pre"> </span>//24位深度通道和8位模板通道
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;<span style="white-space:pre"> </span>//说明此纹理作用是绑定至深度/模板缓存中
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
hr = g_pd3dDevice->CreateTexture2D( &descDepth, NULL, &g_pDepthStencil );
if( FAILED( hr ) )
return hr;
// Create the depth stencil view //这个是深度/模板缓存
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
ZeroMemory( &descDSV, sizeof(descDSV) );
descDSV.Format = descDepth.Format;
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDSV.Texture2D.MipSlice = 0;
hr = g_pd3dDevice->CreateDepthStencilView( g_pDepthStencil, &descDSV, &g_pDepthStencilView );
if( FAILED( hr ) )
return hr;
g_pImmediateContext->OMSetRenderTargets( 1, &g_pRenderTargetView, g_pDepthStencilView );
知识三:纹理过滤
1.纹理的放大
纹理为什么要放大:我们保存的纹理的大小是64*64,然而物体的大小是256*256,那么就需要放大纹理,两个纹理像素点之间的距离就由0变成了1.那么多出来的这个像素点到底绘制什么颜色。就需要计算
计算的方法有两种,
第一种:常量差值:和最近的点一个颜色(点过滤)
第二种:线性差值:求附近两点平均值(线性过滤)
2.纹理的缩小
当然缩小的原因就是纹理比物体大了
有一种东西叫做mipmap链,创建一个mipmap链(美工的工作),将贴图一次缩小。如果没有手动创建mipmap链,D3D会在使用时自动创建
知识四:纹理寻址方式
前面提到纹理的坐标(u,v)的范围是0~1,世界上纹理坐标可以超出此范围,超出范围的纹理贴图靠寻址模式来定义
1.Wrap寻址,超出范围的地方不断重复原来纹理图片
2.Border寻址,超出范围的地方显示固定颜色,颜色可以自己设定
3.Clamp寻址,超出范围的地方用最近一组纹理坐标代替
4.Mirror寻址,超出范围的地方和原图镜像代替
纹理的寻址方式和过滤方式需要在.fx文件中设定
</pre><pre name="code" class="cpp">SampleState mySample
{
Filer = MIN_MAG_MIP_LINEAR;
Filer = MIN_POINT_MAG_POINT_MIP_LINER;<span style="white-space:pre"> </span>//其中min为缩小,mag放大,mip是mipmap。liner是线性,point是点,可自由搭配
AddressU = WRAP;
AddressV = WRAP;<span style="white-space:pre"> </span>//选项是以上4中寻址之一
}
最后 代码示例
C++
struct SimpleVertex
{
XMFLOAT3 Pos;
XMFLOAT2 Tex;
};
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size:14px; white-space: pre;"> </span><span style="font-size:10px;">D3D11_TEXTURE2D_DESC descDepth;</span></span>
ZeroMemory( &descDepth, sizeof(descDepth) );
descDepth.Width = width;
descDepth.Height = height;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
hr = g_pd3dDevice->CreateTexture2D( &descDepth, NULL, &g_pDepthStencil );
if( FAILED( hr ) )
return hr;
// Create the depth stencil view //这个是深度/模板缓存
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
ZeroMemory( &descDSV, sizeof(descDSV) );
descDSV.Format = descDepth.Format;
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDSV.Texture2D.MipSlice = 0;
hr = g_pd3dDevice->CreateDepthStencilView( g_pDepthStencil, &descDSV, &g_pDepthStencilView );
if( FAILED( hr ) )
return hr;
g_pImmediateContext->OMSetRenderTargets( 1, &g_pRenderTargetView, g_pDepthStencilView );
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "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 },
};
.fx文件
float4 PS( PS_INPUT input) : SV_Target
{
return txDiffuse.Sample( samLinear, input.Tex ) ;
}