欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Direct3D纹理映射

程序员文章站 2022-07-13 10:10:39
...

1. 纹理坐标

  • Direct3D使用的纹理坐标由水平的u轴和垂直的v轴组成,并且为了处理不同尺寸的纹理,Direct3D将纹理坐标规范化为[0,1]
  • 为了在实体的三角形单元中显示纹理,我们需要在顶点坐标中添加纹理坐标,再加纹理上相应的三角形区域映射到三角形单元上

Direct3D纹理映射

struct Vertex
{
    float _x, _y, _z;
    float _nx, _ny, _nz;
    float _u, _v; //Texture coordinates
}

#define VertexFVF D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1
//D3DFVF_TEX取值为0~8,表示顶点中含有0~8对纹理坐标

2. 创建和使用纹理

  • Direct3D9中,纹理使用IDirect3DTexture9表示,创建纹理通常从图象文件中读取,使用D3DXCreateTextureFromFile函数,该函数可以读取bmp, jpg, dds, dib, png和tga格式的图象
IDirect3DTexture9 *pTex;
D3DXCreateTextureFromFile(Device,
                          TEXT("Filename"),
                          &pTex);
  • 创建纹理后,设置当前活动纹理
IDirect3DDeivec::SetTexture(DWORD stage, IDirect3DTexture9 *pTexture);
  • 在Direct3D中,最多可以设置8层纹理,若要禁用某层纹理,可以将该层纹理的pTex参数设置为0
device->SetTexture(0, 0);

3. 纹理过滤

  • 纹理映射到屏幕空间中时,由于尺度变换,视角变换等因素,会发生一定程度的畸变,为了克服这类畸变,Direct3D使用了纹理过滤技术
  • Direct3D提供了三种纹理过滤器
device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_TYPE)
device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_TYPE)

//使用各项异性过滤时,需要检查D3DCAPS9获取硬件支持的质量水平,并设置各向异性过滤水平值
device->SetSamplerState(0, D3DSAMP_MAXANISOTROPIC, value);

最近点采样

Direct3D纹理映射

双线性过滤

Direct3D纹理映射

各向异性过滤

Direct3D纹理映射

4. 多级渐进纹理(Mipmap)

  • 由于屏幕上的三角形和纹理三角形的大小由于视角远近等原因通常不一样,为了消除二者差异带来的影响,我们可以为纹理创建一个渐进纹理链,渐进纹理需要独立设置纹理过滤器,如果硬件支持Mipmap,D3DXCreateTextureFromFile会自动创建一个渐进纹理链。
device->SetSamplerStates(0. D3DSAMP_MIPFILTER, Filter);

5. 寻址模式

之前说过,Direct3D将纹理坐标规范化到[0,1]中,但有时坐标有可能会超出这一区间,为此,Direct3D定义了四种寻址模式来处理这类情形,当纹理坐标被设置为u(3,0),v(0,3)时,四种寻址模式的效果如下

  • 重复寻址模式(WRAP):重复寻址模式使纹理在每个整数结点处重复箝
    Direct3D纹理映射

  • 镜像寻址模式(MIRROR):和重复寻址模式类似,但重复方式为镜像,每个相邻纹理互为镜像
    Direct3D纹理映射

  • 边界颜色寻址模式(BORDER):在超出范围的区域使用边界颜色进行填充
    Direct3D纹理映射

  • 箝位寻址模式(CLAMP):超出范围的部分,将范围内最后一个像素的颜色延伸到图元边界
    Direct3D纹理映射

  • 纹理寻址模式通过SetSamplerState进行设置

device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);

6. 例子,在正方形上以不同模式绘制纹理

#include "texquad.h"

using namespace d3d;

struct Vertex
{
    float _x, _y, _z;
    float _nx, _ny, _nz;
    float _u, _v;
    Vertex(float x, float y, float z,
           float nx, float ny, float nz,
           float u, float v) :
           _x(x), _y(y), _z(z), _nx(nx), _ny(ny), _nz(nz), _u(u), _v(v)
    {
    }
    static const DWORD FVF;
};
const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;

bool Setup()
{
    ::MessageBox(0, TEXT("Press \'CBMW\' for sampler address modes. Press \'ALP\' for sampling modes. Press G for grid texture, Press for DirectX Logo"),
                 TEXT("Tips"), MB_OK);
    //Set Vertex Buffer
    pD3DDEV->CreateVertexBuffer(6 * sizeof(Vertex), D3DUSAGE_WRITEONLY, Vertex::FVF, D3DPOOL_MANAGED, &pVB, 0);
    Vertex *v;
    pVB->Lock(0, 0, (void**)&v, 0);

    v[0] = Vertex(1.5f, 1.5f, 1.0f, 0.0f, 0.0f, 1.0f, 3.0f, 0.0f);
    v[1] = Vertex(1.5f, -1.5f, 1.0f, 0.0f, 0.0f, 1.0f, 3.0f, 3.0f);
    v[2] = Vertex(-1.5f, -1.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 3.0f);

    v[3] = Vertex(1.5f, 1.5f, 1.0f, 0.0f, 0.0f, 1.0f, 3.0f, 0.0f);
    v[4] = Vertex(-1.5f, -1.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 3.0f);
    v[5] = Vertex(-1.5f, 1.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);

    pVB->Unlock();

    //Set Address mode

    pD3DDEV->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
    pD3DDEV->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);


    //Load Texture
    D3DXCreateTextureFromFile(pD3DDEV, TEXT("grid.bmp"), &pTex);

    pD3DDEV->SetTexture(0, pTex);
    pD3DDEV->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
    pD3DDEV->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
    pD3DDEV->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);

    //Shut down light
    pD3DDEV->SetRenderState(D3DRS_LIGHTING, false);

    //Set Camera
    D3DXMATRIX cam;
    D3DXVECTOR3 EyeAt(0.0f, 0.0f, -2.0f);
    D3DXVECTOR3 LookAt(0.0f, 0.0f, 0.0f);
    D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
    D3DXMatrixLookAtLH(&cam, &EyeAt, &LookAt, &up);
    pD3DDEV->SetTransform(D3DTS_VIEW, &cam);

    //Set Projection
    D3DXMATRIX proj;
    D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI / 2,
                               800.0f / 600.0f,
                               1.0f, 1000.0f);
    pD3DDEV->SetTransform(D3DTS_PROJECTION, &proj);

    return true;
}

bool Render(float DeltaTime)
{
    pD3DDEV->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);

    if( SUCCEEDED(pD3DDEV->BeginScene()) )
    {
        //Get Sampler address mode
        if( ::GetAsyncKeyState('C') & 0x8000f )
        {
            pD3DDEV->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
            pD3DDEV->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
        }
        if( ::GetAsyncKeyState('B') & 0x8000f )
        {
            pD3DDEV->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);
            pD3DDEV->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);
        }
        if( ::GetAsyncKeyState('W') & 0x8000f )
        {
            pD3DDEV->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
            pD3DDEV->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
        }
        if( ::GetAsyncKeyState('M') & 0x8000f )
        {
            pD3DDEV->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR);
            pD3DDEV->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_MIRROR);
        }

        //Get Sampling mode
        if( ::GetAsyncKeyState('A') & 0x8000f )
        {
            pD3DDEV->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
            pD3DDEV->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
            pD3DDEV->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_ANISOTROPIC);
            pD3DDEV->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, 16);
        }
        if( ::GetAsyncKeyState('L') & 0x8000f )
        {
            pD3DDEV->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
            pD3DDEV->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
            pD3DDEV->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
        }
        if( ::GetAsyncKeyState('P') & 0x8000f )
        {
            pD3DDEV->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
            pD3DDEV->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
            pD3DDEV->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
        }

        //Set Texture
        if( ::GetAsyncKeyState('G') & 0x8000f )
        {
            Release<IDirect3DTexture9>(pTex);
            D3DXCreateTextureFromFile(pD3DDEV, TEXT("grid.bmp"), &pTex);
            pD3DDEV->SetTexture(0, pTex);
        }
        if( ::GetAsyncKeyState('D') & 0x8000f )
        {
            Release<IDirect3DTexture9>(pTex);
            D3DXCreateTextureFromFile(pD3DDEV, TEXT("dx5_logo.bmp"), &pTex);
            pD3DDEV->SetTexture(0, pTex);
        }

        pD3DDEV->SetStreamSource(0, pVB, 0, sizeof(Vertex));
        pD3DDEV->SetFVF(Vertex::FVF);
        pD3DDEV->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);

        pD3DDEV->EndScene();
    }
    pD3DDEV->Present(0, 0, 0, 0);

    return true;
}

Written with StackEdit.