7 纹理映射

来源:互联网 发布:网络照片素材 编辑:程序博客网 时间:2024/05/01 05:00

  借助纹理映射技术,可以把图像数据映射到三角形单元中,为3D图型添加更具细节的描绘

使用纹理映射,需要学习

映射方式

纹理创建

纹理过滤


纹理坐标

D3D所使用的纹理坐标由平面坐标构成  水平u轴 和 竖直v轴

由坐标对 (u,v)标识的纹理元素称为纹理元

之前说过,纹理映射是把图像数据映射到三角形单元中,在3d世界中所有的单元都是由三角形构成的

要实现纹理映射,需要给顶点中添加一项纹理坐标  D3DFVF_TEX1

为每个需要纹理映射的图形的顶点添加相应的纹理坐标点,相当于每个三角形在纹理图像中都有对应的纹理块

纹理映射在图形3d变换到屏幕坐标,光栅化过程中才会进行,在此之前,3d流水线处理的都是大量的三角形组成的网格


创建和启用纹理

纹理创建函数

 HRESULT  D3DXCreateTextureFromFile(  __in   LPDIRECT3DDEVICE9 pDevice,  __in   LPCTSTR pSrcFile,  __out  LPDIRECT3DTEXTURE9 *ppTexture);

从文件载入纹理,可以载入格式有:.bmp, .dds, .dib, .hdr, .jpg, .pfm, .png, .ppm, and .tga.

返回值为载入成功或失败原因


载入后,为设备设置当前纹理

共有8层纹理可以设置,多层纹理可以带来更加细腻的视觉效果

初期只用一层:Device->SetTexture(0, Tex);

参数1是纹理层号(0开始),参数2是纹理指针,指向创建的指针,也就是创建函数的输出值


要禁用一层纹理,把参数2设为0即可

如果场景中各个三角形用的纹理不同,可以设置一个画一个,在绘制之前 换掉纹理即可


许多小型游戏的纹理都在一张图片上,使用的时候只需要不同的纹理坐标即可区分


纹理过滤器

在进行纹理映射的时候,大多情况下纹理三角形和屏幕三角形的大小是不同的,这种时候,纹理三角形就必须为了适应屏幕三角形而变化,放大或缩小,在变化的时候会有畸变发生,为了克服这个,诞生了纹理过滤器


D3D有三种过滤器,每种都提供一种质量水平,质量越高,运算开销越大,处理速度越慢

使用哪一种需要在具体情况下权衡


1最近点采样 

默认的方式,处理速度最快,不需要额外的运算,直接提取最近的有纹理的点的纹理

在纹理三角形和屏幕三角形大小差别不大,或者纹理比较简单的时候效果可以接受,但是一旦差别较大就会很畸形


2线性纹理过滤

这是建议使用的纹理过滤,处理效果一般,速度也不错,至少应该使用这种纹理过滤方式


3各向异性纹理过滤

效果最好,需要牺牲速度

在D3D中,需要设定D3DSAMP_MAXANISOTROPY的值

它决定各向异性过滤的质量水平


各向异性过滤  用来过滤、处理当视角变化造成3D物体表面倾斜时做成的纹理错误

两大显卡厂商 ATI和NVIDIA产品都有相应的支持,在显卡驱动中可以设置硬件过滤质量


这里DX里的D3DSAMP_MAXANISOTROPY是取的这个硬件值作为各向异性过滤的最大质量

设置值越大对硬件消耗越大

在设置这个值时,需要先调用设备的 GetDeviceCaps函数检查返回的D3DCAOS9参数,获得取值的范围(不大于硬件支持的最大值)


多级渐进纹理

为了提高纹理映射效率和质量,尽量解决纹理映射时产生的畸变且具备更高效率

解决方法是采用多级渐进纹理,尽量消除屏幕三角形和纹理三角形大小的差异


创建一个多级渐进纹理链,为纹理创建一系列分辨率逐渐减小的纹理图像,并对每个分辨率所采用的过滤方式进行定制

以便保留重要细节,使图像不产生严重失真


多级渐进纹理过滤器用于控制D3D使用多级渐进纹理的方式,做一个设置取值即可

常用值是

D3DTEXF_NONE    禁用多级纹理过滤器

D3DTEXF_POINT   选择与屏幕三角形尺寸最接近的纹理

D3DTEXF_LINEAR  选择与屏幕三角形尺寸最接近的两个纹理,然后取线性组合,形成最终的颜色值

Device->SetSamplerState(0,D3DSAMP_MIPFILTER,Filter)

Filter取值为上述三个常量


由于硬件的良好支持,多级渐进处理速度和效果都不错,应用很多



寻址模式

顶点中的纹理坐标范围都在[0,1]区间,但是实际应用中有很多情况会超过这个范围

D3D中有4种用于应对的寻址模式

重复

边界颜色

钳位

镜像

按照实际需要选择合适的寻址模式


例程

//////////////////////////////////////////////////////////////////////////////////////////////////// // File: texCube.cpp// // Author: Frank Luna (C) All Rights Reserved//// System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0 //// Desc: Renders a textured cube.  Demonstrates creating a texture, setting//       texture filters, enabling a texture, and texture coordinates.  Use//       the arrow keys to orbit the scene.//          //////////////////////////////////////////////////////////////////////////////////////////////////#include "d3dUtility.h"#include "cube.h"#include "vertex.h"//// Globals//IDirect3DDevice9*     Device = 0; const int Width  = 640;const int Height = 480; Cube*              Box = 0;IDirect3DTexture9* Tex = 0;//// Framework Functions//bool Setup(){//// Create the cube.//Box = new Cube(Device);//// Set a directional light.//D3DLIGHT9 light;::ZeroMemory(&light, sizeof(light));light.Type      = D3DLIGHT_DIRECTIONAL;light.Ambient   = D3DXCOLOR(0.8f, 0.8f, 0.8f, 1.0f);light.Diffuse   = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);light.Specular  = D3DXCOLOR(0.2f, 0.2f, 0.2f, 1.0f);light.Direction = D3DXVECTOR3(1.0f, -1.0f, 0.0f);Device->SetLight(0, &light);Device->LightEnable(0, true);Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);Device->SetRenderState(D3DRS_SPECULARENABLE, true);//// Create texture.//D3DXCreateTextureFromFile(Device,"crate.jpg",&Tex);// // Set Texture Filter States.//Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);//// Set the projection matrix.//D3DXMATRIX proj;D3DXMatrixPerspectiveFovLH(&proj,D3DX_PI * 0.5f, // 90 - degree(float)Width / (float)Height,1.0f,1000.0f);Device->SetTransform(D3DTS_PROJECTION, &proj);return true;}void Cleanup(){d3d::Delete<Cube*>(Box);d3d::Release<IDirect3DTexture9*>(Tex);}bool Display(float timeDelta){if( Device ){// // Update the scene: update camera position.//static float angle  = (3.0f * D3DX_PI) / 2.0f;static float height = 2.0f;if( ::GetAsyncKeyState(VK_LEFT) & 0x8000f )angle -= 0.5f * timeDelta;if( ::GetAsyncKeyState(VK_RIGHT) & 0x8000f )angle += 0.5f * timeDelta;if( ::GetAsyncKeyState(VK_UP) & 0x8000f )height += 5.0f * timeDelta;if( ::GetAsyncKeyState(VK_DOWN) & 0x8000f )height -= 5.0f * timeDelta;D3DXVECTOR3 position( cosf(angle) * 3.0f, height, sinf(angle) * 3.0f );D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);D3DXMATRIX V;D3DXMatrixLookAtLH(&V, &position, &target, &up);Device->SetTransform(D3DTS_VIEW, &V);//// Draw the scene://Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);Device->BeginScene();Device->SetMaterial(&d3d::WHITE_MTRL);Device->SetTexture(0, Tex);Box->draw(0, 0, 0);Device->EndScene();Device->Present(0, 0, 0, 0);}return true;}//// WndProc//LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){switch( msg ){case WM_DESTROY:::PostQuitMessage(0);break;case WM_KEYDOWN:if( wParam == VK_ESCAPE )::DestroyWindow(hwnd);break;}return ::DefWindowProc(hwnd, msg, wParam, lParam);}//// WinMain//int WINAPI WinMain(HINSTANCE hinstance,   HINSTANCE prevInstance,    PSTR cmdLine,   int showCmd){if(!d3d::InitD3D(hinstance,Width, Height, true, D3DDEVTYPE_HAL, &Device)){::MessageBox(0, "InitD3D() - FAILED", 0, 0);return 0;}if(!Setup()){::MessageBox(0, "Setup() - FAILED", 0, 0);return 0;}d3d::EnterMsgLoop( Display );Cleanup();Device->Release();return 0;}





0 0