D3D纹理

2023-10-27

纹理映射是一种将图形施加到表面的技术。以简单的一堵墙为例,这种技术可以只需要两个绘制有砖纹理的三角形即可。这样就可以为表面增加大量的细节,而不必使用大量的多边形。

纹理映射使用了图像数据并将图像数据绘制(映射)到表面上。该表面看上去就像有一幅图在它上面。所以,如果有一堵墙,并将砖块的纹理施加到这堵墙上面,那么即便只是这个表面使用了两个三角形,它看上去也像场景中的一堵墙。

    Direct3D中的纹理就是一幅映射到表面上的图像,这样可以让表面显示比实际上更多的细节。在3D场景中实现纹理映射,最常见的方法是从外部文件加载图像数据。该文件可以存在于硬盘、软盘或光盘等载体上,同样该文件可以在场景中的多个表面上共享使用。

在Direct3D中实现纹理映射的最小工作量就是为Direct3D纹理对象加载一幅图像,为顶点结构和FVF的每个顶点指定纹理坐标,并在渲染几何图形之前添加纹理。Direct3D支持的图像文件格式有:
■ 联合图像专家组(.jpg)
■ Windows位图(.bmp)
■ 光栅图像文件存储格式(.tga)
■ 可移植的网络图像文件格式(.png)
■ 直接绘图表面格式(.dds)
■ 可移植的像素映射格式(.ppm)
■ Windows设备无关位图格式(.dib)
■ 高动态范围格式(.hdr)
■ 可移植的浮点映射格式(.pfm)

在Direct3D中加载图像时要用到一个名为LPDIRECT3DTEXTURE9的结构。LPDIRECT3DTEXTURE9结构是Direct3D中的纹理对象,在加载1D或2D纹理图像时要用到该结构。无论何时创建LPDIRECT3DTEXTURE9纹理对象,都要调用对象的Release()函数对其进行释放。创建纹理时,可以选择手动将图像数据加载到对象上,或使用Direct3D的函数将文件中的图像数据加载到对象上。本书将从文件加载图像数据入手,虽然读者可以从Direct3D支持的任何图像文件格式加载图像文件,但这里主要涉及他图像文件格式是.bmp和.tga这两种图像文件格式。

 为了创建空的纹理图像,读者可以使用D3DXCreateTexture()函数手动将数据添加到纹理中。一旦成功创建纹理对象,D3DXCreateTexture()函数就返回一个D3D_OK值(如果出现错误就会返回其他值)。如果函数返回且纹理对象为NULL(空),那么纹理创建就存在问题。

HRESULT WINAPI D3DXCreateTexture(
LPDIRECT3DDEVICE9 pDevice,
// Direct3D9的设备对象
UINT Width, // 图像宽度
UINT Height, // 图像高度
UINT MipLevels, // 图片的图层,一般用D3DX_DEFAULT,与图像质量有关
DWORD Usage, //设定这个纹理的使用方法
D3DFORMAT Format, // 每个颜色成分使用的位数
D3DPOOL Pool, // 纹理对象驻留的内存类别
LPDIRECT3DTEXTURE9 * ppTexture // 指向新创建的纹理对象
);

    高度和宽度是图像的分辨率,设备对象是渲染要用的Direct3D9设备对象。为了创建无错的纹理对象就要成功地创建设备对象。为了使用该函数,同样要了解正在创建的纹理的宽度和高度。

       图像的参数MipLevels中Mipmap的总数与图像质量有关。默认情况下,该标识符为0,如果正在创建一个要渲染的纹理,那么该标识符为D3DUSAGE_RENDERTARGET,如果该纹理是动态纹理,则该标识符为D3DUSAGE_DYNAMIC。本书出于开发目的,多数情况下将该标识符设为0,除了在本章后面的后台渲染演示程序时该标识符的设置为非0。

       Format参数将确定每个颜色成分使用的位数,同样,颜色成分的数量确定了整幅图像的大小。从文件加载图像时,可以将该参数设为0,这样Direct3D可以根据文件自身的内容选择正确的图像格式。从文件加载图像时,也不可能总知道图像的格式。

       Pool参数确定了纹理对象驻留的内存类别。该参数可以取值为D3DPOOL_DEFAULT,这样可以将内存放置到视频内存中(这是默认的);取值为D3DPOOL_MANAGED时,则是将纹理对象保存在系统内存中;当Pool取值为D3DPOOL_SYSTEMMEN时,则是将纹理对象保存在计算机的RAM内存中。如果Direct3D设备丢失,则不必重新创建资源。使用经过管理的资源可以避免在设备丢失的情况下恢复纹理对象。

       D3DXCreateTexture()函数原型中的最后一个参数通过函数调用正在创建的纹理对象。如果调用该函数后,该参数不为NULL(空),并且如果函数的返回值为D3D_OK,则函数调用成功。

    创建Direct3D纹理要用到另一个函数是D3DXCreateTextureFromFile()。该函数会通知Direct3D从指定的文件加载纹理并将其加载到内存中,该函数的原型如:

HRESULT WINAPI D3DXCreateTextureFromFile(
LPDIRECT3DDEVICE9 pDevice,
// 设备对象
LPCTSTR pSrcFile, // 图像文件名
LPDIRECT3DTEXTURE9 * ppTexture // 用来储存载入图片的纹理对象实例
);

  为了使从文件加载图像的方法发挥更多的控制作用,可以使用D3DXCreateTextureFromFileEx()函数:

HRESULT WINAPI D3DXCreateTextureFromFileEx(
LPDIRECT3DDEVICE9 pDevice,
// D3D设备对象
LPCTSTR pSrcFile, // 指明加载图像位置的字符串
UINT Width, // 图像宽度
UINT Height, // 图像高度
UINT MipLevels, // 图片的图层,一般用D3DX_DEFAULT,与图像质量有关
DWORD Usage, //设定这个纹理的使用方法
D3DFORMAT Format, // 每个颜色成分使用的位数
D3DPOOL Pool, // 纹理对象驻留的内存类别
DWORD Filter, // 处理图像质量,并控制D3D填充图像数据的方法
DWORD MipFilter, // 像素过滤方式
D3DCOLOR ColorKey, // 透明色,设定这个颜色,在显示时,这图像中的这个颜色将忽略
D3DXIMAGE_INFO * pSrcInfo, // 记录载入图片信息
PALETTEENTRY * pPalette, // 记录调色板信息
LPDIRECT3DTEXTURE9 * ppTexture // 用来储存载入图片的纹理对象实例
);

  该函数的参数包括pDevice、Width、Height、MipLevels、Usage、Format、Pool、和ppTexture等,最后一个参数和D3DXCreateTexture()函数中的该参数的定义相同。参数pSrcFile是指明加载图像位置的字符串,它和D3DXCreateTextureFromFile()函数中的该参数的功能相同。

       Filter参数处理图像质量,并控制Direct3D填充图像数据的方法。在指明纹理图像为原始图像宽度和高度一半,或是比原始图像小时,这个参数非常有用。例如,如果使用该函数创建的图像只有原始图像尺寸的一半,那么可以使用D3DX_FILTER_BOX标识符。这样就会用2×2的盒子将图像的像素平均处理。查看DirectX文档的D3DX_FILTER一节内容,可以看到该参数可以使用的多个标识值。

       MipFilter参数除了用于纹理图像的mipmap之外,和Filter参数完全相同。滤镜的目的是为了控制要加载到图形应用程序中的纹理图像质量。有时候,最终可以在不放弃全部图像质量的情况下,使用低质量的滤波,获取应用的纹理图像质量。

       ColorKey参数是用于指定图像中像素透明或不可见时的颜色值。可以将与发送给该参数的颜色相配的每个像素设为透明,并且可以用纯黑色替代。这对那些有一部分内容不可见的图像,例如菜单按钮和句色的二维图像,非常有用。

       pSrcInfo参数返回一个包含原始图像所有信息的结构。该信息存储在D3DIMAGE_INFO结构中,包含了图像的原始宽度和高度、格式、深度、Mip级别、资源类型和文件格式类型。

       最后一个新出现的参数pPalette用于返回用该函数加载的所有经过调色处理的纹理图像的调色板。典型情况下,这些图像是8位图像(即所有的颜色成分都是8位的),如今很少使用。过去该函数被限制了在纹理中可以使用的位数。调色板可以采用8位数据。并以足够好的级别将纹理显示在屏幕上。如今使用的是32位的图像,比以前要高很多,所以要更好地在屏幕上显示纹理,没必要使用调色板。将纹理对象加载到内存后,接下来可以将它显示在3D场景中的某个表面上。使用Direct3D设备对象的SetTexture()函数可以完成这项工作。要在渲染所有假设要在表面上显示该纹理的几何图形前调用该函数。SetTexture()函数只有两个参数,函数原型:

HRESULT SetTexture(
DWORD Sampler,
// 纹理要施加的采样器阶段
IDirect3DBaseTexture9 * pTexture // Direct3D9纹理对象
);

   SetTexture()函数中的第一个参数是纹理要施加的采样器阶段。该参数值位于0~1之间。支持纹理的最大数量取决于硬件。调用Direct3D对象的GetDeviceCaps()函数,并使用该函数填充D3DCAP9对象就可以了解计算机的硬件性能。D3DCAP9对象成员存储了采样器阶段总数,该对象的值要么是MaxSimultaneousTexture,要么是MaxTextureBlendStages。

       SetTexture()函数中的最后一个参数是Direct3D9纹理对象。如果函数中该参数的值为NULL,就会清空限定在采样器阶段的所有纹理。

纹理坐标

最后要做的事情是为顶点指定纹理坐标。纹理坐标是一对浮点值,用于访问纹理图像中的信息。在处理二维图像时,纹理坐标范围从0.0~1.0,分别称为“tu”和“tv”。tu和tv分别用于设置顶点纹理信息起始位置的宽度比和高度比。可以在多边形表面上的不同点之间对纹理图像做内插处理。重要的是在定义纹理坐标时要保持一致,这样才能按照预期的方式映射图像。

        为了指明顶点的纹理坐标,必须在顶点纹理结构中指定两个以上的浮点值,并且要为顶点FVF添加一个新的标识符。具体示例如程序清单4.5所示。

更新后用于2D纹理映射的顶点结构和FVF标识符

struct stD3DVertex
{
float x, y, z;
unsigned
long color;
float tu, tv;
};

#define D3DFVF_VERTEX(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)

  因为顶点结构中有两个新的浮点参数,所以要确保图元定义了所有必要的信息。

使用纹理坐标定义图元的示例

    {-0.3f, -0.4f, 0, D3DCOLOR_XRGB(255, 255, 255), 0, 1},
{
0.3f, -0.4f, 0, D3DCOLOR_XRGB(255, 255, 255), 1, 1},
{
0.3f, 0.4f, 0, D3DCOLOR_XRGB(255, 255, 255), 1, 0},

{
0.3f, 0.4f, 0, D3DCOLOR_XRGB(255, 255, 255), 1, 0},
{
-0.3f, 0.4f, 0, D3DCOLOR_XRGB(255, 255, 255), 0, 0},
{
-0.3f, -0.4f, 0, D3DCOLOR_XRGB(255, 255, 255), 0, 1}
};

   纹理坐标的开始位置在图像的左上角(tu=0, tv=0),结束位置在图像的右下角。左上角的位置设定在纹理坐标的(0, 0)处,左下角的位置在(0, 1)处,右上角的位置在(1, 0)处,右下角的位置在(1, 1)处。这之间可以是0~1之间的任何数值(如0.2和0.5等)。

借助纹理坐标可以使用纹理图像的任意部分内容。如果只想使用一半的纹理,那么只要将纹理坐标的水平方向和垂直方向各设为0.5即可。

Mipmap

Mipmap是一系列纹理,它包含了低分辨率的原始纹理图像。每个Mipmap级别有一个宽度和高度,它们分别是该Mipmap之前的那个Mipmap级别的一半。例如,第一个mip级别是原始纹理宽度和高度的一半,而第二个mip级别则是第一个mip级别纹理宽度和高度的一半。使用Mipmap的目的是在观察者靠近或远离某个表面时为纹理图像保留幅度比,这也可称为缩小率和放大率。同样借助Mipmap可以减小需要将纹理发送给渲染管道的带宽。如果物体远离观察视角,那么只要使用较低的分辨率替代原始分辨率即可。这样做的好处就是还可以提高性能。只要在程序中设置了Mipmap级别,Direct3D就负责为程序调用正确的Mipmap级别。

对于D3DXCreateTextureFromFile()和D3DXCreateTexture()函数中的Miplevels和MipFilter两个参数,为它们设定不同的参数值即可完成Mipmap的设置。Direct3D可以生成Mipmap,所以实际上在图像编辑器中没必要手动创建这些Mipmap。Mipmap示例如图

纹理图像的Mipmap级别示例(从256×256到128×128再到64×64,依此类推)

纹理质量
        有很多不同的可供选择的纹理采样模式,每种模式都会影响到纹理对象在Direct3D中的外观。默认情况下,Direct3D(和OpenGL)使用最近点采样模式。这种采样模式最快也最简单,并且它使用对应于顶点纹理坐标的最近纹理像素将纹理映射到表面上。使用程序清单4.7中的代码可以设置最近点纹理过滤。

g_D3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);

g_D3DDevice
->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);

g_D3DDevice
->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);

   如程序清单4.7所示的一样,可以将滤波模式设置为min(缩小率)、mag(放大率)和mip(mipmap)。

SetSamplerState()函数的参数包括采样器阶段(或纹理单位,该值在0~1之间)、要选择的模式以及要设置的状态值。

       为了使用线性滤波,可以将采样器的状态设置为D3DTEXF_LINEAR。D3DTEXF_LINEAR Direct3D(和OpenGL)中使用的纹理滤波技术是双线性纹理滤波技术。在对min、mag和mip使用D3DTEXF_LINEAR时,双线性滤波基于2×2区域中距离采样点4个最近的纹理像素进行滤波。这种滤波方式要比不使用滤波方式或使用最近点滤波可以获得更好的图像质量,但它的计算速度不快。在对min、mag和mip使用线性滤波使,也可以采用三线滤波。这一点可以从滤波模式设定为bi或是tri看出。

       各向同性滤波是可以实现的第三种滤波模式。双线性滤波和三线滤波的主要问题在于当表面和观察者之间有急剧的角度变化时,就会出现块斑。这类问题被称为各想同性失真。使用各向同性滤波就可以避免出现块斑,并且在渲染纹理图像时能获取最佳的质量。虽然各向同性滤波的质量很高,但它的计算速度是最慢的。将采样器状态设置为D3DTEXF_ANISOTROPIC就可以使用各向同性滤波。

Textures演示程序

#include<d3d9.h>
#include
<d3dx9.h>

#define WINDOW_CLASS "UGPDX"
#define WINDOW_NAME "D3D Texture Mapping"
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480

// Function Prototypes...
bool InitializeD3D(HWND hWnd, bool fullscreen);
bool InitializeObjects();
void RenderScene();
void Shutdown();


// Direct3D object and device.
LPDIRECT3D9 g_D3D = NULL;
LPDIRECT3DDEVICE9 g_D3DDevice
= NULL;

// Matrices.
D3DXMATRIX g_projection;
D3DXMATRIX g_ViewMatrix;

// Vertex buffer to hold the geometry.
LPDIRECT3DVERTEXBUFFER9 g_VertexBuffer = NULL;

// Holds a texture image.
LPDIRECT3DTEXTURE9 g_Texture = NULL;

// A structure for our custom vertex type
struct stD3DVertex
{
float x, y, z;
unsigned
long color;
float tu, tv;
};

// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_VERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)


LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(
0);
return 0;
break;

case WM_KEYUP:
if(wParam == VK_ESCAPE) PostQuitMessage(0);
break;
}

return DefWindowProc(hWnd, msg, wParam, lParam);
}


int WINAPI WinMain(HINSTANCE hInst, HINSTANCE prevhInst, LPSTR cmdLine, int show)
{
// Register the window class
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
WINDOW_CLASS, NULL };
RegisterClassEx(
&wc);

// Create the application's window
HWND hWnd = CreateWindow(WINDOW_CLASS, WINDOW_NAME, WS_OVERLAPPEDWINDOW,
100, 100, WINDOW_WIDTH, WINDOW_HEIGHT,
GetDesktopWindow(), NULL, wc.hInstance, NULL);

// Initialize Direct3D
if(InitializeD3D(hWnd, false))
{
// Show the window
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);

// Enter the message loop
MSG msg;
ZeroMemory(
&msg, sizeof(msg));

while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage(
&msg);
DispatchMessage(
&msg);
}
else
RenderScene();
}
}

// Release any and all resources.
Shutdown();

// Unregister our window.
UnregisterClass(WINDOW_CLASS, wc.hInstance);
return 0;
}


bool InitializeD3D(HWND hWnd, bool fullscreen)
{
D3DDISPLAYMODE displayMode;

// Create the D3D object.
g_D3D = Direct3DCreate9(D3D_SDK_VERSION);
if(g_D3D == NULL) return false;

// Get the desktop display mode.
if(FAILED(g_D3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode)))
return false;

// Set up the structure used to create the D3DDevice
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(
&d3dpp, sizeof(d3dpp));

if(fullscreen)
{
d3dpp.Windowed
= FALSE;
d3dpp.BackBufferWidth
= WINDOW_WIDTH;
d3dpp.BackBufferHeight
= WINDOW_HEIGHT;
}
else
d3dpp.Windowed
= TRUE;
d3dpp.SwapEffect
= D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat
= displayMode.Format;

// Create the D3DDevice
if(FAILED(g_D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_D3DDevice)))
{
return false;
}

// Initialize any objects we will be displaying.
if(!InitializeObjects()) return false;

return true;
}


bool InitializeObjects()
{
// Fill in our structure to draw an object.
// x, y, z, color, texture coords.
stD3DVertex objData[] =
{
{
-0.3f, -0.4f, 0, D3DCOLOR_XRGB(255,255,255), 0, 1},
{
0.3f, -0.4f, 0, D3DCOLOR_XRGB(255,255,255), 1, 1},
{
0.3f, 0.4f, 0, D3DCOLOR_XRGB(255,255,255), 1, 0},

{
0.3f, 0.4f, 0, D3DCOLOR_XRGB(255,255,255), 1, 0},
{
-0.3f, 0.4f, 0, D3DCOLOR_XRGB(255,255,255), 0, 0},
{
-0.3f, -0.4f, 0, D3DCOLOR_XRGB(255,255,255), 0, 1}
};

// Create the vertex buffer.
if(FAILED(g_D3DDevice->CreateVertexBuffer(sizeof(objData), 0,
D3DFVF_VERTEX, D3DPOOL_DEFAULT,
&g_VertexBuffer, NULL))) return false;

// Fill the vertex buffer.
void *ptr;

if(FAILED(g_VertexBuffer->Lock(0, sizeof(objData),
(
void**)&ptr, 0))) return false;

memcpy(ptr, objData,
sizeof(objData));

g_VertexBuffer
->Unlock();


// Load the texture image from file.
if(D3DXCreateTextureFromFile(g_D3DDevice, "ugp.tga",&g_Texture) != D3D_OK) return false;

// Set the image states to get a good quality image.
// 设置放大过滤器为线性过滤器
g_D3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
// 设置缩小过滤器为线性过滤器
g_D3DDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

// Set default rendering states.
g_D3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
g_D3DDevice
->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

// Set the projection matrix.
D3DXMatrixPerspectiveFovLH(&g_projection, 45.0f,
WINDOW_WIDTH
/WINDOW_HEIGHT, 0.1f, 1000.0f);

g_D3DDevice
->SetTransform(D3DTS_PROJECTION, &g_projection);

// Define camera information.
D3DXVECTOR3 cameraPos(0.0f, 0.0f, -1.0f);
D3DXVECTOR3 lookAtPos(
0.0f, 0.0f, 0.0f);
D3DXVECTOR3 upDir(
0.0f, 1.0f, 0.0f);

// Build view matrix.
D3DXMatrixLookAtLH(&g_ViewMatrix, &cameraPos,
&lookAtPos, &upDir);

return true;
}


void RenderScene()
{
// Clear the backbuffer.
g_D3DDevice->Clear(0, NULL, D3DCLEAR_TARGET,
D3DCOLOR_XRGB(
0,0,0), 1.0f, 0);

// Begin the scene. Start rendering.
g_D3DDevice->BeginScene();

// Apply the view (camera).
g_D3DDevice->SetTransform(D3DTS_VIEW, &g_ViewMatrix);

// Draw square.
g_D3DDevice->SetTexture(0, g_Texture);
g_D3DDevice
->SetStreamSource(0, g_VertexBuffer, 0, sizeof(stD3DVertex));
g_D3DDevice
->SetFVF(D3DFVF_VERTEX);
g_D3DDevice
->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);

// End the scene. Stop rendering.
g_D3DDevice->EndScene();

// Display the scene.
g_D3DDevice->Present(NULL, NULL, NULL, NULL);
}


void Shutdown()
{
if(g_D3DDevice != NULL) g_D3DDevice->Release();
g_D3DDevice
= NULL;

if(g_D3D != NULL) g_D3D->Release();
g_D3D
= NULL;

if(g_VertexBuffer != NULL) g_VertexBuffer->Release();
g_VertexBuffer
= NULL;

if(g_Texture != NULL) g_Texture->Release();
g_Texture
= NULL;
}

/*
分配一个纹理到一个设备层
HRESULT SetTexture(
DWORD Stage,
IDirect3DBaseTexture9 *pTexture
);
参数(Parameters)
Stage
[in] Stage identifier to which the texture is set. Stage identifiers are zero-based. The maximum
number of stages supported is determined from two caps: D3DCAPS.MaxSimultaneousTextureStages and
D3DCAPS9.MaxTextureBlendingStages.
Displacement Mapping uses a special stage index, called D3DDDMAPSAMPLER.
Vertex Textures use a special stage index called D3DVERTEXTEXTURESAMPLER.

[in(用户给出参数的值)]标志要设置纹理的设备层,从0开始.支持的最大设备层数由两个标志决定:

D3DCAPS.MaxSimultaneousTextureStages 和 D3DCAPS9.MaxTextureBlendingStages.

位移映射 使用特殊的层索引,称为 D3DDDMAPSAMPLER

顶点文理 使用特殊的层索引,称为 D3DVERTEXTEXTURESAMPLER

pTexture
[in] Pointer to an IDirect3DBaseTexture9 interface, representing the texture being set.

IDirect3DBaseTexture9的指针,代表要设置的纹理
返回值(Return Value)

If the method succeeds, the return value is D3D_OK.

If the method fails, the return value can be D3DERR_INVALIDCALL.

如果该方法成功,返回值是D3D_OK

如果该方法失败,返回值可能是D3DERR_INVALICALL

备注(Remarks)

IDirect3DDevice9::SetTexture is not allowed if the texture is created with a pool type of D3DPOOL_SCRATCH.
IDirect3DDevice9::SetTexture is not allowed with a pool type of D3DPOOL_SYSTEMMEM texture unless DevCaps is set with D3DDEVCAPS_TEXTURESYSTEMMEMORY.

IDirect3DDevice9::SetTexture 不允许(调用)若文理是以D3DPOOL_SCRATCH类型池创建的话.

同样D3DPOOL_SYSTEMMEM池类型创建的纹理也不允许,除非DevCaps设置为D3DDEVCAPS_TEXTURESYSTEMMEMORY.


调用IDirect3DDevice9::SetSamplerState(),可分别设置纹理过滤的放大过滤器和缩小过滤器。
将第一个参数设置为纹理过滤器关联的纹理层序号(0~7)。如果要设置放大过滤器,第二个
参数设为D3DSAMP_MAGFILTER,如果要设置缩小过滤器,第二个参数设为D3DSAMP_MINFILTER。第
三个参数可设为表示最近点采样的枚举常量D3DTEXF_POINT。下列代码将纹理层0的纹理过滤方式
设置为最近点采样。
g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);

如果纹理的大小和屏幕图元的实际大小将近,那么采用最近点采样方法对图像质量的影响不大。
但是,如果大小相差太多,就会降低图像精度,从而影响图像质量,出现色块或闪烁的失真现象。
*/

  

最近点采样

最近点采样是4种过滤方式中速度最快但效果最差的过滤方式。Direct3D计算得到的纹理元素地址通常是一个浮点数值,而非整数的纹理下标值,当使用最近点采样时,Direct3D会复制与这个浮点值地址最接近的整数地址的纹理元素的颜色。

设置最近点采样的具体方法如下:调用IDirect3DDevice9::SetSamplerState(),可分别设置纹理过滤的放大过滤器和缩小过滤器。将第一个参数设置为纹理过滤器关联的纹理层序号(0~7)。如果要设置放大过滤器,第二个参数设为D3DSAMP_MAGFILTER,如果要设置缩小过滤器,第二个参数设为D3DSAMP_MINFILTER。第三个参数可设为表示最近点采样的枚举常量D3DTEXF_POINT。下列代码将纹理层0的纹理过滤方式设置为最近点采样。

g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);

如果纹理的大小和屏幕图元的实际大小将近,那么采用最近点采样方法对图像质量的影响不大。但是,如果大小相差太多,就会降低图像精度,从而影响图像质量,出现色块或闪烁的失真现象。

 

线性纹理过滤

线性纹理过滤是目前使用最广泛的纹理过滤方法。它与最近点采样相比,能有效地提高图像的显示质量,并且对系统性能影响不大。线性纹理过滤取得与计算得到的纹理元素的浮点地址最接近的上、下、左、右4个纹理元素,对这4个纹理元素进行加权平均,得到最终显示的颜色值。

与设置最近点采样的方法相似,调用函数IDirect3DDevice9::SetSamplerState()设置线性纹理过滤,所不同的是第三个参数设置为D3DTEXF_LINEAR。下面的代码将纹理层0的放大和缩小过滤器设置为线性纹理过滤。

g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);

因为是在单一纹理层上的线性过滤,而且是x、y方向上的线性过滤,所以称为双线性纹理过滤。目前大多数显卡都为线性纹理过滤进行了优化,所以使用线性纹理过滤一方面可以获得较好的图形质量,另一方面对程序性能影响不大。

 

各项异性纹理过滤

当三维物体表面与投影平面不平行时,它在屏幕上的投影会有拉长或扭曲,这种现象称为各项异性(anisotropy)。当一个各向异性图元的像素映射到纹理元素时,它的形状发生扭曲。Direct3D根据屏幕像素反向转换到纹理元素的延长度,决定各项异性程度。

要使用各项异性纹理过滤,还应当设置最大各项异性程度值。通过将函数IDirect3DDevive9::SetSamplerState()的第一个参数设为纹理层索引,第二个参数设为D3DSAMP_MAXANISOTOPY,第三个参数设为大于1的任何值,可以完成最大各项异性程度值的设置。下面的示例代码指定了最大各项异性值为4。

g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
g_device->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, 4);

最大各项异性程度值D3DSAMP_MAXANISOTROPY为1时,表示禁用各项异性过滤。一般说来,其值越大,图像效果越好,计算量越大,速度越慢。需要注意的是,在设置最大各项异性之前,应调用IDirect3D9::GetDeviceCaps()函数,查询当前设备支持的Direct3D特性,获取当前设备支持的最大各项异性度的取值范围,具体代码如下:

DWORD get_max_anisotropy(IDirect3DDevice9* device)
{
D3DCAPS9 caps;
device->GetDeviceCaps(&caps);

	return caps.MaxAnisotropy;
}

//

1.什么是纹理坐标呢?
一般的纹理都是一个二维的图片,比如一幅画什么的,纹理坐标就是指画中每一个像素的坐标。当然还有其他格式的坐标,比如3为坐标---立体纹理坐标;一维坐标等等。

2.纹理坐标有啥用呢?
当画一个primitive的时候,需要给这个primitive填充颜色,当然不是简简单单的刷上一个颜色,要的是更复杂的东东。这个时候就需要给这个primitive指定一个纹理,制定完成后就等着画图了。画图的时候,DirectX 根据指定的primitive中的坐标------0.0到1.0,从纹理中去取,比如把一个纹理的都整个设置给了一个primitive,然后(0.5, 0.7)这个点的颜色就是(0.5*texture_width, 0.5*texture_height)的颜色值,当然啦,如果取出来的坐标不是一个整数,那么就最近取一个点的色值了。通过这种方法达到给primitive中的每个点赋值来达到显示效果。

当然啦,也可以不指定整个坐标给primitive,比如只想设置纹理的上半面给primitive,则设置纹理坐标为(0.0, 0.0) ,(0.5, 0.0); (0.0, 0.5),(0.5,0.5)

3.坐标映射的过程:
屏幕中的每个像素坐标映射到primitive上(当然,也可以说成每个primitive坐标映射到屏幕上),延后映射后的像素坐标(primitive坐标)再去从相应的纹理中根据纹理坐标来去除该坐标对应点的色值。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

D3D纹理 的相关文章

  • 如何以编程方式在 qml 中渲染 vtk 项目?

    到目前为止 我了解到我们在 QML 中有两个线程 我们的主应用程序线程和我们的 场景图 线程 http doc qt io qt 5 qtquick visualcanvas scenegraph html http doc qt io q
  • 使用 openGL、SOIL 加载图像

    我尝试了很多使用 SOIL 在 openGL 中加载和显示图像的示例 运行下面的源代码时 它仅显示一个没有图像的白色四边形 我尝试打开一个名为 foto 的图像 我将图像文件放在程序的文件夹中 bool keyStates new bool
  • 如何将 3D 图像输出到 3D 电视?

    我有一台 3D 电视 如果我不至少尝试让它显示我自己创作的漂亮 3D 图像 我就会逃避我的责任 作为一个极客 我之前已经完成了非常基本的 OpenGL 编程 因此我了解所涉及的概念 假设我可以为自己渲染一个简单的四面体或立方体并使其旋转一点
  • 纹理openGl。 C++、qt

    我试图用草纹理覆盖我的地形 由高度图制成 但它没有按预期工作 我什至无法在简单的 GL QUAD 上获取纹理 结果是多色网络 void GLWidget initializeGL glEnable GL TEXTURE 2D 在 QGLwi
  • (定义一个宏)方便OpenGL命令调试?

    有时插入条件打印和检查需要很长时间glGetError 使用二分搜索的形式来缩小范围 其中第一个函数调用是 OpenGL 首先报告错误 我认为如果有一种方法可以构建一个宏 我可以包装所有可能失败的 GL 调用 并有条件地调用 那就太酷了gl
  • 在 OpenGL 中,为什么 glVertexAttribPointer 要求“指针”参数以 void* 形式传入?

    规格为glVertexAttribPointer如下 void glVertexAttribPointer GLuint index GLint size GLenum type GLboolean normalized GLsizei s
  • OpenGL:调试“单通道线框渲染”

    我正在尝试实现论文 单通道线框渲染 它看起来很简单 但它给了我所期望的厚暗值 论文没有给出计算海拔高度的确切代码 所以我按照自己认为合适的方式进行了操作 代码应该将三个顶点投影到视口空间中 获取它们的 高度 并将它们发送到片段着色器 片段着
  • 使用 glDrawElements 时在 OpenGL 核心配置文件中选取三角形

    我正在使用 glDrawElements 绘制三角形网格 并且希望能够使用鼠标单击来拾取 选择三角形 三角形的网格可以很大 在固定功能 OpenGL 中 可以使用 GL SELECT http content gpwiki org inde
  • 为什么我的 FPS 相机一劳永逸地滚动?

    如果我忽略四元数代数的肮脏细节 我想我理解了旋转和平移变换背后的数学 但仍然不明白我做错了什么 为什么我的相机一劳永逸地滚动 更具体地说 我应该如何从相机的方向 旋转矩阵 计算相机视图矩阵 我正在用 Python 编写一个简约的 3d 引擎
  • 如何安装适用于 Windows C++ 的最新版本 OpenGL?

    我正在使用 Visual Studio 2010 运行 Windows 7 包含的 OpenGL 版本 include 是版本 1 1 我希望使用合理的当前版本 某种版本 3 或 4 我需要做什么才能达到该状态 OpenGL SDK 页面位
  • OpenGL 着色器不与着色器程序链接

    我正在尝试使用 GLFW GLEW 添加着色器 我收到一个错误 指出着色器已加载 但它们没有有效的对象代码 这是我用于加载着色器的代码 class SHADER public void LoadShaders const char vert
  • 使用 GLSL 着色器在同一片段着色器中定义的多个子例程类型无法正常工作

    我正在开发一个使用 GLSL 着色器的程序 我编写了 2 种不同的方法来用 2 种不同的方法计算 ADS 环境光 漫反射 镜面反射 着色 为了正确完成这项工作 我使用子例程来使用一种或另一种方法来计算 ADS 着色 这是片段着色器代码的一部
  • 将像素传递给 glTexImage2D() 后会发生什么?

    例如 如果我创建一个像素数组 如下所示 int getPixels int pixels new int 10 pixels 0 1 pixels 1 0 pixels 1 1 etc glTexImage2D getPixels glTe
  • 使用draw()而不是eventloop时的pyglet

    我正在尝试用 pyglet 画一个圆 但当我使用 draw 函数而不是 app run 循环时 它是不可见的 有什么建议我可以做什么吗 谢谢 from math import from pyglet gl import window pyg
  • 安卓后退按钮不起作用

    我正在使用 cocos2dx 制作一个小游戏 在游戏的活动中我提供以下函数来处理后退按钮 Override public boolean onKeyDown int keyCode KeyEvent event return super o
  • 为什么拥有单独的投影矩阵但结合模型和视图矩阵会有好处?

    当您学习 3D 编程时 您会被告知用 3 个变换矩阵来思考是最简单的 模型矩阵 该矩阵对于每个模型都是独立的 它根据需要旋转和缩放对象 最后将其移动到 3D 世界中的最终位置 模型矩阵将模型坐标转换为世界坐标 视图矩阵 对于大量对象 如果不
  • GLSL NVidia 方形神器

    当 GLSL 着色器在以下 GPU 上生成不正确的图像时 我遇到了问题 GT 430 GT 770 GTX 570显卡760 但在这些上正常工作 英特尔高清显卡 2500英特尔高清4000英特尔4400显卡740MRadeon HD 631
  • Glew+GLFW Win32 无依赖项 Visual Studio

    是否可以在不将文件复制到 C 的情况下构建并链接 Glew 和 GLFW 我找不到任何说明如何在不将 DLL 复制到 C 上的 Visual Studio 目录的情况下使用这些库的文档 我只想包含项目目录中所需的所有 dll 和 lib 文
  • [cocos2d-x]当我尝试在 Windows 10 中运行“python android-build.py -p 19 cpp-tests”时出现错误

    当我尝试运行命令时python android build p cpp tests 我收到如图所示的错误 在此之前 我收到了另一条关于 Android SDK Tools 版本兼容性的错误消息 所以 我只是将 sdk 版本从 26 0 0
  • 如何仅剪切剪切平面的交集(而不是并集)?

    在 OpenGL JOGL 中 当使用多个剪切平面时 似乎会应用所有剪切平面的并集 我想要的是路口要应用的所有剪裁平面 这可能吗 请参阅下面的简化二维示例 Edit An example of clipping by vertex shad

随机推荐

  • lrzsz hisi 移植

    configure prefix INSTALL make CC aarch64 mix210 linux gcc
  • C++:vector

    目录 一 关于vector 二 vector的相关函数 三 相关函数的使用 构造函数 size 编辑 push back 迭代器iterator reserve resize find insert erase sort 一 关于vecto
  • 亚马逊运营:A9排序算法与A10排序算法对比

    文章目录 1 A9算法 2 A10算法 4 技巧 5 参考 1 A9算法 当我们在亚马逊电商平台上搜索一个query 对应返回多个商品 商品排序越靠前 曝光机会越多 越能够被用户点击进而提高转化 满足搜索query的商品特别多 那么亚马逊搜
  • Android Studio 3.0 清除项目用不到的资源

    自己也是一直找 一直找 真正要清除无用资源需要通过Android studio的 Remove Unused Resources选项功能来清除无用资源 操作步骤 选中工程 右键选中Refactor 从Refactor中选中Remove Un
  • Econometrics/Stata再学习(一)

    Tips 1 For large data set memory 2 price index 长时间数据要注意平价 3 在做调查之前 一定要先思考想要什么样的图 是否又方差差异 大体趋势的形式 再去设计问卷问题 调查策略 从相关性到因果关系
  • 通过java实现微信公众号发送微信消息

    感谢好多老哥提供的文档 哈哈 这里我就只是代码贴出来 方便以后copy 1获取token String token Wechat getAccess token appId appSecret getString access token
  • repost: mysql之row_format、溢出页(overflow pages)、mysql数据类型(varchar、text、blob、json)

    repost https blog csdn net aecuhty88306453 article details 102196591 MySQL数据行 row format 溢出的深入理解 在 mysql中 若一张表里面不存在varch
  • mysql 函数使用

    1 GROUP CONCAT 功能 将group by产生的同一个分组中的值连接起来 返回一个字符串结果 语法 group concat distinct 要连接的字段 order by 排序字段 asc desc separator 分隔
  • 苹果APP安装包ipa如何安装在手机上

    苹果APP安装包ipa如何安装在手机上 苹果APP的安装比安卓复杂且困难 很多人不知道如何将ipa文件安装到手机上 以下是几种苹果APP安装在iOS设备的方式 供大家参考 一 上架App Store 这是最正规的方式 虽然审核过程复杂 时间
  • idea 部署SpringBoot项目时打成jar包一些坑的总结

    前一段时间 公司分配给我做一些微服务的功能 比如一些分析 一些可以拿出来的模块 所以采用了SpringBoot搭建的微服务项目 至于关于SpringBoot的介绍 这里就不展开了 今天主要写的是这两天我需要把我本地的项目部署到服务器上 遇到
  • HTML输入框标签

    1
  • 华院计算|切比雪夫,他带起了俄罗斯现代数学的发展

    俄罗斯的数学家们常说 他们的现代数学是由切比雪夫带动而建立和发展起来的 图1 帕夫努蒂 切比雪夫 1869年 帕夫努蒂 切比雪夫 Pafnuty Lvovich Chebyshev 1821年5月16 日 1894年12月8日 出生于离莫斯
  • 编译ORBSLAM2中遇到的一些问题

    从github中下载源码后 按照readme一步步来 安装完各种依赖后 直接运行了build sh 需要注意的是 之前在14 04中安装完依赖后 cmake报错 根据错误信息锁定为cmake版本低 于是重装了cmake 3 9 成功编译 后
  • java 判断当天_java判断一个时间是否是今天的方法

    java判断时间是否是今天 public class Test java 判断一个时间是不是今天的时间范围内 param args public static void main String args String time 2017 0
  • [计算机毕业设计]基于OpenCV的图像梯度与边缘检测

    目录 前言 课题背景与意义 课题实现技术思路 一 图像梯度与几种算子 三 基于OpenCV的实现 最后 前言 大四是整个大学期间最忙碌的时光 一边要忙着准备考研 考公 考教资或者实习为毕业后面临的就业升学做准备 一边要为毕业设计耗费大量精力
  • LinkedHashSet和LinkedHashMap手记

    LinkedHashSet和LinkedHashMap手记 LinkedHashSet和LinkedHashMap是Java集合框架中的两个重要类 它们是HashSet和HashMap的变体 它们在维护插入顺序方面提供了额外的功能 这使得它
  • WVP-PRO+ZLMediaKit搭建GB28181视频平台(linux详细教学)

    文章目录 一 安装WVP PRO 1 源码下载 链接内任选其一 https doc wvp pro cn 2 修改配置 仔细查看每行都有说明注释 3 编译前端页面 4 打包为jar 上传到服务器 二 安装ZLMediaKit 1 前置环境安
  • Android10 Settings系列(五)恢复出厂设置添加重启和关机按钮,增加恢复出厂设置电量限制

    一 前言 这个应该算是一个通用需求 因为源码中的恢复出厂设置确实只有关机 没有恢复出厂设置之后重启的功能 二 准备工作 恢复出厂设置这个找到对应的类很简单 这里直接给出对应的处理类 packages apps Settings src co
  • jaspersoft studio6.x 设计医院检查报告单样式

    今天百度无意检索到医院的检查报告单 我想尝试一下自己对jaspersoft studio6 x 报表工具的掌握情况 我简单编写了一个血液检查单 效果展示如下 百度图片库关于血液检查报告单样式 jaspersoft studio 设计截图 源
  • D3D纹理

    纹理映射是一种将图形施加到表面的技术 以简单的一堵墙为例 这种技术可以只需要两个绘制有砖纹理的三角形即可 这样就可以为表面增加大量的细节 而不必使用大量的多边形 纹理映射使用了图像数据并将图像数据绘制 映射 到表面上 该表面看上去就像有一幅