7 纹理映射

  借助纹理映射技术,可以把图像数据映射到三角形单元中,为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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值