3D图形学编程基础-基于Direct3D11-学习记录(三)纹理的使用

来源:互联网 发布:淘宝客服都要交押金吗 编辑:程序博客网 时间:2024/04/30 22:53

每个笔记的介绍内容是跟着教材书走的,这次记录的是纹理的使用环节

单靠修改每个顶点的属性来描绘整个世界显然是不太科学的,消耗太大了,所以就用到了纹理。 简单的来说,纹理就是把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 *mFireMapD3DX11CreateShaderResourceViewFromFile(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 ) ;}





0 0