DirectX 9 Tutorial
acmilan2016/08/15软件综合 IP:四川

基于Direct3D 9。

绘制了一个蓝色的背景,然后没有了。

Direct3D程序与普通Win32 GUI程序的不同之处:

  1. XXXXXyle = CS_CLASSDC; // 表示多个窗口使用同一个DC
  2. wc.hbrBackground = NULL; // 不使用GDI清空背景
  3. 不使用GetMessage循环接收消息,而是使用PeekMessage循环提取消息
  4. 不使用WM_PAINT进行窗口重绘,而是在PeekMessage没有未处理消息并返回FALSE时绘制

编译这个程序需要Visual C++ 2008/2010 + DirectX SDK Jun 2010或Visual C++ 2012以上版本

<code class="language-cpp">// dxstart1.cpp : 定义控制台应用程序的入口点。
//

//#include "stdafx.h"
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <d3d9.h>
#include <strsafe.h>
#pragma comment(lib, "d3d9.lib")
#ifdef _UNICODE
#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:wmainCRTStartup")
#else
#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
#endif

// 释放接口的工具函数
template <class i>
void safe_release(I **interf)
{
	if (*interf != NULL)
	{
		(*interf)->Release();
		*interf = NULL;
	}
}

///////////////////////////////////////

LPDIRECT3D9 pD3D = NULL;
LPDIRECT3DDEVICE9 pD3DDevice = NULL;

///////////////////////////////////////

// 初始化Direct3D
HRESULT InitD3D(HWND hwnd)
{
	HRESULT hr = S_OK;

	// 创建Direct3D 9根接口
	pD3D = Direct3DCreate9(D3D_SDK_VERSION);
	if (pD3D == NULL)
	{
		hr = E_FAIL;
		goto ret;
	}

	// 配置Direct3D 9设备
	D3DPRESENT_PARAMETERS d3dpp;
	RtlZeroMemory(&d3dpp, sizeof d3dpp);
	d3dpp.Windowed = TRUE; // 窗口化
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // 交换缓冲加载后被删除
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; // 显示模式

	// 创建Direct3D 9设备接口
	hr = pD3D->CreateDevice(
		D3DADAPTER_DEFAULT, // 默认适配器
		D3DDEVTYPE_HAL, // 硬件驱动
		hwnd, // 窗体
		D3DCREATE_SOFTWARE_VERTEXPROCESSING, // 顶点像素渲染方式
		&d3dpp, // 参数
		&pD3DDevice); // 返回的设备接口
	if (FAILED(hr)) goto ret;

ret:
	return hr;
}

// 绘制图形
void Render()
{
	HRESULT hr = S_OK;

	if (pD3DDevice == NULL)
		goto ret;

	// 清空缓存
	hr = pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET,
		D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);

	// 开始绘制场景
	hr = pD3DDevice->BeginScene();
	if (FAILED(hr)) goto present;

	// 结束绘制场景
	hr = pD3DDevice->EndScene();

present:
	// 显示缓存内容
	hr = pD3DDevice->Present(NULL, NULL, NULL, NULL);

ret:
	return;
}

// 清理Direct3D
void CleanupD3D()
{
	safe_release(&pD3DDevice);
	safe_release(&pD3D);
}

///////////////////////////////////////

// 窗口函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_DESTROY:
		// 窗口销毁时退出消息循环
		PostQuitMessage(0);
		return 0;
	default:
		// 其它消息作默认处理
		return DefWindowProc(hwnd, msg, wParam, lParam);
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	// 创建窗口的过程,见《Windows程序设计(第5版)》
	WNDCLASSEX wc = {
		sizeof wc,
		CS_CLASSDC, // 所有窗口共享同一个DC
		WndProc,
		0, 0,
		GetModuleHandle(NULL),
		LoadIcon(NULL, IDI_APPLICATION),
		LoadCursor(NULL, IDC_ARROW),
		NULL, // 此处不需要用GDI清空窗口
		NULL,
		_T("MainWndClass"),
		LoadIcon(NULL, IDI_APPLICATION)
	};
	RegisterClassEx(&wc);

	HWND hMainWnd = CreateWindowEx(
		WS_EX_OVERLAPPEDWINDOW, _T("MainWndClass"),
		_T("Main Window"), WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, wc.hInstance, NULL);

	// 初始化Direct3D
	if (FAILED(InitD3D(hMainWnd)))
	{
		CleanupD3D();
		return 0;
	}

	ShowWindow(hMainWnd, SW_SHOWDEFAULT);
	UpdateWindow(hMainWnd);

	MSG msg;
	RtlZeroMemory(&msg, sizeof msg);
	while (msg.message != WM_QUIT)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			// 空闲时绘制图形
			Render();
		}
	}

	// 清理Direct3D
	CleanupD3D();
	return (int)msg.wParam;
}
</class></strsafe.h></d3d9.h></tchar.h></windowsx.h></windows.h></code>

[修改于 7年7个月前 - 2016/10/18 00:58:43]

来自:计算机科学 / 软件综合
5
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
acmilan 作者
7年9个月前 修改于 7年7个月前 IP:四川
824505

画一个三角形

要点:

  • 程序启动时SetRenderState设置D3DRS_CULLMODE为CULL_NONE关闭剔除,D3DRS_LIGHTING为FALSE关闭光照
  • 定义一个结构体,含有x、y、z、rhw、color五个参数,然后CreateVertexBuffer建立一个顶点缓冲区,Lock获取指针,用memcpy复制进去,Unlock释放
  • 绘制时使用SetStreamSource、SetFVF、DrawPrimitive绘制三角形

效果:

ssssssss.png

代码:

<code class="language-cpp">// dxstart1.cpp : 定义控制台应用程序的入口点。
//

//#include "stdafx.h"
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <d3d9.h>
#include <strsafe.h>
#pragma comment(lib, "d3d9.lib")
#ifdef _UNICODE
#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:wmainCRTStartup")
#else
#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
#endif

// 释放接口的工具函数
template <class i>
void safe_release(I **interf)
{
	if (*interf != NULL)
	{
		(*interf)->Release();
		*interf = NULL;
	}
}

///////////////////////////////////////

LPDIRECT3D9 pD3D = NULL;
LPDIRECT3DDEVICE9 pD3DDevice = NULL;
LPDIRECT3DVERTEXBUFFER9 pVB = NULL; // 顶点缓冲区实例

// 自定义顶点结构体
struct CUSTOMVERTEX
{
	FLOAT x, y, z, rhw; // 未变换的x,y,z
	DWORD color; // 颜色
};

// 自定义顶点格式
// 未变换顶点+面反射色
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)

///////////////////////////////////////

// 初始化顶点缓冲区(被InitD3D调用)
HRESULT InitVB()
{
	HRESULT hr = S_OK;

	// 三角形(未变换)
	CUSTOMVERTEX vertices[] = {
		{ 300.0f, 100.0f, 0.5f, 1.0f, 0xffff0000 },
		{ 400.0f, 300.0f, 0.5f, 1.0f, 0xff00ff00 },
		{ 200.0f, 300.0f, 0.5f, 1.0f, 0xff00ffff },
	};

	// 创建顶点缓冲区
	hr = pD3DDevice->CreateVertexBuffer(
		sizeof vertices, // 大小
		0, // 怎样使用缓存的额外信息
		D3DFVF_CUSTOMVERTEX, // 自定义顶点格式
		D3DPOOL_DEFAULT, // 顶点缓冲存储方式
		&pVB, // 返回顶点缓存实例
		NULL); // 保留
	if (FAILED(hr)) goto ret;

	// 锁定并获取缓冲区指针
	void *pVertices = NULL;
	hr = pVB->Lock(0, sizeof vertices, &pVertices, 0);
	if (FAILED(hr)) goto ret;

	// 将顶点数据复制到缓冲区
	memcpy(pVertices, vertices, sizeof vertices);

	// 释放锁定
	hr = pVB->Unlock();
	if (FAILED(hr)) goto ret;

ret:
	return hr;
}

// 初始化Direct3D
HRESULT InitD3D(HWND hwnd)
{
	HRESULT hr = S_OK;

	// 创建Direct3D 9根接口
	pD3D = Direct3DCreate9(D3D_SDK_VERSION);
	if (pD3D == NULL)
	{
		hr = E_FAIL;
		goto ret;
	}

	// 配置Direct3D 9设备
	D3DPRESENT_PARAMETERS d3dpp;
	RtlZeroMemory(&d3dpp, sizeof d3dpp);
	d3dpp.Windowed = TRUE; // 窗口化
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // 交换缓冲加载后被删除
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; // 显示模式

	// 创建Direct3D 9设备接口
	hr = pD3D->CreateDevice(
		D3DADAPTER_DEFAULT, // 默认适配器
		D3DDEVTYPE_HAL, // 硬件驱动
		hwnd, // 窗体
		D3DCREATE_SOFTWARE_VERTEXPROCESSING, // 顶点像素渲染方式
		&d3dpp, // 参数
		&pD3DDevice); // 返回的设备接口
	if (FAILED(hr)) goto ret;

	// 设置剔除模式为NONE,这样可以看到三角形背面
	pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
	// 关闭光照系统,这样可以显示出本身的颜色
	pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);

	// 初始化顶点缓冲区
	hr = InitVB();
	if (FAILED(hr)) goto ret;

ret:
	return hr;
}

// 绘制图形
void Render()
{
	HRESULT hr = S_OK;

	if (pD3DDevice == NULL)
		goto ret;

	// 清空缓存
	hr = pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET,
		D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);

	// 开始绘制场景
	hr = pD3DDevice->BeginScene();
	if (FAILED(hr)) goto present;

	// 绘制三角形
	// 设置数据流0为pVB
	hr = pD3DDevice->SetStreamSource(0, pVB, 0, sizeof(CUSTOMVERTEX));
	// 设置顶点格式
	hr = pD3DDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
	// 按三角形列表绘制数据流0
	hr = pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

	// 结束绘制场景
	hr = pD3DDevice->EndScene();

present:
	// 显示缓存内容
	hr = pD3DDevice->Present(NULL, NULL, NULL, NULL);

ret:
	return;
}

// 清理Direct3D
void CleanupD3D()
{
	safe_release(&pVB);
	safe_release(&pD3DDevice);
	safe_release(&pD3D);
}

///////////////////////////////////////

// 窗口函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_DESTROY:
		// 窗口销毁时退出消息循环
		PostQuitMessage(0);
		return 0;
	default:
		// 其它消息作默认处理
		return DefWindowProc(hwnd, msg, wParam, lParam);
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	// 创建窗口的过程,见《Windows程序设计(第5版)》
	WNDCLASSEX wc = {
		sizeof wc,
		CS_CLASSDC, // 所有窗口共享同一个DC
		WndProc,
		0, 0,
		GetModuleHandle(NULL),
		LoadIcon(NULL, IDI_APPLICATION),
		LoadCursor(NULL, IDC_ARROW),
		NULL, // 此处不需要用GDI清空窗口
		NULL,
		_T("MainWndClass"),
		LoadIcon(NULL, IDI_APPLICATION)
	};
	RegisterClassEx(&wc);

	HWND hMainWnd = CreateWindowEx(
		WS_EX_OVERLAPPEDWINDOW, _T("MainWndClass"),
		_T("Main Window"), WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, wc.hInstance, NULL);

	// 初始化Direct3D
	if (FAILED(InitD3D(hMainWnd)))
	{
		CleanupD3D();
		return 0;
	}

	ShowWindow(hMainWnd, SW_SHOWDEFAULT);
	UpdateWindow(hMainWnd);

	MSG msg;
	RtlZeroMemory(&msg, sizeof msg);
	while (msg.message != WM_QUIT)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			// 空闲时绘制图形
			Render();
		}
	}

	// 清理Direct3D
	CleanupD3D();
	return (int)msg.wParam;
}
</class></strsafe.h></d3d9.h></tchar.h></windowsx.h></windows.h></code>
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
7年9个月前 修改于 7年7个月前 IP:四川
824513

让三角形旋转起来

除Render调用SetupMatrices设置三个基本变换矩阵外,注意几个细节改变:

  1. CUSTOMVERTEX删除了rhw元素,这样变成了未变换的x,y,z和颜色
  2. D3DFVF_CUSTOMVERTEX中D3DFVF_XYZRHW变为D3DFVF_XYZ
  3. InitVB中三角形的坐标数据作了调整
  4. InitD3D中pD3DDevice->SetRenderState设置剔出模式为NONE,这样可以看到三角形背面
  5. InitD3D中pD3DDevice->SetRenderState关闭光照系统,这样可以显示出本身的颜色

d3d_b.png

<code class="language-cpp">///////////////////////////////////////

LPDIRECT3D9 pD3D = NULL;
LPDIRECT3DDEVICE9 pD3DDevice = NULL;
LPDIRECT3DVERTEXBUFFER9 pVB = NULL; // 顶点缓冲区实例

// 自定义顶点结构体
struct CUSTOMVERTEX
{
	FLOAT x, y, z; // 未变换的x,y,z
	DWORD color; // 颜色
};

// 自定义顶点格式
// 未变换顶点+面反射色
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)

///////////////////////////////////////

// 初始化顶点缓冲区(被InitD3D调用)
HRESULT InitVB()
{
	HRESULT hr = S_OK;

	// 三角形(未变换)
	CUSTOMVERTEX vertices[] = {
		{ -1.0f, -1.0f, 0.0f, 0xffff0000 },
		{ 1.0f, -1.0f, 0.0f, 0xff00ff00 },
		{ 0.0f, 1.0f, 0.0f, 0xff00ffff },
	};

	// 创建顶点缓冲区
	hr = pD3DDevice->CreateVertexBuffer(
		sizeof vertices, // 大小
		0, // 怎样使用缓存的额外信息
		D3DFVF_CUSTOMVERTEX, // 自定义顶点格式
		D3DPOOL_DEFAULT, // 顶点缓冲存储方式
		&pVB, // 返回顶点缓存实例
		NULL); // 保留
	if (FAILED(hr)) goto ret;

	// 锁定并获取缓冲区指针
	void *pVertices = NULL;
	hr = pVB->Lock(0, sizeof vertices, &pVertices, 0);
	if (FAILED(hr)) goto ret;

	// 将顶点数据复制到缓冲区
	memcpy(pVertices, vertices, sizeof vertices);

	// 释放锁定
	hr = pVB->Unlock();
	if (FAILED(hr)) goto ret;

ret:
	return hr;
}

// 初始化Direct3D
HRESULT InitD3D(HWND hwnd)
{
	HRESULT hr = S_OK;

	// 创建Direct3D 9根接口
	pD3D = Direct3DCreate9(D3D_SDK_VERSION);
	if (pD3D == NULL)
	{
		hr = E_FAIL;
		goto ret;
	}

	// 配置Direct3D 9设备
	D3DPRESENT_PARAMETERS d3dpp;
	RtlZeroMemory(&d3dpp, sizeof d3dpp);
	d3dpp.Windowed = TRUE; // 窗口化
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // 交换缓冲加载后被删除
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; // 显示模式

	// 创建Direct3D 9设备接口
	hr = pD3D->CreateDevice(
		D3DADAPTER_DEFAULT, // 默认适配器
		D3DDEVTYPE_HAL, // 硬件驱动
		hwnd, // 窗体
		D3DCREATE_SOFTWARE_VERTEXPROCESSING, // 顶点像素渲染方式
		&d3dpp, // 参数
		&pD3DDevice); // 返回的设备接口
	if (FAILED(hr)) goto ret;

	// 设置剔除模式为NONE,这样可以看到三角形背面
	pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
	// 关闭光照系统,这样可以显示出本身的颜色
	pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);

	// 初始化顶点缓冲区
	hr = InitVB();
	if (FAILED(hr)) goto ret;

ret:
	return hr;
}

#include <d3dx9.h>
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib, "winmm.lib") // timeGetTime

// 设置世界、观察、投影变换矩阵
void SetupMatrices()
{
	HRESULT hr;

	// 设定世界变换矩阵为沿Y轴不停旋转
	D3DXMATRIXA16 matWorld;
	UINT iTime = timeGetTime() % 1000;
	FLOAT fAngle = iTime * (2.0f * D3DX_PI) / 1000.0f;
	D3DXMatrixRotationY(&matWorld, fAngle);
	hr = pD3DDevice->SetTransform(D3DTS_WORLD, &matWorld);

	// 设定观察变换矩阵
	D3DXMATRIXA16 matView;
	D3DXVECTOR3 vEyePt(0.0f, 3.0f, -5.0f); // 眼睛的位置
	D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f); //观察的位置
	D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f); //向上的方向
	D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);
	hr = pD3DDevice->SetTransform(D3DTS_VIEW, &matView);

	// 设定投影变换矩阵
	D3DXMATRIXA16 matProj;
	// 距离缩小比例、屏幕纵横比、最近剪切平面、最远剪切平面
	D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f);
	hr = pD3DDevice->SetTransform(D3DTS_PROJECTION, &matProj);
}

// 绘制图形
void Render()
{
	HRESULT hr = S_OK;

	if (pD3DDevice == NULL)
		goto ret;

	// 清空缓存
	hr = pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET,
		D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);

	// 开始绘制场景
	hr = pD3DDevice->BeginScene();
	if (FAILED(hr)) goto present;

	// 设置变换矩阵
	SetupMatrices();

	// 绘制三角形
	// 设置数据流0为pVB
	hr = pD3DDevice->SetStreamSource(0, pVB, 0, sizeof(CUSTOMVERTEX));
	// 设置顶点格式
	hr = pD3DDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
	// 按三角形列表绘制数据流0
	hr = pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

	// 结束绘制场景
	hr = pD3DDevice->EndScene();

present:
	// 显示缓存内容
	hr = pD3DDevice->Present(NULL, NULL, NULL, NULL);

ret:
	return;
}

// 清理Direct3D
void CleanupD3D()
{
	safe_release(&pVB);
	safe_release(&pD3DDevice);
	safe_release(&pD3D);
}

///////////////////////////////////////
</d3dx9.h></code>
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
7年9个月前 修改于 7年7个月前 IP:四川
824531

绘制更复杂的图形

这里绘制了一个圆柱体,不过由于出了点问题,变成了一个莫比乌斯环。

d3d_c.png

除了InitVB函数中算法的改变以外,还有以下细节改变:

  1. CUSTOMVERTEX结构体中FLOAT x, y, z;改成了等价的D3DXVECTOR3 position;
  2. SetupMatrices函数中D3DXMatrixRotationY改为了D3DXMatrixRotationX
  3. Render函数中绘制数据流的指令由D3DPT_TRIANGLELIST改为D3DPT_TRIANGLESTRIP,同时最后一个参数指定2*50 - 2个项
<code class="language-cpp">///////////////////////////////////////

LPDIRECT3D9 pD3D = NULL;
LPDIRECT3DDEVICE9 pD3DDevice = NULL;
LPDIRECT3DVERTEXBUFFER9 pVB = NULL; // 顶点缓冲区实例

#include <d3dx9.h>
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib, "winmm.lib") // timeGetTime

// 自定义顶点结构体
struct CUSTOMVERTEX
{
	D3DXVECTOR3 position; // 未变换的x,y,z
	DWORD color; // 颜色
};

// 自定义顶点格式
// 未变换顶点+面反射色
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)

///////////////////////////////////////

// 初始化顶点缓冲区(被InitD3D调用)
HRESULT InitVB()
{
	HRESULT hr = S_OK;

	// 创建顶点缓冲区
	hr = pD3DDevice->CreateVertexBuffer(
		50 * 2 * sizeof(CUSTOMVERTEX), // 大小
		0, // 怎样使用缓存的额外信息
		D3DFVF_CUSTOMVERTEX, // 自定义顶点格式
		D3DPOOL_DEFAULT, // 顶点缓冲存储方式
		&pVB, // 返回顶点缓存实例
		NULL); // 保留
	if (FAILED(hr)) goto ret;

	// 锁定并获取缓冲区指针
	CUSTOMVERTEX *pVertices = NULL;
	hr = pVB->Lock(0, 0, (void**)&pVertices, 0);
	if (FAILED(hr)) goto ret;

	// 在缓冲区写入圆柱面的数据
	for (DWORD i = 0; i < 50; i++)
	{
		FLOAT theta = (2 * D3DX_PI * i) / (50 - 1);
		pVertices[2 * i].position = D3DXVECTOR3(sinf(theta), -1.0f, cosf(theta));
		pVertices[2 * i].color = D3DCOLOR_XRGB(0, 255, 255);
		pVertices[2 * i + 1].position = D3DXVECTOR3(sinf(theta), 1.0f, cosf(theta));
		pVertices[2 * i + 1].color = D3DCOLOR_XRGB(255, 255, 255);
	}

	// 释放锁定
	hr = pVB->Unlock();
	if (FAILED(hr)) goto ret;

ret:
	return hr;
}

// 初始化Direct3D
HRESULT InitD3D(HWND hwnd)
{
	HRESULT hr = S_OK;

	// 创建Direct3D 9根接口
	pD3D = Direct3DCreate9(D3D_SDK_VERSION);
	if (pD3D == NULL)
	{
		hr = E_FAIL;
		goto ret;
	}

	// 配置Direct3D 9设备
	D3DPRESENT_PARAMETERS d3dpp;
	RtlZeroMemory(&d3dpp, sizeof d3dpp);
	d3dpp.Windowed = TRUE; // 窗口化
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // 交换缓冲加载后被删除
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; // 显示模式

	// 创建Direct3D 9设备接口
	hr = pD3D->CreateDevice(
		D3DADAPTER_DEFAULT, // 默认适配器
		D3DDEVTYPE_HAL, // 硬件驱动
		hwnd, // 窗体
		D3DCREATE_SOFTWARE_VERTEXPROCESSING, // 顶点像素渲染方式
		&d3dpp, // 参数
		&pD3DDevice); // 返回的设备接口
	if (FAILED(hr)) goto ret;

	// 设置剔除模式为NONE,这样可以看到三角形背面
	pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
	// 关闭光照系统,这样可以显示出本身的颜色
	pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);

	// 初始化顶点缓冲区
	hr = InitVB();
	if (FAILED(hr)) goto ret;

ret:
	return hr;
}

// 设置世界、观察、投影变换矩阵
void SetupMatrices()
{
	HRESULT hr;

	// 设定世界变换矩阵为沿Y轴不停旋转
	D3DXMATRIXA16 matWorld;
	UINT iTime = timeGetTime() % 1000;
	FLOAT fAngle = iTime * (2.0f * D3DX_PI) / 1000.0f;
	D3DXMatrixRotationX(&matWorld, fAngle);
	hr = pD3DDevice->SetTransform(D3DTS_WORLD, &matWorld);

	// 设定观察变换矩阵
	D3DXMATRIXA16 matView;
	D3DXVECTOR3 vEyePt(0.0f, 3.0f, -5.0f); // 眼睛的位置
	D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f); //观察的位置
	D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f); //向上的方向
	D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);
	hr = pD3DDevice->SetTransform(D3DTS_VIEW, &matView);

	// 设定投影变换矩阵
	D3DXMATRIXA16 matProj;
	// 距离缩小比例、屏幕纵横比、最近剪切平面、最远剪切平面
	D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f);
	hr = pD3DDevice->SetTransform(D3DTS_PROJECTION, &matProj);
}

// 绘制图形
void Render()
{
	HRESULT hr = S_OK;

	if (pD3DDevice == NULL)
		goto ret;

	// 清空缓存
	hr = pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET,
		D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);

	// 开始绘制场景
	hr = pD3DDevice->BeginScene();
	if (FAILED(hr)) goto present;

	// 设置变换矩阵
	SetupMatrices();

	// 绘制三角形
	// 设置数据流0为pVB
	hr = pD3DDevice->SetStreamSource(0, pVB, 0, sizeof(CUSTOMVERTEX));
	// 设置顶点格式
	hr = pD3DDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
	// 按三角形列表绘制数据流0
	hr = pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2 * 50 - 2);

	// 结束绘制场景
	hr = pD3DDevice->EndScene();

present:
	// 显示缓存内容
	hr = pD3DDevice->Present(NULL, NULL, NULL, NULL);

ret:
	return;
}

// 清理Direct3D
void CleanupD3D()
{
	safe_release(&pVB);
	safe_release(&pD3DDevice);
	safe_release(&pD3D);
}

///////////////////////////////////////
</d3dx9.h></code>

补充解决办法——

添加深度缓冲区支持即可解决莫比乌斯环问题。

效果:

d3d_d.png

<code class="language-cpp">// 在InitD3D函数中加上这几句

d3dpp.EnableAutoDepthStencil = TRUE; // 开启深度模板
d3dpp.AutoDepthStencilFormat = D3DFMT_D16; // 16位

// ...

// 打开zbuffer
pD3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);

// 在Render函数中将

// 清空缓存
hr = pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET,
	D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);

// 改为

// 清空缓存
hr = pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
	D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);
</code>
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
7年9个月前 修改于 7年7个月前 IP:四川
824534

添加光照效果

d3d_e.png

主要在Render中调用SetupLights设置了材质和光照。

除此之外,进行了如下修改:

  1. 将CUSTOMVERTEX中color替换成了normal法向量(D3DFVF_NORMAL)
  2. 在InitD3D中对normal法向量进行初始化
  3. 在InitD3D中注释掉了关闭光照系统的代码
<code class="language-cpp">///////////////////////////////////////

LPDIRECT3D9 pD3D = NULL;
LPDIRECT3DDEVICE9 pD3DDevice = NULL;
LPDIRECT3DVERTEXBUFFER9 pVB = NULL; // 顶点缓冲区实例

#include <d3dx9.h>
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib, "winmm.lib") // timeGetTime

// 自定义顶点结构体
struct CUSTOMVERTEX
{
	D3DXVECTOR3 position; // 未变换的x,y,z
	D3DXVECTOR3 normal; // 表面法向量
};

// 自定义顶点格式
// 未变换顶点+表面法向量
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL)

///////////////////////////////////////

// 初始化顶点缓冲区(被InitD3D调用)
HRESULT InitVB()
{
	HRESULT hr = S_OK;

	// 创建顶点缓冲区
	hr = pD3DDevice->CreateVertexBuffer(
		50 * 2 * sizeof(CUSTOMVERTEX), // 大小
		0, // 怎样使用缓存的额外信息
		D3DFVF_CUSTOMVERTEX, // 自定义顶点格式
		D3DPOOL_DEFAULT, // 顶点缓冲存储方式
		&pVB, // 返回顶点缓存实例
		NULL); // 保留
	if (FAILED(hr)) goto ret;

	// 锁定并获取缓冲区指针
	CUSTOMVERTEX *pVertices = NULL;
	hr = pVB->Lock(0, 0, (void**)&pVertices, 0);
	if (FAILED(hr)) goto ret;

	// 在缓冲区写入圆柱面的数据
	for (DWORD i = 0; i < 50; i++)
	{
		FLOAT theta = (2 * D3DX_PI * i) / (50 - 1);
		pVertices[2 * i].position = D3DXVECTOR3(sinf(theta), -1.0f, cosf(theta));
		pVertices[2 * i].normal = D3DXVECTOR3(sinf(theta), 0, cosf(theta));
		pVertices[2 * i + 1].position = D3DXVECTOR3(sinf(theta), 1.0f, cosf(theta));
		pVertices[2 * i + 1].normal = D3DXVECTOR3(sinf(theta), 0, cosf(theta));
	}

	// 释放锁定
	hr = pVB->Unlock();
	if (FAILED(hr)) goto ret;

ret:
	return hr;
}

// 初始化Direct3D
HRESULT InitD3D(HWND hwnd)
{
	HRESULT hr = S_OK;

	// 创建Direct3D 9根接口
	pD3D = Direct3DCreate9(D3D_SDK_VERSION);
	if (pD3D == NULL)
	{
		hr = E_FAIL;
		goto ret;
	}

	// 配置Direct3D 9设备
	D3DPRESENT_PARAMETERS d3dpp;
	RtlZeroMemory(&d3dpp, sizeof d3dpp);
	d3dpp.Windowed = TRUE; // 窗口化
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // 交换缓冲加载后被删除
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; // 显示模式
	d3dpp.EnableAutoDepthStencil = TRUE; // 开启深度模板
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16; // 16位

	// 创建Direct3D 9设备接口
	hr = pD3D->CreateDevice(
		D3DADAPTER_DEFAULT, // 默认适配器
		D3DDEVTYPE_HAL, // 硬件驱动
		hwnd, // 窗体
		D3DCREATE_SOFTWARE_VERTEXPROCESSING, // 顶点像素渲染方式
		&d3dpp, // 参数
		&pD3DDevice); // 返回的设备接口
	if (FAILED(hr)) goto ret;

	// 设置剔除模式为NONE,这样可以看到三角形背面
	pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
	// 关闭光照系统,这样可以显示出本身的颜色(注释掉)
	//pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
	// 打开zbuffer
	pD3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);

	// 初始化顶点缓冲区
	hr = InitVB();
	if (FAILED(hr)) goto ret;

ret:
	return hr;
}

// 设置世界、观察、投影变换矩阵
void SetupMatrices()
{
	HRESULT hr;

	// 设定世界变换矩阵为沿Y轴不停旋转
	D3DXMATRIXA16 matWorld;
	UINT iTime = timeGetTime() % 1000;
	FLOAT fAngle = iTime * (2.0f * D3DX_PI) / 1000.0f;
	D3DXMatrixRotationX(&matWorld, fAngle);
	hr = pD3DDevice->SetTransform(D3DTS_WORLD, &matWorld);

	// 设定观察变换矩阵
	D3DXMATRIXA16 matView;
	D3DXVECTOR3 vEyePt(0.0f, 3.0f, -5.0f); // 眼睛的位置
	D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f); //观察的位置
	D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f); //向上的方向
	D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);
	hr = pD3DDevice->SetTransform(D3DTS_VIEW, &matView);

	// 设定投影变换矩阵
	D3DXMATRIXA16 matProj;
	// 距离缩小比例、屏幕纵横比、最近剪切平面、最远剪切平面
	D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f);
	hr = pD3DDevice->SetTransform(D3DTS_PROJECTION, &matProj);
}

// 设置材质和光照
void SetupLights()
{
	// 设置材质
	D3DMATERIAL9 mtrl;
	ZeroMemory(&mtrl, sizeof(D3DMATERIAL9));
	mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;
	mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;
	mtrl.Diffuse.b = mtrl.Ambient.b = 0.0f;
	mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;
	pD3DDevice->SetMaterial(&mtrl);

	// 设置平行光照
	D3DXVECTOR3 vecDir;
	D3DLIGHT9 light;
	ZeroMemory(&light, sizeof(D3DLIGHT9));
	light.Type = D3DLIGHT_DIRECTIONAL;
	light.Diffuse.r = 1.0f;
	light.Diffuse.g = 1.0f;
	light.Diffuse.b = 1.0f;
	vecDir = D3DXVECTOR3(cosf(timeGetTime() / 350.0f),
		1.0f,
		sinf(timeGetTime() / 350.0f));
	D3DXVec3Normalize((D3DXVECTOR3*)&light.Direction, &vecDir);
	light.Range = 1000.0f;
	pD3DDevice->SetLight(0, &light);
	pD3DDevice->LightEnable(0, TRUE);
	pD3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);

	// 设置微弱均匀光照(以免物体阴影处太暗)
	pD3DDevice->SetRenderState(D3DRS_AMBIENT, 0x00202020);
}

// 绘制图形
void Render()
{
	HRESULT hr = S_OK;

	if (pD3DDevice == NULL)
		goto ret;

	// 清空缓存
	hr = pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
		D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);

	// 开始绘制场景
	hr = pD3DDevice->BeginScene();
	if (FAILED(hr)) goto present;

	// 设置材质和光照
	SetupLights();

	// 设置变换矩阵
	SetupMatrices();

	// 绘制三角形
	// 设置数据流0为pVB
	hr = pD3DDevice->SetStreamSource(0, pVB, 0, sizeof(CUSTOMVERTEX));
	// 设置顶点格式
	hr = pD3DDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
	// 按三角形列表绘制数据流0
	hr = pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2 * 50 - 2);

	// 结束绘制场景
	hr = pD3DDevice->EndScene();

present:
	// 显示缓存内容
	hr = pD3DDevice->Present(NULL, NULL, NULL, NULL);

ret:
	return;
}

// 清理Direct3D
void CleanupD3D()
{
	safe_release(&pVB);
	safe_release(&pD3DDevice);
	safe_release(&pD3D);
}

///////////////////////////////////////
</d3dx9.h></code>
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
7年9个月前 修改于 7年7个月前 IP:四川
824536

然后。。。

这个帖子中完成了Direct3D 9 Tutorial中的Tutorial 1-4(CreateDevice、Vertices、Matrices、Lights),后面还有两个入门示例Tutorial 5: Textures、Tutorial 6: Meshes。

除此之外,DirectX SDK自带的DirectX Sample Browser中还有不少入门示例,有兴趣的同学可以进行更深入的研究学习。

API参考:Windows DirectX Graphics Documentation

SDK参考:DirectX Documentation for C++

d3d_sample.png

d3d_doc1.png

d3d_doc2.png

引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
所属分类
上级专业
同级专业
acmilan
进士 学者 笔友
文章
461
回复
2934
学术分
4
2009/05/30注册,5年3个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}