D3D9固定功能渲染流水线

本文详细介绍了Direct3D9的渲染流程,包括库的初始化、设备性能检查、多重采样设置、创建设备、锁定和修改后备缓冲区、COM对象的使用、枚举常量、顶点格式和三大变换、渲染状态、顶点缓冲区和索引缓冲区、Mesh三维网格的创建和操作、颜色处理、灯光和材质、纹理应用、像素混合、摄像机设置,以及拾取和文本显示等关键概念和技术。

1、D3D库的初始化 

//初始化库
IDirect3D9* d3d = 0;
d3d = Direct3DCreate9(D3D_SDK_VERSION);

 2、设备性能检查

//检查设备能力
D3DCAPS9 devCaps;
HRESULT hResult;
hResult = d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &devCaps);
//D3DDEVTYPE_REF
int vp = 0;
if (hResult && (devCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT))
{
     vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
else
{
	vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}

3、多重采样设置

D3DMULTISAMPLE_TYPE multiType = D3DMULTISAMPLE_NONE;
multiType = D3DMULTISAMPLE_8_SAMPLES;
DWORD quality;
d3d->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
	D3DFMT_A8R8G8B8, true, D3DMULTISAMPLE_8_SAMPLES, &quality);

 4、创建设备

//创建设备
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));

d3dpp.BackBufferCount = 1;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferWidth = width;
d3dpp.BackBufferHeight = height;
d3dpp.Windowed = windowed;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.MultiSampleType = multiType;
d3dpp.MultiSampleQuality = quality;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hwnd;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;

hResult = d3d->CreateDevice(D3DADAPTER_DEFAULT, devtype, hwnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
		&d3dpp, dev);
if (FAILED(hResult))
{
	d3d->Release();
	d3d = 0;
	return false;
}

 5、锁定和修改后备缓冲区

IDirect3DSurface9* surface;

//1、通过swapchain获取后备缓冲区
IDirect3DSwapChain9* chain;
(*dev)->GetSwapChain(0, &chain);
chain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &surface);

//2、通过设备获取后备缓冲区
(*dev)->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &surface);
D3DSURFACE_DESC sDesc;
surface->GetDesc(&sDesc);
D3DLOCKED_RECT lockedRect;
surface->LockRect(&lockedRect,0,0);
//直接按像素修改后备缓冲区
DWORD* imageData = (DWORD*)lockedRect.pBits;
for (int i = 0; i < sDesc.Height; i++)
{
	for (int j = 0; j < sDesc.Width; j++)
	{
		int index = i * lockedRect.Pitch / 4 + j;
		imageData[index] = 0xffff0000; // red
	}
}
surface->UnlockRect();
surface->Release();

6、D3D中使用的COM对象

IDirect3D9
IDirect3DDevice9
IDirect3DSurface9
IDirect3DSwapChain9
IDirect3DVertexBuffer9
IDirect3DIndexBuffer9
IDirect3DTexture9

ID3DXBuffer
ID3DXMesh
ID3DXBaseMesh

7、枚举常量

//像素格式
D3DFMT_A8R8G8B8
D3DFMT_X8R8G8B8
D3DFMT_R8G8B8

//深度缓冲区和蒙版格式
D3DFMT_D24S8
D3DFMT_D24X8
D3DFMT_D32

//内存池
D3DPOOL_DEFAULT  高性能
D3DPOOL_MANAGED  D3D库管理

//缓存使用方式
D3DUSAGE_WRITEONLY
D3DUSAGE_DYNAMIC   非动态的缓存使用显存,处理速度快,
但应用程序读写慢,应该在软件初始化时设置一次
D3DUSAGE_POINTS

//索引格式,
D3DFMT_INDEX16   常用
D3DFMT_INDEX32

8、顶点格式和三大变换

//灵活顶点格式,需要与顶点结构体的定义保持一致
DWORD fvf = D3DFVF_XYZ | D3DFVF_DIFFUSE; //带颜色
fvf = D3DFVF_XYZ | D3DFVF_NORMAL| D3DFVF_TEX1; //带纹理和法向量


//世界坐标系
D3DXMatrixTranslation(&pyramMatrix, 5, 5, 5);
pDevice->SetTransform(D3DTS_WORLD, &pyramMatrix);


//视图坐标系
static float angle = (3.0f * D3DX_PI) / 2.0f;
static float cameraHeight = 0.0f;
static float cameraHeightDirection = 5.0f;

D3DXVECTOR3 position(cosf(angle) * 10.0f, cameraHeight, sinf(angle) * 10.0f);

// the camera is targetted at the origin of the world
D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);

// the worlds up vector
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);

D3DXMATRIX V;
D3DXMatrixLookAtLH(&V, &position, &target, &up);
pDevice->SetTransform(D3DTS_VIEW, &V);

//投影坐标系
D3DXMATRIX project;
D3DXMatrixPerspectiveFovLH(&project, D3DX_PI * 0.5, 640 / (float)480, 1.0f, 1000.0f);
pDevice->SetTransform(D3DTS_PROJECTION, &project);

9、渲染状态

//剔除规则
pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
//填充模式 D3DFILL_WIREFRAME
pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
//着色模式 D3DSHADE_FLAT
pDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);

10、顶点缓冲区和索引缓冲区

IDirect3DVertexBuffer9* vBuffer = NULL;	
HRESULT hr;
hr = pDevice->CreateVertexBuffer(3 * sizeof(Vertex), 
	D3DUSAGE_WRITEONLY,
	Vertex::fvf, D3DPOOL_MANAGED, &vBuffer, NULL);

IDirect3DIndexBuffer9*  IB = 0;
hr = pDevice->CreateIndexBuffer(
	36 * sizeof(WORD),
	D3DUSAGE_WRITEONLY,
	D3DFMT_INDEX16,
	D3DPOOL_MANAGED,
	&IB,
	0);

//读写缓冲区内容
Vertex* vertex;
vBuffer->Lock(0, 0, (void**)&vertex, 0);
......
vBuffer->Unlock();


WORD* indices = 0;
IB->Lock(0, 0, (void**)&indices, 0);
......
IB->Unlock();

//获取属性信息
D3DINDEXBUFFER_DESC indexDesc;
IB->GetDesc(&indexDesc);

D3DVERTEXBUFFER_DESC verDesc;
vBuffer->GetDesc(&verDesc);

11、绘图

pDevice->BeginScene();

pDevice->SetStreamSource(0, vBuffer, 0, sizeof(Vertex));
pDevice->SetFVF(Vertex::fvf);

pDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,1);

//使用索引
pDevice->SetIndices(IB);
pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);

pDevice->EndScene();
pDevice->Present(0, 0, 0, 0);

12、Mesh三维网格

ID3DXMesh* obj[5] = {0,0,0,0,0};

//使用内置函数创建Mesh
D3DXCreateTeapot(pDevice, &obj[0], NULL);
D3DXCreateBox(pDevice, 2, 3, 5, &obj[1], NULL);
D3DXCreateCylinder(
	pDevice,
	1.0f, // radius at negative z end
	1.0f, // radius at positive z end
	3.0f, // length of cylinder
	10,   // slices
	10,   // stacks
	&obj[2],
	0);
D3DXCreateTorus(
	pDevice,
	1.0f, // inner radius
	3.0f, // outer radius
	10,   // sides
	10,   // rings
	&obj[3],
	0);
D3DXCreateSphere(
	pDevice,
	1.0f, // radius
	10,   // slices
	10,   // stacks
	&obj[4],
	0);

D3DXCreatePolygon(...);
D3DXCreateText(...);

//绘图Mesh
obj[i]->DrawSubset(0);

 获取Mesh的信息

D3DXCreateTeapot(pDevice, &obj[0], NULL);

//ID3DXMesh 的基类 ID3DXBaseMesh
//ID3DXMesh 只支持 Triangle List 类型
IDirect3DVertexBuffer9* pVertex;
obj[0]->GetVertexBuffer(&pVertex);	
D3DVERTEXBUFFER_DESC teapotDesc;
pVertex->GetDesc(&teapotDesc);
	
IDirect3DIndexBuffer9* pIndex;
obj[0]->GetIndexBuffer(&pIndex);

//创建空的Mesh,手工填充顶点和索引数据
hr = D3DXCreateMeshFVF(
		12,
		24,
		D3DXMESH_MANAGED,
		Vertex::FVF,
		Device,
		&obj[0]);
BYTE* pData;
obj[0]->LockVertexBuffer(D3DLOCK_READONLY, (void**)&pData);
obj[0]->UnlockVertexBuffer();
obj[0]->LockIndexBuffer(D3DLOCK_READONLY, (void**)&pData);
obj[0]->UnlockIndexBuffer();

DWORD fvf = obj[0]->GetFVF(); //顶点格式
DWORD nVertices = obj[0]->GetNumVertices(); //顶点数量
DWORD nBytePerV = obj[0]->GetNumBytesPerVertex(); //每个顶点字节数
DWORD nFaces = obj[0]->GetNumFaces(); //三角形数量

 子集和属性缓冲区

一个Mesh可包含多个子集,子集是使用相同属性渲染的一组三角形集合。属性是材质、纹理和渲染状态。每个三角型有一个属性ID,有相同属性ID的三角形属于同一个子集。

	DWORD *buff;	
	obj[0]->LockAttributeBuffer(D3DLOCK_READONLY, &buff);
	DWORD attID =  buff[0];
	attID = buff[nFaces-1];
	obj[0]->UnlockAttributeBuffer();

属性表和邻接信息表

	ID3DXMesh *optMesh;
	obj[0]->Optimize(D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT |
		D3DXMESHOPT_STRIPREORDER | D3DXMESHOPT_VERTEXCACHE, NULL, NULL, 
		NULL, NULL,&optMesh);

	//obj[0]->OptimizeInplace(D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT |
	//	D3DXMESHOPT_STRIPREORDER | D3DXMESHOPT_VERTEXCACHE, NULL, NULL, 
	//	NULL, NULL);
	//D3DXMESHOPT_ATTRSORT 产生 Mesh 的 AttributeTable
	DWORD numSubset = 0;
	optMesh->GetAttributeTable(0, &numSubset);
	//每个子集对于一项
	D3DXATTRIBUTERANGE* table = new D3DXATTRIBUTERANGE[numSubset];
	optMesh->GetAttributeTable(table, &numSubset);

	obj[0]->SetAttributeTable(table, numSubset);

	//邻接信息表,每一项对应一个邻接三角形,每个三角形都有三项。
	//-1表示没有邻接三角形。
	int adjSize = optMesh->GetNumFaces() * 3;
	DWORD *adjInfo = new DWORD[adjSize];
	optMesh->GenerateAdjacency(0.001f, adjInfo);

	ID3DXMesh* clone;
	optMesh->CloneMeshFVF(optMesh->GetOptions(),
		//增加纹理坐标属性
		D3DFVF_XYZ| D3DFVF_NORMAL| D3DFVF_TEX1,
		pDevice,&clone);

 手工创建Mesh

需要填充顶点、索引和属性缓冲区三种信息。

hr = D3DXCreateMeshFVF( 12,	24,	D3DXMESH_MANAGED,
	Vertex::FVF, Device, &Mesh);
	
Vertex* v = 0;
Mesh->LockVertexBuffer(0, (void**)&v);
//填充顶点缓冲区
Mesh->UnlockVertexBuffer();

WORD* i = 0;
Mesh->LockIndexBuffer(0, (void**)&i);
//填充索引缓冲区
Mesh->UnlockIndexBuffer();

DWORD* attributeBuffer = 0;
Mesh->LockAttributeBuffer(0, &attributeBuffer);
//指定每个三角形所属的子集
//attributeBuffer[a] = 0;
Mesh->UnlockAttributeBuffer();

//产生邻接信息和属性表
std::vector<DWORD> adjacencyBuffer(Mesh->GetNumFaces() * 3);
Mesh->GenerateAdjacency(0.0f, &adjacencyBuffer[0]);

hr = Mesh->OptimizeInplace(		
	D3DXMESHOPT_ATTRSORT |
	D3DXMESHOPT_COMPACT  |
	D3DXMESHOPT_VERTEXCACHE,
	&adjacencyBuffer[0],
	0, 0, 0);

//另一种方式
D3DVERTEXELEMENT9 velement[MAX_FVF_DECL_SIZE];
D3DXDeclaratorFromFVF(D3DFVF_XYZ | D3DFVF_NORMAL, velement);

ID3DXMesh *mesh;
D3DXCreateMesh(12, 24, D3DXMESH_MANAGED,
	velement,
	pDevice,
	&mesh);

从文件中加载Mesh模型

ID3DXMesh* shipMesh;
ID3DXBuffer* shipAdj;
ID3DXBuffer* shipMaterial;

vector<D3DMATERIAL9> shipMaterials;
std::vector<IDirect3DTexture9*> shipTextures;

DWORD numMaterail = 0;

HRESULT hr =  D3DXLoadMeshFromX(L"bigship1.x", D3DXMESH_MANAGED, pDevice,
	&shipAdj, &shipMaterial, NULL, &numMaterail, &shipMesh);

//材质,每个子集对应一项
if (numMaterail > 0 && shipMaterial != nullptr)
{
	D3DXMATERIAL* m = (D3DXMATERIAL*)shipMaterial->GetBufferPointer();
	for (int i = 0; i < numMaterail; ++i)
	{
		m[i].MatD3D.Ambient = m[i].MatD3D.Diffuse; //没有包含环境光
		shipMaterials.push_back(m[i].MatD3D);
		if (m[i].pTextureFilename != 0) //纹理文件名
		{
			IDirect3DTexture9* tex = 0;
			D3DXCreateTextureFromFileA(pDevice, m[i].pTextureFilename, &tex);
			shipTextures.push_back(tex);
		}
	}
}
shipMaterial->Release();

//计算顶点向量
if (!(shipMesh->GetFVF() & D3DFVF_NORMAL))
{
	ID3DXMesh* temp = nullptr;
	shipMesh->CloneMeshFVF(shipMesh->GetOptions(),
		shipMesh->GetFVF() | D3DFVF_NORMAL, pDevice, &temp);
	D3DXComputeNormals(temp, (DWORD*)shipAdj->GetBufferPointer());
	shipMesh->Release();
	shipMesh = temp;
}

//优化Mesh模型
shipMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE,
(DWORD*)shipAdj->GetBufferPointer(), NULL, NULL, NULL);
shipAdj->Release();

渐进式网格progressive mesh

ID3DXPMesh* pMesh = 0;
std::vector<D3DMATERIAL9> shipMaterials;
std::vector<IDirect3DTexture9*> shipTextures;

ID3DXMesh* SphereMesh = 0;
ID3DXMesh* BoxMesh = 0;

shipMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE,
	(DWORD*)shipAdj->GetBufferPointer(),
	(DWORD*)shipAdj->GetBufferPointer(), NULL, NULL);

//使用优化后的邻接表		
hr = D3DXGeneratePMesh(shipMesh, (DWORD*)shipAdj->GetBufferPointer(),
	NULL, NULL, 1, D3DXMESHSIMP_FACE, &pMesh);

pMesh->SetNumFaces(pMesh->GetMaxFaces());

    BYTE* vb = 0;
	shipMesh->LockVertexBuffer(0, (void**)&vb);
	D3DXVECTOR3 center;
	float radius;
	hr = D3DXComputeBoundingSphere(
		(D3DXVECTOR3*)vb,
		shipMesh->GetNumVertices(),
		D3DXGetFVFVertexSize(mesh->GetFVF()),
		&center,
		&radius);

	D3DXVECTOR3 _min, _max;
	hr = D3DXComputeBoundingBox(
		(D3DXVECTOR3*)vb,
		mesh->GetNumVertices(),
		D3DXGetFVFVertexSize(mesh->GetFVF()),
		&_min,
		&_max);

	mesh->UnlockVertexBuffer();
	//创建sphere Mesh
	D3DXCreateSphere(
		pDevice,
		radius,
		20,
		20,
		&SphereMesh,
		0);

	//创建 box mesh
	D3DXCreateBox(
		pDevice,
		_max.x - _min.x,
		_max.y - _min.y,
		_max.z - _min.z,
		&BoxMesh,
		0);

//绘制
        for (int i = 0; i < shipMaterials.size(); i++)
		{
			// draw pmesh
			pDevice->SetMaterial(&shipMaterials[i]);
			if(shipTextures.size()>i+1)
				pDevice->SetTexture(0, shipTextures[i]);
			pMesh->DrawSubset(i);

			// draw wireframe outline
			pDevice->SetMaterial(&d3d::YELLOW_MTRL);
			pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
			pMesh->DrawSubset(i);
			pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
		}

		pDevice->SetMaterial(& pyramMaterial);
		pDevice->SetTexture(0, 0); // disable texture

		pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
		//pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
		//pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

		//if (RenderBoundingSphere)
			SphereMesh->DrawSubset(0);
		//else
			//BoxMesh->DrawSubset(0);
		pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);

13、颜色

D3DCOLOR color; //字节序 a,r, g, b;
color = D3DCOLOR_ARGB(255, 255, 0, 0);
D3DCOLORVALUE value{ 1.0f,0,0,1.0f };  //r, g, b, a;

D3DXCOLOR xcolor(color);  //r, g, b, a 与 D3DCOLORVALUE 可互换
D3DXCOLOR xcolor2(value);

顶点格式: D3DFVF_XYZ | D3DFVF_DIFFUSE

//启动顶点颜色时,需要关闭光照
pDevice->SetRenderState(D3DRS_LIGHTING, false);

//启用着色模式 D3DSHADE_FLAT
pDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);

14、灯光和材质

三种类型的光,每种光都包含光的三种成分。材质是物体对光的每种成分的反射率。三角形共顶点的法向量可能不一致,可以取三角形的法向量。

//方向光
	D3DLIGHT9 dirLight; 
	::ZeroMemory(&dirLight, sizeof(dirLight));
	dirLight.Type = D3DLIGHT_DIRECTIONAL;
	dirLight.Diffuse = d3d::WHITE;  //漫反射光 D3DCOLORVALUE
	dirLight.Specular = d3d::WHITE * 0.3f; //镜面反射光
	dirLight.Ambient = d3d::WHITE * 0.6f;  //环境光
	dirLight.Direction = D3DXVECTOR3(1.0f, 0.0f, 0.0f);
	pDevice->SetLight(0, &dirLight);

//点光源
	D3DXCOLOR   c = d3d::WHITE;
	D3DLIGHT9 pointLight;
	pointLight.Type = D3DLIGHT_POINT;
	pointLight.Ambient = c * 0.6f;
	pointLight.Diffuse = c;
	pointLight.Specular = c * 0.6f;
	pointLight.Position = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
	pointLight.Range = 1000.0f; //有效范围
	pointLight.Falloff = 1.0f;
	pointLight.Attenuation0 = 1.0f; //衰减系数
	pointLight.Attenuation1 = 0.0f;
	pointLight.Attenuation2 = 0.0f;
	pDevice->SetLight(1, &pointLight);
	//pDevice->LightEnable(0, true);

//聚光灯	
	D3DLIGHT9 spotLight ;
	spotLight.Type = D3DLIGHT_SPOT;
	spotLight.Ambient = c * 0.0f;
	spotLight.Diffuse = c;
	spotLight.Specular = c* 0.6f;
	spotLight.Position = D3DXVECTOR3(0.0f, 0.0f, -5.0f);
	spotLight.Direction = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
	spotLight.Range = 1000.0f;
	spotLight.Falloff = 1.0f;
	spotLight.Attenuation0 = 1.0f;
	spotLight.Attenuation1 = 0.0f;
	spotLight.Attenuation2 = 0.0f;
	spotLight.Theta = 0.4f;
	spotLight.Phi = 0.9f;
	//
	// Set and Enable spotlight.
	//
	pDevice->SetLight(2, &spotLight);

    //启用镜面反射光
	pDevice->SetRenderState(D3DRS_SPECULARENABLE, true);
    //打开1号灯
    pDevice->LightEnable(1, true);


    D3DMATERIAL9 pyramMaterial;
	pyramMaterial.Ambient = d3d::WHITE;
	pyramMaterial.Diffuse = d3d::RED;
	pyramMaterial.Specular = d3d::WHITE;
	pyramMaterial.Emissive = d3d::BLACK; //自发光
	pyramMaterial.Power = 5.0f; //镜面光增强系数

    pDevice->SetMaterial(&pyramMaterial);

    //顶点的最终颜色可以直接指定颜色(需要关闭灯光),也可以通过
    //灯光、材质、纹理以及顶点的法向量计算(需要开启灯光)。
	pDevice->SetRenderState(D3DRS_LIGHTING, true);
	pDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true);

15、纹理

纹理是可以映射到三角形的像素矩阵。纹理应用在最后的栅格化阶段,由于大小不一致,使用三种过滤器。放大、缩小和多级纹理过滤器。

fvf = D3DFVF_XYZ | D3DFVF_NORMAL| D3DFVF_TEX1;

D3DXCreateTextureFromFile(pDevice, L"crate.jpg", &texture);
//缩小、放大过滤器
pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
//D3DTEXF_POINT; D3DTEXF_NONE;

//D3DTEXF_ANISOTROPIC 时需要设置各向异性级别
pDevice->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, 3);

//多级渐远纹理过滤器
//D3DTEXF_POINT; D3DTEXF_NONE;
pDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

//纹理的寻址方式
pDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
pDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);

//D3DTADDRESS_MIRROR;  镜像
//D3DTADDRESS_CLAMP;   夹取
//D3DTADDRESS_WRAP;    平铺
//D3DTADDRESS_BORDER;  边框,需要设置边框颜色
pDevice->SetSamplerState(0, D3DSAMP_BORDERCOLOR, D3DCOLOR_ARGB(255, 120, 125, 10));


pDevice->SetTexture(0, texture); //设置纹理
......
pDevice->SetTexture(0, 0);  //关闭纹理

5b88e11cc27b46568d6d9b758181a4ae.png2cd666473371474c9be0d8ed81d28fdd.png

061bb3bcd5c2441c97161ff3764e4206.png 646e9a0bcd5e4e92a229041353bb99ec.png

 16、像素混合

	// 启用像素融合
	m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);

	m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);

OutputPixel = SourcePixel * SourceBlendFactor + DestPixel * DestBlendFactor 

源像素为将写入后备缓冲器的像素值, 目标像素为当前在后备缓冲区的像素值。

//设置源像素混合系数
pDevice->SetRenderState(D3DRS_SRCBLEND,  D3DBLEND_SRCCOLOR);

//设置目标像素混合系数
pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);


//D3DBLEND_ZERO ,     D3DBLEND_ONE 
//D3DBLEND_SRCCOLOR , D3DBLEND_INVSRCCOLOR 
//D3DBLEND_DESTCOLOR ,D3DBLEND_INVDESTCOLOR 
//D3DBLEND_SRCALPHA(默认的源像素混合系数) ,D3DBLEND_INVSRCALPHA(默认的目标像素混合系数) 	
//D3DBLEND_DESTALPHA ,D3DBLEND_INVDESTALPHA 
//D3DBLEND_SRCALPHASAT  (f、f、f、1); f = min(As, 1 - Ad)

Alpha值的来源可以从顶点的颜色、材质中通过着色模式计算获得,也可以通过纹理中的Alpha通道,获得每个像素的Alpha值。默认情况下,优先使用纹理的alpha通道,不存在则从顶点颜色中获取。可以通过函数直接指定Alpha值来源。

//使用颜色、材质
pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

//使用纹理的Alpha通道,DDS文件格式可包含Alpha通道数据
pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

17、摄像机

	D3DXVECTOR3 position(0, 10, 0); //摄像机上移动10.
	D3DXVECTOR3 target(0.0f, 10.0f, 10.0f);
	D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);

	D3DXMATRIX v1;
	D3DXMatrixLookAtLH(&v1, &position, &target, &up);
	
	D3DXMATRIX v2;
	D3DXMatrixTranslation(&v2, 0, -10, 0);//把场景中的所有物体下移10
	
	//v1==v2

	D3DXVECTOR3 up2(0.0f, -1.0f, 0.0f);//上方向沿X轴顺时针旋转180°。
    D3DXMATRIX v3;
	D3DXMatrixLookAtLH(&v3, &position, &target, &up2);
	
	D3DXMATRIX v4,v5;
	D3DXMatrixRotationX(&v4, -D3DX_PI);//把场景中的所有物体逆时针旋转180°
	D3DXMatrixMultiply(&v5, &v2, &v4);
    //v3==v5

18、文本显示

D3D提供的ID3DXFont接口使用GDI进行文本绘制,速度稍慢,但支持复杂的字体和格式化。

	ID3DXFont* d3dFont;
	D3DXFONT_DESC fontDesc;
	fontDesc.Height = 25;    // in logical units
	fontDesc.Width = 12;    // in logical units
	fontDesc.Weight = 500;   // boldness, range 0(light) - 1000(bold)
	fontDesc.Italic = false;
	fontDesc.CharSet = DEFAULT_CHARSET;
	fontDesc.Quality = 0;
	fontDesc.OutputPrecision = 0;
	fontDesc.MipLevels = 0;
	fontDesc.PitchAndFamily = 0;
	wcscpy_s(fontDesc.FaceName, L"Times New Roman"); // font style

	ZeroMemory(&fontDesc, sizeof(D3DXFONT_DESC));
	HRESULT hr=D3DXCreateFontIndirect(pDevice, &fontDesc, &d3dFont);
	RECT rect{ 0,0,width,height };
	d3dFont->DrawTextW(NULL, L"TEXT TO DRAW", -1, &rect, DT_TOP | DT_LEFT,0XFF00FF00);

19、拾取

当用户在窗口范围内点击时,如何判读点击位置选中了三维空间中的一个模型?

47a35f30ac1e49feb1cce7a3b4b11805.png

首先将鼠标位置(x,y)映射到透视投影窗口的p点。先后经过视口变换的逆变换,透视投影变换的逆变换。由于没有深度信息,只需要进行缩放和平移操作。

Ray CalcPickingRay(IDirect3DDevice9* device, int x, int y)
{
	float px = 0.0f, py = 0.0f;

	D3DVIEWPORT9 vp;
	device->GetViewport(&vp);
	D3DXMATRIX proj;
	device->GetTransform(D3DTS_PROJECTION, &proj);

	px = (((2.0f * x) / vp.Width) - 1.0f) / proj(0, 0);
	py = (((-2.0f * y) / vp.Height) + 1.0f) / proj(1, 1);

	Ray ray;
	ray._origin = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
	ray._direction = D3DXVECTOR3(px, py, 1.0f);
	return ray;
}

然后计算原点到p点的射线与各个模型是否相交。由于射线处于视图空间,为简便计算,将射线变换回世界空间,要用到视图变换的逆变换。

void TransformRay(Ray* ray, D3DXMATRIX* T)
{
	// transform the ray's origin, w = 1.
	D3DXVec3TransformCoord(
		&ray->_origin,
		&ray->_origin,
		T);

	// transform the ray's direction, w = 0.
	D3DXVec3TransformNormal(
		&ray->_direction,
		&ray->_direction,
		T);

	// normalize the direction
	D3DXVec3Normalize(&ray->_direction, &ray->_direction);
}

其中,T为视图变换矩阵的逆矩阵。

		// transform the ray to world space
		D3DXMATRIX view;
		sDemo->pDevice->GetTransform(D3DTS_VIEW, &view);
		D3DXMATRIX viewInverse;
		D3DXMatrixInverse(&viewInverse, 0, &view);

相交即计算球体中心点到射线距离等于半径的点。为一元二次方程至少有一个大于等于0的解。

bool RaySphereIntTest(Ray* ray, BoundingSphere* sphere)
{
	D3DXVECTOR3 v = ray->_origin - sphere->_center;

	float b = 2.0f * D3DXVec3Dot(&ray->_direction, &v);
	float c = D3DXVec3Dot(&v, &v) - (sphere->_radius * sphere->_radius);

	// find the discriminant
	float discriminant = (b * b) - (4.0f * c);

	// test for imaginary number
	if (discriminant < 0.0f)
		return false;

	discriminant = sqrtf(discriminant);

	float s0 = (-b + discriminant) / 2.0f;
	float s1 = (-b - discriminant) / 2.0f;

	// if a solution is >= 0, then we intersected the sphere
	if (s0 >= 0.0f || s1 >= 0.0f)
		return true;

	return false;
}

一个例子的源代码下载地址:

 D3D9固定功能渲染流水线演示实例资源icon-default.png?t=N7T8https://download.youkuaiyun.com/download/eamon100/87723692

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值